1 /*- 2 * Copyright (c) 2011 NetApp, Inc. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $FreeBSD$ 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 * $FreeBSD$ 55 */ 56 57 #include <sys/cdefs.h> 58 __FBSDID("$FreeBSD$"); 59 60 #include <sys/ioctl.h> 61 #include <sys/stat.h> 62 #include <sys/disk.h> 63 #include <sys/queue.h> 64 65 #include <machine/specialreg.h> 66 #include <machine/vmm.h> 67 68 #include <dirent.h> 69 #include <dlfcn.h> 70 #include <errno.h> 71 #include <err.h> 72 #include <fcntl.h> 73 #include <getopt.h> 74 #include <libgen.h> 75 #include <limits.h> 76 #include <stdio.h> 77 #include <stdlib.h> 78 #include <string.h> 79 #include <sysexits.h> 80 #include <termios.h> 81 #include <unistd.h> 82 83 #include <vmmapi.h> 84 85 #include "userboot.h" 86 87 #define MB (1024 * 1024UL) 88 #define GB (1024 * 1024 * 1024UL) 89 #define BSP 0 90 91 #define NDISKS 32 92 93 static char *host_base; 94 static struct termios term, oldterm; 95 static int disk_fd[NDISKS]; 96 static int ndisks; 97 static int consin_fd, consout_fd; 98 99 static char *vmname, *progname; 100 static struct vmctx *ctx; 101 102 static uint64_t gdtbase, cr3, rsp; 103 104 static void cb_exit(void *arg, int v); 105 106 /* 107 * Console i/o callbacks 108 */ 109 110 static void 111 cb_putc(void *arg, int ch) 112 { 113 char c = ch; 114 115 (void) write(consout_fd, &c, 1); 116 } 117 118 static int 119 cb_getc(void *arg) 120 { 121 char c; 122 123 if (read(consin_fd, &c, 1) == 1) 124 return (c); 125 return (-1); 126 } 127 128 static int 129 cb_poll(void *arg) 130 { 131 int n; 132 133 if (ioctl(consin_fd, FIONREAD, &n) >= 0) 134 return (n > 0); 135 return (0); 136 } 137 138 /* 139 * Host filesystem i/o callbacks 140 */ 141 142 struct cb_file { 143 int cf_isdir; 144 size_t cf_size; 145 struct stat cf_stat; 146 union { 147 int fd; 148 DIR *dir; 149 } cf_u; 150 }; 151 152 static int 153 cb_open(void *arg, const char *filename, void **hp) 154 { 155 struct cb_file *cf; 156 char path[PATH_MAX]; 157 158 if (!host_base) 159 return (ENOENT); 160 161 strlcpy(path, host_base, PATH_MAX); 162 if (path[strlen(path) - 1] == '/') 163 path[strlen(path) - 1] = 0; 164 strlcat(path, filename, PATH_MAX); 165 cf = malloc(sizeof(struct cb_file)); 166 if (stat(path, &cf->cf_stat) < 0) { 167 free(cf); 168 return (errno); 169 } 170 171 cf->cf_size = cf->cf_stat.st_size; 172 if (S_ISDIR(cf->cf_stat.st_mode)) { 173 cf->cf_isdir = 1; 174 cf->cf_u.dir = opendir(path); 175 if (!cf->cf_u.dir) 176 goto out; 177 *hp = cf; 178 return (0); 179 } 180 if (S_ISREG(cf->cf_stat.st_mode)) { 181 cf->cf_isdir = 0; 182 cf->cf_u.fd = open(path, O_RDONLY); 183 if (cf->cf_u.fd < 0) 184 goto out; 185 *hp = cf; 186 return (0); 187 } 188 189 out: 190 free(cf); 191 return (EINVAL); 192 } 193 194 static int 195 cb_close(void *arg, void *h) 196 { 197 struct cb_file *cf = h; 198 199 if (cf->cf_isdir) 200 closedir(cf->cf_u.dir); 201 else 202 close(cf->cf_u.fd); 203 free(cf); 204 205 return (0); 206 } 207 208 static int 209 cb_isdir(void *arg, void *h) 210 { 211 struct cb_file *cf = h; 212 213 return (cf->cf_isdir); 214 } 215 216 static int 217 cb_read(void *arg, void *h, void *buf, size_t size, size_t *resid) 218 { 219 struct cb_file *cf = h; 220 ssize_t sz; 221 222 if (cf->cf_isdir) 223 return (EINVAL); 224 sz = read(cf->cf_u.fd, buf, size); 225 if (sz < 0) 226 return (EINVAL); 227 *resid = size - sz; 228 return (0); 229 } 230 231 static int 232 cb_readdir(void *arg, void *h, uint32_t *fileno_return, uint8_t *type_return, 233 size_t *namelen_return, char *name) 234 { 235 struct cb_file *cf = h; 236 struct dirent *dp; 237 238 if (!cf->cf_isdir) 239 return (EINVAL); 240 241 dp = readdir(cf->cf_u.dir); 242 if (!dp) 243 return (ENOENT); 244 245 /* 246 * Note: d_namlen is in the range 0..255 and therefore less 247 * than PATH_MAX so we don't need to test before copying. 248 */ 249 *fileno_return = dp->d_fileno; 250 *type_return = dp->d_type; 251 *namelen_return = dp->d_namlen; 252 memcpy(name, dp->d_name, dp->d_namlen); 253 name[dp->d_namlen] = 0; 254 255 return (0); 256 } 257 258 static int 259 cb_seek(void *arg, void *h, uint64_t offset, int whence) 260 { 261 struct cb_file *cf = h; 262 263 if (cf->cf_isdir) 264 return (EINVAL); 265 if (lseek(cf->cf_u.fd, offset, whence) < 0) 266 return (errno); 267 return (0); 268 } 269 270 static int 271 cb_stat(void *arg, void *h, int *mode, int *uid, int *gid, uint64_t *size) 272 { 273 struct cb_file *cf = h; 274 275 *mode = cf->cf_stat.st_mode; 276 *uid = cf->cf_stat.st_uid; 277 *gid = cf->cf_stat.st_gid; 278 *size = cf->cf_stat.st_size; 279 return (0); 280 } 281 282 /* 283 * Disk image i/o callbacks 284 */ 285 286 static int 287 cb_diskread(void *arg, int unit, uint64_t from, void *to, size_t size, 288 size_t *resid) 289 { 290 ssize_t n; 291 292 if (unit < 0 || unit >= ndisks ) 293 return (EIO); 294 n = pread(disk_fd[unit], to, size, from); 295 if (n < 0) 296 return (errno); 297 *resid = size - n; 298 return (0); 299 } 300 301 static int 302 cb_diskioctl(void *arg, int unit, u_long cmd, void *data) 303 { 304 struct stat sb; 305 306 if (unit < 0 || unit >= ndisks) 307 return (EBADF); 308 309 switch (cmd) { 310 case DIOCGSECTORSIZE: 311 *(u_int *)data = 512; 312 break; 313 case DIOCGMEDIASIZE: 314 if (fstat(disk_fd[unit], &sb) == 0) 315 *(off_t *)data = sb.st_size; 316 else 317 return (ENOTTY); 318 break; 319 default: 320 return (ENOTTY); 321 } 322 323 return (0); 324 } 325 326 /* 327 * Guest virtual machine i/o callbacks 328 */ 329 static int 330 cb_copyin(void *arg, const void *from, uint64_t to, size_t size) 331 { 332 char *ptr; 333 334 to &= 0x7fffffff; 335 336 ptr = vm_map_gpa(ctx, to, size); 337 if (ptr == NULL) 338 return (EFAULT); 339 340 memcpy(ptr, from, size); 341 return (0); 342 } 343 344 static int 345 cb_copyout(void *arg, uint64_t from, void *to, size_t size) 346 { 347 char *ptr; 348 349 from &= 0x7fffffff; 350 351 ptr = vm_map_gpa(ctx, from, size); 352 if (ptr == NULL) 353 return (EFAULT); 354 355 memcpy(to, ptr, size); 356 return (0); 357 } 358 359 static void 360 cb_setreg(void *arg, int r, uint64_t v) 361 { 362 int error; 363 enum vm_reg_name vmreg; 364 365 vmreg = VM_REG_LAST; 366 367 switch (r) { 368 case 4: 369 vmreg = VM_REG_GUEST_RSP; 370 rsp = v; 371 break; 372 default: 373 break; 374 } 375 376 if (vmreg == VM_REG_LAST) { 377 printf("test_setreg(%d): not implemented\n", r); 378 cb_exit(NULL, USERBOOT_EXIT_QUIT); 379 } 380 381 error = vm_set_register(ctx, BSP, vmreg, v); 382 if (error) { 383 perror("vm_set_register"); 384 cb_exit(NULL, USERBOOT_EXIT_QUIT); 385 } 386 } 387 388 static void 389 cb_setmsr(void *arg, int r, uint64_t v) 390 { 391 int error; 392 enum vm_reg_name vmreg; 393 394 vmreg = VM_REG_LAST; 395 396 switch (r) { 397 case MSR_EFER: 398 vmreg = VM_REG_GUEST_EFER; 399 break; 400 default: 401 break; 402 } 403 404 if (vmreg == VM_REG_LAST) { 405 printf("test_setmsr(%d): not implemented\n", r); 406 cb_exit(NULL, USERBOOT_EXIT_QUIT); 407 } 408 409 error = vm_set_register(ctx, BSP, vmreg, v); 410 if (error) { 411 perror("vm_set_msr"); 412 cb_exit(NULL, USERBOOT_EXIT_QUIT); 413 } 414 } 415 416 static void 417 cb_setcr(void *arg, int r, uint64_t v) 418 { 419 int error; 420 enum vm_reg_name vmreg; 421 422 vmreg = VM_REG_LAST; 423 424 switch (r) { 425 case 0: 426 vmreg = VM_REG_GUEST_CR0; 427 break; 428 case 3: 429 vmreg = VM_REG_GUEST_CR3; 430 cr3 = v; 431 break; 432 case 4: 433 vmreg = VM_REG_GUEST_CR4; 434 break; 435 default: 436 break; 437 } 438 439 if (vmreg == VM_REG_LAST) { 440 printf("test_setcr(%d): not implemented\n", r); 441 cb_exit(NULL, USERBOOT_EXIT_QUIT); 442 } 443 444 error = vm_set_register(ctx, BSP, vmreg, v); 445 if (error) { 446 perror("vm_set_cr"); 447 cb_exit(NULL, USERBOOT_EXIT_QUIT); 448 } 449 } 450 451 static void 452 cb_setgdt(void *arg, uint64_t base, size_t size) 453 { 454 int error; 455 456 error = vm_set_desc(ctx, BSP, VM_REG_GUEST_GDTR, base, size - 1, 0); 457 if (error != 0) { 458 perror("vm_set_desc(gdt)"); 459 cb_exit(NULL, USERBOOT_EXIT_QUIT); 460 } 461 462 gdtbase = base; 463 } 464 465 static void 466 cb_exec(void *arg, uint64_t rip) 467 { 468 int error; 469 470 if (cr3 == 0) 471 error = vm_setup_freebsd_registers_i386(ctx, BSP, rip, gdtbase, 472 rsp); 473 else 474 error = vm_setup_freebsd_registers(ctx, BSP, rip, cr3, gdtbase, 475 rsp); 476 if (error) { 477 perror("vm_setup_freebsd_registers"); 478 cb_exit(NULL, USERBOOT_EXIT_QUIT); 479 } 480 481 cb_exit(NULL, 0); 482 } 483 484 /* 485 * Misc 486 */ 487 488 static void 489 cb_delay(void *arg, int usec) 490 { 491 492 usleep(usec); 493 } 494 495 static void 496 cb_exit(void *arg, int v) 497 { 498 499 tcsetattr(consout_fd, TCSAFLUSH, &oldterm); 500 exit(v); 501 } 502 503 static void 504 cb_getmem(void *arg, uint64_t *ret_lowmem, uint64_t *ret_highmem) 505 { 506 507 *ret_lowmem = vm_get_lowmem_size(ctx); 508 *ret_highmem = vm_get_highmem_size(ctx); 509 } 510 511 struct env { 512 const char *str; /* name=value */ 513 SLIST_ENTRY(env) next; 514 }; 515 516 static SLIST_HEAD(envhead, env) envhead; 517 518 static void 519 addenv(const char *str) 520 { 521 struct env *env; 522 523 env = malloc(sizeof(struct env)); 524 env->str = str; 525 SLIST_INSERT_HEAD(&envhead, env, next); 526 } 527 528 static const char * 529 cb_getenv(void *arg, int num) 530 { 531 int i; 532 struct env *env; 533 534 i = 0; 535 SLIST_FOREACH(env, &envhead, next) { 536 if (i == num) 537 return (env->str); 538 i++; 539 } 540 541 return (NULL); 542 } 543 544 static int 545 cb_vm_set_register(void *arg, int vcpu, int reg, uint64_t val) 546 { 547 548 return (vm_set_register(ctx, vcpu, reg, val)); 549 } 550 551 static int 552 cb_vm_set_desc(void *arg, int vcpu, int reg, uint64_t base, u_int limit, 553 u_int access) 554 { 555 556 return (vm_set_desc(ctx, vcpu, reg, base, limit, access)); 557 } 558 559 static struct loader_callbacks cb = { 560 .getc = cb_getc, 561 .putc = cb_putc, 562 .poll = cb_poll, 563 564 .open = cb_open, 565 .close = cb_close, 566 .isdir = cb_isdir, 567 .read = cb_read, 568 .readdir = cb_readdir, 569 .seek = cb_seek, 570 .stat = cb_stat, 571 572 .diskread = cb_diskread, 573 .diskioctl = cb_diskioctl, 574 575 .copyin = cb_copyin, 576 .copyout = cb_copyout, 577 .setreg = cb_setreg, 578 .setmsr = cb_setmsr, 579 .setcr = cb_setcr, 580 .setgdt = cb_setgdt, 581 .exec = cb_exec, 582 583 .delay = cb_delay, 584 .exit = cb_exit, 585 .getmem = cb_getmem, 586 587 .getenv = cb_getenv, 588 589 /* Version 4 additions */ 590 .vm_set_register = cb_vm_set_register, 591 .vm_set_desc = cb_vm_set_desc, 592 }; 593 594 static int 595 altcons_open(char *path) 596 { 597 struct stat sb; 598 int err; 599 int fd; 600 601 /* 602 * Allow stdio to be passed in so that the same string 603 * can be used for the bhyveload console and bhyve com-port 604 * parameters 605 */ 606 if (!strcmp(path, "stdio")) 607 return (0); 608 609 err = stat(path, &sb); 610 if (err == 0) { 611 if (!S_ISCHR(sb.st_mode)) 612 err = ENOTSUP; 613 else { 614 fd = open(path, O_RDWR | O_NONBLOCK); 615 if (fd < 0) 616 err = errno; 617 else 618 consin_fd = consout_fd = fd; 619 } 620 } 621 622 return (err); 623 } 624 625 static int 626 disk_open(char *path) 627 { 628 int err, fd; 629 630 if (ndisks >= NDISKS) 631 return (ERANGE); 632 633 err = 0; 634 fd = open(path, O_RDONLY); 635 636 if (fd > 0) { 637 disk_fd[ndisks] = fd; 638 ndisks++; 639 } else 640 err = errno; 641 642 return (err); 643 } 644 645 static void 646 usage(void) 647 { 648 649 fprintf(stderr, 650 "usage: %s [-S][-c <console-device>] [-d <disk-path>] [-e <name=value>]\n" 651 " %*s [-h <host-path>] [-m memsize[K|k|M|m|G|g|T|t]] <vmname>\n", 652 progname, 653 (int)strlen(progname), ""); 654 exit(1); 655 } 656 657 int 658 main(int argc, char** argv) 659 { 660 char *loader; 661 void *h; 662 void (*func)(struct loader_callbacks *, void *, int, int); 663 uint64_t mem_size; 664 int opt, error, need_reinit, memflags; 665 666 progname = basename(argv[0]); 667 668 loader = NULL; 669 670 memflags = 0; 671 mem_size = 256 * MB; 672 673 consin_fd = STDIN_FILENO; 674 consout_fd = STDOUT_FILENO; 675 676 while ((opt = getopt(argc, argv, "CSc:d:e:h:l:m:")) != -1) { 677 switch (opt) { 678 case 'c': 679 error = altcons_open(optarg); 680 if (error != 0) 681 errx(EX_USAGE, "Could not open '%s'", optarg); 682 break; 683 684 case 'd': 685 error = disk_open(optarg); 686 if (error != 0) 687 errx(EX_USAGE, "Could not open '%s'", optarg); 688 break; 689 690 case 'e': 691 addenv(optarg); 692 break; 693 694 case 'h': 695 host_base = optarg; 696 break; 697 698 case 'l': 699 if (loader != NULL) 700 errx(EX_USAGE, "-l can only be given once"); 701 loader = strdup(optarg); 702 if (loader == NULL) 703 err(EX_OSERR, "malloc"); 704 break; 705 706 case 'm': 707 error = vm_parse_memsize(optarg, &mem_size); 708 if (error != 0) 709 errx(EX_USAGE, "Invalid memsize '%s'", optarg); 710 break; 711 case 'C': 712 memflags |= VM_MEM_F_INCORE; 713 break; 714 case 'S': 715 memflags |= VM_MEM_F_WIRED; 716 break; 717 case '?': 718 usage(); 719 } 720 } 721 722 argc -= optind; 723 argv += optind; 724 725 if (argc != 1) 726 usage(); 727 728 vmname = argv[0]; 729 730 need_reinit = 0; 731 error = vm_create(vmname); 732 if (error) { 733 if (errno != EEXIST) { 734 perror("vm_create"); 735 exit(1); 736 } 737 need_reinit = 1; 738 } 739 740 ctx = vm_open(vmname); 741 if (ctx == NULL) { 742 perror("vm_open"); 743 exit(1); 744 } 745 746 if (need_reinit) { 747 error = vm_reinit(ctx); 748 if (error) { 749 perror("vm_reinit"); 750 exit(1); 751 } 752 } 753 754 vm_set_memflags(ctx, memflags); 755 error = vm_setup_memory(ctx, mem_size, VM_MMAP_ALL); 756 if (error) { 757 perror("vm_setup_memory"); 758 exit(1); 759 } 760 761 if (loader == NULL) { 762 loader = strdup("/boot/userboot.so"); 763 if (loader == NULL) 764 err(EX_OSERR, "malloc"); 765 } 766 h = dlopen(loader, RTLD_LOCAL); 767 if (!h) { 768 printf("%s\n", dlerror()); 769 free(loader); 770 return (1); 771 } 772 func = dlsym(h, "loader_main"); 773 if (!func) { 774 printf("%s\n", dlerror()); 775 free(loader); 776 return (1); 777 } 778 779 tcgetattr(consout_fd, &term); 780 oldterm = term; 781 cfmakeraw(&term); 782 term.c_cflag |= CLOCAL; 783 784 tcsetattr(consout_fd, TCSAFLUSH, &term); 785 786 addenv("smbios.bios.vendor=BHYVE"); 787 addenv("boot_serial=1"); 788 789 func(&cb, NULL, USERBOOT_VERSION_4, ndisks); 790 791 free(loader); 792 return (0); 793 } 794