1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2011 NetApp, Inc. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 /*- 30 * Copyright (c) 2011 Google, Inc. 31 * All rights reserved. 32 * 33 * Redistribution and use in source and binary forms, with or without 34 * modification, are permitted provided that the following conditions 35 * are met: 36 * 1. Redistributions of source code must retain the above copyright 37 * notice, this list of conditions and the following disclaimer. 38 * 2. Redistributions in binary form must reproduce the above copyright 39 * notice, this list of conditions and the following disclaimer in the 40 * documentation and/or other materials provided with the distribution. 41 * 42 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 43 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 44 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 45 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 46 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 47 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 48 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 49 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 50 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 51 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 52 * SUCH DAMAGE. 53 */ 54 55 #include <sys/cdefs.h> 56 #include <sys/ioctl.h> 57 #include <sys/stat.h> 58 #include <sys/disk.h> 59 #include <sys/queue.h> 60 61 #include <machine/specialreg.h> 62 #include <machine/vmm.h> 63 64 #include <assert.h> 65 #include <dirent.h> 66 #include <dlfcn.h> 67 #include <errno.h> 68 #include <err.h> 69 #include <fcntl.h> 70 #include <getopt.h> 71 #include <libgen.h> 72 #include <limits.h> 73 #include <setjmp.h> 74 #include <stdio.h> 75 #include <stdlib.h> 76 #include <string.h> 77 #include <sysexits.h> 78 #include <termios.h> 79 #include <unistd.h> 80 81 #include <capsicum_helpers.h> 82 #include <vmmapi.h> 83 84 #include "userboot.h" 85 86 #define MB (1024 * 1024UL) 87 #define GB (1024 * 1024 * 1024UL) 88 #define BSP 0 89 90 #define NDISKS 32 91 92 /* 93 * Reason for our loader reload and reentry, though these aren't really used 94 * at the moment. 95 */ 96 enum { 97 /* 0 cannot be allocated; setjmp(3) return. */ 98 JMP_SWAPLOADER = 0x01, 99 JMP_REBOOT, 100 }; 101 102 static struct termios term, oldterm; 103 static int disk_fd[NDISKS]; 104 static int ndisks; 105 static int consin_fd, consout_fd; 106 static int hostbase_fd = -1; 107 108 static void *loader_hdl; 109 static char *loader; 110 static int explicit_loader_fd = -1; 111 static jmp_buf jb; 112 113 static char *vmname, *progname; 114 static struct vmctx *ctx; 115 static struct vcpu *vcpu; 116 117 static uint64_t gdtbase, cr3, rsp; 118 119 static void cb_exit(void *arg, int v); 120 121 /* 122 * Console i/o callbacks 123 */ 124 125 static void 126 cb_putc(void *arg __unused, int ch) 127 { 128 char c = ch; 129 130 (void) write(consout_fd, &c, 1); 131 } 132 133 static int 134 cb_getc(void *arg __unused) 135 { 136 char c; 137 138 if (read(consin_fd, &c, 1) == 1) 139 return (c); 140 return (-1); 141 } 142 143 static int 144 cb_poll(void *arg __unused) 145 { 146 int n; 147 148 if (ioctl(consin_fd, FIONREAD, &n) >= 0) 149 return (n > 0); 150 return (0); 151 } 152 153 /* 154 * Host filesystem i/o callbacks 155 */ 156 157 struct cb_file { 158 int cf_isdir; 159 size_t cf_size; 160 struct stat cf_stat; 161 union { 162 int fd; 163 DIR *dir; 164 } cf_u; 165 }; 166 167 static int 168 cb_open(void *arg __unused, const char *filename, void **hp) 169 { 170 struct cb_file *cf; 171 struct stat sb; 172 int fd; 173 174 cf = NULL; 175 if (hostbase_fd == -1) 176 return (ENOENT); 177 178 /* Absolute paths are relative to our hostbase, chop off leading /. */ 179 if (filename[0] == '/') 180 filename++; 181 182 /* Lookup of /, use . instead. */ 183 if (filename[0] == '\0') 184 filename = "."; 185 186 /* May be opening the root dir */ 187 fd = openat(hostbase_fd, filename, O_RDONLY | O_RESOLVE_BENEATH); 188 if (fd < 0) 189 return (errno); 190 191 if (fstat(fd, &sb) < 0) { 192 int serrno = errno; 193 194 close(fd); 195 return (serrno); 196 } else if (!S_ISDIR(sb.st_mode) && !S_ISREG(sb.st_mode)) { 197 close(fd); 198 return (EINVAL); 199 } 200 201 cf = malloc(sizeof(struct cb_file)); 202 if (cf == NULL) { 203 close(fd); 204 return (ENOMEM); 205 } 206 207 cf->cf_stat = sb; 208 cf->cf_size = cf->cf_stat.st_size; 209 210 if (S_ISDIR(cf->cf_stat.st_mode)) { 211 cf->cf_isdir = 1; 212 cf->cf_u.dir = fdopendir(fd); 213 if (cf->cf_u.dir == NULL) { 214 close(fd); 215 free(cf); 216 return (ENOMEM); 217 } 218 } else { 219 cf->cf_isdir = 0; 220 cf->cf_u.fd = fd; 221 } 222 *hp = cf; 223 return (0); 224 } 225 226 static int 227 cb_close(void *arg __unused, void *h) 228 { 229 struct cb_file *cf = h; 230 231 if (cf->cf_isdir) 232 closedir(cf->cf_u.dir); 233 else 234 close(cf->cf_u.fd); 235 free(cf); 236 237 return (0); 238 } 239 240 static int 241 cb_isdir(void *arg __unused, void *h) 242 { 243 struct cb_file *cf = h; 244 245 return (cf->cf_isdir); 246 } 247 248 static int 249 cb_read(void *arg __unused, void *h, void *buf, size_t size, size_t *resid) 250 { 251 struct cb_file *cf = h; 252 ssize_t sz; 253 254 if (cf->cf_isdir) 255 return (EINVAL); 256 sz = read(cf->cf_u.fd, buf, size); 257 if (sz < 0) 258 return (EINVAL); 259 *resid = size - sz; 260 return (0); 261 } 262 263 static int 264 cb_readdir(void *arg __unused, void *h, uint32_t *fileno_return, 265 uint8_t *type_return, size_t *namelen_return, char *name) 266 { 267 struct cb_file *cf = h; 268 struct dirent *dp; 269 270 if (!cf->cf_isdir) 271 return (EINVAL); 272 273 dp = readdir(cf->cf_u.dir); 274 if (!dp) 275 return (ENOENT); 276 277 /* 278 * Note: d_namlen is in the range 0..255 and therefore less 279 * than PATH_MAX so we don't need to test before copying. 280 */ 281 *fileno_return = dp->d_fileno; 282 *type_return = dp->d_type; 283 *namelen_return = dp->d_namlen; 284 memcpy(name, dp->d_name, dp->d_namlen); 285 name[dp->d_namlen] = 0; 286 287 return (0); 288 } 289 290 static int 291 cb_seek(void *arg __unused, void *h, uint64_t offset, int whence) 292 { 293 struct cb_file *cf = h; 294 295 if (cf->cf_isdir) 296 return (EINVAL); 297 if (lseek(cf->cf_u.fd, offset, whence) < 0) 298 return (errno); 299 return (0); 300 } 301 302 static int 303 cb_stat(void *arg __unused, void *h, struct stat *sbp) 304 { 305 struct cb_file *cf = h; 306 307 memset(sbp, 0, sizeof(struct stat)); 308 sbp->st_mode = cf->cf_stat.st_mode; 309 sbp->st_uid = cf->cf_stat.st_uid; 310 sbp->st_gid = cf->cf_stat.st_gid; 311 sbp->st_size = cf->cf_stat.st_size; 312 sbp->st_mtime = cf->cf_stat.st_mtime; 313 sbp->st_dev = cf->cf_stat.st_dev; 314 sbp->st_ino = cf->cf_stat.st_ino; 315 316 return (0); 317 } 318 319 /* 320 * Disk image i/o callbacks 321 */ 322 323 static int 324 cb_diskread(void *arg __unused, int unit, uint64_t from, void *to, size_t size, 325 size_t *resid) 326 { 327 ssize_t n; 328 329 if (unit < 0 || unit >= ndisks) 330 return (EIO); 331 n = pread(disk_fd[unit], to, size, from); 332 if (n < 0) 333 return (errno); 334 *resid = size - n; 335 return (0); 336 } 337 338 static int 339 cb_diskwrite(void *arg __unused, int unit, uint64_t offset, void *src, 340 size_t size, size_t *resid) 341 { 342 ssize_t n; 343 344 if (unit < 0 || unit >= ndisks) 345 return (EIO); 346 n = pwrite(disk_fd[unit], src, size, offset); 347 if (n < 0) 348 return (errno); 349 *resid = size - n; 350 return (0); 351 } 352 353 static int 354 cb_diskioctl(void *arg __unused, int unit, u_long cmd, void *data) 355 { 356 struct stat sb; 357 358 if (unit < 0 || unit >= ndisks) 359 return (EBADF); 360 361 switch (cmd) { 362 case DIOCGSECTORSIZE: 363 *(u_int *)data = 512; 364 break; 365 case DIOCGMEDIASIZE: 366 if (fstat(disk_fd[unit], &sb) != 0) 367 return (ENOTTY); 368 if (S_ISCHR(sb.st_mode) && 369 ioctl(disk_fd[unit], DIOCGMEDIASIZE, &sb.st_size) != 0) 370 return (ENOTTY); 371 *(off_t *)data = sb.st_size; 372 break; 373 default: 374 return (ENOTTY); 375 } 376 377 return (0); 378 } 379 380 /* 381 * Guest virtual machine i/o callbacks 382 */ 383 static int 384 cb_copyin(void *arg __unused, const void *from, uint64_t to, size_t size) 385 { 386 char *ptr; 387 388 to &= 0x7fffffff; 389 390 ptr = vm_map_gpa(ctx, to, size); 391 if (ptr == NULL) 392 return (EFAULT); 393 394 memcpy(ptr, from, size); 395 return (0); 396 } 397 398 static int 399 cb_copyout(void *arg __unused, uint64_t from, void *to, size_t size) 400 { 401 char *ptr; 402 403 from &= 0x7fffffff; 404 405 ptr = vm_map_gpa(ctx, from, size); 406 if (ptr == NULL) 407 return (EFAULT); 408 409 memcpy(to, ptr, size); 410 return (0); 411 } 412 413 static void 414 cb_setreg(void *arg __unused, int r, uint64_t v) 415 { 416 int error; 417 enum vm_reg_name vmreg; 418 419 vmreg = VM_REG_LAST; 420 421 switch (r) { 422 case 4: 423 vmreg = VM_REG_GUEST_RSP; 424 rsp = v; 425 break; 426 default: 427 break; 428 } 429 430 if (vmreg == VM_REG_LAST) { 431 printf("test_setreg(%d): not implemented\n", r); 432 cb_exit(NULL, USERBOOT_EXIT_QUIT); 433 } 434 435 error = vm_set_register(vcpu, vmreg, v); 436 if (error) { 437 perror("vm_set_register"); 438 cb_exit(NULL, USERBOOT_EXIT_QUIT); 439 } 440 } 441 442 static void 443 cb_setmsr(void *arg __unused, int r, uint64_t v) 444 { 445 int error; 446 enum vm_reg_name vmreg; 447 448 vmreg = VM_REG_LAST; 449 450 switch (r) { 451 case MSR_EFER: 452 vmreg = VM_REG_GUEST_EFER; 453 break; 454 default: 455 break; 456 } 457 458 if (vmreg == VM_REG_LAST) { 459 printf("test_setmsr(%d): not implemented\n", r); 460 cb_exit(NULL, USERBOOT_EXIT_QUIT); 461 } 462 463 error = vm_set_register(vcpu, vmreg, v); 464 if (error) { 465 perror("vm_set_msr"); 466 cb_exit(NULL, USERBOOT_EXIT_QUIT); 467 } 468 } 469 470 static void 471 cb_setcr(void *arg __unused, int r, uint64_t v) 472 { 473 int error; 474 enum vm_reg_name vmreg; 475 476 vmreg = VM_REG_LAST; 477 478 switch (r) { 479 case 0: 480 vmreg = VM_REG_GUEST_CR0; 481 break; 482 case 3: 483 vmreg = VM_REG_GUEST_CR3; 484 cr3 = v; 485 break; 486 case 4: 487 vmreg = VM_REG_GUEST_CR4; 488 break; 489 default: 490 break; 491 } 492 493 if (vmreg == VM_REG_LAST) { 494 printf("test_setcr(%d): not implemented\n", r); 495 cb_exit(NULL, USERBOOT_EXIT_QUIT); 496 } 497 498 error = vm_set_register(vcpu, vmreg, v); 499 if (error) { 500 perror("vm_set_cr"); 501 cb_exit(NULL, USERBOOT_EXIT_QUIT); 502 } 503 } 504 505 static void 506 cb_setgdt(void *arg __unused, uint64_t base, size_t size) 507 { 508 int error; 509 510 error = vm_set_desc(vcpu, VM_REG_GUEST_GDTR, base, size - 1, 0); 511 if (error != 0) { 512 perror("vm_set_desc(gdt)"); 513 cb_exit(NULL, USERBOOT_EXIT_QUIT); 514 } 515 516 gdtbase = base; 517 } 518 519 static void 520 cb_exec(void *arg __unused, uint64_t rip) 521 { 522 int error; 523 524 if (cr3 == 0) 525 error = vm_setup_freebsd_registers_i386(vcpu, rip, gdtbase, 526 rsp); 527 else 528 error = vm_setup_freebsd_registers(vcpu, rip, cr3, gdtbase, 529 rsp); 530 if (error) { 531 perror("vm_setup_freebsd_registers"); 532 cb_exit(NULL, USERBOOT_EXIT_QUIT); 533 } 534 535 cb_exit(NULL, 0); 536 } 537 538 /* 539 * Misc 540 */ 541 542 static void 543 cb_delay(void *arg __unused, int usec) 544 { 545 546 usleep(usec); 547 } 548 549 static void 550 cb_exit(void *arg __unused, int v) 551 { 552 553 tcsetattr(consout_fd, TCSAFLUSH, &oldterm); 554 if (v == USERBOOT_EXIT_REBOOT) 555 longjmp(jb, JMP_REBOOT); 556 exit(v); 557 } 558 559 static void 560 cb_getmem(void *arg __unused, uint64_t *ret_lowmem, uint64_t *ret_highmem) 561 { 562 563 *ret_lowmem = vm_get_lowmem_size(ctx); 564 *ret_highmem = vm_get_highmem_size(ctx); 565 } 566 567 struct env { 568 char *str; /* name=value */ 569 SLIST_ENTRY(env) next; 570 }; 571 572 static SLIST_HEAD(envhead, env) envhead; 573 574 static void 575 addenv(const char *str) 576 { 577 struct env *env; 578 579 env = malloc(sizeof(struct env)); 580 if (env == NULL) 581 err(EX_OSERR, "malloc"); 582 env->str = strdup(str); 583 if (env->str == NULL) 584 err(EX_OSERR, "strdup"); 585 SLIST_INSERT_HEAD(&envhead, env, next); 586 } 587 588 static char * 589 cb_getenv(void *arg __unused, int num) 590 { 591 int i; 592 struct env *env; 593 594 i = 0; 595 SLIST_FOREACH(env, &envhead, next) { 596 if (i == num) 597 return (env->str); 598 i++; 599 } 600 601 return (NULL); 602 } 603 604 static int 605 cb_vm_set_register(void *arg __unused, int vcpuid, int reg, uint64_t val) 606 { 607 608 assert(vcpuid == BSP); 609 return (vm_set_register(vcpu, reg, val)); 610 } 611 612 static int 613 cb_vm_set_desc(void *arg __unused, int vcpuid, int reg, uint64_t base, 614 u_int limit, u_int access) 615 { 616 617 assert(vcpuid == BSP); 618 return (vm_set_desc(vcpu, reg, base, limit, access)); 619 } 620 621 static void 622 cb_swap_interpreter(void *arg __unused, const char *interp_req) 623 { 624 625 /* 626 * If the user specified a loader but we detected a mismatch, we should 627 * not try to pivot to a different loader on them. 628 */ 629 free(loader); 630 if (explicit_loader_fd != -1) { 631 perror("requested loader interpreter does not match guest userboot"); 632 cb_exit(NULL, 1); 633 } 634 if (interp_req == NULL || *interp_req == '\0') { 635 perror("guest failed to request an interpreter"); 636 cb_exit(NULL, 1); 637 } 638 639 if (asprintf(&loader, "userboot_%s.so", interp_req) == -1) 640 err(EX_OSERR, "malloc"); 641 longjmp(jb, JMP_SWAPLOADER); 642 } 643 644 static struct loader_callbacks cb = { 645 .getc = cb_getc, 646 .putc = cb_putc, 647 .poll = cb_poll, 648 649 .open = cb_open, 650 .close = cb_close, 651 .isdir = cb_isdir, 652 .read = cb_read, 653 .readdir = cb_readdir, 654 .seek = cb_seek, 655 .stat = cb_stat, 656 657 .diskread = cb_diskread, 658 .diskwrite = cb_diskwrite, 659 .diskioctl = cb_diskioctl, 660 661 .copyin = cb_copyin, 662 .copyout = cb_copyout, 663 .setreg = cb_setreg, 664 .setmsr = cb_setmsr, 665 .setcr = cb_setcr, 666 .setgdt = cb_setgdt, 667 .exec = cb_exec, 668 669 .delay = cb_delay, 670 .exit = cb_exit, 671 .getmem = cb_getmem, 672 673 .getenv = cb_getenv, 674 675 /* Version 4 additions */ 676 .vm_set_register = cb_vm_set_register, 677 .vm_set_desc = cb_vm_set_desc, 678 679 /* Version 5 additions */ 680 .swap_interpreter = cb_swap_interpreter, 681 }; 682 683 static int 684 altcons_open(char *path) 685 { 686 struct stat sb; 687 int err; 688 int fd; 689 690 /* 691 * Allow stdio to be passed in so that the same string 692 * can be used for the bhyveload console and bhyve com-port 693 * parameters 694 */ 695 if (!strcmp(path, "stdio")) 696 return (0); 697 698 err = stat(path, &sb); 699 if (err == 0) { 700 if (!S_ISCHR(sb.st_mode)) 701 err = ENOTSUP; 702 else { 703 fd = open(path, O_RDWR | O_NONBLOCK); 704 if (fd < 0) 705 err = errno; 706 else 707 consin_fd = consout_fd = fd; 708 } 709 } 710 711 return (err); 712 } 713 714 static int 715 disk_open(char *path) 716 { 717 int fd; 718 719 if (ndisks >= NDISKS) 720 return (ERANGE); 721 722 fd = open(path, O_RDWR); 723 if (fd < 0) 724 fd = open(path, O_RDONLY); 725 if (fd < 0) 726 return (errno); 727 728 disk_fd[ndisks] = fd; 729 ndisks++; 730 731 return (0); 732 } 733 734 static void 735 usage(void) 736 { 737 738 fprintf(stderr, 739 "usage: %s [-S][-c <console-device>] [-d <disk-path>] [-e <name=value>]\n" 740 " %*s [-h <host-path>] [-m memsize[K|k|M|m|G|g|T|t]] <vmname>\n", 741 progname, 742 (int)strlen(progname), ""); 743 exit(1); 744 } 745 746 static void 747 hostbase_open(const char *base) 748 { 749 cap_rights_t rights; 750 751 if (hostbase_fd != -1) 752 close(hostbase_fd); 753 hostbase_fd = open(base, O_DIRECTORY | O_PATH); 754 if (hostbase_fd == -1) 755 err(EX_OSERR, "open"); 756 757 if (caph_rights_limit(hostbase_fd, cap_rights_init(&rights, CAP_FSTATAT, 758 CAP_LOOKUP, CAP_PREAD)) < 0) 759 err(EX_OSERR, "caph_rights_limit"); 760 } 761 762 static void 763 loader_open(int bootfd) 764 { 765 int fd; 766 767 if (loader == NULL) { 768 loader = strdup("userboot.so"); 769 if (loader == NULL) 770 err(EX_OSERR, "malloc"); 771 } 772 773 assert(bootfd >= 0 || explicit_loader_fd >= 0); 774 if (explicit_loader_fd >= 0) 775 fd = explicit_loader_fd; 776 else 777 fd = openat(bootfd, loader, O_RDONLY | O_RESOLVE_BENEATH); 778 if (fd == -1) 779 err(EX_OSERR, "openat"); 780 781 loader_hdl = fdlopen(fd, RTLD_LOCAL); 782 if (!loader_hdl) 783 errx(EX_OSERR, "dlopen: %s", dlerror()); 784 if (fd != explicit_loader_fd) 785 close(fd); 786 } 787 788 int 789 main(int argc, char** argv) 790 { 791 void (*func)(struct loader_callbacks *, void *, int, int); 792 uint64_t mem_size; 793 int bootfd, opt, error, memflags, need_reinit; 794 795 bootfd = -1; 796 progname = basename(argv[0]); 797 798 memflags = 0; 799 mem_size = 256 * MB; 800 801 consin_fd = STDIN_FILENO; 802 consout_fd = STDOUT_FILENO; 803 804 while ((opt = getopt(argc, argv, "CSc:d:e:h:l:m:")) != -1) { 805 switch (opt) { 806 case 'c': 807 error = altcons_open(optarg); 808 if (error != 0) 809 errx(EX_USAGE, "Could not open '%s'", optarg); 810 break; 811 812 case 'd': 813 error = disk_open(optarg); 814 if (error != 0) 815 errx(EX_USAGE, "Could not open '%s'", optarg); 816 break; 817 818 case 'e': 819 addenv(optarg); 820 break; 821 822 case 'h': 823 hostbase_open(optarg); 824 break; 825 826 case 'l': 827 if (loader != NULL) 828 errx(EX_USAGE, "-l can only be given once"); 829 loader = strdup(optarg); 830 if (loader == NULL) 831 err(EX_OSERR, "malloc"); 832 explicit_loader_fd = open(loader, O_RDONLY); 833 if (explicit_loader_fd == -1) 834 err(EX_OSERR, "%s", loader); 835 break; 836 837 case 'm': 838 error = vm_parse_memsize(optarg, &mem_size); 839 if (error != 0) 840 errx(EX_USAGE, "Invalid memsize '%s'", optarg); 841 break; 842 case 'C': 843 memflags |= VM_MEM_F_INCORE; 844 break; 845 case 'S': 846 memflags |= VM_MEM_F_WIRED; 847 break; 848 case '?': 849 usage(); 850 } 851 } 852 853 argc -= optind; 854 argv += optind; 855 856 if (argc != 1) 857 usage(); 858 859 vmname = argv[0]; 860 861 need_reinit = 0; 862 error = vm_create(vmname); 863 if (error) { 864 if (errno != EEXIST) 865 err(1, "vm_create"); 866 need_reinit = 1; 867 } 868 869 ctx = vm_open(vmname); 870 if (ctx == NULL) 871 err(1, "vm_open"); 872 873 /* 874 * If we weren't given an explicit loader to use, we need to support the 875 * guest requesting a different one. 876 */ 877 if (explicit_loader_fd == -1) { 878 cap_rights_t rights; 879 880 bootfd = open("/boot", O_DIRECTORY | O_PATH); 881 if (bootfd == -1) 882 err(1, "open"); 883 884 /* 885 * bootfd will be used to do a lookup of our loader and do an 886 * fdlopen(3) on the loader; thus, we need mmap(2) in addition 887 * to the more usual lookup rights. 888 */ 889 if (caph_rights_limit(bootfd, cap_rights_init(&rights, 890 CAP_FSTATAT, CAP_LOOKUP, CAP_MMAP_RX, CAP_PREAD)) < 0) 891 err(1, "caph_rights_limit"); 892 } 893 894 vcpu = vm_vcpu_open(ctx, BSP); 895 896 caph_cache_catpages(); 897 if (caph_enter() < 0) 898 err(1, "caph_enter"); 899 900 /* 901 * setjmp in the case the guest wants to swap out interpreter, 902 * cb_swap_interpreter will swap out loader as appropriate and set 903 * need_reinit so that we end up in a clean state once again. 904 */ 905 if (setjmp(jb) != 0) { 906 dlclose(loader_hdl); 907 loader_hdl = NULL; 908 909 need_reinit = 1; 910 } 911 912 if (need_reinit) { 913 error = vm_reinit(ctx); 914 if (error) 915 err(1, "vm_reinit"); 916 } 917 918 vm_set_memflags(ctx, memflags); 919 error = vm_setup_memory(ctx, mem_size, VM_MMAP_ALL); 920 if (error) 921 err(1, "vm_setup_memory"); 922 923 loader_open(bootfd); 924 func = dlsym(loader_hdl, "loader_main"); 925 if (!func) 926 errx(1, "dlsym: %s", dlerror()); 927 928 tcgetattr(consout_fd, &term); 929 oldterm = term; 930 cfmakeraw(&term); 931 term.c_cflag |= CLOCAL; 932 933 tcsetattr(consout_fd, TCSAFLUSH, &term); 934 935 addenv("smbios.bios.vendor=BHYVE"); 936 addenv("boot_serial=1"); 937 938 func(&cb, NULL, USERBOOT_VERSION_5, ndisks); 939 940 free(loader); 941 return (0); 942 } 943