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 818bf0882eSKyle 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 92*24cd5c26SKyle Evans /* 93*24cd5c26SKyle Evans * Reason for our loader reload and reentry, though these aren't really used 94*24cd5c26SKyle Evans * at the moment. 95*24cd5c26SKyle Evans */ 96*24cd5c26SKyle Evans enum { 97*24cd5c26SKyle Evans /* 0 cannot be allocated; setjmp(3) return. */ 98*24cd5c26SKyle Evans JMP_SWAPLOADER = 0x01, 99*24cd5c26SKyle Evans JMP_REBOOT, 100*24cd5c26SKyle Evans }; 101*24cd5c26SKyle Evans 102c487da1eSNeel Natu static struct termios term, oldterm; 103cf087c12SPeter Grehan static int disk_fd[NDISKS]; 104cf087c12SPeter Grehan static int ndisks; 1056380102cSPeter Grehan static int consin_fd, consout_fd; 1066779d44bSKyle Evans static int hostbase_fd = -1; 107c487da1eSNeel Natu 108d3d381b2SKyle Evans static void *loader_hdl; 109d3d381b2SKyle Evans static char *loader; 11067082f07SKyle Evans static int explicit_loader_fd = -1; 111d3d381b2SKyle Evans static jmp_buf jb; 112d3d381b2SKyle Evans 113b060ba50SNeel Natu static char *vmname, *progname; 114c487da1eSNeel Natu static struct vmctx *ctx; 1157d9ef309SJohn Baldwin static struct vcpu *vcpu; 116c487da1eSNeel Natu 117c487da1eSNeel Natu static uint64_t gdtbase, cr3, rsp; 118c487da1eSNeel Natu 119c487da1eSNeel Natu static void cb_exit(void *arg, int v); 120c487da1eSNeel Natu 121c487da1eSNeel Natu /* 122c487da1eSNeel Natu * Console i/o callbacks 123c487da1eSNeel Natu */ 124c487da1eSNeel Natu 125c487da1eSNeel Natu static void 126ad43dd69SMark Johnston cb_putc(void *arg __unused, int ch) 127c487da1eSNeel Natu { 128c487da1eSNeel Natu char c = ch; 129c487da1eSNeel Natu 1306380102cSPeter Grehan (void) write(consout_fd, &c, 1); 131c487da1eSNeel Natu } 132c487da1eSNeel Natu 133c487da1eSNeel Natu static int 134ad43dd69SMark Johnston cb_getc(void *arg __unused) 135c487da1eSNeel Natu { 136c487da1eSNeel Natu char c; 137c487da1eSNeel Natu 1386380102cSPeter Grehan if (read(consin_fd, &c, 1) == 1) 139c487da1eSNeel Natu return (c); 140c487da1eSNeel Natu return (-1); 141c487da1eSNeel Natu } 142c487da1eSNeel Natu 143c487da1eSNeel Natu static int 144ad43dd69SMark Johnston cb_poll(void *arg __unused) 145c487da1eSNeel Natu { 146c487da1eSNeel Natu int n; 147c487da1eSNeel Natu 1486380102cSPeter Grehan if (ioctl(consin_fd, FIONREAD, &n) >= 0) 149c487da1eSNeel Natu return (n > 0); 150c487da1eSNeel Natu return (0); 151c487da1eSNeel Natu } 152c487da1eSNeel Natu 153c487da1eSNeel Natu /* 154c487da1eSNeel Natu * Host filesystem i/o callbacks 155c487da1eSNeel Natu */ 156c487da1eSNeel Natu 157c487da1eSNeel Natu struct cb_file { 158c487da1eSNeel Natu int cf_isdir; 159c487da1eSNeel Natu size_t cf_size; 160c487da1eSNeel Natu struct stat cf_stat; 161c487da1eSNeel Natu union { 162c487da1eSNeel Natu int fd; 163c487da1eSNeel Natu DIR *dir; 164c487da1eSNeel Natu } cf_u; 165c487da1eSNeel Natu }; 166c487da1eSNeel Natu 167c487da1eSNeel Natu static int 168ad43dd69SMark Johnston cb_open(void *arg __unused, const char *filename, void **hp) 169c487da1eSNeel Natu { 170c487da1eSNeel Natu struct cb_file *cf; 1716779d44bSKyle Evans struct stat sb; 1726779d44bSKyle Evans int fd, flags; 173c487da1eSNeel Natu 1746779d44bSKyle Evans cf = NULL; 1756779d44bSKyle Evans fd = -1; 1766779d44bSKyle Evans flags = O_RDONLY | O_RESOLVE_BENEATH; 1776779d44bSKyle Evans if (hostbase_fd == -1) 178c487da1eSNeel Natu return (ENOENT); 179c487da1eSNeel Natu 1806779d44bSKyle Evans /* Absolute paths are relative to our hostbase, chop off leading /. */ 1816779d44bSKyle Evans if (filename[0] == '/') 1826779d44bSKyle Evans filename++; 1836779d44bSKyle Evans 1846779d44bSKyle Evans /* Lookup of /, use . instead. */ 1856779d44bSKyle Evans if (filename[0] == '\0') 1866779d44bSKyle Evans filename = "."; 1876779d44bSKyle Evans 1886779d44bSKyle Evans if (fstatat(hostbase_fd, filename, &sb, AT_RESOLVE_BENEATH) < 0) 189c487da1eSNeel Natu return (errno); 1906779d44bSKyle Evans 1916779d44bSKyle Evans if (!S_ISDIR(sb.st_mode) && !S_ISREG(sb.st_mode)) 1926779d44bSKyle Evans return (EINVAL); 1936779d44bSKyle Evans 1946779d44bSKyle Evans if (S_ISDIR(sb.st_mode)) 1956779d44bSKyle Evans flags |= O_DIRECTORY; 1966779d44bSKyle Evans 1976779d44bSKyle Evans /* May be opening the root dir */ 1986779d44bSKyle Evans fd = openat(hostbase_fd, filename, flags); 1996779d44bSKyle Evans if (fd < 0) 2006779d44bSKyle Evans return (errno); 2016779d44bSKyle Evans 2026779d44bSKyle Evans cf = malloc(sizeof(struct cb_file)); 2036779d44bSKyle Evans if (cf == NULL) { 2046779d44bSKyle Evans close(fd); 2056779d44bSKyle Evans return (ENOMEM); 206c487da1eSNeel Natu } 207c487da1eSNeel Natu 2086779d44bSKyle Evans cf->cf_stat = sb; 2098f61276dSPedro F. Giffuni cf->cf_size = cf->cf_stat.st_size; 2106779d44bSKyle Evans 211c487da1eSNeel Natu if (S_ISDIR(cf->cf_stat.st_mode)) { 212c487da1eSNeel Natu cf->cf_isdir = 1; 2136779d44bSKyle Evans cf->cf_u.dir = fdopendir(fd); 2146779d44bSKyle Evans if (cf->cf_u.dir == NULL) { 2156779d44bSKyle Evans close(fd); 216c487da1eSNeel Natu free(cf); 2176779d44bSKyle Evans return (ENOMEM); 2186779d44bSKyle Evans } 2196779d44bSKyle Evans } else { 2206779d44bSKyle Evans assert(S_ISREG(cf->cf_stat.st_mode)); 2216779d44bSKyle Evans cf->cf_isdir = 0; 2226779d44bSKyle Evans cf->cf_u.fd = fd; 2236779d44bSKyle Evans } 2246779d44bSKyle Evans *hp = cf; 2256779d44bSKyle Evans return (0); 226c487da1eSNeel Natu } 227c487da1eSNeel Natu 228c487da1eSNeel Natu static int 229ad43dd69SMark Johnston cb_close(void *arg __unused, void *h) 230c487da1eSNeel Natu { 231c487da1eSNeel Natu struct cb_file *cf = h; 232c487da1eSNeel Natu 233c487da1eSNeel Natu if (cf->cf_isdir) 234c487da1eSNeel Natu closedir(cf->cf_u.dir); 235c487da1eSNeel Natu else 236c487da1eSNeel Natu close(cf->cf_u.fd); 237c487da1eSNeel Natu free(cf); 238c487da1eSNeel Natu 239c487da1eSNeel Natu return (0); 240c487da1eSNeel Natu } 241c487da1eSNeel Natu 242c487da1eSNeel Natu static int 243ad43dd69SMark Johnston cb_isdir(void *arg __unused, void *h) 244c487da1eSNeel Natu { 245c487da1eSNeel Natu struct cb_file *cf = h; 246c487da1eSNeel Natu 247c487da1eSNeel Natu return (cf->cf_isdir); 248c487da1eSNeel Natu } 249c487da1eSNeel Natu 250c487da1eSNeel Natu static int 251ad43dd69SMark Johnston cb_read(void *arg __unused, void *h, void *buf, size_t size, size_t *resid) 252c487da1eSNeel Natu { 253c487da1eSNeel Natu struct cb_file *cf = h; 254c487da1eSNeel Natu ssize_t sz; 255c487da1eSNeel Natu 256c487da1eSNeel Natu if (cf->cf_isdir) 257c487da1eSNeel Natu return (EINVAL); 258c487da1eSNeel Natu sz = read(cf->cf_u.fd, buf, size); 259c487da1eSNeel Natu if (sz < 0) 260c487da1eSNeel Natu return (EINVAL); 261c487da1eSNeel Natu *resid = size - sz; 262c487da1eSNeel Natu return (0); 263c487da1eSNeel Natu } 264c487da1eSNeel Natu 265c487da1eSNeel Natu static int 266ad43dd69SMark Johnston cb_readdir(void *arg __unused, void *h, uint32_t *fileno_return, 267ad43dd69SMark Johnston uint8_t *type_return, size_t *namelen_return, char *name) 268c487da1eSNeel Natu { 269c487da1eSNeel Natu struct cb_file *cf = h; 270c487da1eSNeel Natu struct dirent *dp; 271c487da1eSNeel Natu 272c487da1eSNeel Natu if (!cf->cf_isdir) 273c487da1eSNeel Natu return (EINVAL); 274c487da1eSNeel Natu 275c487da1eSNeel Natu dp = readdir(cf->cf_u.dir); 276c487da1eSNeel Natu if (!dp) 277c487da1eSNeel Natu return (ENOENT); 278c487da1eSNeel Natu 279c487da1eSNeel Natu /* 280c487da1eSNeel Natu * Note: d_namlen is in the range 0..255 and therefore less 281c487da1eSNeel Natu * than PATH_MAX so we don't need to test before copying. 282c487da1eSNeel Natu */ 283c487da1eSNeel Natu *fileno_return = dp->d_fileno; 284c487da1eSNeel Natu *type_return = dp->d_type; 285c487da1eSNeel Natu *namelen_return = dp->d_namlen; 286c487da1eSNeel Natu memcpy(name, dp->d_name, dp->d_namlen); 287c487da1eSNeel Natu name[dp->d_namlen] = 0; 288c487da1eSNeel Natu 289c487da1eSNeel Natu return (0); 290c487da1eSNeel Natu } 291c487da1eSNeel Natu 292c487da1eSNeel Natu static int 293ad43dd69SMark Johnston cb_seek(void *arg __unused, void *h, uint64_t offset, int whence) 294c487da1eSNeel Natu { 295c487da1eSNeel Natu struct cb_file *cf = h; 296c487da1eSNeel Natu 297c487da1eSNeel Natu if (cf->cf_isdir) 298c487da1eSNeel Natu return (EINVAL); 299c487da1eSNeel Natu if (lseek(cf->cf_u.fd, offset, whence) < 0) 300c487da1eSNeel Natu return (errno); 301c487da1eSNeel Natu return (0); 302c487da1eSNeel Natu } 303c487da1eSNeel Natu 304c487da1eSNeel Natu static int 305ad43dd69SMark Johnston cb_stat(void *arg __unused, void *h, struct stat *sbp) 306c487da1eSNeel Natu { 307c487da1eSNeel Natu struct cb_file *cf = h; 308c487da1eSNeel Natu 30953f151f9SSimon J. Gerraty memset(sbp, 0, sizeof(struct stat)); 31053f151f9SSimon J. Gerraty sbp->st_mode = cf->cf_stat.st_mode; 31153f151f9SSimon J. Gerraty sbp->st_uid = cf->cf_stat.st_uid; 31253f151f9SSimon J. Gerraty sbp->st_gid = cf->cf_stat.st_gid; 31353f151f9SSimon J. Gerraty sbp->st_size = cf->cf_stat.st_size; 31453f151f9SSimon J. Gerraty sbp->st_mtime = cf->cf_stat.st_mtime; 31553f151f9SSimon J. Gerraty sbp->st_dev = cf->cf_stat.st_dev; 31653f151f9SSimon J. Gerraty sbp->st_ino = cf->cf_stat.st_ino; 31753f151f9SSimon J. Gerraty 318c487da1eSNeel Natu return (0); 319c487da1eSNeel Natu } 320c487da1eSNeel Natu 321c487da1eSNeel Natu /* 322c487da1eSNeel Natu * Disk image i/o callbacks 323c487da1eSNeel Natu */ 324c487da1eSNeel Natu 325c487da1eSNeel Natu static int 326ad43dd69SMark Johnston cb_diskread(void *arg __unused, int unit, uint64_t from, void *to, size_t size, 327c487da1eSNeel Natu size_t *resid) 328c487da1eSNeel Natu { 329c487da1eSNeel Natu ssize_t n; 330c487da1eSNeel Natu 331cf087c12SPeter Grehan if (unit < 0 || unit >= ndisks) 332c487da1eSNeel Natu return (EIO); 333cf087c12SPeter Grehan n = pread(disk_fd[unit], to, size, from); 334c487da1eSNeel Natu if (n < 0) 335c487da1eSNeel Natu return (errno); 336c487da1eSNeel Natu *resid = size - n; 337c487da1eSNeel Natu return (0); 338c487da1eSNeel Natu } 339c487da1eSNeel Natu 340a10c6f55SNeel Natu static int 341ad43dd69SMark Johnston cb_diskwrite(void *arg __unused, int unit, uint64_t offset, void *src, 342ad43dd69SMark Johnston size_t size, size_t *resid) 343cc71ff72SConrad Meyer { 344cc71ff72SConrad Meyer ssize_t n; 345cc71ff72SConrad Meyer 346cc71ff72SConrad Meyer if (unit < 0 || unit >= ndisks) 347cc71ff72SConrad Meyer return (EIO); 348cc71ff72SConrad Meyer n = pwrite(disk_fd[unit], src, size, offset); 349cc71ff72SConrad Meyer if (n < 0) 350cc71ff72SConrad Meyer return (errno); 351cc71ff72SConrad Meyer *resid = size - n; 352cc71ff72SConrad Meyer return (0); 353cc71ff72SConrad Meyer } 354cc71ff72SConrad Meyer 355cc71ff72SConrad Meyer static int 356ad43dd69SMark Johnston cb_diskioctl(void *arg __unused, int unit, u_long cmd, void *data) 357a10c6f55SNeel Natu { 358a10c6f55SNeel Natu struct stat sb; 359a10c6f55SNeel Natu 360cf087c12SPeter Grehan if (unit < 0 || unit >= ndisks) 361a10c6f55SNeel Natu return (EBADF); 362a10c6f55SNeel Natu 363a10c6f55SNeel Natu switch (cmd) { 364a10c6f55SNeel Natu case DIOCGSECTORSIZE: 365a10c6f55SNeel Natu *(u_int *)data = 512; 366a10c6f55SNeel Natu break; 367a10c6f55SNeel Natu case DIOCGMEDIASIZE: 3686589ee29SAndriy Gapon if (fstat(disk_fd[unit], &sb) != 0) 369a10c6f55SNeel Natu return (ENOTTY); 3706589ee29SAndriy Gapon if (S_ISCHR(sb.st_mode) && 3716589ee29SAndriy Gapon ioctl(disk_fd[unit], DIOCGMEDIASIZE, &sb.st_size) != 0) 3726589ee29SAndriy Gapon return (ENOTTY); 3736589ee29SAndriy Gapon *(off_t *)data = sb.st_size; 374a10c6f55SNeel Natu break; 375a10c6f55SNeel Natu default: 376a10c6f55SNeel Natu return (ENOTTY); 377a10c6f55SNeel Natu } 378a10c6f55SNeel Natu 379a10c6f55SNeel Natu return (0); 380a10c6f55SNeel Natu } 381a10c6f55SNeel Natu 382c487da1eSNeel Natu /* 383c487da1eSNeel Natu * Guest virtual machine i/o callbacks 384c487da1eSNeel Natu */ 385c487da1eSNeel Natu static int 386ad43dd69SMark Johnston cb_copyin(void *arg __unused, const void *from, uint64_t to, size_t size) 387c487da1eSNeel Natu { 388b060ba50SNeel Natu char *ptr; 389c487da1eSNeel Natu 390c487da1eSNeel Natu to &= 0x7fffffff; 391b060ba50SNeel Natu 392b060ba50SNeel Natu ptr = vm_map_gpa(ctx, to, size); 393b060ba50SNeel Natu if (ptr == NULL) 394c487da1eSNeel Natu return (EFAULT); 395c487da1eSNeel Natu 396b060ba50SNeel Natu memcpy(ptr, from, size); 397c487da1eSNeel Natu return (0); 398c487da1eSNeel Natu } 399c487da1eSNeel Natu 400c487da1eSNeel Natu static int 401ad43dd69SMark Johnston cb_copyout(void *arg __unused, uint64_t from, void *to, size_t size) 402c487da1eSNeel Natu { 403b060ba50SNeel Natu char *ptr; 404c487da1eSNeel Natu 405c487da1eSNeel Natu from &= 0x7fffffff; 406b060ba50SNeel Natu 407b060ba50SNeel Natu ptr = vm_map_gpa(ctx, from, size); 408b060ba50SNeel Natu if (ptr == NULL) 409c487da1eSNeel Natu return (EFAULT); 410c487da1eSNeel Natu 411b060ba50SNeel Natu memcpy(to, ptr, size); 412c487da1eSNeel Natu return (0); 413c487da1eSNeel Natu } 414c487da1eSNeel Natu 415c487da1eSNeel Natu static void 416ad43dd69SMark Johnston cb_setreg(void *arg __unused, int r, uint64_t v) 417c487da1eSNeel Natu { 418c487da1eSNeel Natu int error; 419c487da1eSNeel Natu enum vm_reg_name vmreg; 420c487da1eSNeel Natu 421c487da1eSNeel Natu vmreg = VM_REG_LAST; 422c487da1eSNeel Natu 423c487da1eSNeel Natu switch (r) { 424c487da1eSNeel Natu case 4: 425c487da1eSNeel Natu vmreg = VM_REG_GUEST_RSP; 426c487da1eSNeel Natu rsp = v; 427c487da1eSNeel Natu break; 428c487da1eSNeel Natu default: 429c487da1eSNeel Natu break; 430c487da1eSNeel Natu } 431c487da1eSNeel Natu 432c487da1eSNeel Natu if (vmreg == VM_REG_LAST) { 433c487da1eSNeel Natu printf("test_setreg(%d): not implemented\n", r); 434c487da1eSNeel Natu cb_exit(NULL, USERBOOT_EXIT_QUIT); 435c487da1eSNeel Natu } 436c487da1eSNeel Natu 4377d9ef309SJohn Baldwin error = vm_set_register(vcpu, vmreg, v); 438c487da1eSNeel Natu if (error) { 439c487da1eSNeel Natu perror("vm_set_register"); 440c487da1eSNeel Natu cb_exit(NULL, USERBOOT_EXIT_QUIT); 441c487da1eSNeel Natu } 442c487da1eSNeel Natu } 443c487da1eSNeel Natu 444c487da1eSNeel Natu static void 445ad43dd69SMark Johnston cb_setmsr(void *arg __unused, int r, uint64_t v) 446c487da1eSNeel Natu { 447c487da1eSNeel Natu int error; 448c487da1eSNeel Natu enum vm_reg_name vmreg; 449c487da1eSNeel Natu 450c487da1eSNeel Natu vmreg = VM_REG_LAST; 451c487da1eSNeel Natu 452c487da1eSNeel Natu switch (r) { 453c487da1eSNeel Natu case MSR_EFER: 454c487da1eSNeel Natu vmreg = VM_REG_GUEST_EFER; 455c487da1eSNeel Natu break; 456c487da1eSNeel Natu default: 457c487da1eSNeel Natu break; 458c487da1eSNeel Natu } 459c487da1eSNeel Natu 460c487da1eSNeel Natu if (vmreg == VM_REG_LAST) { 461c487da1eSNeel Natu printf("test_setmsr(%d): not implemented\n", r); 462c487da1eSNeel Natu cb_exit(NULL, USERBOOT_EXIT_QUIT); 463c487da1eSNeel Natu } 464c487da1eSNeel Natu 4657d9ef309SJohn Baldwin error = vm_set_register(vcpu, vmreg, v); 466c487da1eSNeel Natu if (error) { 467c487da1eSNeel Natu perror("vm_set_msr"); 468c487da1eSNeel Natu cb_exit(NULL, USERBOOT_EXIT_QUIT); 469c487da1eSNeel Natu } 470c487da1eSNeel Natu } 471c487da1eSNeel Natu 472c487da1eSNeel Natu static void 473ad43dd69SMark Johnston cb_setcr(void *arg __unused, int r, uint64_t v) 474c487da1eSNeel Natu { 475c487da1eSNeel Natu int error; 476c487da1eSNeel Natu enum vm_reg_name vmreg; 477c487da1eSNeel Natu 478c487da1eSNeel Natu vmreg = VM_REG_LAST; 479c487da1eSNeel Natu 480c487da1eSNeel Natu switch (r) { 481c487da1eSNeel Natu case 0: 482c487da1eSNeel Natu vmreg = VM_REG_GUEST_CR0; 483c487da1eSNeel Natu break; 484c487da1eSNeel Natu case 3: 485c487da1eSNeel Natu vmreg = VM_REG_GUEST_CR3; 486c487da1eSNeel Natu cr3 = v; 487c487da1eSNeel Natu break; 488c487da1eSNeel Natu case 4: 489c487da1eSNeel Natu vmreg = VM_REG_GUEST_CR4; 490c487da1eSNeel Natu break; 491c487da1eSNeel Natu default: 492c487da1eSNeel Natu break; 493c487da1eSNeel Natu } 494c487da1eSNeel Natu 495c487da1eSNeel Natu if (vmreg == VM_REG_LAST) { 496c487da1eSNeel Natu printf("test_setcr(%d): not implemented\n", r); 497c487da1eSNeel Natu cb_exit(NULL, USERBOOT_EXIT_QUIT); 498c487da1eSNeel Natu } 499c487da1eSNeel Natu 5007d9ef309SJohn Baldwin error = vm_set_register(vcpu, vmreg, v); 501c487da1eSNeel Natu if (error) { 502c487da1eSNeel Natu perror("vm_set_cr"); 503c487da1eSNeel Natu cb_exit(NULL, USERBOOT_EXIT_QUIT); 504c487da1eSNeel Natu } 505c487da1eSNeel Natu } 506c487da1eSNeel Natu 507c487da1eSNeel Natu static void 508ad43dd69SMark Johnston cb_setgdt(void *arg __unused, uint64_t base, size_t size) 509c487da1eSNeel Natu { 510c487da1eSNeel Natu int error; 511c487da1eSNeel Natu 5127d9ef309SJohn Baldwin error = vm_set_desc(vcpu, VM_REG_GUEST_GDTR, base, size - 1, 0); 513c487da1eSNeel Natu if (error != 0) { 514c487da1eSNeel Natu perror("vm_set_desc(gdt)"); 515c487da1eSNeel Natu cb_exit(NULL, USERBOOT_EXIT_QUIT); 516c487da1eSNeel Natu } 517c487da1eSNeel Natu 518c487da1eSNeel Natu gdtbase = base; 519c487da1eSNeel Natu } 520c487da1eSNeel Natu 521c487da1eSNeel Natu static void 522ad43dd69SMark Johnston cb_exec(void *arg __unused, uint64_t rip) 523c487da1eSNeel Natu { 524c487da1eSNeel Natu int error; 525c487da1eSNeel Natu 52600f3efe1SJohn Baldwin if (cr3 == 0) 5277d9ef309SJohn Baldwin error = vm_setup_freebsd_registers_i386(vcpu, rip, gdtbase, 52800f3efe1SJohn Baldwin rsp); 52900f3efe1SJohn Baldwin else 5307d9ef309SJohn Baldwin error = vm_setup_freebsd_registers(vcpu, rip, cr3, gdtbase, 53100f3efe1SJohn Baldwin rsp); 532c487da1eSNeel Natu if (error) { 533c487da1eSNeel Natu perror("vm_setup_freebsd_registers"); 534c487da1eSNeel Natu cb_exit(NULL, USERBOOT_EXIT_QUIT); 535c487da1eSNeel Natu } 536c487da1eSNeel Natu 537c487da1eSNeel Natu cb_exit(NULL, 0); 538c487da1eSNeel Natu } 539c487da1eSNeel Natu 540c487da1eSNeel Natu /* 541c487da1eSNeel Natu * Misc 542c487da1eSNeel Natu */ 543c487da1eSNeel Natu 544c487da1eSNeel Natu static void 545ad43dd69SMark Johnston cb_delay(void *arg __unused, int usec) 546c487da1eSNeel Natu { 547c487da1eSNeel Natu 548c487da1eSNeel Natu usleep(usec); 549c487da1eSNeel Natu } 550c487da1eSNeel Natu 551c487da1eSNeel Natu static void 552ad43dd69SMark Johnston cb_exit(void *arg __unused, int v) 553c487da1eSNeel Natu { 554c487da1eSNeel Natu 5556380102cSPeter Grehan tcsetattr(consout_fd, TCSAFLUSH, &oldterm); 556*24cd5c26SKyle Evans if (v == USERBOOT_EXIT_REBOOT) 557*24cd5c26SKyle Evans longjmp(jb, JMP_REBOOT); 558c487da1eSNeel Natu exit(v); 559c487da1eSNeel Natu } 560c487da1eSNeel Natu 561c487da1eSNeel Natu static void 562ad43dd69SMark Johnston cb_getmem(void *arg __unused, uint64_t *ret_lowmem, uint64_t *ret_highmem) 563c487da1eSNeel Natu { 564c487da1eSNeel Natu 565be679db4SNeel Natu *ret_lowmem = vm_get_lowmem_size(ctx); 566be679db4SNeel Natu *ret_highmem = vm_get_highmem_size(ctx); 567c487da1eSNeel Natu } 568c487da1eSNeel Natu 569b6afa84bSNeel Natu struct env { 570cb37fc82SWarner Losh char *str; /* name=value */ 571b6afa84bSNeel Natu SLIST_ENTRY(env) next; 572b6afa84bSNeel Natu }; 573b6afa84bSNeel Natu 574b6afa84bSNeel Natu static SLIST_HEAD(envhead, env) envhead; 575b6afa84bSNeel Natu 576b6afa84bSNeel Natu static void 577ad43dd69SMark Johnston addenv(const char *str) 578b6afa84bSNeel Natu { 579b6afa84bSNeel Natu struct env *env; 580b6afa84bSNeel Natu 581b6afa84bSNeel Natu env = malloc(sizeof(struct env)); 582ad43dd69SMark Johnston if (env == NULL) 583ad43dd69SMark Johnston err(EX_OSERR, "malloc"); 584ad43dd69SMark Johnston env->str = strdup(str); 585ad43dd69SMark Johnston if (env->str == NULL) 586ad43dd69SMark Johnston err(EX_OSERR, "strdup"); 587b6afa84bSNeel Natu SLIST_INSERT_HEAD(&envhead, env, next); 588b6afa84bSNeel Natu } 589b6afa84bSNeel Natu 590e8e6a5f9SWarner Losh static char * 591ad43dd69SMark Johnston cb_getenv(void *arg __unused, int num) 592c3e9ce33SNeel Natu { 593b6afa84bSNeel Natu int i; 594b6afa84bSNeel Natu struct env *env; 595c3e9ce33SNeel Natu 596b6afa84bSNeel Natu i = 0; 597b6afa84bSNeel Natu SLIST_FOREACH(env, &envhead, next) { 598b6afa84bSNeel Natu if (i == num) 599b6afa84bSNeel Natu return (env->str); 600b6afa84bSNeel Natu i++; 601b6afa84bSNeel Natu } 602c3e9ce33SNeel Natu 603c3e9ce33SNeel Natu return (NULL); 604c3e9ce33SNeel Natu } 605c3e9ce33SNeel Natu 60648f337b8SMarcel Moolenaar static int 6077d9ef309SJohn Baldwin cb_vm_set_register(void *arg __unused, int vcpuid, int reg, uint64_t val) 60848f337b8SMarcel Moolenaar { 60948f337b8SMarcel Moolenaar 6107d9ef309SJohn Baldwin assert(vcpuid == BSP); 6117d9ef309SJohn Baldwin return (vm_set_register(vcpu, reg, val)); 61248f337b8SMarcel Moolenaar } 61348f337b8SMarcel Moolenaar 61448f337b8SMarcel Moolenaar static int 6157d9ef309SJohn Baldwin cb_vm_set_desc(void *arg __unused, int vcpuid, int reg, uint64_t base, 616ad43dd69SMark Johnston u_int limit, u_int access) 61748f337b8SMarcel Moolenaar { 61848f337b8SMarcel Moolenaar 6197d9ef309SJohn Baldwin assert(vcpuid == BSP); 6207d9ef309SJohn Baldwin return (vm_set_desc(vcpu, reg, base, limit, access)); 62148f337b8SMarcel Moolenaar } 62248f337b8SMarcel Moolenaar 623d3d381b2SKyle Evans static void 624ad43dd69SMark Johnston cb_swap_interpreter(void *arg __unused, const char *interp_req) 625d3d381b2SKyle Evans { 626d3d381b2SKyle Evans 627d3d381b2SKyle Evans /* 628d3d381b2SKyle Evans * If the user specified a loader but we detected a mismatch, we should 629d3d381b2SKyle Evans * not try to pivot to a different loader on them. 630d3d381b2SKyle Evans */ 631d3d381b2SKyle Evans free(loader); 632bf7c4fcbSKyle Evans if (explicit_loader_fd != -1) { 633d3d381b2SKyle Evans perror("requested loader interpreter does not match guest userboot"); 634d3d381b2SKyle Evans cb_exit(NULL, 1); 635d3d381b2SKyle Evans } 636d3d381b2SKyle Evans if (interp_req == NULL || *interp_req == '\0') { 637d3d381b2SKyle Evans perror("guest failed to request an interpreter"); 638d3d381b2SKyle Evans cb_exit(NULL, 1); 639d3d381b2SKyle Evans } 640d3d381b2SKyle Evans 641bf7c4fcbSKyle Evans if (asprintf(&loader, "userboot_%s.so", interp_req) == -1) 642d3d381b2SKyle Evans err(EX_OSERR, "malloc"); 643*24cd5c26SKyle Evans longjmp(jb, JMP_SWAPLOADER); 644d3d381b2SKyle Evans } 645d3d381b2SKyle Evans 646a10c6f55SNeel Natu static struct loader_callbacks cb = { 647c487da1eSNeel Natu .getc = cb_getc, 648c487da1eSNeel Natu .putc = cb_putc, 649c487da1eSNeel Natu .poll = cb_poll, 650c487da1eSNeel Natu 651c487da1eSNeel Natu .open = cb_open, 652c487da1eSNeel Natu .close = cb_close, 653c487da1eSNeel Natu .isdir = cb_isdir, 654c487da1eSNeel Natu .read = cb_read, 655c487da1eSNeel Natu .readdir = cb_readdir, 656c487da1eSNeel Natu .seek = cb_seek, 657c487da1eSNeel Natu .stat = cb_stat, 658c487da1eSNeel Natu 659c487da1eSNeel Natu .diskread = cb_diskread, 660cc71ff72SConrad Meyer .diskwrite = cb_diskwrite, 661a10c6f55SNeel Natu .diskioctl = cb_diskioctl, 662c487da1eSNeel Natu 663c487da1eSNeel Natu .copyin = cb_copyin, 664c487da1eSNeel Natu .copyout = cb_copyout, 665c487da1eSNeel Natu .setreg = cb_setreg, 666c487da1eSNeel Natu .setmsr = cb_setmsr, 667c487da1eSNeel Natu .setcr = cb_setcr, 668c487da1eSNeel Natu .setgdt = cb_setgdt, 669c487da1eSNeel Natu .exec = cb_exec, 670c487da1eSNeel Natu 671c487da1eSNeel Natu .delay = cb_delay, 672c487da1eSNeel Natu .exit = cb_exit, 673c487da1eSNeel Natu .getmem = cb_getmem, 674c3e9ce33SNeel Natu 675c3e9ce33SNeel Natu .getenv = cb_getenv, 67648f337b8SMarcel Moolenaar 67748f337b8SMarcel Moolenaar /* Version 4 additions */ 67848f337b8SMarcel Moolenaar .vm_set_register = cb_vm_set_register, 67948f337b8SMarcel Moolenaar .vm_set_desc = cb_vm_set_desc, 680d3d381b2SKyle Evans 681d3d381b2SKyle Evans /* Version 5 additions */ 682d3d381b2SKyle Evans .swap_interpreter = cb_swap_interpreter, 683c487da1eSNeel Natu }; 684c487da1eSNeel Natu 6856380102cSPeter Grehan static int 6866380102cSPeter Grehan altcons_open(char *path) 6876380102cSPeter Grehan { 6886380102cSPeter Grehan struct stat sb; 6896380102cSPeter Grehan int err; 6906380102cSPeter Grehan int fd; 6916380102cSPeter Grehan 6926380102cSPeter Grehan /* 6936380102cSPeter Grehan * Allow stdio to be passed in so that the same string 6946380102cSPeter Grehan * can be used for the bhyveload console and bhyve com-port 6956380102cSPeter Grehan * parameters 6966380102cSPeter Grehan */ 6976380102cSPeter Grehan if (!strcmp(path, "stdio")) 6986380102cSPeter Grehan return (0); 6996380102cSPeter Grehan 7006380102cSPeter Grehan err = stat(path, &sb); 7016380102cSPeter Grehan if (err == 0) { 7026380102cSPeter Grehan if (!S_ISCHR(sb.st_mode)) 7036380102cSPeter Grehan err = ENOTSUP; 7046380102cSPeter Grehan else { 7056380102cSPeter Grehan fd = open(path, O_RDWR | O_NONBLOCK); 7066380102cSPeter Grehan if (fd < 0) 7076380102cSPeter Grehan err = errno; 7086380102cSPeter Grehan else 7096380102cSPeter Grehan consin_fd = consout_fd = fd; 7106380102cSPeter Grehan } 7116380102cSPeter Grehan } 7126380102cSPeter Grehan 7136380102cSPeter Grehan return (err); 7146380102cSPeter Grehan } 7156380102cSPeter Grehan 716cf087c12SPeter Grehan static int 717cf087c12SPeter Grehan disk_open(char *path) 718cf087c12SPeter Grehan { 719a0bc451fSSean Chittenden int fd; 720cf087c12SPeter Grehan 7210db293c1SAllan Jude if (ndisks >= NDISKS) 722cf087c12SPeter Grehan return (ERANGE); 723cf087c12SPeter Grehan 7245a023bd2SRobert Wing fd = open(path, O_RDWR); 725a0bc451fSSean Chittenden if (fd < 0) 726a0bc451fSSean Chittenden return (errno); 727cf087c12SPeter Grehan 728cf087c12SPeter Grehan disk_fd[ndisks] = fd; 729cf087c12SPeter Grehan ndisks++; 730cf087c12SPeter Grehan 731a0bc451fSSean Chittenden return (0); 732cf087c12SPeter Grehan } 733cf087c12SPeter Grehan 734c487da1eSNeel Natu static void 735c487da1eSNeel Natu usage(void) 736c487da1eSNeel Natu { 737c487da1eSNeel Natu 738b060ba50SNeel Natu fprintf(stderr, 7399b1aa8d6SNeel Natu "usage: %s [-S][-c <console-device>] [-d <disk-path>] [-e <name=value>]\n" 7406ee52c65SRoman Bogorodskiy " %*s [-h <host-path>] [-m memsize[K|k|M|m|G|g|T|t]] <vmname>\n", 7416380102cSPeter Grehan progname, 742b5331f4dSNeel Natu (int)strlen(progname), ""); 743c487da1eSNeel Natu exit(1); 744c487da1eSNeel Natu } 745c487da1eSNeel Natu 7466779d44bSKyle Evans static void 7476779d44bSKyle Evans hostbase_open(const char *base) 7486779d44bSKyle Evans { 749c067be72SKyle Evans cap_rights_t rights; 7506779d44bSKyle Evans 7516779d44bSKyle Evans if (hostbase_fd != -1) 7526779d44bSKyle Evans close(hostbase_fd); 7536779d44bSKyle Evans hostbase_fd = open(base, O_DIRECTORY | O_PATH); 7546779d44bSKyle Evans if (hostbase_fd == -1) 7556779d44bSKyle Evans err(EX_OSERR, "open"); 756c067be72SKyle Evans 757c067be72SKyle Evans if (caph_rights_limit(hostbase_fd, cap_rights_init(&rights, CAP_FSTATAT, 758c067be72SKyle Evans CAP_LOOKUP, CAP_READ)) < 0) 759c067be72SKyle Evans err(EX_OSERR, "caph_rights_limit"); 7606779d44bSKyle Evans } 7616779d44bSKyle Evans 762bf7c4fcbSKyle Evans static void 763bf7c4fcbSKyle Evans loader_open(int bootfd) 764bf7c4fcbSKyle Evans { 765bf7c4fcbSKyle Evans int fd; 766bf7c4fcbSKyle Evans 767bf7c4fcbSKyle Evans if (loader == NULL) { 768bf7c4fcbSKyle Evans loader = strdup("userboot.so"); 769bf7c4fcbSKyle Evans if (loader == NULL) 770bf7c4fcbSKyle Evans err(EX_OSERR, "malloc"); 771bf7c4fcbSKyle Evans } 772bf7c4fcbSKyle Evans 773bf7c4fcbSKyle Evans assert(bootfd >= 0 || explicit_loader_fd >= 0); 774bf7c4fcbSKyle Evans if (explicit_loader_fd >= 0) 775bf7c4fcbSKyle Evans fd = explicit_loader_fd; 776bf7c4fcbSKyle Evans else 777bf7c4fcbSKyle Evans fd = openat(bootfd, loader, O_RDONLY | O_RESOLVE_BENEATH); 778bf7c4fcbSKyle Evans if (fd == -1) 779bf7c4fcbSKyle Evans err(EX_OSERR, "openat"); 780bf7c4fcbSKyle Evans 781bf7c4fcbSKyle Evans loader_hdl = fdlopen(fd, RTLD_LOCAL); 782bf7c4fcbSKyle Evans if (!loader_hdl) 783bf7c4fcbSKyle Evans errx(EX_OSERR, "dlopen: %s", dlerror()); 784*24cd5c26SKyle Evans if (fd != explicit_loader_fd) 785*24cd5c26SKyle Evans close(fd); 786bf7c4fcbSKyle Evans } 787bf7c4fcbSKyle Evans 788c487da1eSNeel Natu int 789c487da1eSNeel Natu main(int argc, char** argv) 790c487da1eSNeel Natu { 791a10c6f55SNeel Natu void (*func)(struct loader_callbacks *, void *, int, int); 792b060ba50SNeel Natu uint64_t mem_size; 793bf7c4fcbSKyle Evans int bootfd, opt, error, memflags, need_reinit; 794c487da1eSNeel Natu 795bf7c4fcbSKyle Evans bootfd = -1; 796b5331f4dSNeel Natu progname = basename(argv[0]); 797c487da1eSNeel Natu 7989b1aa8d6SNeel Natu memflags = 0; 799b060ba50SNeel Natu mem_size = 256 * MB; 800c487da1eSNeel Natu 8016380102cSPeter Grehan consin_fd = STDIN_FILENO; 8026380102cSPeter Grehan consout_fd = STDOUT_FILENO; 8036380102cSPeter Grehan 804568e3a8dSMarcel Moolenaar while ((opt = getopt(argc, argv, "CSc:d:e:h:l:m:")) != -1) { 805c487da1eSNeel Natu switch (opt) { 8066380102cSPeter Grehan case 'c': 8076380102cSPeter Grehan error = altcons_open(optarg); 8086380102cSPeter Grehan if (error != 0) 8096380102cSPeter Grehan errx(EX_USAGE, "Could not open '%s'", optarg); 8106380102cSPeter Grehan break; 811cf087c12SPeter Grehan 812c487da1eSNeel Natu case 'd': 813cf087c12SPeter Grehan error = disk_open(optarg); 814cf087c12SPeter Grehan if (error != 0) 815cf087c12SPeter Grehan errx(EX_USAGE, "Could not open '%s'", optarg); 816c487da1eSNeel Natu break; 817c487da1eSNeel Natu 818b6afa84bSNeel Natu case 'e': 819b6afa84bSNeel Natu addenv(optarg); 820b6afa84bSNeel Natu break; 821b6afa84bSNeel Natu 822c487da1eSNeel Natu case 'h': 8236779d44bSKyle Evans hostbase_open(optarg); 824c487da1eSNeel Natu break; 825c487da1eSNeel Natu 8268c96dcc1SMarcel Moolenaar case 'l': 8278c96dcc1SMarcel Moolenaar if (loader != NULL) 8288c96dcc1SMarcel Moolenaar errx(EX_USAGE, "-l can only be given once"); 8298c96dcc1SMarcel Moolenaar loader = strdup(optarg); 8308c96dcc1SMarcel Moolenaar if (loader == NULL) 8318c96dcc1SMarcel Moolenaar err(EX_OSERR, "malloc"); 832bf7c4fcbSKyle Evans explicit_loader_fd = open(loader, O_RDONLY); 833bf7c4fcbSKyle Evans if (explicit_loader_fd == -1) 834bf7c4fcbSKyle Evans err(EX_OSERR, "%s", loader); 8358c96dcc1SMarcel Moolenaar break; 8368c96dcc1SMarcel Moolenaar 837c487da1eSNeel Natu case 'm': 838200758f1SNeel Natu error = vm_parse_memsize(optarg, &mem_size); 839200758f1SNeel Natu if (error != 0) 840200758f1SNeel Natu errx(EX_USAGE, "Invalid memsize '%s'", optarg); 841c487da1eSNeel Natu break; 842568e3a8dSMarcel Moolenaar case 'C': 843568e3a8dSMarcel Moolenaar memflags |= VM_MEM_F_INCORE; 844568e3a8dSMarcel Moolenaar break; 8459b1aa8d6SNeel Natu case 'S': 8469b1aa8d6SNeel Natu memflags |= VM_MEM_F_WIRED; 8479b1aa8d6SNeel Natu break; 848c487da1eSNeel Natu case '?': 849c487da1eSNeel Natu usage(); 850c487da1eSNeel Natu } 851c487da1eSNeel Natu } 852c487da1eSNeel Natu 853c487da1eSNeel Natu argc -= optind; 854c487da1eSNeel Natu argv += optind; 855c487da1eSNeel Natu 856c487da1eSNeel Natu if (argc != 1) 857c487da1eSNeel Natu usage(); 858c487da1eSNeel Natu 859c487da1eSNeel Natu vmname = argv[0]; 860c487da1eSNeel Natu 8615fcf252fSNeel Natu need_reinit = 0; 862c487da1eSNeel Natu error = vm_create(vmname); 8635fcf252fSNeel Natu if (error) { 8645fcf252fSNeel Natu if (errno != EEXIST) { 865c487da1eSNeel Natu perror("vm_create"); 866c487da1eSNeel Natu exit(1); 8675fcf252fSNeel Natu } 8685fcf252fSNeel Natu need_reinit = 1; 869c487da1eSNeel Natu } 870c487da1eSNeel Natu 871c487da1eSNeel Natu ctx = vm_open(vmname); 872c487da1eSNeel Natu if (ctx == NULL) { 873c487da1eSNeel Natu perror("vm_open"); 874c487da1eSNeel Natu exit(1); 875c487da1eSNeel Natu } 876c487da1eSNeel Natu 877bf7c4fcbSKyle Evans /* 878bf7c4fcbSKyle Evans * If we weren't given an explicit loader to use, we need to support the 879bf7c4fcbSKyle Evans * guest requesting a different one. 880bf7c4fcbSKyle Evans */ 881bf7c4fcbSKyle Evans if (explicit_loader_fd == -1) { 882c067be72SKyle Evans cap_rights_t rights; 883c067be72SKyle Evans 884bf7c4fcbSKyle Evans bootfd = open("/boot", O_DIRECTORY | O_PATH); 885bf7c4fcbSKyle Evans if (bootfd == -1) { 886bf7c4fcbSKyle Evans perror("open"); 887bf7c4fcbSKyle Evans exit(1); 888bf7c4fcbSKyle Evans } 889c067be72SKyle Evans 890c067be72SKyle Evans /* 891c067be72SKyle Evans * bootfd will be used to do a lookup of our loader and do an 892c067be72SKyle Evans * fdlopen(3) on the loader; thus, we need mmap(2) in addition 893c067be72SKyle Evans * to the more usual lookup rights. 894c067be72SKyle Evans */ 895c067be72SKyle Evans if (caph_rights_limit(bootfd, cap_rights_init(&rights, 896c067be72SKyle Evans CAP_FSTATAT, CAP_LOOKUP, CAP_MMAP_RX, CAP_READ)) < 0) { 897c067be72SKyle Evans perror("caph_rights_limit"); 898c067be72SKyle Evans exit(1); 899c067be72SKyle Evans } 900bf7c4fcbSKyle Evans } 901bf7c4fcbSKyle Evans 9027d9ef309SJohn Baldwin vcpu = vm_vcpu_open(ctx, BSP); 9037d9ef309SJohn Baldwin 9048bf0882eSKyle Evans caph_cache_catpages(); 9058bf0882eSKyle Evans if (caph_enter() < 0) { 9068bf0882eSKyle Evans perror("caph_enter"); 9078bf0882eSKyle Evans exit(1); 9088bf0882eSKyle Evans } 9098bf0882eSKyle Evans 910d3d381b2SKyle Evans /* 911d3d381b2SKyle Evans * setjmp in the case the guest wants to swap out interpreter, 912d3d381b2SKyle Evans * cb_swap_interpreter will swap out loader as appropriate and set 913d3d381b2SKyle Evans * need_reinit so that we end up in a clean state once again. 914d3d381b2SKyle Evans */ 915bf7c4fcbSKyle Evans if (setjmp(jb) != 0) { 916bf7c4fcbSKyle Evans dlclose(loader_hdl); 917bf7c4fcbSKyle Evans loader_hdl = NULL; 918bf7c4fcbSKyle Evans 919bf7c4fcbSKyle Evans need_reinit = 1; 920bf7c4fcbSKyle Evans } 921d3d381b2SKyle Evans 9225fcf252fSNeel Natu if (need_reinit) { 9235fcf252fSNeel Natu error = vm_reinit(ctx); 9245fcf252fSNeel Natu if (error) { 9255fcf252fSNeel Natu perror("vm_reinit"); 9265fcf252fSNeel Natu exit(1); 9275fcf252fSNeel Natu } 9285fcf252fSNeel Natu } 9295fcf252fSNeel Natu 9309b1aa8d6SNeel Natu vm_set_memflags(ctx, memflags); 931b060ba50SNeel Natu error = vm_setup_memory(ctx, mem_size, VM_MMAP_ALL); 932c487da1eSNeel Natu if (error) { 933b060ba50SNeel Natu perror("vm_setup_memory"); 934c487da1eSNeel Natu exit(1); 935c487da1eSNeel Natu } 936c487da1eSNeel Natu 937bf7c4fcbSKyle Evans loader_open(bootfd); 938d3d381b2SKyle Evans func = dlsym(loader_hdl, "loader_main"); 9398c96dcc1SMarcel Moolenaar if (!func) { 9408c96dcc1SMarcel Moolenaar printf("%s\n", dlerror()); 9418c96dcc1SMarcel Moolenaar free(loader); 9428c96dcc1SMarcel Moolenaar return (1); 9438c96dcc1SMarcel Moolenaar } 9448c96dcc1SMarcel Moolenaar 9456380102cSPeter Grehan tcgetattr(consout_fd, &term); 946c487da1eSNeel Natu oldterm = term; 9476380102cSPeter Grehan cfmakeraw(&term); 9486380102cSPeter Grehan term.c_cflag |= CLOCAL; 9496380102cSPeter Grehan 9506380102cSPeter Grehan tcsetattr(consout_fd, TCSAFLUSH, &term); 9516380102cSPeter Grehan 952b6afa84bSNeel Natu addenv("smbios.bios.vendor=BHYVE"); 953b6afa84bSNeel Natu addenv("boot_serial=1"); 954b6afa84bSNeel Natu 955d3d381b2SKyle Evans func(&cb, NULL, USERBOOT_VERSION_5, ndisks); 9568c96dcc1SMarcel Moolenaar 9578c96dcc1SMarcel Moolenaar free(loader); 9588c96dcc1SMarcel Moolenaar return (0); 959c487da1eSNeel Natu } 960