bhyveload.c revision 267399
1156230Smux/*- 2156230Smux * Copyright (c) 2011 NetApp, Inc. 3156230Smux * All rights reserved. 4156230Smux * 5156230Smux * Redistribution and use in source and binary forms, with or without 6156230Smux * modification, are permitted provided that the following conditions 7156230Smux * are met: 8156230Smux * 1. Redistributions of source code must retain the above copyright 9156230Smux * notice, this list of conditions and the following disclaimer. 10156230Smux * 2. Redistributions in binary form must reproduce the above copyright 11156230Smux * notice, this list of conditions and the following disclaimer in the 12156230Smux * documentation and/or other materials provided with the distribution. 13156230Smux * 14156230Smux * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND 15156230Smux * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16156230Smux * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17156230Smux * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE 18156230Smux * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19156230Smux * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20156230Smux * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21156230Smux * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22156230Smux * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23156230Smux * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24156230Smux * SUCH DAMAGE. 25156230Smux * 26156230Smux * $FreeBSD: stable/10/usr.sbin/bhyveload/bhyveload.c 267399 2014-06-12 15:20:59Z jhb $ 27156230Smux */ 28156230Smux 29156230Smux/*- 30156230Smux * Copyright (c) 2011 Google, Inc. 31156230Smux * All rights reserved. 32156230Smux * 33156230Smux * Redistribution and use in source and binary forms, with or without 34156230Smux * modification, are permitted provided that the following conditions 35156230Smux * are met: 36156701Smux * 1. Redistributions of source code must retain the above copyright 37156230Smux * notice, this list of conditions and the following disclaimer. 38156230Smux * 2. Redistributions in binary form must reproduce the above copyright 39156230Smux * notice, this list of conditions and the following disclaimer in the 40156230Smux * documentation and/or other materials provided with the distribution. 41156230Smux * 42156230Smux * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 43156230Smux * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 44156230Smux * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 45156230Smux * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 46156230Smux * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 47156230Smux * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 48156230Smux * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 49156230Smux * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 50156230Smux * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 51156230Smux * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 52156230Smux * SUCH DAMAGE. 53156230Smux * 54156230Smux * $FreeBSD: stable/10/usr.sbin/bhyveload/bhyveload.c 267399 2014-06-12 15:20:59Z jhb $ 55156230Smux */ 56156230Smux 57156230Smux#include <sys/cdefs.h> 58156230Smux__FBSDID("$FreeBSD: stable/10/usr.sbin/bhyveload/bhyveload.c 267399 2014-06-12 15:20:59Z jhb $"); 59156230Smux 60156230Smux#include <sys/ioctl.h> 61156230Smux#include <sys/stat.h> 62156230Smux#include <sys/disk.h> 63156230Smux#include <sys/queue.h> 64156230Smux 65156230Smux#include <machine/specialreg.h> 66156230Smux#include <machine/vmm.h> 67156701Smux 68156701Smux#include <dirent.h> 69156701Smux#include <dlfcn.h> 70156701Smux#include <errno.h> 71156701Smux#include <err.h> 72156701Smux#include <fcntl.h> 73156701Smux#include <getopt.h> 74156701Smux#include <libgen.h> 75156701Smux#include <limits.h> 76156701Smux#include <stdio.h> 77156701Smux#include <stdlib.h> 78156701Smux#include <string.h> 79156701Smux#include <sysexits.h> 80156701Smux#include <termios.h> 81156701Smux#include <unistd.h> 82156701Smux 83156701Smux#include <vmmapi.h> 84156701Smux 85156230Smux#include "userboot.h" 86156230Smux 87156230Smux#define MB (1024 * 1024UL) 88156230Smux#define GB (1024 * 1024 * 1024UL) 89156230Smux#define BSP 0 90156230Smux 91156230Smuxstatic char *host_base; 92156230Smuxstatic struct termios term, oldterm; 93156230Smuxstatic int disk_fd = -1; 94156230Smuxstatic int consin_fd, consout_fd; 95156230Smux 96156230Smuxstatic char *vmname, *progname; 97156230Smuxstatic struct vmctx *ctx; 98156230Smux 99156230Smuxstatic uint64_t gdtbase, cr3, rsp; 100156230Smux 101156230Smuxstatic void cb_exit(void *arg, int v); 102156230Smux 103156230Smux/* 104156230Smux * Console i/o callbacks 105156230Smux */ 106156230Smux 107156230Smuxstatic void 108156230Smuxcb_putc(void *arg, int ch) 109156230Smux{ 110156230Smux char c = ch; 111156230Smux 112156230Smux (void) write(consout_fd, &c, 1); 113156230Smux} 114156230Smux 115156230Smuxstatic int 116156230Smuxcb_getc(void *arg) 117156230Smux{ 118156230Smux char c; 119156230Smux 120156230Smux if (read(consin_fd, &c, 1) == 1) 121156230Smux return (c); 122156230Smux return (-1); 123156230Smux} 124156230Smux 125156230Smuxstatic int 126156230Smuxcb_poll(void *arg) 127156230Smux{ 128156230Smux int n; 129156230Smux 130156230Smux if (ioctl(consin_fd, FIONREAD, &n) >= 0) 131156230Smux return (n > 0); 132156230Smux return (0); 133156230Smux} 134156230Smux 135156230Smux/* 136156230Smux * Host filesystem i/o callbacks 137156230Smux */ 138156230Smux 139156230Smuxstruct cb_file { 140156230Smux int cf_isdir; 141156230Smux size_t cf_size; 142156230Smux struct stat cf_stat; 143156230Smux union { 144156230Smux int fd; 145156230Smux DIR *dir; 146156230Smux } cf_u; 147156230Smux}; 148156230Smux 149156230Smuxstatic int 150156230Smuxcb_open(void *arg, const char *filename, void **hp) 151156230Smux{ 152156230Smux struct stat st; 153156230Smux struct cb_file *cf; 154156230Smux char path[PATH_MAX]; 155156230Smux 156156230Smux if (!host_base) 157156230Smux return (ENOENT); 158156230Smux 159156230Smux strlcpy(path, host_base, PATH_MAX); 160156230Smux if (path[strlen(path) - 1] == '/') 161156230Smux path[strlen(path) - 1] = 0; 162156230Smux strlcat(path, filename, PATH_MAX); 163156230Smux cf = malloc(sizeof(struct cb_file)); 164156230Smux if (stat(path, &cf->cf_stat) < 0) { 165156230Smux free(cf); 166156230Smux return (errno); 167156230Smux } 168156230Smux 169156230Smux cf->cf_size = st.st_size; 170156230Smux if (S_ISDIR(cf->cf_stat.st_mode)) { 171156230Smux cf->cf_isdir = 1; 172156230Smux cf->cf_u.dir = opendir(path); 173156230Smux if (!cf->cf_u.dir) 174156230Smux goto out; 175156230Smux *hp = cf; 176156230Smux return (0); 177156230Smux } 178156230Smux if (S_ISREG(cf->cf_stat.st_mode)) { 179156230Smux cf->cf_isdir = 0; 180156230Smux cf->cf_u.fd = open(path, O_RDONLY); 181156230Smux if (cf->cf_u.fd < 0) 182156230Smux goto out; 183156230Smux *hp = cf; 184156230Smux return (0); 185156230Smux } 186156230Smux 187156230Smuxout: 188156230Smux free(cf); 189156230Smux return (EINVAL); 190156230Smux} 191156230Smux 192156230Smuxstatic int 193156230Smuxcb_close(void *arg, void *h) 194156230Smux{ 195156230Smux struct cb_file *cf = h; 196156230Smux 197156230Smux if (cf->cf_isdir) 198156230Smux closedir(cf->cf_u.dir); 199156230Smux else 200156230Smux close(cf->cf_u.fd); 201156230Smux free(cf); 202156230Smux 203156230Smux return (0); 204186781Slulf} 205186781Slulf 206156230Smuxstatic int 207186781Slulfcb_isdir(void *arg, void *h) 208156230Smux{ 209156230Smux struct cb_file *cf = h; 210156230Smux 211156230Smux return (cf->cf_isdir); 212156230Smux} 213156230Smux 214156230Smuxstatic int 215156230Smuxcb_read(void *arg, void *h, void *buf, size_t size, size_t *resid) 216156230Smux{ 217156230Smux struct cb_file *cf = h; 218156230Smux ssize_t sz; 219156230Smux 220156230Smux if (cf->cf_isdir) 221156230Smux return (EINVAL); 222156230Smux sz = read(cf->cf_u.fd, buf, size); 223156230Smux if (sz < 0) 224156230Smux return (EINVAL); 225156251Smux *resid = size - sz; 226156230Smux return (0); 227156230Smux} 228156230Smux 229156230Smuxstatic int 230156230Smuxcb_readdir(void *arg, void *h, uint32_t *fileno_return, uint8_t *type_return, 231156230Smux size_t *namelen_return, char *name) 232156230Smux{ 233156230Smux struct cb_file *cf = h; 234156230Smux struct dirent *dp; 235156230Smux 236156230Smux if (!cf->cf_isdir) 237156230Smux return (EINVAL); 238156230Smux 239156230Smux dp = readdir(cf->cf_u.dir); 240156230Smux if (!dp) 241156230Smux return (ENOENT); 242156230Smux 243156230Smux /* 244156230Smux * Note: d_namlen is in the range 0..255 and therefore less 245156230Smux * than PATH_MAX so we don't need to test before copying. 246156230Smux */ 247156230Smux *fileno_return = dp->d_fileno; 248156230Smux *type_return = dp->d_type; 249156230Smux *namelen_return = dp->d_namlen; 250156230Smux memcpy(name, dp->d_name, dp->d_namlen); 251186781Slulf name[dp->d_namlen] = 0; 252186781Slulf 253186781Slulf return (0); 254186781Slulf} 255186781Slulf 256186781Slulfstatic int 257186781Slulfcb_seek(void *arg, void *h, uint64_t offset, int whence) 258186781Slulf{ 259186781Slulf struct cb_file *cf = h; 260186781Slulf 261186781Slulf if (cf->cf_isdir) 262186781Slulf return (EINVAL); 263186781Slulf if (lseek(cf->cf_u.fd, offset, whence) < 0) 264186781Slulf return (errno); 265186781Slulf return (0); 266186781Slulf} 267186781Slulf 268186781Slulfstatic int 269186781Slulfcb_stat(void *arg, void *h, int *mode, int *uid, int *gid, uint64_t *size) 270186781Slulf{ 271186781Slulf struct cb_file *cf = h; 272186781Slulf 273186781Slulf *mode = cf->cf_stat.st_mode; 274186781Slulf *uid = cf->cf_stat.st_uid; 275186781Slulf *gid = cf->cf_stat.st_gid; 276156230Smux *size = cf->cf_stat.st_size; 277156230Smux return (0); 278156230Smux} 279156230Smux 280156230Smux/* 281156230Smux * Disk image i/o callbacks 282156230Smux */ 283156230Smux 284156230Smuxstatic int 285156230Smuxcb_diskread(void *arg, int unit, uint64_t from, void *to, size_t size, 286156230Smux size_t *resid) 287186781Slulf{ 288156230Smux ssize_t n; 289156230Smux 290156230Smux if (unit != 0 || disk_fd == -1) 291156230Smux return (EIO); 292156230Smux n = pread(disk_fd, to, size, from); 293186781Slulf if (n < 0) 294186781Slulf return (errno); 295186781Slulf *resid = size - n; 296186781Slulf return (0); 297186781Slulf} 298186781Slulf 299186781Slulfstatic int 300186781Slulfcb_diskioctl(void *arg, int unit, u_long cmd, void *data) 301186781Slulf{ 302186781Slulf struct stat sb; 303186781Slulf 304186781Slulf if (unit != 0 || disk_fd == -1) 305186781Slulf return (EBADF); 306186781Slulf 307186781Slulf switch (cmd) { 308186781Slulf case DIOCGSECTORSIZE: 309186781Slulf *(u_int *)data = 512; 310186781Slulf break; 311186781Slulf case DIOCGMEDIASIZE: 312186781Slulf if (fstat(disk_fd, &sb) == 0) 313186781Slulf *(off_t *)data = sb.st_size; 314186781Slulf else 315186781Slulf return (ENOTTY); 316186781Slulf break; 317186781Slulf default: 318186781Slulf return (ENOTTY); 319186781Slulf } 320186781Slulf 321186781Slulf return (0); 322186781Slulf} 323186781Slulf 324186781Slulf/* 325186781Slulf * Guest virtual machine i/o callbacks 326186781Slulf */ 327186781Slulfstatic int 328186781Slulfcb_copyin(void *arg, const void *from, uint64_t to, size_t size) 329186781Slulf{ 330186781Slulf char *ptr; 331186781Slulf 332156230Smux to &= 0x7fffffff; 333156230Smux 334156230Smux ptr = vm_map_gpa(ctx, to, size); 335156230Smux if (ptr == NULL) 336156230Smux return (EFAULT); 337156230Smux 338156230Smux memcpy(ptr, from, size); 339156230Smux return (0); 340156230Smux} 341156230Smux 342156230Smuxstatic int 343156230Smuxcb_copyout(void *arg, uint64_t from, void *to, size_t size) 344156230Smux{ 345156230Smux char *ptr; 346156230Smux 347156230Smux from &= 0x7fffffff; 348156230Smux 349156230Smux ptr = vm_map_gpa(ctx, from, size); 350156230Smux if (ptr == NULL) 351156230Smux return (EFAULT); 352156230Smux 353156230Smux memcpy(to, ptr, size); 354156230Smux return (0); 355156230Smux} 356156230Smux 357156230Smuxstatic void 358156230Smuxcb_setreg(void *arg, int r, uint64_t v) 359156230Smux{ 360156230Smux int error; 361156230Smux enum vm_reg_name vmreg; 362156230Smux 363156230Smux vmreg = VM_REG_LAST; 364156230Smux 365156230Smux switch (r) { 366156230Smux case 4: 367156230Smux vmreg = VM_REG_GUEST_RSP; 368156230Smux rsp = v; 369156230Smux break; 370156230Smux default: 371156230Smux break; 372156230Smux } 373156230Smux 374156230Smux if (vmreg == VM_REG_LAST) { 375156230Smux printf("test_setreg(%d): not implemented\n", r); 376156230Smux cb_exit(NULL, USERBOOT_EXIT_QUIT); 377156230Smux } 378156230Smux 379156230Smux error = vm_set_register(ctx, BSP, vmreg, v); 380156230Smux if (error) { 381156230Smux perror("vm_set_register"); 382156230Smux cb_exit(NULL, USERBOOT_EXIT_QUIT); 383156230Smux } 384156230Smux} 385156230Smux 386156230Smuxstatic void 387156230Smuxcb_setmsr(void *arg, int r, uint64_t v) 388156230Smux{ 389156230Smux int error; 390156230Smux enum vm_reg_name vmreg; 391156230Smux 392156230Smux vmreg = VM_REG_LAST; 393156230Smux 394156230Smux switch (r) { 395156230Smux case MSR_EFER: 396156230Smux vmreg = VM_REG_GUEST_EFER; 397156230Smux break; 398156230Smux default: 399156230Smux break; 400156230Smux } 401156230Smux 402156230Smux if (vmreg == VM_REG_LAST) { 403156230Smux printf("test_setmsr(%d): not implemented\n", r); 404156230Smux cb_exit(NULL, USERBOOT_EXIT_QUIT); 405156230Smux } 406156230Smux 407156230Smux error = vm_set_register(ctx, BSP, vmreg, v); 408156230Smux if (error) { 409156230Smux perror("vm_set_msr"); 410156230Smux cb_exit(NULL, USERBOOT_EXIT_QUIT); 411156230Smux } 412156230Smux} 413156230Smux 414156230Smuxstatic void 415156230Smuxcb_setcr(void *arg, int r, uint64_t v) 416156230Smux{ 417156230Smux int error; 418156230Smux enum vm_reg_name vmreg; 419156230Smux 420156230Smux vmreg = VM_REG_LAST; 421156230Smux 422156230Smux switch (r) { 423156230Smux case 0: 424156230Smux vmreg = VM_REG_GUEST_CR0; 425156230Smux break; 426156230Smux case 3: 427156230Smux vmreg = VM_REG_GUEST_CR3; 428156230Smux cr3 = v; 429156230Smux break; 430156230Smux case 4: 431156230Smux vmreg = VM_REG_GUEST_CR4; 432156230Smux break; 433156230Smux default: 434156230Smux break; 435156230Smux } 436156230Smux 437156230Smux if (vmreg == VM_REG_LAST) { 438156230Smux printf("test_setcr(%d): not implemented\n", r); 439156230Smux cb_exit(NULL, USERBOOT_EXIT_QUIT); 440156230Smux } 441156230Smux 442156230Smux error = vm_set_register(ctx, BSP, vmreg, v); 443156230Smux if (error) { 444156230Smux perror("vm_set_cr"); 445156230Smux cb_exit(NULL, USERBOOT_EXIT_QUIT); 446156230Smux } 447156230Smux} 448156230Smux 449156230Smuxstatic void 450156230Smuxcb_setgdt(void *arg, uint64_t base, size_t size) 451156230Smux{ 452156230Smux int error; 453156230Smux 454156230Smux error = vm_set_desc(ctx, BSP, VM_REG_GUEST_GDTR, base, size - 1, 0); 455156230Smux if (error != 0) { 456156230Smux perror("vm_set_desc(gdt)"); 457156230Smux cb_exit(NULL, USERBOOT_EXIT_QUIT); 458156230Smux } 459156230Smux 460156230Smux gdtbase = base; 461156230Smux} 462156230Smux 463156230Smuxstatic void 464156230Smuxcb_exec(void *arg, uint64_t rip) 465156230Smux{ 466156230Smux int error; 467156230Smux 468156230Smux if (cr3 == 0) 469156230Smux error = vm_setup_freebsd_registers_i386(ctx, BSP, rip, gdtbase, 470156230Smux rsp); 471156230Smux else 472156230Smux error = vm_setup_freebsd_registers(ctx, BSP, rip, cr3, gdtbase, 473156230Smux rsp); 474156230Smux if (error) { 475156230Smux perror("vm_setup_freebsd_registers"); 476156230Smux cb_exit(NULL, USERBOOT_EXIT_QUIT); 477156230Smux } 478156230Smux 479156230Smux cb_exit(NULL, 0); 480156230Smux} 481156230Smux 482156230Smux/* 483156230Smux * Misc 484156230Smux */ 485156230Smux 486156230Smuxstatic void 487156230Smuxcb_delay(void *arg, int usec) 488156230Smux{ 489156230Smux 490156230Smux usleep(usec); 491156230Smux} 492156230Smux 493156230Smuxstatic void 494156230Smuxcb_exit(void *arg, int v) 495156230Smux{ 496156230Smux 497156230Smux tcsetattr(consout_fd, TCSAFLUSH, &oldterm); 498156230Smux exit(v); 499156230Smux} 500156230Smux 501156230Smuxstatic void 502156230Smuxcb_getmem(void *arg, uint64_t *ret_lowmem, uint64_t *ret_highmem) 503156230Smux{ 504156230Smux 505156230Smux vm_get_memory_seg(ctx, 0, ret_lowmem, NULL); 506156230Smux vm_get_memory_seg(ctx, 4 * GB, ret_highmem, NULL); 507156230Smux} 508156230Smux 509156230Smuxstruct env { 510156230Smux const char *str; /* name=value */ 511156230Smux SLIST_ENTRY(env) next; 512156230Smux}; 513156230Smux 514156230Smuxstatic SLIST_HEAD(envhead, env) envhead; 515156230Smux 516156230Smuxstatic void 517156230Smuxaddenv(const char *str) 518156230Smux{ 519156230Smux struct env *env; 520156230Smux 521156230Smux env = malloc(sizeof(struct env)); 522156230Smux env->str = str; 523156230Smux SLIST_INSERT_HEAD(&envhead, env, next); 524156230Smux} 525156230Smux 526156230Smuxstatic const char * 527156230Smuxcb_getenv(void *arg, int num) 528156230Smux{ 529156230Smux int i; 530156230Smux struct env *env; 531156230Smux 532156230Smux i = 0; 533156230Smux SLIST_FOREACH(env, &envhead, next) { 534156230Smux if (i == num) 535156230Smux return (env->str); 536156230Smux i++; 537156230Smux } 538156230Smux 539156230Smux return (NULL); 540156230Smux} 541156230Smux 542156230Smuxstatic struct loader_callbacks cb = { 543156230Smux .getc = cb_getc, 544156230Smux .putc = cb_putc, 545156230Smux .poll = cb_poll, 546156230Smux 547156230Smux .open = cb_open, 548156230Smux .close = cb_close, 549156230Smux .isdir = cb_isdir, 550156230Smux .read = cb_read, 551156230Smux .readdir = cb_readdir, 552156230Smux .seek = cb_seek, 553156230Smux .stat = cb_stat, 554156230Smux 555156230Smux .diskread = cb_diskread, 556156230Smux .diskioctl = cb_diskioctl, 557156230Smux 558156230Smux .copyin = cb_copyin, 559156230Smux .copyout = cb_copyout, 560156230Smux .setreg = cb_setreg, 561156230Smux .setmsr = cb_setmsr, 562156230Smux .setcr = cb_setcr, 563156230Smux .setgdt = cb_setgdt, 564156230Smux .exec = cb_exec, 565156230Smux 566156230Smux .delay = cb_delay, 567156230Smux .exit = cb_exit, 568156230Smux .getmem = cb_getmem, 569156230Smux 570156230Smux .getenv = cb_getenv, 571156230Smux}; 572156230Smux 573156230Smuxstatic int 574156230Smuxaltcons_open(char *path) 575186781Slulf{ 576186781Slulf struct stat sb; 577186781Slulf int err; 578186781Slulf int fd; 579186781Slulf 580186781Slulf /* 581186781Slulf * Allow stdio to be passed in so that the same string 582186781Slulf * can be used for the bhyveload console and bhyve com-port 583186781Slulf * parameters 584186781Slulf */ 585186781Slulf if (!strcmp(path, "stdio")) 586186781Slulf return (0); 587186781Slulf 588186781Slulf err = stat(path, &sb); 589186781Slulf if (err == 0) { 590186781Slulf if (!S_ISCHR(sb.st_mode)) 591186781Slulf err = ENOTSUP; 592186781Slulf else { 593186781Slulf fd = open(path, O_RDWR | O_NONBLOCK); 594186781Slulf if (fd < 0) 595186781Slulf err = errno; 596186781Slulf else 597186781Slulf consin_fd = consout_fd = fd; 598186781Slulf } 599186781Slulf } 600186781Slulf 601186781Slulf return (err); 602186781Slulf} 603186781Slulf 604186781Slulfstatic void 605186781Slulfusage(void) 606186781Slulf{ 607186781Slulf 608186781Slulf fprintf(stderr, 609186781Slulf "usage: %s [-m mem-size] [-d <disk-path>] [-h <host-path>]\n" 610186781Slulf " %*s [-e <name=value>] [-c <console-device>] <vmname>\n", 611186781Slulf progname, 612186781Slulf (int)strlen(progname), ""); 613186781Slulf exit(1); 614186781Slulf} 615186781Slulf 616186781Slulfint 617186781Slulfmain(int argc, char** argv) 618186781Slulf{ 619186781Slulf void *h; 620186781Slulf void (*func)(struct loader_callbacks *, void *, int, int); 621186781Slulf uint64_t mem_size; 622186781Slulf int opt, error; 623186781Slulf char *disk_image; 624186781Slulf 625186781Slulf progname = basename(argv[0]); 626186781Slulf 627186781Slulf mem_size = 256 * MB; 628186781Slulf disk_image = NULL; 629186781Slulf 630186781Slulf consin_fd = STDIN_FILENO; 631186781Slulf consout_fd = STDOUT_FILENO; 632186781Slulf 633186781Slulf while ((opt = getopt(argc, argv, "c:d:e:h:m:")) != -1) { 634186781Slulf switch (opt) { 635186781Slulf case 'c': 636186781Slulf error = altcons_open(optarg); 637186781Slulf if (error != 0) 638186781Slulf errx(EX_USAGE, "Could not open '%s'", optarg); 639186781Slulf break; 640186781Slulf case 'd': 641186781Slulf disk_image = optarg; 642186781Slulf break; 643186781Slulf 644186781Slulf case 'e': 645 addenv(optarg); 646 break; 647 648 case 'h': 649 host_base = optarg; 650 break; 651 652 case 'm': 653 error = vm_parse_memsize(optarg, &mem_size); 654 if (error != 0) 655 errx(EX_USAGE, "Invalid memsize '%s'", optarg); 656 break; 657 case '?': 658 usage(); 659 } 660 } 661 662 argc -= optind; 663 argv += optind; 664 665 if (argc != 1) 666 usage(); 667 668 vmname = argv[0]; 669 670 error = vm_create(vmname); 671 if (error != 0 && errno != EEXIST) { 672 perror("vm_create"); 673 exit(1); 674 675 } 676 677 ctx = vm_open(vmname); 678 if (ctx == NULL) { 679 perror("vm_open"); 680 exit(1); 681 } 682 683 error = vm_setup_memory(ctx, mem_size, VM_MMAP_ALL); 684 if (error) { 685 perror("vm_setup_memory"); 686 exit(1); 687 } 688 689 tcgetattr(consout_fd, &term); 690 oldterm = term; 691 cfmakeraw(&term); 692 term.c_cflag |= CLOCAL; 693 694 tcsetattr(consout_fd, TCSAFLUSH, &term); 695 696 h = dlopen("/boot/userboot.so", RTLD_LOCAL); 697 if (!h) { 698 printf("%s\n", dlerror()); 699 return (1); 700 } 701 func = dlsym(h, "loader_main"); 702 if (!func) { 703 printf("%s\n", dlerror()); 704 return (1); 705 } 706 707 if (disk_image) { 708 disk_fd = open(disk_image, O_RDONLY); 709 } 710 711 addenv("smbios.bios.vendor=BHYVE"); 712 addenv("boot_serial=1"); 713 714 func(&cb, NULL, USERBOOT_VERSION_3, disk_fd >= 0); 715} 716