1c487da1eSNeel Natu /*- 2eebd9d53SWarner 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 29c487da1eSNeel Natu /*- 30c487da1eSNeel Natu * Copyright (c) 2011 Google, Inc. 31c487da1eSNeel Natu * All rights reserved. 32c487da1eSNeel Natu * 33c487da1eSNeel Natu * Redistribution and use in source and binary forms, with or without 34c487da1eSNeel Natu * modification, are permitted provided that the following conditions 35c487da1eSNeel Natu * are met: 36c487da1eSNeel Natu * 1. Redistributions of source code must retain the above copyright 37c487da1eSNeel Natu * notice, this list of conditions and the following disclaimer. 38c487da1eSNeel Natu * 2. Redistributions in binary form must reproduce the above copyright 39c487da1eSNeel Natu * notice, this list of conditions and the following disclaimer in the 40c487da1eSNeel Natu * documentation and/or other materials provided with the distribution. 41c487da1eSNeel Natu * 42c487da1eSNeel Natu * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 43c487da1eSNeel Natu * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 44c487da1eSNeel Natu * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 45c487da1eSNeel Natu * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 46c487da1eSNeel Natu * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 47c487da1eSNeel Natu * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 48c487da1eSNeel Natu * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 49c487da1eSNeel Natu * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 50c487da1eSNeel Natu * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 51c487da1eSNeel Natu * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 52c487da1eSNeel Natu * SUCH DAMAGE. 53c487da1eSNeel Natu */ 54c487da1eSNeel Natu 55c487da1eSNeel Natu #include <sys/cdefs.h> 56c487da1eSNeel Natu #include <sys/ioctl.h> 57c487da1eSNeel Natu #include <sys/stat.h> 58a10c6f55SNeel Natu #include <sys/disk.h> 59b6afa84bSNeel Natu #include <sys/queue.h> 60c487da1eSNeel Natu 61c487da1eSNeel Natu #include <machine/specialreg.h> 62c487da1eSNeel Natu #include <machine/vmm.h> 63c487da1eSNeel Natu 647d9ef309SJohn Baldwin #include <assert.h> 65c487da1eSNeel Natu #include <dirent.h> 66c487da1eSNeel Natu #include <dlfcn.h> 67c487da1eSNeel Natu #include <errno.h> 68200758f1SNeel Natu #include <err.h> 69c487da1eSNeel Natu #include <fcntl.h> 70c487da1eSNeel Natu #include <getopt.h> 71b5331f4dSNeel Natu #include <libgen.h> 72c487da1eSNeel Natu #include <limits.h> 73d3d381b2SKyle Evans #include <setjmp.h> 74c487da1eSNeel Natu #include <stdio.h> 75c487da1eSNeel Natu #include <stdlib.h> 76c487da1eSNeel Natu #include <string.h> 77200758f1SNeel Natu #include <sysexits.h> 78c487da1eSNeel Natu #include <termios.h> 79c487da1eSNeel Natu #include <unistd.h> 80c487da1eSNeel Natu 81*8bf0882eSKyle Evans #include <capsicum_helpers.h> 82c487da1eSNeel Natu #include <vmmapi.h> 83c487da1eSNeel Natu 84c487da1eSNeel Natu #include "userboot.h" 85c487da1eSNeel Natu 86c487da1eSNeel Natu #define MB (1024 * 1024UL) 87c487da1eSNeel Natu #define GB (1024 * 1024 * 1024UL) 88c487da1eSNeel Natu #define BSP 0 89c487da1eSNeel Natu 90cf087c12SPeter Grehan #define NDISKS 32 91cf087c12SPeter Grehan 92c487da1eSNeel Natu static struct termios term, oldterm; 93cf087c12SPeter Grehan static int disk_fd[NDISKS]; 94cf087c12SPeter Grehan static int ndisks; 956380102cSPeter Grehan static int consin_fd, consout_fd; 966779d44bSKyle Evans static int hostbase_fd = -1; 97c487da1eSNeel Natu 98d3d381b2SKyle Evans static void *loader_hdl; 99d3d381b2SKyle Evans static char *loader; 100bf7c4fcbSKyle Evans static int explicit_loader_fd; 101d3d381b2SKyle Evans static jmp_buf jb; 102d3d381b2SKyle Evans 103b060ba50SNeel Natu static char *vmname, *progname; 104c487da1eSNeel Natu static struct vmctx *ctx; 1057d9ef309SJohn Baldwin static struct vcpu *vcpu; 106c487da1eSNeel Natu 107c487da1eSNeel Natu static uint64_t gdtbase, cr3, rsp; 108c487da1eSNeel Natu 109c487da1eSNeel Natu static void cb_exit(void *arg, int v); 110c487da1eSNeel Natu 111c487da1eSNeel Natu /* 112c487da1eSNeel Natu * Console i/o callbacks 113c487da1eSNeel Natu */ 114c487da1eSNeel Natu 115c487da1eSNeel Natu static void 116ad43dd69SMark Johnston cb_putc(void *arg __unused, int ch) 117c487da1eSNeel Natu { 118c487da1eSNeel Natu char c = ch; 119c487da1eSNeel Natu 1206380102cSPeter Grehan (void) write(consout_fd, &c, 1); 121c487da1eSNeel Natu } 122c487da1eSNeel Natu 123c487da1eSNeel Natu static int 124ad43dd69SMark Johnston cb_getc(void *arg __unused) 125c487da1eSNeel Natu { 126c487da1eSNeel Natu char c; 127c487da1eSNeel Natu 1286380102cSPeter Grehan if (read(consin_fd, &c, 1) == 1) 129c487da1eSNeel Natu return (c); 130c487da1eSNeel Natu return (-1); 131c487da1eSNeel Natu } 132c487da1eSNeel Natu 133c487da1eSNeel Natu static int 134ad43dd69SMark Johnston cb_poll(void *arg __unused) 135c487da1eSNeel Natu { 136c487da1eSNeel Natu int n; 137c487da1eSNeel Natu 1386380102cSPeter Grehan if (ioctl(consin_fd, FIONREAD, &n) >= 0) 139c487da1eSNeel Natu return (n > 0); 140c487da1eSNeel Natu return (0); 141c487da1eSNeel Natu } 142c487da1eSNeel Natu 143c487da1eSNeel Natu /* 144c487da1eSNeel Natu * Host filesystem i/o callbacks 145c487da1eSNeel Natu */ 146c487da1eSNeel Natu 147c487da1eSNeel Natu struct cb_file { 148c487da1eSNeel Natu int cf_isdir; 149c487da1eSNeel Natu size_t cf_size; 150c487da1eSNeel Natu struct stat cf_stat; 151c487da1eSNeel Natu union { 152c487da1eSNeel Natu int fd; 153c487da1eSNeel Natu DIR *dir; 154c487da1eSNeel Natu } cf_u; 155c487da1eSNeel Natu }; 156c487da1eSNeel Natu 157c487da1eSNeel Natu static int 158ad43dd69SMark Johnston cb_open(void *arg __unused, const char *filename, void **hp) 159c487da1eSNeel Natu { 160c487da1eSNeel Natu struct cb_file *cf; 1616779d44bSKyle Evans struct stat sb; 1626779d44bSKyle Evans int fd, flags; 163c487da1eSNeel Natu 1646779d44bSKyle Evans cf = NULL; 1656779d44bSKyle Evans fd = -1; 1666779d44bSKyle Evans flags = O_RDONLY | O_RESOLVE_BENEATH; 1676779d44bSKyle Evans if (hostbase_fd == -1) 168c487da1eSNeel Natu return (ENOENT); 169c487da1eSNeel Natu 1706779d44bSKyle Evans /* Absolute paths are relative to our hostbase, chop off leading /. */ 1716779d44bSKyle Evans if (filename[0] == '/') 1726779d44bSKyle Evans filename++; 1736779d44bSKyle Evans 1746779d44bSKyle Evans /* Lookup of /, use . instead. */ 1756779d44bSKyle Evans if (filename[0] == '\0') 1766779d44bSKyle Evans filename = "."; 1776779d44bSKyle Evans 1786779d44bSKyle Evans if (fstatat(hostbase_fd, filename, &sb, AT_RESOLVE_BENEATH) < 0) 179c487da1eSNeel Natu return (errno); 1806779d44bSKyle Evans 1816779d44bSKyle Evans if (!S_ISDIR(sb.st_mode) && !S_ISREG(sb.st_mode)) 1826779d44bSKyle Evans return (EINVAL); 1836779d44bSKyle Evans 1846779d44bSKyle Evans if (S_ISDIR(sb.st_mode)) 1856779d44bSKyle Evans flags |= O_DIRECTORY; 1866779d44bSKyle Evans 1876779d44bSKyle Evans /* May be opening the root dir */ 1886779d44bSKyle Evans fd = openat(hostbase_fd, filename, flags); 1896779d44bSKyle Evans if (fd < 0) 1906779d44bSKyle Evans return (errno); 1916779d44bSKyle Evans 1926779d44bSKyle Evans cf = malloc(sizeof(struct cb_file)); 1936779d44bSKyle Evans if (cf == NULL) { 1946779d44bSKyle Evans close(fd); 1956779d44bSKyle Evans return (ENOMEM); 196c487da1eSNeel Natu } 197c487da1eSNeel Natu 1986779d44bSKyle Evans cf->cf_stat = sb; 1998f61276dSPedro F. Giffuni cf->cf_size = cf->cf_stat.st_size; 2006779d44bSKyle Evans 201c487da1eSNeel Natu if (S_ISDIR(cf->cf_stat.st_mode)) { 202c487da1eSNeel Natu cf->cf_isdir = 1; 2036779d44bSKyle Evans cf->cf_u.dir = fdopendir(fd); 2046779d44bSKyle Evans if (cf->cf_u.dir == NULL) { 2056779d44bSKyle Evans close(fd); 206c487da1eSNeel Natu free(cf); 2076779d44bSKyle Evans return (ENOMEM); 2086779d44bSKyle Evans } 2096779d44bSKyle Evans } else { 2106779d44bSKyle Evans assert(S_ISREG(cf->cf_stat.st_mode)); 2116779d44bSKyle Evans cf->cf_isdir = 0; 2126779d44bSKyle Evans cf->cf_u.fd = fd; 2136779d44bSKyle Evans } 2146779d44bSKyle Evans *hp = cf; 2156779d44bSKyle Evans return (0); 216c487da1eSNeel Natu } 217c487da1eSNeel Natu 218c487da1eSNeel Natu static int 219ad43dd69SMark Johnston cb_close(void *arg __unused, void *h) 220c487da1eSNeel Natu { 221c487da1eSNeel Natu struct cb_file *cf = h; 222c487da1eSNeel Natu 223c487da1eSNeel Natu if (cf->cf_isdir) 224c487da1eSNeel Natu closedir(cf->cf_u.dir); 225c487da1eSNeel Natu else 226c487da1eSNeel Natu close(cf->cf_u.fd); 227c487da1eSNeel Natu free(cf); 228c487da1eSNeel Natu 229c487da1eSNeel Natu return (0); 230c487da1eSNeel Natu } 231c487da1eSNeel Natu 232c487da1eSNeel Natu static int 233ad43dd69SMark Johnston cb_isdir(void *arg __unused, void *h) 234c487da1eSNeel Natu { 235c487da1eSNeel Natu struct cb_file *cf = h; 236c487da1eSNeel Natu 237c487da1eSNeel Natu return (cf->cf_isdir); 238c487da1eSNeel Natu } 239c487da1eSNeel Natu 240c487da1eSNeel Natu static int 241ad43dd69SMark Johnston cb_read(void *arg __unused, void *h, void *buf, size_t size, size_t *resid) 242c487da1eSNeel Natu { 243c487da1eSNeel Natu struct cb_file *cf = h; 244c487da1eSNeel Natu ssize_t sz; 245c487da1eSNeel Natu 246c487da1eSNeel Natu if (cf->cf_isdir) 247c487da1eSNeel Natu return (EINVAL); 248c487da1eSNeel Natu sz = read(cf->cf_u.fd, buf, size); 249c487da1eSNeel Natu if (sz < 0) 250c487da1eSNeel Natu return (EINVAL); 251c487da1eSNeel Natu *resid = size - sz; 252c487da1eSNeel Natu return (0); 253c487da1eSNeel Natu } 254c487da1eSNeel Natu 255c487da1eSNeel Natu static int 256ad43dd69SMark Johnston cb_readdir(void *arg __unused, void *h, uint32_t *fileno_return, 257ad43dd69SMark Johnston uint8_t *type_return, size_t *namelen_return, char *name) 258c487da1eSNeel Natu { 259c487da1eSNeel Natu struct cb_file *cf = h; 260c487da1eSNeel Natu struct dirent *dp; 261c487da1eSNeel Natu 262c487da1eSNeel Natu if (!cf->cf_isdir) 263c487da1eSNeel Natu return (EINVAL); 264c487da1eSNeel Natu 265c487da1eSNeel Natu dp = readdir(cf->cf_u.dir); 266c487da1eSNeel Natu if (!dp) 267c487da1eSNeel Natu return (ENOENT); 268c487da1eSNeel Natu 269c487da1eSNeel Natu /* 270c487da1eSNeel Natu * Note: d_namlen is in the range 0..255 and therefore less 271c487da1eSNeel Natu * than PATH_MAX so we don't need to test before copying. 272c487da1eSNeel Natu */ 273c487da1eSNeel Natu *fileno_return = dp->d_fileno; 274c487da1eSNeel Natu *type_return = dp->d_type; 275c487da1eSNeel Natu *namelen_return = dp->d_namlen; 276c487da1eSNeel Natu memcpy(name, dp->d_name, dp->d_namlen); 277c487da1eSNeel Natu name[dp->d_namlen] = 0; 278c487da1eSNeel Natu 279c487da1eSNeel Natu return (0); 280c487da1eSNeel Natu } 281c487da1eSNeel Natu 282c487da1eSNeel Natu static int 283ad43dd69SMark Johnston cb_seek(void *arg __unused, void *h, uint64_t offset, int whence) 284c487da1eSNeel Natu { 285c487da1eSNeel Natu struct cb_file *cf = h; 286c487da1eSNeel Natu 287c487da1eSNeel Natu if (cf->cf_isdir) 288c487da1eSNeel Natu return (EINVAL); 289c487da1eSNeel Natu if (lseek(cf->cf_u.fd, offset, whence) < 0) 290c487da1eSNeel Natu return (errno); 291c487da1eSNeel Natu return (0); 292c487da1eSNeel Natu } 293c487da1eSNeel Natu 294c487da1eSNeel Natu static int 295ad43dd69SMark Johnston cb_stat(void *arg __unused, void *h, struct stat *sbp) 296c487da1eSNeel Natu { 297c487da1eSNeel Natu struct cb_file *cf = h; 298c487da1eSNeel Natu 29953f151f9SSimon J. Gerraty memset(sbp, 0, sizeof(struct stat)); 30053f151f9SSimon J. Gerraty sbp->st_mode = cf->cf_stat.st_mode; 30153f151f9SSimon J. Gerraty sbp->st_uid = cf->cf_stat.st_uid; 30253f151f9SSimon J. Gerraty sbp->st_gid = cf->cf_stat.st_gid; 30353f151f9SSimon J. Gerraty sbp->st_size = cf->cf_stat.st_size; 30453f151f9SSimon J. Gerraty sbp->st_mtime = cf->cf_stat.st_mtime; 30553f151f9SSimon J. Gerraty sbp->st_dev = cf->cf_stat.st_dev; 30653f151f9SSimon J. Gerraty sbp->st_ino = cf->cf_stat.st_ino; 30753f151f9SSimon J. Gerraty 308c487da1eSNeel Natu return (0); 309c487da1eSNeel Natu } 310c487da1eSNeel Natu 311c487da1eSNeel Natu /* 312c487da1eSNeel Natu * Disk image i/o callbacks 313c487da1eSNeel Natu */ 314c487da1eSNeel Natu 315c487da1eSNeel Natu static int 316ad43dd69SMark Johnston cb_diskread(void *arg __unused, int unit, uint64_t from, void *to, size_t size, 317c487da1eSNeel Natu size_t *resid) 318c487da1eSNeel Natu { 319c487da1eSNeel Natu ssize_t n; 320c487da1eSNeel Natu 321cf087c12SPeter Grehan if (unit < 0 || unit >= ndisks) 322c487da1eSNeel Natu return (EIO); 323cf087c12SPeter Grehan n = pread(disk_fd[unit], to, size, from); 324c487da1eSNeel Natu if (n < 0) 325c487da1eSNeel Natu return (errno); 326c487da1eSNeel Natu *resid = size - n; 327c487da1eSNeel Natu return (0); 328c487da1eSNeel Natu } 329c487da1eSNeel Natu 330a10c6f55SNeel Natu static int 331ad43dd69SMark Johnston cb_diskwrite(void *arg __unused, int unit, uint64_t offset, void *src, 332ad43dd69SMark Johnston size_t size, size_t *resid) 333cc71ff72SConrad Meyer { 334cc71ff72SConrad Meyer ssize_t n; 335cc71ff72SConrad Meyer 336cc71ff72SConrad Meyer if (unit < 0 || unit >= ndisks) 337cc71ff72SConrad Meyer return (EIO); 338cc71ff72SConrad Meyer n = pwrite(disk_fd[unit], src, size, offset); 339cc71ff72SConrad Meyer if (n < 0) 340cc71ff72SConrad Meyer return (errno); 341cc71ff72SConrad Meyer *resid = size - n; 342cc71ff72SConrad Meyer return (0); 343cc71ff72SConrad Meyer } 344cc71ff72SConrad Meyer 345cc71ff72SConrad Meyer static int 346ad43dd69SMark Johnston cb_diskioctl(void *arg __unused, int unit, u_long cmd, void *data) 347a10c6f55SNeel Natu { 348a10c6f55SNeel Natu struct stat sb; 349a10c6f55SNeel Natu 350cf087c12SPeter Grehan if (unit < 0 || unit >= ndisks) 351a10c6f55SNeel Natu return (EBADF); 352a10c6f55SNeel Natu 353a10c6f55SNeel Natu switch (cmd) { 354a10c6f55SNeel Natu case DIOCGSECTORSIZE: 355a10c6f55SNeel Natu *(u_int *)data = 512; 356a10c6f55SNeel Natu break; 357a10c6f55SNeel Natu case DIOCGMEDIASIZE: 3586589ee29SAndriy Gapon if (fstat(disk_fd[unit], &sb) != 0) 359a10c6f55SNeel Natu return (ENOTTY); 3606589ee29SAndriy Gapon if (S_ISCHR(sb.st_mode) && 3616589ee29SAndriy Gapon ioctl(disk_fd[unit], DIOCGMEDIASIZE, &sb.st_size) != 0) 3626589ee29SAndriy Gapon return (ENOTTY); 3636589ee29SAndriy Gapon *(off_t *)data = sb.st_size; 364a10c6f55SNeel Natu break; 365a10c6f55SNeel Natu default: 366a10c6f55SNeel Natu return (ENOTTY); 367a10c6f55SNeel Natu } 368a10c6f55SNeel Natu 369a10c6f55SNeel Natu return (0); 370a10c6f55SNeel Natu } 371a10c6f55SNeel Natu 372c487da1eSNeel Natu /* 373c487da1eSNeel Natu * Guest virtual machine i/o callbacks 374c487da1eSNeel Natu */ 375c487da1eSNeel Natu static int 376ad43dd69SMark Johnston cb_copyin(void *arg __unused, const void *from, uint64_t to, size_t size) 377c487da1eSNeel Natu { 378b060ba50SNeel Natu char *ptr; 379c487da1eSNeel Natu 380c487da1eSNeel Natu to &= 0x7fffffff; 381b060ba50SNeel Natu 382b060ba50SNeel Natu ptr = vm_map_gpa(ctx, to, size); 383b060ba50SNeel Natu if (ptr == NULL) 384c487da1eSNeel Natu return (EFAULT); 385c487da1eSNeel Natu 386b060ba50SNeel Natu memcpy(ptr, from, size); 387c487da1eSNeel Natu return (0); 388c487da1eSNeel Natu } 389c487da1eSNeel Natu 390c487da1eSNeel Natu static int 391ad43dd69SMark Johnston cb_copyout(void *arg __unused, uint64_t from, void *to, size_t size) 392c487da1eSNeel Natu { 393b060ba50SNeel Natu char *ptr; 394c487da1eSNeel Natu 395c487da1eSNeel Natu from &= 0x7fffffff; 396b060ba50SNeel Natu 397b060ba50SNeel Natu ptr = vm_map_gpa(ctx, from, size); 398b060ba50SNeel Natu if (ptr == NULL) 399c487da1eSNeel Natu return (EFAULT); 400c487da1eSNeel Natu 401b060ba50SNeel Natu memcpy(to, ptr, size); 402c487da1eSNeel Natu return (0); 403c487da1eSNeel Natu } 404c487da1eSNeel Natu 405c487da1eSNeel Natu static void 406ad43dd69SMark Johnston cb_setreg(void *arg __unused, int r, uint64_t v) 407c487da1eSNeel Natu { 408c487da1eSNeel Natu int error; 409c487da1eSNeel Natu enum vm_reg_name vmreg; 410c487da1eSNeel Natu 411c487da1eSNeel Natu vmreg = VM_REG_LAST; 412c487da1eSNeel Natu 413c487da1eSNeel Natu switch (r) { 414c487da1eSNeel Natu case 4: 415c487da1eSNeel Natu vmreg = VM_REG_GUEST_RSP; 416c487da1eSNeel Natu rsp = v; 417c487da1eSNeel Natu break; 418c487da1eSNeel Natu default: 419c487da1eSNeel Natu break; 420c487da1eSNeel Natu } 421c487da1eSNeel Natu 422c487da1eSNeel Natu if (vmreg == VM_REG_LAST) { 423c487da1eSNeel Natu printf("test_setreg(%d): not implemented\n", r); 424c487da1eSNeel Natu cb_exit(NULL, USERBOOT_EXIT_QUIT); 425c487da1eSNeel Natu } 426c487da1eSNeel Natu 4277d9ef309SJohn Baldwin error = vm_set_register(vcpu, vmreg, v); 428c487da1eSNeel Natu if (error) { 429c487da1eSNeel Natu perror("vm_set_register"); 430c487da1eSNeel Natu cb_exit(NULL, USERBOOT_EXIT_QUIT); 431c487da1eSNeel Natu } 432c487da1eSNeel Natu } 433c487da1eSNeel Natu 434c487da1eSNeel Natu static void 435ad43dd69SMark Johnston cb_setmsr(void *arg __unused, int r, uint64_t v) 436c487da1eSNeel Natu { 437c487da1eSNeel Natu int error; 438c487da1eSNeel Natu enum vm_reg_name vmreg; 439c487da1eSNeel Natu 440c487da1eSNeel Natu vmreg = VM_REG_LAST; 441c487da1eSNeel Natu 442c487da1eSNeel Natu switch (r) { 443c487da1eSNeel Natu case MSR_EFER: 444c487da1eSNeel Natu vmreg = VM_REG_GUEST_EFER; 445c487da1eSNeel Natu break; 446c487da1eSNeel Natu default: 447c487da1eSNeel Natu break; 448c487da1eSNeel Natu } 449c487da1eSNeel Natu 450c487da1eSNeel Natu if (vmreg == VM_REG_LAST) { 451c487da1eSNeel Natu printf("test_setmsr(%d): not implemented\n", r); 452c487da1eSNeel Natu cb_exit(NULL, USERBOOT_EXIT_QUIT); 453c487da1eSNeel Natu } 454c487da1eSNeel Natu 4557d9ef309SJohn Baldwin error = vm_set_register(vcpu, vmreg, v); 456c487da1eSNeel Natu if (error) { 457c487da1eSNeel Natu perror("vm_set_msr"); 458c487da1eSNeel Natu cb_exit(NULL, USERBOOT_EXIT_QUIT); 459c487da1eSNeel Natu } 460c487da1eSNeel Natu } 461c487da1eSNeel Natu 462c487da1eSNeel Natu static void 463ad43dd69SMark Johnston cb_setcr(void *arg __unused, int r, uint64_t v) 464c487da1eSNeel Natu { 465c487da1eSNeel Natu int error; 466c487da1eSNeel Natu enum vm_reg_name vmreg; 467c487da1eSNeel Natu 468c487da1eSNeel Natu vmreg = VM_REG_LAST; 469c487da1eSNeel Natu 470c487da1eSNeel Natu switch (r) { 471c487da1eSNeel Natu case 0: 472c487da1eSNeel Natu vmreg = VM_REG_GUEST_CR0; 473c487da1eSNeel Natu break; 474c487da1eSNeel Natu case 3: 475c487da1eSNeel Natu vmreg = VM_REG_GUEST_CR3; 476c487da1eSNeel Natu cr3 = v; 477c487da1eSNeel Natu break; 478c487da1eSNeel Natu case 4: 479c487da1eSNeel Natu vmreg = VM_REG_GUEST_CR4; 480c487da1eSNeel Natu break; 481c487da1eSNeel Natu default: 482c487da1eSNeel Natu break; 483c487da1eSNeel Natu } 484c487da1eSNeel Natu 485c487da1eSNeel Natu if (vmreg == VM_REG_LAST) { 486c487da1eSNeel Natu printf("test_setcr(%d): not implemented\n", r); 487c487da1eSNeel Natu cb_exit(NULL, USERBOOT_EXIT_QUIT); 488c487da1eSNeel Natu } 489c487da1eSNeel Natu 4907d9ef309SJohn Baldwin error = vm_set_register(vcpu, vmreg, v); 491c487da1eSNeel Natu if (error) { 492c487da1eSNeel Natu perror("vm_set_cr"); 493c487da1eSNeel Natu cb_exit(NULL, USERBOOT_EXIT_QUIT); 494c487da1eSNeel Natu } 495c487da1eSNeel Natu } 496c487da1eSNeel Natu 497c487da1eSNeel Natu static void 498ad43dd69SMark Johnston cb_setgdt(void *arg __unused, uint64_t base, size_t size) 499c487da1eSNeel Natu { 500c487da1eSNeel Natu int error; 501c487da1eSNeel Natu 5027d9ef309SJohn Baldwin error = vm_set_desc(vcpu, VM_REG_GUEST_GDTR, base, size - 1, 0); 503c487da1eSNeel Natu if (error != 0) { 504c487da1eSNeel Natu perror("vm_set_desc(gdt)"); 505c487da1eSNeel Natu cb_exit(NULL, USERBOOT_EXIT_QUIT); 506c487da1eSNeel Natu } 507c487da1eSNeel Natu 508c487da1eSNeel Natu gdtbase = base; 509c487da1eSNeel Natu } 510c487da1eSNeel Natu 511c487da1eSNeel Natu static void 512ad43dd69SMark Johnston cb_exec(void *arg __unused, uint64_t rip) 513c487da1eSNeel Natu { 514c487da1eSNeel Natu int error; 515c487da1eSNeel Natu 51600f3efe1SJohn Baldwin if (cr3 == 0) 5177d9ef309SJohn Baldwin error = vm_setup_freebsd_registers_i386(vcpu, rip, gdtbase, 51800f3efe1SJohn Baldwin rsp); 51900f3efe1SJohn Baldwin else 5207d9ef309SJohn Baldwin error = vm_setup_freebsd_registers(vcpu, rip, cr3, gdtbase, 52100f3efe1SJohn Baldwin rsp); 522c487da1eSNeel Natu if (error) { 523c487da1eSNeel Natu perror("vm_setup_freebsd_registers"); 524c487da1eSNeel Natu cb_exit(NULL, USERBOOT_EXIT_QUIT); 525c487da1eSNeel Natu } 526c487da1eSNeel Natu 527c487da1eSNeel Natu cb_exit(NULL, 0); 528c487da1eSNeel Natu } 529c487da1eSNeel Natu 530c487da1eSNeel Natu /* 531c487da1eSNeel Natu * Misc 532c487da1eSNeel Natu */ 533c487da1eSNeel Natu 534c487da1eSNeel Natu static void 535ad43dd69SMark Johnston cb_delay(void *arg __unused, int usec) 536c487da1eSNeel Natu { 537c487da1eSNeel Natu 538c487da1eSNeel Natu usleep(usec); 539c487da1eSNeel Natu } 540c487da1eSNeel Natu 541c487da1eSNeel Natu static void 542ad43dd69SMark Johnston cb_exit(void *arg __unused, int v) 543c487da1eSNeel Natu { 544c487da1eSNeel Natu 5456380102cSPeter Grehan tcsetattr(consout_fd, TCSAFLUSH, &oldterm); 546c487da1eSNeel Natu exit(v); 547c487da1eSNeel Natu } 548c487da1eSNeel Natu 549c487da1eSNeel Natu static void 550ad43dd69SMark Johnston cb_getmem(void *arg __unused, uint64_t *ret_lowmem, uint64_t *ret_highmem) 551c487da1eSNeel Natu { 552c487da1eSNeel Natu 553be679db4SNeel Natu *ret_lowmem = vm_get_lowmem_size(ctx); 554be679db4SNeel Natu *ret_highmem = vm_get_highmem_size(ctx); 555c487da1eSNeel Natu } 556c487da1eSNeel Natu 557b6afa84bSNeel Natu struct env { 558cb37fc82SWarner Losh char *str; /* name=value */ 559b6afa84bSNeel Natu SLIST_ENTRY(env) next; 560b6afa84bSNeel Natu }; 561b6afa84bSNeel Natu 562b6afa84bSNeel Natu static SLIST_HEAD(envhead, env) envhead; 563b6afa84bSNeel Natu 564b6afa84bSNeel Natu static void 565ad43dd69SMark Johnston addenv(const char *str) 566b6afa84bSNeel Natu { 567b6afa84bSNeel Natu struct env *env; 568b6afa84bSNeel Natu 569b6afa84bSNeel Natu env = malloc(sizeof(struct env)); 570ad43dd69SMark Johnston if (env == NULL) 571ad43dd69SMark Johnston err(EX_OSERR, "malloc"); 572ad43dd69SMark Johnston env->str = strdup(str); 573ad43dd69SMark Johnston if (env->str == NULL) 574ad43dd69SMark Johnston err(EX_OSERR, "strdup"); 575b6afa84bSNeel Natu SLIST_INSERT_HEAD(&envhead, env, next); 576b6afa84bSNeel Natu } 577b6afa84bSNeel Natu 578e8e6a5f9SWarner Losh static char * 579ad43dd69SMark Johnston cb_getenv(void *arg __unused, int num) 580c3e9ce33SNeel Natu { 581b6afa84bSNeel Natu int i; 582b6afa84bSNeel Natu struct env *env; 583c3e9ce33SNeel Natu 584b6afa84bSNeel Natu i = 0; 585b6afa84bSNeel Natu SLIST_FOREACH(env, &envhead, next) { 586b6afa84bSNeel Natu if (i == num) 587b6afa84bSNeel Natu return (env->str); 588b6afa84bSNeel Natu i++; 589b6afa84bSNeel Natu } 590c3e9ce33SNeel Natu 591c3e9ce33SNeel Natu return (NULL); 592c3e9ce33SNeel Natu } 593c3e9ce33SNeel Natu 59448f337b8SMarcel Moolenaar static int 5957d9ef309SJohn Baldwin cb_vm_set_register(void *arg __unused, int vcpuid, int reg, uint64_t val) 59648f337b8SMarcel Moolenaar { 59748f337b8SMarcel Moolenaar 5987d9ef309SJohn Baldwin assert(vcpuid == BSP); 5997d9ef309SJohn Baldwin return (vm_set_register(vcpu, reg, val)); 60048f337b8SMarcel Moolenaar } 60148f337b8SMarcel Moolenaar 60248f337b8SMarcel Moolenaar static int 6037d9ef309SJohn Baldwin cb_vm_set_desc(void *arg __unused, int vcpuid, int reg, uint64_t base, 604ad43dd69SMark Johnston u_int limit, u_int access) 60548f337b8SMarcel Moolenaar { 60648f337b8SMarcel Moolenaar 6077d9ef309SJohn Baldwin assert(vcpuid == BSP); 6087d9ef309SJohn Baldwin return (vm_set_desc(vcpu, reg, base, limit, access)); 60948f337b8SMarcel Moolenaar } 61048f337b8SMarcel Moolenaar 611d3d381b2SKyle Evans static void 612ad43dd69SMark Johnston cb_swap_interpreter(void *arg __unused, const char *interp_req) 613d3d381b2SKyle Evans { 614d3d381b2SKyle Evans 615d3d381b2SKyle Evans /* 616d3d381b2SKyle Evans * If the user specified a loader but we detected a mismatch, we should 617d3d381b2SKyle Evans * not try to pivot to a different loader on them. 618d3d381b2SKyle Evans */ 619d3d381b2SKyle Evans free(loader); 620bf7c4fcbSKyle Evans if (explicit_loader_fd != -1) { 621d3d381b2SKyle Evans perror("requested loader interpreter does not match guest userboot"); 622d3d381b2SKyle Evans cb_exit(NULL, 1); 623d3d381b2SKyle Evans } 624d3d381b2SKyle Evans if (interp_req == NULL || *interp_req == '\0') { 625d3d381b2SKyle Evans perror("guest failed to request an interpreter"); 626d3d381b2SKyle Evans cb_exit(NULL, 1); 627d3d381b2SKyle Evans } 628d3d381b2SKyle Evans 629bf7c4fcbSKyle Evans if (asprintf(&loader, "userboot_%s.so", interp_req) == -1) 630d3d381b2SKyle Evans err(EX_OSERR, "malloc"); 631d3d381b2SKyle Evans longjmp(jb, 1); 632d3d381b2SKyle Evans } 633d3d381b2SKyle Evans 634a10c6f55SNeel Natu static struct loader_callbacks cb = { 635c487da1eSNeel Natu .getc = cb_getc, 636c487da1eSNeel Natu .putc = cb_putc, 637c487da1eSNeel Natu .poll = cb_poll, 638c487da1eSNeel Natu 639c487da1eSNeel Natu .open = cb_open, 640c487da1eSNeel Natu .close = cb_close, 641c487da1eSNeel Natu .isdir = cb_isdir, 642c487da1eSNeel Natu .read = cb_read, 643c487da1eSNeel Natu .readdir = cb_readdir, 644c487da1eSNeel Natu .seek = cb_seek, 645c487da1eSNeel Natu .stat = cb_stat, 646c487da1eSNeel Natu 647c487da1eSNeel Natu .diskread = cb_diskread, 648cc71ff72SConrad Meyer .diskwrite = cb_diskwrite, 649a10c6f55SNeel Natu .diskioctl = cb_diskioctl, 650c487da1eSNeel Natu 651c487da1eSNeel Natu .copyin = cb_copyin, 652c487da1eSNeel Natu .copyout = cb_copyout, 653c487da1eSNeel Natu .setreg = cb_setreg, 654c487da1eSNeel Natu .setmsr = cb_setmsr, 655c487da1eSNeel Natu .setcr = cb_setcr, 656c487da1eSNeel Natu .setgdt = cb_setgdt, 657c487da1eSNeel Natu .exec = cb_exec, 658c487da1eSNeel Natu 659c487da1eSNeel Natu .delay = cb_delay, 660c487da1eSNeel Natu .exit = cb_exit, 661c487da1eSNeel Natu .getmem = cb_getmem, 662c3e9ce33SNeel Natu 663c3e9ce33SNeel Natu .getenv = cb_getenv, 66448f337b8SMarcel Moolenaar 66548f337b8SMarcel Moolenaar /* Version 4 additions */ 66648f337b8SMarcel Moolenaar .vm_set_register = cb_vm_set_register, 66748f337b8SMarcel Moolenaar .vm_set_desc = cb_vm_set_desc, 668d3d381b2SKyle Evans 669d3d381b2SKyle Evans /* Version 5 additions */ 670d3d381b2SKyle Evans .swap_interpreter = cb_swap_interpreter, 671c487da1eSNeel Natu }; 672c487da1eSNeel Natu 6736380102cSPeter Grehan static int 6746380102cSPeter Grehan altcons_open(char *path) 6756380102cSPeter Grehan { 6766380102cSPeter Grehan struct stat sb; 6776380102cSPeter Grehan int err; 6786380102cSPeter Grehan int fd; 6796380102cSPeter Grehan 6806380102cSPeter Grehan /* 6816380102cSPeter Grehan * Allow stdio to be passed in so that the same string 6826380102cSPeter Grehan * can be used for the bhyveload console and bhyve com-port 6836380102cSPeter Grehan * parameters 6846380102cSPeter Grehan */ 6856380102cSPeter Grehan if (!strcmp(path, "stdio")) 6866380102cSPeter Grehan return (0); 6876380102cSPeter Grehan 6886380102cSPeter Grehan err = stat(path, &sb); 6896380102cSPeter Grehan if (err == 0) { 6906380102cSPeter Grehan if (!S_ISCHR(sb.st_mode)) 6916380102cSPeter Grehan err = ENOTSUP; 6926380102cSPeter Grehan else { 6936380102cSPeter Grehan fd = open(path, O_RDWR | O_NONBLOCK); 6946380102cSPeter Grehan if (fd < 0) 6956380102cSPeter Grehan err = errno; 6966380102cSPeter Grehan else 6976380102cSPeter Grehan consin_fd = consout_fd = fd; 6986380102cSPeter Grehan } 6996380102cSPeter Grehan } 7006380102cSPeter Grehan 7016380102cSPeter Grehan return (err); 7026380102cSPeter Grehan } 7036380102cSPeter Grehan 704cf087c12SPeter Grehan static int 705cf087c12SPeter Grehan disk_open(char *path) 706cf087c12SPeter Grehan { 707a0bc451fSSean Chittenden int fd; 708cf087c12SPeter Grehan 7090db293c1SAllan Jude if (ndisks >= NDISKS) 710cf087c12SPeter Grehan return (ERANGE); 711cf087c12SPeter Grehan 7125a023bd2SRobert Wing fd = open(path, O_RDWR); 713a0bc451fSSean Chittenden if (fd < 0) 714a0bc451fSSean Chittenden return (errno); 715cf087c12SPeter Grehan 716cf087c12SPeter Grehan disk_fd[ndisks] = fd; 717cf087c12SPeter Grehan ndisks++; 718cf087c12SPeter Grehan 719a0bc451fSSean Chittenden return (0); 720cf087c12SPeter Grehan } 721cf087c12SPeter Grehan 722c487da1eSNeel Natu static void 723c487da1eSNeel Natu usage(void) 724c487da1eSNeel Natu { 725c487da1eSNeel Natu 726b060ba50SNeel Natu fprintf(stderr, 7279b1aa8d6SNeel Natu "usage: %s [-S][-c <console-device>] [-d <disk-path>] [-e <name=value>]\n" 7286ee52c65SRoman Bogorodskiy " %*s [-h <host-path>] [-m memsize[K|k|M|m|G|g|T|t]] <vmname>\n", 7296380102cSPeter Grehan progname, 730b5331f4dSNeel Natu (int)strlen(progname), ""); 731c487da1eSNeel Natu exit(1); 732c487da1eSNeel Natu } 733c487da1eSNeel Natu 7346779d44bSKyle Evans static void 7356779d44bSKyle Evans hostbase_open(const char *base) 7366779d44bSKyle Evans { 7376779d44bSKyle Evans 7386779d44bSKyle Evans if (hostbase_fd != -1) 7396779d44bSKyle Evans close(hostbase_fd); 7406779d44bSKyle Evans hostbase_fd = open(base, O_DIRECTORY | O_PATH); 7416779d44bSKyle Evans if (hostbase_fd == -1) 7426779d44bSKyle Evans err(EX_OSERR, "open"); 7436779d44bSKyle Evans } 7446779d44bSKyle Evans 745bf7c4fcbSKyle Evans static void 746bf7c4fcbSKyle Evans loader_open(int bootfd) 747bf7c4fcbSKyle Evans { 748bf7c4fcbSKyle Evans int fd; 749bf7c4fcbSKyle Evans 750bf7c4fcbSKyle Evans if (loader == NULL) { 751bf7c4fcbSKyle Evans loader = strdup("userboot.so"); 752bf7c4fcbSKyle Evans if (loader == NULL) 753bf7c4fcbSKyle Evans err(EX_OSERR, "malloc"); 754bf7c4fcbSKyle Evans } 755bf7c4fcbSKyle Evans 756bf7c4fcbSKyle Evans assert(bootfd >= 0 || explicit_loader_fd >= 0); 757bf7c4fcbSKyle Evans if (explicit_loader_fd >= 0) 758bf7c4fcbSKyle Evans fd = explicit_loader_fd; 759bf7c4fcbSKyle Evans else 760bf7c4fcbSKyle Evans fd = openat(bootfd, loader, O_RDONLY | O_RESOLVE_BENEATH); 761bf7c4fcbSKyle Evans if (fd == -1) 762bf7c4fcbSKyle Evans err(EX_OSERR, "openat"); 763bf7c4fcbSKyle Evans 764bf7c4fcbSKyle Evans loader_hdl = fdlopen(fd, RTLD_LOCAL); 765bf7c4fcbSKyle Evans if (!loader_hdl) 766bf7c4fcbSKyle Evans errx(EX_OSERR, "dlopen: %s", dlerror()); 767bf7c4fcbSKyle Evans } 768bf7c4fcbSKyle Evans 769c487da1eSNeel Natu int 770c487da1eSNeel Natu main(int argc, char** argv) 771c487da1eSNeel Natu { 772a10c6f55SNeel Natu void (*func)(struct loader_callbacks *, void *, int, int); 773b060ba50SNeel Natu uint64_t mem_size; 774bf7c4fcbSKyle Evans int bootfd, opt, error, memflags, need_reinit; 775c487da1eSNeel Natu 776bf7c4fcbSKyle Evans bootfd = -1; 777b5331f4dSNeel Natu progname = basename(argv[0]); 778c487da1eSNeel Natu 7799b1aa8d6SNeel Natu memflags = 0; 780b060ba50SNeel Natu mem_size = 256 * MB; 781c487da1eSNeel Natu 7826380102cSPeter Grehan consin_fd = STDIN_FILENO; 7836380102cSPeter Grehan consout_fd = STDOUT_FILENO; 7846380102cSPeter Grehan 785568e3a8dSMarcel Moolenaar while ((opt = getopt(argc, argv, "CSc:d:e:h:l:m:")) != -1) { 786c487da1eSNeel Natu switch (opt) { 7876380102cSPeter Grehan case 'c': 7886380102cSPeter Grehan error = altcons_open(optarg); 7896380102cSPeter Grehan if (error != 0) 7906380102cSPeter Grehan errx(EX_USAGE, "Could not open '%s'", optarg); 7916380102cSPeter Grehan break; 792cf087c12SPeter Grehan 793c487da1eSNeel Natu case 'd': 794cf087c12SPeter Grehan error = disk_open(optarg); 795cf087c12SPeter Grehan if (error != 0) 796cf087c12SPeter Grehan errx(EX_USAGE, "Could not open '%s'", optarg); 797c487da1eSNeel Natu break; 798c487da1eSNeel Natu 799b6afa84bSNeel Natu case 'e': 800b6afa84bSNeel Natu addenv(optarg); 801b6afa84bSNeel Natu break; 802b6afa84bSNeel Natu 803c487da1eSNeel Natu case 'h': 8046779d44bSKyle Evans hostbase_open(optarg); 805c487da1eSNeel Natu break; 806c487da1eSNeel Natu 8078c96dcc1SMarcel Moolenaar case 'l': 8088c96dcc1SMarcel Moolenaar if (loader != NULL) 8098c96dcc1SMarcel Moolenaar errx(EX_USAGE, "-l can only be given once"); 8108c96dcc1SMarcel Moolenaar loader = strdup(optarg); 8118c96dcc1SMarcel Moolenaar if (loader == NULL) 8128c96dcc1SMarcel Moolenaar err(EX_OSERR, "malloc"); 813bf7c4fcbSKyle Evans explicit_loader_fd = open(loader, O_RDONLY); 814bf7c4fcbSKyle Evans if (explicit_loader_fd == -1) 815bf7c4fcbSKyle Evans err(EX_OSERR, "%s", loader); 8168c96dcc1SMarcel Moolenaar break; 8178c96dcc1SMarcel Moolenaar 818c487da1eSNeel Natu case 'm': 819200758f1SNeel Natu error = vm_parse_memsize(optarg, &mem_size); 820200758f1SNeel Natu if (error != 0) 821200758f1SNeel Natu errx(EX_USAGE, "Invalid memsize '%s'", optarg); 822c487da1eSNeel Natu break; 823568e3a8dSMarcel Moolenaar case 'C': 824568e3a8dSMarcel Moolenaar memflags |= VM_MEM_F_INCORE; 825568e3a8dSMarcel Moolenaar break; 8269b1aa8d6SNeel Natu case 'S': 8279b1aa8d6SNeel Natu memflags |= VM_MEM_F_WIRED; 8289b1aa8d6SNeel Natu break; 829c487da1eSNeel Natu case '?': 830c487da1eSNeel Natu usage(); 831c487da1eSNeel Natu } 832c487da1eSNeel Natu } 833c487da1eSNeel Natu 834c487da1eSNeel Natu argc -= optind; 835c487da1eSNeel Natu argv += optind; 836c487da1eSNeel Natu 837c487da1eSNeel Natu if (argc != 1) 838c487da1eSNeel Natu usage(); 839c487da1eSNeel Natu 840c487da1eSNeel Natu vmname = argv[0]; 841c487da1eSNeel Natu 8425fcf252fSNeel Natu need_reinit = 0; 843c487da1eSNeel Natu error = vm_create(vmname); 8445fcf252fSNeel Natu if (error) { 8455fcf252fSNeel Natu if (errno != EEXIST) { 846c487da1eSNeel Natu perror("vm_create"); 847c487da1eSNeel Natu exit(1); 8485fcf252fSNeel Natu } 8495fcf252fSNeel Natu need_reinit = 1; 850c487da1eSNeel Natu } 851c487da1eSNeel Natu 852c487da1eSNeel Natu ctx = vm_open(vmname); 853c487da1eSNeel Natu if (ctx == NULL) { 854c487da1eSNeel Natu perror("vm_open"); 855c487da1eSNeel Natu exit(1); 856c487da1eSNeel Natu } 857c487da1eSNeel Natu 858bf7c4fcbSKyle Evans /* 859bf7c4fcbSKyle Evans * If we weren't given an explicit loader to use, we need to support the 860bf7c4fcbSKyle Evans * guest requesting a different one. 861bf7c4fcbSKyle Evans */ 862bf7c4fcbSKyle Evans if (explicit_loader_fd == -1) { 863bf7c4fcbSKyle Evans bootfd = open("/boot", O_DIRECTORY | O_PATH); 864bf7c4fcbSKyle Evans if (bootfd == -1) { 865bf7c4fcbSKyle Evans perror("open"); 866bf7c4fcbSKyle Evans exit(1); 867bf7c4fcbSKyle Evans } 868bf7c4fcbSKyle Evans } 869bf7c4fcbSKyle Evans 8707d9ef309SJohn Baldwin vcpu = vm_vcpu_open(ctx, BSP); 8717d9ef309SJohn Baldwin 872*8bf0882eSKyle Evans caph_cache_catpages(); 873*8bf0882eSKyle Evans if (caph_enter() < 0) { 874*8bf0882eSKyle Evans perror("caph_enter"); 875*8bf0882eSKyle Evans exit(1); 876*8bf0882eSKyle Evans } 877*8bf0882eSKyle Evans 878d3d381b2SKyle Evans /* 879d3d381b2SKyle Evans * setjmp in the case the guest wants to swap out interpreter, 880d3d381b2SKyle Evans * cb_swap_interpreter will swap out loader as appropriate and set 881d3d381b2SKyle Evans * need_reinit so that we end up in a clean state once again. 882d3d381b2SKyle Evans */ 883bf7c4fcbSKyle Evans if (setjmp(jb) != 0) { 884bf7c4fcbSKyle Evans dlclose(loader_hdl); 885bf7c4fcbSKyle Evans loader_hdl = NULL; 886bf7c4fcbSKyle Evans 887bf7c4fcbSKyle Evans need_reinit = 1; 888bf7c4fcbSKyle Evans } 889d3d381b2SKyle Evans 8905fcf252fSNeel Natu if (need_reinit) { 8915fcf252fSNeel Natu error = vm_reinit(ctx); 8925fcf252fSNeel Natu if (error) { 8935fcf252fSNeel Natu perror("vm_reinit"); 8945fcf252fSNeel Natu exit(1); 8955fcf252fSNeel Natu } 8965fcf252fSNeel Natu } 8975fcf252fSNeel Natu 8989b1aa8d6SNeel Natu vm_set_memflags(ctx, memflags); 899b060ba50SNeel Natu error = vm_setup_memory(ctx, mem_size, VM_MMAP_ALL); 900c487da1eSNeel Natu if (error) { 901b060ba50SNeel Natu perror("vm_setup_memory"); 902c487da1eSNeel Natu exit(1); 903c487da1eSNeel Natu } 904c487da1eSNeel Natu 905bf7c4fcbSKyle Evans loader_open(bootfd); 906d3d381b2SKyle Evans func = dlsym(loader_hdl, "loader_main"); 9078c96dcc1SMarcel Moolenaar if (!func) { 9088c96dcc1SMarcel Moolenaar printf("%s\n", dlerror()); 9098c96dcc1SMarcel Moolenaar free(loader); 9108c96dcc1SMarcel Moolenaar return (1); 9118c96dcc1SMarcel Moolenaar } 9128c96dcc1SMarcel Moolenaar 9136380102cSPeter Grehan tcgetattr(consout_fd, &term); 914c487da1eSNeel Natu oldterm = term; 9156380102cSPeter Grehan cfmakeraw(&term); 9166380102cSPeter Grehan term.c_cflag |= CLOCAL; 9176380102cSPeter Grehan 9186380102cSPeter Grehan tcsetattr(consout_fd, TCSAFLUSH, &term); 9196380102cSPeter Grehan 920b6afa84bSNeel Natu addenv("smbios.bios.vendor=BHYVE"); 921b6afa84bSNeel Natu addenv("boot_serial=1"); 922b6afa84bSNeel Natu 923d3d381b2SKyle Evans func(&cb, NULL, USERBOOT_VERSION_5, ndisks); 9248c96dcc1SMarcel Moolenaar 9258c96dcc1SMarcel Moolenaar free(loader); 9268c96dcc1SMarcel Moolenaar return (0); 927c487da1eSNeel Natu } 928