1c487da1eSNeel Natu /*- 2*eebd9d53SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 31de7b4b8SPedro F. Giffuni * 4c487da1eSNeel Natu * Copyright (c) 2011 NetApp, Inc. 5c487da1eSNeel Natu * All rights reserved. 6c487da1eSNeel Natu * 7c487da1eSNeel Natu * Redistribution and use in source and binary forms, with or without 8c487da1eSNeel Natu * modification, are permitted provided that the following conditions 9c487da1eSNeel Natu * are met: 10c487da1eSNeel Natu * 1. Redistributions of source code must retain the above copyright 11c487da1eSNeel Natu * notice, this list of conditions and the following disclaimer. 12c487da1eSNeel Natu * 2. Redistributions in binary form must reproduce the above copyright 13c487da1eSNeel Natu * notice, this list of conditions and the following disclaimer in the 14c487da1eSNeel Natu * documentation and/or other materials provided with the distribution. 15c487da1eSNeel Natu * 16c487da1eSNeel Natu * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND 17c487da1eSNeel Natu * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18c487da1eSNeel Natu * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19c487da1eSNeel Natu * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE 20c487da1eSNeel Natu * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21c487da1eSNeel Natu * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22c487da1eSNeel Natu * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23c487da1eSNeel Natu * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24c487da1eSNeel Natu * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25c487da1eSNeel Natu * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26c487da1eSNeel Natu * SUCH DAMAGE. 27c487da1eSNeel Natu * 28c487da1eSNeel Natu * $FreeBSD$ 29c487da1eSNeel Natu */ 30c487da1eSNeel Natu 31c487da1eSNeel Natu /*- 32c487da1eSNeel Natu * Copyright (c) 2011 Google, Inc. 33c487da1eSNeel Natu * All rights reserved. 34c487da1eSNeel Natu * 35c487da1eSNeel Natu * Redistribution and use in source and binary forms, with or without 36c487da1eSNeel Natu * modification, are permitted provided that the following conditions 37c487da1eSNeel Natu * are met: 38c487da1eSNeel Natu * 1. Redistributions of source code must retain the above copyright 39c487da1eSNeel Natu * notice, this list of conditions and the following disclaimer. 40c487da1eSNeel Natu * 2. Redistributions in binary form must reproduce the above copyright 41c487da1eSNeel Natu * notice, this list of conditions and the following disclaimer in the 42c487da1eSNeel Natu * documentation and/or other materials provided with the distribution. 43c487da1eSNeel Natu * 44c487da1eSNeel Natu * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 45c487da1eSNeel Natu * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 46c487da1eSNeel Natu * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 47c487da1eSNeel Natu * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 48c487da1eSNeel Natu * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 49c487da1eSNeel Natu * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 50c487da1eSNeel Natu * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 51c487da1eSNeel Natu * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 52c487da1eSNeel Natu * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 53c487da1eSNeel Natu * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 54c487da1eSNeel Natu * SUCH DAMAGE. 55c487da1eSNeel Natu * 56c487da1eSNeel Natu * $FreeBSD$ 57c487da1eSNeel Natu */ 58c487da1eSNeel Natu 59c487da1eSNeel Natu #include <sys/cdefs.h> 60c487da1eSNeel Natu __FBSDID("$FreeBSD$"); 61c487da1eSNeel Natu 62c487da1eSNeel Natu #include <sys/ioctl.h> 63c487da1eSNeel Natu #include <sys/stat.h> 64a10c6f55SNeel Natu #include <sys/disk.h> 65b6afa84bSNeel Natu #include <sys/queue.h> 66c487da1eSNeel Natu 67c487da1eSNeel Natu #include <machine/specialreg.h> 68c487da1eSNeel Natu #include <machine/vmm.h> 69c487da1eSNeel Natu 707d9ef309SJohn Baldwin #include <assert.h> 71c487da1eSNeel Natu #include <dirent.h> 72c487da1eSNeel Natu #include <dlfcn.h> 73c487da1eSNeel Natu #include <errno.h> 74200758f1SNeel Natu #include <err.h> 75c487da1eSNeel Natu #include <fcntl.h> 76c487da1eSNeel Natu #include <getopt.h> 77b5331f4dSNeel Natu #include <libgen.h> 78c487da1eSNeel Natu #include <limits.h> 79d3d381b2SKyle Evans #include <setjmp.h> 80c487da1eSNeel Natu #include <stdio.h> 81c487da1eSNeel Natu #include <stdlib.h> 82c487da1eSNeel Natu #include <string.h> 83200758f1SNeel Natu #include <sysexits.h> 84c487da1eSNeel Natu #include <termios.h> 85c487da1eSNeel Natu #include <unistd.h> 86c487da1eSNeel Natu 87c487da1eSNeel Natu #include <vmmapi.h> 88c487da1eSNeel Natu 89c487da1eSNeel Natu #include "userboot.h" 90c487da1eSNeel Natu 91c487da1eSNeel Natu #define MB (1024 * 1024UL) 92c487da1eSNeel Natu #define GB (1024 * 1024 * 1024UL) 93c487da1eSNeel Natu #define BSP 0 94c487da1eSNeel Natu 95cf087c12SPeter Grehan #define NDISKS 32 96cf087c12SPeter Grehan 97384305ffSPeter Grehan static char *host_base; 98c487da1eSNeel Natu static struct termios term, oldterm; 99cf087c12SPeter Grehan static int disk_fd[NDISKS]; 100cf087c12SPeter Grehan static int ndisks; 1016380102cSPeter Grehan static int consin_fd, consout_fd; 102c487da1eSNeel Natu 103d3d381b2SKyle Evans static int need_reinit; 104d3d381b2SKyle Evans 105d3d381b2SKyle Evans static void *loader_hdl; 106d3d381b2SKyle Evans static char *loader; 107d3d381b2SKyle Evans static int explicit_loader; 108d3d381b2SKyle Evans static jmp_buf jb; 109d3d381b2SKyle Evans 110b060ba50SNeel Natu static char *vmname, *progname; 111c487da1eSNeel Natu static struct vmctx *ctx; 1127d9ef309SJohn Baldwin static struct vcpu *vcpu; 113c487da1eSNeel Natu 114c487da1eSNeel Natu static uint64_t gdtbase, cr3, rsp; 115c487da1eSNeel Natu 116c487da1eSNeel Natu static void cb_exit(void *arg, int v); 117c487da1eSNeel Natu 118c487da1eSNeel Natu /* 119c487da1eSNeel Natu * Console i/o callbacks 120c487da1eSNeel Natu */ 121c487da1eSNeel Natu 122c487da1eSNeel Natu static void 123ad43dd69SMark Johnston cb_putc(void *arg __unused, int ch) 124c487da1eSNeel Natu { 125c487da1eSNeel Natu char c = ch; 126c487da1eSNeel Natu 1276380102cSPeter Grehan (void) write(consout_fd, &c, 1); 128c487da1eSNeel Natu } 129c487da1eSNeel Natu 130c487da1eSNeel Natu static int 131ad43dd69SMark Johnston cb_getc(void *arg __unused) 132c487da1eSNeel Natu { 133c487da1eSNeel Natu char c; 134c487da1eSNeel Natu 1356380102cSPeter Grehan if (read(consin_fd, &c, 1) == 1) 136c487da1eSNeel Natu return (c); 137c487da1eSNeel Natu return (-1); 138c487da1eSNeel Natu } 139c487da1eSNeel Natu 140c487da1eSNeel Natu static int 141ad43dd69SMark Johnston cb_poll(void *arg __unused) 142c487da1eSNeel Natu { 143c487da1eSNeel Natu int n; 144c487da1eSNeel Natu 1456380102cSPeter Grehan if (ioctl(consin_fd, FIONREAD, &n) >= 0) 146c487da1eSNeel Natu return (n > 0); 147c487da1eSNeel Natu return (0); 148c487da1eSNeel Natu } 149c487da1eSNeel Natu 150c487da1eSNeel Natu /* 151c487da1eSNeel Natu * Host filesystem i/o callbacks 152c487da1eSNeel Natu */ 153c487da1eSNeel Natu 154c487da1eSNeel Natu struct cb_file { 155c487da1eSNeel Natu int cf_isdir; 156c487da1eSNeel Natu size_t cf_size; 157c487da1eSNeel Natu struct stat cf_stat; 158c487da1eSNeel Natu union { 159c487da1eSNeel Natu int fd; 160c487da1eSNeel Natu DIR *dir; 161c487da1eSNeel Natu } cf_u; 162c487da1eSNeel Natu }; 163c487da1eSNeel Natu 164c487da1eSNeel Natu static int 165ad43dd69SMark Johnston cb_open(void *arg __unused, const char *filename, void **hp) 166c487da1eSNeel Natu { 167c487da1eSNeel Natu struct cb_file *cf; 168c487da1eSNeel Natu char path[PATH_MAX]; 169c487da1eSNeel Natu 170c487da1eSNeel Natu if (!host_base) 171c487da1eSNeel Natu return (ENOENT); 172c487da1eSNeel Natu 173c487da1eSNeel Natu strlcpy(path, host_base, PATH_MAX); 174c487da1eSNeel Natu if (path[strlen(path) - 1] == '/') 175c487da1eSNeel Natu path[strlen(path) - 1] = 0; 176c487da1eSNeel Natu strlcat(path, filename, PATH_MAX); 177c487da1eSNeel Natu cf = malloc(sizeof(struct cb_file)); 178c487da1eSNeel Natu if (stat(path, &cf->cf_stat) < 0) { 179c487da1eSNeel Natu free(cf); 180c487da1eSNeel Natu return (errno); 181c487da1eSNeel Natu } 182c487da1eSNeel Natu 1838f61276dSPedro F. Giffuni cf->cf_size = cf->cf_stat.st_size; 184c487da1eSNeel Natu if (S_ISDIR(cf->cf_stat.st_mode)) { 185c487da1eSNeel Natu cf->cf_isdir = 1; 186c487da1eSNeel Natu cf->cf_u.dir = opendir(path); 187c487da1eSNeel Natu if (!cf->cf_u.dir) 188c487da1eSNeel Natu goto out; 189c487da1eSNeel Natu *hp = cf; 190c487da1eSNeel Natu return (0); 191c487da1eSNeel Natu } 192c487da1eSNeel Natu if (S_ISREG(cf->cf_stat.st_mode)) { 193c487da1eSNeel Natu cf->cf_isdir = 0; 194c487da1eSNeel Natu cf->cf_u.fd = open(path, O_RDONLY); 195c487da1eSNeel Natu if (cf->cf_u.fd < 0) 196c487da1eSNeel Natu goto out; 197c487da1eSNeel Natu *hp = cf; 198c487da1eSNeel Natu return (0); 199c487da1eSNeel Natu } 200c487da1eSNeel Natu 201c487da1eSNeel Natu out: 202c487da1eSNeel Natu free(cf); 203c487da1eSNeel Natu return (EINVAL); 204c487da1eSNeel Natu } 205c487da1eSNeel Natu 206c487da1eSNeel Natu static int 207ad43dd69SMark Johnston cb_close(void *arg __unused, void *h) 208c487da1eSNeel Natu { 209c487da1eSNeel Natu struct cb_file *cf = h; 210c487da1eSNeel Natu 211c487da1eSNeel Natu if (cf->cf_isdir) 212c487da1eSNeel Natu closedir(cf->cf_u.dir); 213c487da1eSNeel Natu else 214c487da1eSNeel Natu close(cf->cf_u.fd); 215c487da1eSNeel Natu free(cf); 216c487da1eSNeel Natu 217c487da1eSNeel Natu return (0); 218c487da1eSNeel Natu } 219c487da1eSNeel Natu 220c487da1eSNeel Natu static int 221ad43dd69SMark Johnston cb_isdir(void *arg __unused, void *h) 222c487da1eSNeel Natu { 223c487da1eSNeel Natu struct cb_file *cf = h; 224c487da1eSNeel Natu 225c487da1eSNeel Natu return (cf->cf_isdir); 226c487da1eSNeel Natu } 227c487da1eSNeel Natu 228c487da1eSNeel Natu static int 229ad43dd69SMark Johnston cb_read(void *arg __unused, void *h, void *buf, size_t size, size_t *resid) 230c487da1eSNeel Natu { 231c487da1eSNeel Natu struct cb_file *cf = h; 232c487da1eSNeel Natu ssize_t sz; 233c487da1eSNeel Natu 234c487da1eSNeel Natu if (cf->cf_isdir) 235c487da1eSNeel Natu return (EINVAL); 236c487da1eSNeel Natu sz = read(cf->cf_u.fd, buf, size); 237c487da1eSNeel Natu if (sz < 0) 238c487da1eSNeel Natu return (EINVAL); 239c487da1eSNeel Natu *resid = size - sz; 240c487da1eSNeel Natu return (0); 241c487da1eSNeel Natu } 242c487da1eSNeel Natu 243c487da1eSNeel Natu static int 244ad43dd69SMark Johnston cb_readdir(void *arg __unused, void *h, uint32_t *fileno_return, 245ad43dd69SMark Johnston uint8_t *type_return, size_t *namelen_return, char *name) 246c487da1eSNeel Natu { 247c487da1eSNeel Natu struct cb_file *cf = h; 248c487da1eSNeel Natu struct dirent *dp; 249c487da1eSNeel Natu 250c487da1eSNeel Natu if (!cf->cf_isdir) 251c487da1eSNeel Natu return (EINVAL); 252c487da1eSNeel Natu 253c487da1eSNeel Natu dp = readdir(cf->cf_u.dir); 254c487da1eSNeel Natu if (!dp) 255c487da1eSNeel Natu return (ENOENT); 256c487da1eSNeel Natu 257c487da1eSNeel Natu /* 258c487da1eSNeel Natu * Note: d_namlen is in the range 0..255 and therefore less 259c487da1eSNeel Natu * than PATH_MAX so we don't need to test before copying. 260c487da1eSNeel Natu */ 261c487da1eSNeel Natu *fileno_return = dp->d_fileno; 262c487da1eSNeel Natu *type_return = dp->d_type; 263c487da1eSNeel Natu *namelen_return = dp->d_namlen; 264c487da1eSNeel Natu memcpy(name, dp->d_name, dp->d_namlen); 265c487da1eSNeel Natu name[dp->d_namlen] = 0; 266c487da1eSNeel Natu 267c487da1eSNeel Natu return (0); 268c487da1eSNeel Natu } 269c487da1eSNeel Natu 270c487da1eSNeel Natu static int 271ad43dd69SMark Johnston cb_seek(void *arg __unused, void *h, uint64_t offset, int whence) 272c487da1eSNeel Natu { 273c487da1eSNeel Natu struct cb_file *cf = h; 274c487da1eSNeel Natu 275c487da1eSNeel Natu if (cf->cf_isdir) 276c487da1eSNeel Natu return (EINVAL); 277c487da1eSNeel Natu if (lseek(cf->cf_u.fd, offset, whence) < 0) 278c487da1eSNeel Natu return (errno); 279c487da1eSNeel Natu return (0); 280c487da1eSNeel Natu } 281c487da1eSNeel Natu 282c487da1eSNeel Natu static int 283ad43dd69SMark Johnston cb_stat(void *arg __unused, void *h, struct stat *sbp) 284c487da1eSNeel Natu { 285c487da1eSNeel Natu struct cb_file *cf = h; 286c487da1eSNeel Natu 28753f151f9SSimon J. Gerraty memset(sbp, 0, sizeof(struct stat)); 28853f151f9SSimon J. Gerraty sbp->st_mode = cf->cf_stat.st_mode; 28953f151f9SSimon J. Gerraty sbp->st_uid = cf->cf_stat.st_uid; 29053f151f9SSimon J. Gerraty sbp->st_gid = cf->cf_stat.st_gid; 29153f151f9SSimon J. Gerraty sbp->st_size = cf->cf_stat.st_size; 29253f151f9SSimon J. Gerraty sbp->st_mtime = cf->cf_stat.st_mtime; 29353f151f9SSimon J. Gerraty sbp->st_dev = cf->cf_stat.st_dev; 29453f151f9SSimon J. Gerraty sbp->st_ino = cf->cf_stat.st_ino; 29553f151f9SSimon J. Gerraty 296c487da1eSNeel Natu return (0); 297c487da1eSNeel Natu } 298c487da1eSNeel Natu 299c487da1eSNeel Natu /* 300c487da1eSNeel Natu * Disk image i/o callbacks 301c487da1eSNeel Natu */ 302c487da1eSNeel Natu 303c487da1eSNeel Natu static int 304ad43dd69SMark Johnston cb_diskread(void *arg __unused, int unit, uint64_t from, void *to, size_t size, 305c487da1eSNeel Natu size_t *resid) 306c487da1eSNeel Natu { 307c487da1eSNeel Natu ssize_t n; 308c487da1eSNeel Natu 309cf087c12SPeter Grehan if (unit < 0 || unit >= ndisks) 310c487da1eSNeel Natu return (EIO); 311cf087c12SPeter Grehan n = pread(disk_fd[unit], to, size, from); 312c487da1eSNeel Natu if (n < 0) 313c487da1eSNeel Natu return (errno); 314c487da1eSNeel Natu *resid = size - n; 315c487da1eSNeel Natu return (0); 316c487da1eSNeel Natu } 317c487da1eSNeel Natu 318a10c6f55SNeel Natu static int 319ad43dd69SMark Johnston cb_diskwrite(void *arg __unused, int unit, uint64_t offset, void *src, 320ad43dd69SMark Johnston size_t size, size_t *resid) 321cc71ff72SConrad Meyer { 322cc71ff72SConrad Meyer ssize_t n; 323cc71ff72SConrad Meyer 324cc71ff72SConrad Meyer if (unit < 0 || unit >= ndisks) 325cc71ff72SConrad Meyer return (EIO); 326cc71ff72SConrad Meyer n = pwrite(disk_fd[unit], src, size, offset); 327cc71ff72SConrad Meyer if (n < 0) 328cc71ff72SConrad Meyer return (errno); 329cc71ff72SConrad Meyer *resid = size - n; 330cc71ff72SConrad Meyer return (0); 331cc71ff72SConrad Meyer } 332cc71ff72SConrad Meyer 333cc71ff72SConrad Meyer static int 334ad43dd69SMark Johnston cb_diskioctl(void *arg __unused, int unit, u_long cmd, void *data) 335a10c6f55SNeel Natu { 336a10c6f55SNeel Natu struct stat sb; 337a10c6f55SNeel Natu 338cf087c12SPeter Grehan if (unit < 0 || unit >= ndisks) 339a10c6f55SNeel Natu return (EBADF); 340a10c6f55SNeel Natu 341a10c6f55SNeel Natu switch (cmd) { 342a10c6f55SNeel Natu case DIOCGSECTORSIZE: 343a10c6f55SNeel Natu *(u_int *)data = 512; 344a10c6f55SNeel Natu break; 345a10c6f55SNeel Natu case DIOCGMEDIASIZE: 3466589ee29SAndriy Gapon if (fstat(disk_fd[unit], &sb) != 0) 347a10c6f55SNeel Natu return (ENOTTY); 3486589ee29SAndriy Gapon if (S_ISCHR(sb.st_mode) && 3496589ee29SAndriy Gapon ioctl(disk_fd[unit], DIOCGMEDIASIZE, &sb.st_size) != 0) 3506589ee29SAndriy Gapon return (ENOTTY); 3516589ee29SAndriy Gapon *(off_t *)data = sb.st_size; 352a10c6f55SNeel Natu break; 353a10c6f55SNeel Natu default: 354a10c6f55SNeel Natu return (ENOTTY); 355a10c6f55SNeel Natu } 356a10c6f55SNeel Natu 357a10c6f55SNeel Natu return (0); 358a10c6f55SNeel Natu } 359a10c6f55SNeel Natu 360c487da1eSNeel Natu /* 361c487da1eSNeel Natu * Guest virtual machine i/o callbacks 362c487da1eSNeel Natu */ 363c487da1eSNeel Natu static int 364ad43dd69SMark Johnston cb_copyin(void *arg __unused, const void *from, uint64_t to, size_t size) 365c487da1eSNeel Natu { 366b060ba50SNeel Natu char *ptr; 367c487da1eSNeel Natu 368c487da1eSNeel Natu to &= 0x7fffffff; 369b060ba50SNeel Natu 370b060ba50SNeel Natu ptr = vm_map_gpa(ctx, to, size); 371b060ba50SNeel Natu if (ptr == NULL) 372c487da1eSNeel Natu return (EFAULT); 373c487da1eSNeel Natu 374b060ba50SNeel Natu memcpy(ptr, from, size); 375c487da1eSNeel Natu return (0); 376c487da1eSNeel Natu } 377c487da1eSNeel Natu 378c487da1eSNeel Natu static int 379ad43dd69SMark Johnston cb_copyout(void *arg __unused, uint64_t from, void *to, size_t size) 380c487da1eSNeel Natu { 381b060ba50SNeel Natu char *ptr; 382c487da1eSNeel Natu 383c487da1eSNeel Natu from &= 0x7fffffff; 384b060ba50SNeel Natu 385b060ba50SNeel Natu ptr = vm_map_gpa(ctx, from, size); 386b060ba50SNeel Natu if (ptr == NULL) 387c487da1eSNeel Natu return (EFAULT); 388c487da1eSNeel Natu 389b060ba50SNeel Natu memcpy(to, ptr, size); 390c487da1eSNeel Natu return (0); 391c487da1eSNeel Natu } 392c487da1eSNeel Natu 393c487da1eSNeel Natu static void 394ad43dd69SMark Johnston cb_setreg(void *arg __unused, int r, uint64_t v) 395c487da1eSNeel Natu { 396c487da1eSNeel Natu int error; 397c487da1eSNeel Natu enum vm_reg_name vmreg; 398c487da1eSNeel Natu 399c487da1eSNeel Natu vmreg = VM_REG_LAST; 400c487da1eSNeel Natu 401c487da1eSNeel Natu switch (r) { 402c487da1eSNeel Natu case 4: 403c487da1eSNeel Natu vmreg = VM_REG_GUEST_RSP; 404c487da1eSNeel Natu rsp = v; 405c487da1eSNeel Natu break; 406c487da1eSNeel Natu default: 407c487da1eSNeel Natu break; 408c487da1eSNeel Natu } 409c487da1eSNeel Natu 410c487da1eSNeel Natu if (vmreg == VM_REG_LAST) { 411c487da1eSNeel Natu printf("test_setreg(%d): not implemented\n", r); 412c487da1eSNeel Natu cb_exit(NULL, USERBOOT_EXIT_QUIT); 413c487da1eSNeel Natu } 414c487da1eSNeel Natu 4157d9ef309SJohn Baldwin error = vm_set_register(vcpu, vmreg, v); 416c487da1eSNeel Natu if (error) { 417c487da1eSNeel Natu perror("vm_set_register"); 418c487da1eSNeel Natu cb_exit(NULL, USERBOOT_EXIT_QUIT); 419c487da1eSNeel Natu } 420c487da1eSNeel Natu } 421c487da1eSNeel Natu 422c487da1eSNeel Natu static void 423ad43dd69SMark Johnston cb_setmsr(void *arg __unused, int r, uint64_t v) 424c487da1eSNeel Natu { 425c487da1eSNeel Natu int error; 426c487da1eSNeel Natu enum vm_reg_name vmreg; 427c487da1eSNeel Natu 428c487da1eSNeel Natu vmreg = VM_REG_LAST; 429c487da1eSNeel Natu 430c487da1eSNeel Natu switch (r) { 431c487da1eSNeel Natu case MSR_EFER: 432c487da1eSNeel Natu vmreg = VM_REG_GUEST_EFER; 433c487da1eSNeel Natu break; 434c487da1eSNeel Natu default: 435c487da1eSNeel Natu break; 436c487da1eSNeel Natu } 437c487da1eSNeel Natu 438c487da1eSNeel Natu if (vmreg == VM_REG_LAST) { 439c487da1eSNeel Natu printf("test_setmsr(%d): not implemented\n", r); 440c487da1eSNeel Natu cb_exit(NULL, USERBOOT_EXIT_QUIT); 441c487da1eSNeel Natu } 442c487da1eSNeel Natu 4437d9ef309SJohn Baldwin error = vm_set_register(vcpu, vmreg, v); 444c487da1eSNeel Natu if (error) { 445c487da1eSNeel Natu perror("vm_set_msr"); 446c487da1eSNeel Natu cb_exit(NULL, USERBOOT_EXIT_QUIT); 447c487da1eSNeel Natu } 448c487da1eSNeel Natu } 449c487da1eSNeel Natu 450c487da1eSNeel Natu static void 451ad43dd69SMark Johnston cb_setcr(void *arg __unused, int r, uint64_t v) 452c487da1eSNeel Natu { 453c487da1eSNeel Natu int error; 454c487da1eSNeel Natu enum vm_reg_name vmreg; 455c487da1eSNeel Natu 456c487da1eSNeel Natu vmreg = VM_REG_LAST; 457c487da1eSNeel Natu 458c487da1eSNeel Natu switch (r) { 459c487da1eSNeel Natu case 0: 460c487da1eSNeel Natu vmreg = VM_REG_GUEST_CR0; 461c487da1eSNeel Natu break; 462c487da1eSNeel Natu case 3: 463c487da1eSNeel Natu vmreg = VM_REG_GUEST_CR3; 464c487da1eSNeel Natu cr3 = v; 465c487da1eSNeel Natu break; 466c487da1eSNeel Natu case 4: 467c487da1eSNeel Natu vmreg = VM_REG_GUEST_CR4; 468c487da1eSNeel Natu break; 469c487da1eSNeel Natu default: 470c487da1eSNeel Natu break; 471c487da1eSNeel Natu } 472c487da1eSNeel Natu 473c487da1eSNeel Natu if (vmreg == VM_REG_LAST) { 474c487da1eSNeel Natu printf("test_setcr(%d): not implemented\n", r); 475c487da1eSNeel Natu cb_exit(NULL, USERBOOT_EXIT_QUIT); 476c487da1eSNeel Natu } 477c487da1eSNeel Natu 4787d9ef309SJohn Baldwin error = vm_set_register(vcpu, vmreg, v); 479c487da1eSNeel Natu if (error) { 480c487da1eSNeel Natu perror("vm_set_cr"); 481c487da1eSNeel Natu cb_exit(NULL, USERBOOT_EXIT_QUIT); 482c487da1eSNeel Natu } 483c487da1eSNeel Natu } 484c487da1eSNeel Natu 485c487da1eSNeel Natu static void 486ad43dd69SMark Johnston cb_setgdt(void *arg __unused, uint64_t base, size_t size) 487c487da1eSNeel Natu { 488c487da1eSNeel Natu int error; 489c487da1eSNeel Natu 4907d9ef309SJohn Baldwin error = vm_set_desc(vcpu, VM_REG_GUEST_GDTR, base, size - 1, 0); 491c487da1eSNeel Natu if (error != 0) { 492c487da1eSNeel Natu perror("vm_set_desc(gdt)"); 493c487da1eSNeel Natu cb_exit(NULL, USERBOOT_EXIT_QUIT); 494c487da1eSNeel Natu } 495c487da1eSNeel Natu 496c487da1eSNeel Natu gdtbase = base; 497c487da1eSNeel Natu } 498c487da1eSNeel Natu 499c487da1eSNeel Natu static void 500ad43dd69SMark Johnston cb_exec(void *arg __unused, uint64_t rip) 501c487da1eSNeel Natu { 502c487da1eSNeel Natu int error; 503c487da1eSNeel Natu 50400f3efe1SJohn Baldwin if (cr3 == 0) 5057d9ef309SJohn Baldwin error = vm_setup_freebsd_registers_i386(vcpu, rip, gdtbase, 50600f3efe1SJohn Baldwin rsp); 50700f3efe1SJohn Baldwin else 5087d9ef309SJohn Baldwin error = vm_setup_freebsd_registers(vcpu, rip, cr3, gdtbase, 50900f3efe1SJohn Baldwin rsp); 510c487da1eSNeel Natu if (error) { 511c487da1eSNeel Natu perror("vm_setup_freebsd_registers"); 512c487da1eSNeel Natu cb_exit(NULL, USERBOOT_EXIT_QUIT); 513c487da1eSNeel Natu } 514c487da1eSNeel Natu 515c487da1eSNeel Natu cb_exit(NULL, 0); 516c487da1eSNeel Natu } 517c487da1eSNeel Natu 518c487da1eSNeel Natu /* 519c487da1eSNeel Natu * Misc 520c487da1eSNeel Natu */ 521c487da1eSNeel Natu 522c487da1eSNeel Natu static void 523ad43dd69SMark Johnston cb_delay(void *arg __unused, int usec) 524c487da1eSNeel Natu { 525c487da1eSNeel Natu 526c487da1eSNeel Natu usleep(usec); 527c487da1eSNeel Natu } 528c487da1eSNeel Natu 529c487da1eSNeel Natu static void 530ad43dd69SMark Johnston cb_exit(void *arg __unused, int v) 531c487da1eSNeel Natu { 532c487da1eSNeel Natu 5336380102cSPeter Grehan tcsetattr(consout_fd, TCSAFLUSH, &oldterm); 534c487da1eSNeel Natu exit(v); 535c487da1eSNeel Natu } 536c487da1eSNeel Natu 537c487da1eSNeel Natu static void 538ad43dd69SMark Johnston cb_getmem(void *arg __unused, uint64_t *ret_lowmem, uint64_t *ret_highmem) 539c487da1eSNeel Natu { 540c487da1eSNeel Natu 541be679db4SNeel Natu *ret_lowmem = vm_get_lowmem_size(ctx); 542be679db4SNeel Natu *ret_highmem = vm_get_highmem_size(ctx); 543c487da1eSNeel Natu } 544c487da1eSNeel Natu 545b6afa84bSNeel Natu struct env { 546cb37fc82SWarner Losh char *str; /* name=value */ 547b6afa84bSNeel Natu SLIST_ENTRY(env) next; 548b6afa84bSNeel Natu }; 549b6afa84bSNeel Natu 550b6afa84bSNeel Natu static SLIST_HEAD(envhead, env) envhead; 551b6afa84bSNeel Natu 552b6afa84bSNeel Natu static void 553ad43dd69SMark Johnston addenv(const char *str) 554b6afa84bSNeel Natu { 555b6afa84bSNeel Natu struct env *env; 556b6afa84bSNeel Natu 557b6afa84bSNeel Natu env = malloc(sizeof(struct env)); 558ad43dd69SMark Johnston if (env == NULL) 559ad43dd69SMark Johnston err(EX_OSERR, "malloc"); 560ad43dd69SMark Johnston env->str = strdup(str); 561ad43dd69SMark Johnston if (env->str == NULL) 562ad43dd69SMark Johnston err(EX_OSERR, "strdup"); 563b6afa84bSNeel Natu SLIST_INSERT_HEAD(&envhead, env, next); 564b6afa84bSNeel Natu } 565b6afa84bSNeel Natu 566e8e6a5f9SWarner Losh static char * 567ad43dd69SMark Johnston cb_getenv(void *arg __unused, int num) 568c3e9ce33SNeel Natu { 569b6afa84bSNeel Natu int i; 570b6afa84bSNeel Natu struct env *env; 571c3e9ce33SNeel Natu 572b6afa84bSNeel Natu i = 0; 573b6afa84bSNeel Natu SLIST_FOREACH(env, &envhead, next) { 574b6afa84bSNeel Natu if (i == num) 575b6afa84bSNeel Natu return (env->str); 576b6afa84bSNeel Natu i++; 577b6afa84bSNeel Natu } 578c3e9ce33SNeel Natu 579c3e9ce33SNeel Natu return (NULL); 580c3e9ce33SNeel Natu } 581c3e9ce33SNeel Natu 58248f337b8SMarcel Moolenaar static int 5837d9ef309SJohn Baldwin cb_vm_set_register(void *arg __unused, int vcpuid, int reg, uint64_t val) 58448f337b8SMarcel Moolenaar { 58548f337b8SMarcel Moolenaar 5867d9ef309SJohn Baldwin assert(vcpuid == BSP); 5877d9ef309SJohn Baldwin return (vm_set_register(vcpu, reg, val)); 58848f337b8SMarcel Moolenaar } 58948f337b8SMarcel Moolenaar 59048f337b8SMarcel Moolenaar static int 5917d9ef309SJohn Baldwin cb_vm_set_desc(void *arg __unused, int vcpuid, int reg, uint64_t base, 592ad43dd69SMark Johnston u_int limit, u_int access) 59348f337b8SMarcel Moolenaar { 59448f337b8SMarcel Moolenaar 5957d9ef309SJohn Baldwin assert(vcpuid == BSP); 5967d9ef309SJohn Baldwin return (vm_set_desc(vcpu, reg, base, limit, access)); 59748f337b8SMarcel Moolenaar } 59848f337b8SMarcel Moolenaar 599d3d381b2SKyle Evans static void 600ad43dd69SMark Johnston cb_swap_interpreter(void *arg __unused, const char *interp_req) 601d3d381b2SKyle Evans { 602d3d381b2SKyle Evans 603d3d381b2SKyle Evans /* 604d3d381b2SKyle Evans * If the user specified a loader but we detected a mismatch, we should 605d3d381b2SKyle Evans * not try to pivot to a different loader on them. 606d3d381b2SKyle Evans */ 607d3d381b2SKyle Evans free(loader); 608d3d381b2SKyle Evans if (explicit_loader == 1) { 609d3d381b2SKyle Evans perror("requested loader interpreter does not match guest userboot"); 610d3d381b2SKyle Evans cb_exit(NULL, 1); 611d3d381b2SKyle Evans } 612d3d381b2SKyle Evans if (interp_req == NULL || *interp_req == '\0') { 613d3d381b2SKyle Evans perror("guest failed to request an interpreter"); 614d3d381b2SKyle Evans cb_exit(NULL, 1); 615d3d381b2SKyle Evans } 616d3d381b2SKyle Evans 617d3d381b2SKyle Evans if (asprintf(&loader, "/boot/userboot_%s.so", interp_req) == -1) 618d3d381b2SKyle Evans err(EX_OSERR, "malloc"); 619d3d381b2SKyle Evans need_reinit = 1; 620d3d381b2SKyle Evans longjmp(jb, 1); 621d3d381b2SKyle Evans } 622d3d381b2SKyle Evans 623a10c6f55SNeel Natu static struct loader_callbacks cb = { 624c487da1eSNeel Natu .getc = cb_getc, 625c487da1eSNeel Natu .putc = cb_putc, 626c487da1eSNeel Natu .poll = cb_poll, 627c487da1eSNeel Natu 628c487da1eSNeel Natu .open = cb_open, 629c487da1eSNeel Natu .close = cb_close, 630c487da1eSNeel Natu .isdir = cb_isdir, 631c487da1eSNeel Natu .read = cb_read, 632c487da1eSNeel Natu .readdir = cb_readdir, 633c487da1eSNeel Natu .seek = cb_seek, 634c487da1eSNeel Natu .stat = cb_stat, 635c487da1eSNeel Natu 636c487da1eSNeel Natu .diskread = cb_diskread, 637cc71ff72SConrad Meyer .diskwrite = cb_diskwrite, 638a10c6f55SNeel Natu .diskioctl = cb_diskioctl, 639c487da1eSNeel Natu 640c487da1eSNeel Natu .copyin = cb_copyin, 641c487da1eSNeel Natu .copyout = cb_copyout, 642c487da1eSNeel Natu .setreg = cb_setreg, 643c487da1eSNeel Natu .setmsr = cb_setmsr, 644c487da1eSNeel Natu .setcr = cb_setcr, 645c487da1eSNeel Natu .setgdt = cb_setgdt, 646c487da1eSNeel Natu .exec = cb_exec, 647c487da1eSNeel Natu 648c487da1eSNeel Natu .delay = cb_delay, 649c487da1eSNeel Natu .exit = cb_exit, 650c487da1eSNeel Natu .getmem = cb_getmem, 651c3e9ce33SNeel Natu 652c3e9ce33SNeel Natu .getenv = cb_getenv, 65348f337b8SMarcel Moolenaar 65448f337b8SMarcel Moolenaar /* Version 4 additions */ 65548f337b8SMarcel Moolenaar .vm_set_register = cb_vm_set_register, 65648f337b8SMarcel Moolenaar .vm_set_desc = cb_vm_set_desc, 657d3d381b2SKyle Evans 658d3d381b2SKyle Evans /* Version 5 additions */ 659d3d381b2SKyle Evans .swap_interpreter = cb_swap_interpreter, 660c487da1eSNeel Natu }; 661c487da1eSNeel Natu 6626380102cSPeter Grehan static int 6636380102cSPeter Grehan altcons_open(char *path) 6646380102cSPeter Grehan { 6656380102cSPeter Grehan struct stat sb; 6666380102cSPeter Grehan int err; 6676380102cSPeter Grehan int fd; 6686380102cSPeter Grehan 6696380102cSPeter Grehan /* 6706380102cSPeter Grehan * Allow stdio to be passed in so that the same string 6716380102cSPeter Grehan * can be used for the bhyveload console and bhyve com-port 6726380102cSPeter Grehan * parameters 6736380102cSPeter Grehan */ 6746380102cSPeter Grehan if (!strcmp(path, "stdio")) 6756380102cSPeter Grehan return (0); 6766380102cSPeter Grehan 6776380102cSPeter Grehan err = stat(path, &sb); 6786380102cSPeter Grehan if (err == 0) { 6796380102cSPeter Grehan if (!S_ISCHR(sb.st_mode)) 6806380102cSPeter Grehan err = ENOTSUP; 6816380102cSPeter Grehan else { 6826380102cSPeter Grehan fd = open(path, O_RDWR | O_NONBLOCK); 6836380102cSPeter Grehan if (fd < 0) 6846380102cSPeter Grehan err = errno; 6856380102cSPeter Grehan else 6866380102cSPeter Grehan consin_fd = consout_fd = fd; 6876380102cSPeter Grehan } 6886380102cSPeter Grehan } 6896380102cSPeter Grehan 6906380102cSPeter Grehan return (err); 6916380102cSPeter Grehan } 6926380102cSPeter Grehan 693cf087c12SPeter Grehan static int 694cf087c12SPeter Grehan disk_open(char *path) 695cf087c12SPeter Grehan { 696a0bc451fSSean Chittenden int fd; 697cf087c12SPeter Grehan 6980db293c1SAllan Jude if (ndisks >= NDISKS) 699cf087c12SPeter Grehan return (ERANGE); 700cf087c12SPeter Grehan 7015a023bd2SRobert Wing fd = open(path, O_RDWR); 702a0bc451fSSean Chittenden if (fd < 0) 703a0bc451fSSean Chittenden return (errno); 704cf087c12SPeter Grehan 705cf087c12SPeter Grehan disk_fd[ndisks] = fd; 706cf087c12SPeter Grehan ndisks++; 707cf087c12SPeter Grehan 708a0bc451fSSean Chittenden return (0); 709cf087c12SPeter Grehan } 710cf087c12SPeter Grehan 711c487da1eSNeel Natu static void 712c487da1eSNeel Natu usage(void) 713c487da1eSNeel Natu { 714c487da1eSNeel Natu 715b060ba50SNeel Natu fprintf(stderr, 7169b1aa8d6SNeel Natu "usage: %s [-S][-c <console-device>] [-d <disk-path>] [-e <name=value>]\n" 7176ee52c65SRoman Bogorodskiy " %*s [-h <host-path>] [-m memsize[K|k|M|m|G|g|T|t]] <vmname>\n", 7186380102cSPeter Grehan progname, 719b5331f4dSNeel Natu (int)strlen(progname), ""); 720c487da1eSNeel Natu exit(1); 721c487da1eSNeel Natu } 722c487da1eSNeel Natu 723c487da1eSNeel Natu int 724c487da1eSNeel Natu main(int argc, char** argv) 725c487da1eSNeel Natu { 726a10c6f55SNeel Natu void (*func)(struct loader_callbacks *, void *, int, int); 727b060ba50SNeel Natu uint64_t mem_size; 728d3d381b2SKyle Evans int opt, error, memflags; 729c487da1eSNeel Natu 730b5331f4dSNeel Natu progname = basename(argv[0]); 731c487da1eSNeel Natu 7329b1aa8d6SNeel Natu memflags = 0; 733b060ba50SNeel Natu mem_size = 256 * MB; 734c487da1eSNeel Natu 7356380102cSPeter Grehan consin_fd = STDIN_FILENO; 7366380102cSPeter Grehan consout_fd = STDOUT_FILENO; 7376380102cSPeter Grehan 738568e3a8dSMarcel Moolenaar while ((opt = getopt(argc, argv, "CSc:d:e:h:l:m:")) != -1) { 739c487da1eSNeel Natu switch (opt) { 7406380102cSPeter Grehan case 'c': 7416380102cSPeter Grehan error = altcons_open(optarg); 7426380102cSPeter Grehan if (error != 0) 7436380102cSPeter Grehan errx(EX_USAGE, "Could not open '%s'", optarg); 7446380102cSPeter Grehan break; 745cf087c12SPeter Grehan 746c487da1eSNeel Natu case 'd': 747cf087c12SPeter Grehan error = disk_open(optarg); 748cf087c12SPeter Grehan if (error != 0) 749cf087c12SPeter Grehan errx(EX_USAGE, "Could not open '%s'", optarg); 750c487da1eSNeel Natu break; 751c487da1eSNeel Natu 752b6afa84bSNeel Natu case 'e': 753b6afa84bSNeel Natu addenv(optarg); 754b6afa84bSNeel Natu break; 755b6afa84bSNeel Natu 756c487da1eSNeel Natu case 'h': 757c487da1eSNeel Natu host_base = optarg; 758c487da1eSNeel Natu break; 759c487da1eSNeel Natu 7608c96dcc1SMarcel Moolenaar case 'l': 7618c96dcc1SMarcel Moolenaar if (loader != NULL) 7628c96dcc1SMarcel Moolenaar errx(EX_USAGE, "-l can only be given once"); 7638c96dcc1SMarcel Moolenaar loader = strdup(optarg); 7648c96dcc1SMarcel Moolenaar if (loader == NULL) 7658c96dcc1SMarcel Moolenaar err(EX_OSERR, "malloc"); 766d3d381b2SKyle Evans explicit_loader = 1; 7678c96dcc1SMarcel Moolenaar break; 7688c96dcc1SMarcel Moolenaar 769c487da1eSNeel Natu case 'm': 770200758f1SNeel Natu error = vm_parse_memsize(optarg, &mem_size); 771200758f1SNeel Natu if (error != 0) 772200758f1SNeel Natu errx(EX_USAGE, "Invalid memsize '%s'", optarg); 773c487da1eSNeel Natu break; 774568e3a8dSMarcel Moolenaar case 'C': 775568e3a8dSMarcel Moolenaar memflags |= VM_MEM_F_INCORE; 776568e3a8dSMarcel Moolenaar break; 7779b1aa8d6SNeel Natu case 'S': 7789b1aa8d6SNeel Natu memflags |= VM_MEM_F_WIRED; 7799b1aa8d6SNeel Natu break; 780c487da1eSNeel Natu case '?': 781c487da1eSNeel Natu usage(); 782c487da1eSNeel Natu } 783c487da1eSNeel Natu } 784c487da1eSNeel Natu 785c487da1eSNeel Natu argc -= optind; 786c487da1eSNeel Natu argv += optind; 787c487da1eSNeel Natu 788c487da1eSNeel Natu if (argc != 1) 789c487da1eSNeel Natu usage(); 790c487da1eSNeel Natu 791c487da1eSNeel Natu vmname = argv[0]; 792c487da1eSNeel Natu 7935fcf252fSNeel Natu need_reinit = 0; 794c487da1eSNeel Natu error = vm_create(vmname); 7955fcf252fSNeel Natu if (error) { 7965fcf252fSNeel Natu if (errno != EEXIST) { 797c487da1eSNeel Natu perror("vm_create"); 798c487da1eSNeel Natu exit(1); 7995fcf252fSNeel Natu } 8005fcf252fSNeel Natu need_reinit = 1; 801c487da1eSNeel Natu } 802c487da1eSNeel Natu 803c487da1eSNeel Natu ctx = vm_open(vmname); 804c487da1eSNeel Natu if (ctx == NULL) { 805c487da1eSNeel Natu perror("vm_open"); 806c487da1eSNeel Natu exit(1); 807c487da1eSNeel Natu } 808c487da1eSNeel Natu 8097d9ef309SJohn Baldwin vcpu = vm_vcpu_open(ctx, BSP); 8107d9ef309SJohn Baldwin 811d3d381b2SKyle Evans /* 812d3d381b2SKyle Evans * setjmp in the case the guest wants to swap out interpreter, 813d3d381b2SKyle Evans * cb_swap_interpreter will swap out loader as appropriate and set 814d3d381b2SKyle Evans * need_reinit so that we end up in a clean state once again. 815d3d381b2SKyle Evans */ 816d3d381b2SKyle Evans setjmp(jb); 817d3d381b2SKyle Evans 8185fcf252fSNeel Natu if (need_reinit) { 8195fcf252fSNeel Natu error = vm_reinit(ctx); 8205fcf252fSNeel Natu if (error) { 8215fcf252fSNeel Natu perror("vm_reinit"); 8225fcf252fSNeel Natu exit(1); 8235fcf252fSNeel Natu } 8245fcf252fSNeel Natu } 8255fcf252fSNeel Natu 8269b1aa8d6SNeel Natu vm_set_memflags(ctx, memflags); 827b060ba50SNeel Natu error = vm_setup_memory(ctx, mem_size, VM_MMAP_ALL); 828c487da1eSNeel Natu if (error) { 829b060ba50SNeel Natu perror("vm_setup_memory"); 830c487da1eSNeel Natu exit(1); 831c487da1eSNeel Natu } 832c487da1eSNeel Natu 8338c96dcc1SMarcel Moolenaar if (loader == NULL) { 8348c96dcc1SMarcel Moolenaar loader = strdup("/boot/userboot.so"); 8358c96dcc1SMarcel Moolenaar if (loader == NULL) 8368c96dcc1SMarcel Moolenaar err(EX_OSERR, "malloc"); 8378c96dcc1SMarcel Moolenaar } 838d3d381b2SKyle Evans if (loader_hdl != NULL) 839d3d381b2SKyle Evans dlclose(loader_hdl); 840d3d381b2SKyle Evans loader_hdl = dlopen(loader, RTLD_LOCAL); 841d3d381b2SKyle Evans if (!loader_hdl) { 8428c96dcc1SMarcel Moolenaar printf("%s\n", dlerror()); 8438c96dcc1SMarcel Moolenaar free(loader); 8448c96dcc1SMarcel Moolenaar return (1); 8458c96dcc1SMarcel Moolenaar } 846d3d381b2SKyle Evans func = dlsym(loader_hdl, "loader_main"); 8478c96dcc1SMarcel Moolenaar if (!func) { 8488c96dcc1SMarcel Moolenaar printf("%s\n", dlerror()); 8498c96dcc1SMarcel Moolenaar free(loader); 8508c96dcc1SMarcel Moolenaar return (1); 8518c96dcc1SMarcel Moolenaar } 8528c96dcc1SMarcel Moolenaar 8536380102cSPeter Grehan tcgetattr(consout_fd, &term); 854c487da1eSNeel Natu oldterm = term; 8556380102cSPeter Grehan cfmakeraw(&term); 8566380102cSPeter Grehan term.c_cflag |= CLOCAL; 8576380102cSPeter Grehan 8586380102cSPeter Grehan tcsetattr(consout_fd, TCSAFLUSH, &term); 8596380102cSPeter Grehan 860b6afa84bSNeel Natu addenv("smbios.bios.vendor=BHYVE"); 861b6afa84bSNeel Natu addenv("boot_serial=1"); 862b6afa84bSNeel Natu 863d3d381b2SKyle Evans func(&cb, NULL, USERBOOT_VERSION_5, ndisks); 8648c96dcc1SMarcel Moolenaar 8658c96dcc1SMarcel Moolenaar free(loader); 8668c96dcc1SMarcel Moolenaar return (0); 867c487da1eSNeel Natu } 868