1223828Sneel/*- 2223828Sneel * Copyright (c) 2011 NetApp, Inc. 3223828Sneel * All rights reserved. 4223828Sneel * 5223828Sneel * Redistribution and use in source and binary forms, with or without 6223828Sneel * modification, are permitted provided that the following conditions 7223828Sneel * are met: 8223828Sneel * 1. Redistributions of source code must retain the above copyright 9223828Sneel * notice, this list of conditions and the following disclaimer. 10223828Sneel * 2. Redistributions in binary form must reproduce the above copyright 11223828Sneel * notice, this list of conditions and the following disclaimer in the 12223828Sneel * documentation and/or other materials provided with the distribution. 13223828Sneel * 14223828Sneel * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND 15223828Sneel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16223828Sneel * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17223828Sneel * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE 18223828Sneel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19223828Sneel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20223828Sneel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21223828Sneel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22223828Sneel * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23223828Sneel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24223828Sneel * SUCH DAMAGE. 25223828Sneel * 26223828Sneel * $FreeBSD$ 27223828Sneel */ 28223828Sneel 29223828Sneel/*- 30223828Sneel * Copyright (c) 2011 Google, Inc. 31223828Sneel * All rights reserved. 32223828Sneel * 33223828Sneel * Redistribution and use in source and binary forms, with or without 34223828Sneel * modification, are permitted provided that the following conditions 35223828Sneel * are met: 36223828Sneel * 1. Redistributions of source code must retain the above copyright 37223828Sneel * notice, this list of conditions and the following disclaimer. 38223828Sneel * 2. Redistributions in binary form must reproduce the above copyright 39223828Sneel * notice, this list of conditions and the following disclaimer in the 40223828Sneel * documentation and/or other materials provided with the distribution. 41223828Sneel * 42223828Sneel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 43223828Sneel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 44223828Sneel * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 45223828Sneel * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 46223828Sneel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 47223828Sneel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 48223828Sneel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 49223828Sneel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 50223828Sneel * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 51223828Sneel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 52223828Sneel * SUCH DAMAGE. 53223828Sneel * 54223828Sneel * $FreeBSD$ 55223828Sneel */ 56223828Sneel 57223828Sneel#include <sys/cdefs.h> 58223828Sneel__FBSDID("$FreeBSD$"); 59223828Sneel 60223828Sneel#include <sys/ioctl.h> 61223828Sneel#include <sys/stat.h> 62242882Sneel#include <sys/disk.h> 63259301Sgrehan#include <sys/queue.h> 64223828Sneel 65223828Sneel#include <machine/specialreg.h> 66223828Sneel#include <machine/vmm.h> 67223828Sneel 68223828Sneel#include <dirent.h> 69223828Sneel#include <dlfcn.h> 70223828Sneel#include <errno.h> 71256176Sneel#include <err.h> 72223828Sneel#include <fcntl.h> 73223828Sneel#include <getopt.h> 74259301Sgrehan#include <libgen.h> 75223828Sneel#include <limits.h> 76223828Sneel#include <stdio.h> 77223828Sneel#include <stdlib.h> 78223828Sneel#include <string.h> 79256176Sneel#include <sysexits.h> 80223828Sneel#include <termios.h> 81223828Sneel#include <unistd.h> 82223828Sneel 83223828Sneel#include <vmmapi.h> 84223828Sneel 85223828Sneel#include "userboot.h" 86223828Sneel 87223828Sneel#define MB (1024 * 1024UL) 88223828Sneel#define GB (1024 * 1024 * 1024UL) 89223828Sneel#define BSP 0 90223828Sneel 91268932Sjhb#define NDISKS 32 92268932Sjhb 93259301Sgrehanstatic char *host_base; 94223828Sneelstatic struct termios term, oldterm; 95268932Sjhbstatic int disk_fd[NDISKS]; 96268932Sjhbstatic int ndisks; 97259301Sgrehanstatic int consin_fd, consout_fd; 98223828Sneel 99248477Sneelstatic char *vmname, *progname; 100223828Sneelstatic struct vmctx *ctx; 101223828Sneel 102223828Sneelstatic uint64_t gdtbase, cr3, rsp; 103223828Sneel 104223828Sneelstatic void cb_exit(void *arg, int v); 105223828Sneel 106223828Sneel/* 107223828Sneel * Console i/o callbacks 108223828Sneel */ 109223828Sneel 110223828Sneelstatic void 111223828Sneelcb_putc(void *arg, int ch) 112223828Sneel{ 113223828Sneel char c = ch; 114223828Sneel 115259301Sgrehan (void) write(consout_fd, &c, 1); 116223828Sneel} 117223828Sneel 118223828Sneelstatic int 119223828Sneelcb_getc(void *arg) 120223828Sneel{ 121223828Sneel char c; 122223828Sneel 123259301Sgrehan if (read(consin_fd, &c, 1) == 1) 124223828Sneel return (c); 125223828Sneel return (-1); 126223828Sneel} 127223828Sneel 128223828Sneelstatic int 129223828Sneelcb_poll(void *arg) 130223828Sneel{ 131223828Sneel int n; 132223828Sneel 133259301Sgrehan if (ioctl(consin_fd, FIONREAD, &n) >= 0) 134223828Sneel return (n > 0); 135223828Sneel return (0); 136223828Sneel} 137223828Sneel 138223828Sneel/* 139223828Sneel * Host filesystem i/o callbacks 140223828Sneel */ 141223828Sneel 142223828Sneelstruct cb_file { 143223828Sneel int cf_isdir; 144223828Sneel size_t cf_size; 145223828Sneel struct stat cf_stat; 146223828Sneel union { 147223828Sneel int fd; 148223828Sneel DIR *dir; 149223828Sneel } cf_u; 150223828Sneel}; 151223828Sneel 152223828Sneelstatic int 153223828Sneelcb_open(void *arg, const char *filename, void **hp) 154223828Sneel{ 155223828Sneel struct stat st; 156223828Sneel struct cb_file *cf; 157223828Sneel char path[PATH_MAX]; 158223828Sneel 159223828Sneel if (!host_base) 160223828Sneel return (ENOENT); 161223828Sneel 162223828Sneel strlcpy(path, host_base, PATH_MAX); 163223828Sneel if (path[strlen(path) - 1] == '/') 164223828Sneel path[strlen(path) - 1] = 0; 165223828Sneel strlcat(path, filename, PATH_MAX); 166223828Sneel cf = malloc(sizeof(struct cb_file)); 167223828Sneel if (stat(path, &cf->cf_stat) < 0) { 168223828Sneel free(cf); 169223828Sneel return (errno); 170223828Sneel } 171223828Sneel 172223828Sneel cf->cf_size = st.st_size; 173223828Sneel if (S_ISDIR(cf->cf_stat.st_mode)) { 174223828Sneel cf->cf_isdir = 1; 175223828Sneel cf->cf_u.dir = opendir(path); 176223828Sneel if (!cf->cf_u.dir) 177223828Sneel goto out; 178223828Sneel *hp = cf; 179223828Sneel return (0); 180223828Sneel } 181223828Sneel if (S_ISREG(cf->cf_stat.st_mode)) { 182223828Sneel cf->cf_isdir = 0; 183223828Sneel cf->cf_u.fd = open(path, O_RDONLY); 184223828Sneel if (cf->cf_u.fd < 0) 185223828Sneel goto out; 186223828Sneel *hp = cf; 187223828Sneel return (0); 188223828Sneel } 189223828Sneel 190223828Sneelout: 191223828Sneel free(cf); 192223828Sneel return (EINVAL); 193223828Sneel} 194223828Sneel 195223828Sneelstatic int 196223828Sneelcb_close(void *arg, void *h) 197223828Sneel{ 198223828Sneel struct cb_file *cf = h; 199223828Sneel 200223828Sneel if (cf->cf_isdir) 201223828Sneel closedir(cf->cf_u.dir); 202223828Sneel else 203223828Sneel close(cf->cf_u.fd); 204223828Sneel free(cf); 205223828Sneel 206223828Sneel return (0); 207223828Sneel} 208223828Sneel 209223828Sneelstatic int 210223828Sneelcb_isdir(void *arg, void *h) 211223828Sneel{ 212223828Sneel struct cb_file *cf = h; 213223828Sneel 214223828Sneel return (cf->cf_isdir); 215223828Sneel} 216223828Sneel 217223828Sneelstatic int 218223828Sneelcb_read(void *arg, void *h, void *buf, size_t size, size_t *resid) 219223828Sneel{ 220223828Sneel struct cb_file *cf = h; 221223828Sneel ssize_t sz; 222223828Sneel 223223828Sneel if (cf->cf_isdir) 224223828Sneel return (EINVAL); 225223828Sneel sz = read(cf->cf_u.fd, buf, size); 226223828Sneel if (sz < 0) 227223828Sneel return (EINVAL); 228223828Sneel *resid = size - sz; 229223828Sneel return (0); 230223828Sneel} 231223828Sneel 232223828Sneelstatic int 233223828Sneelcb_readdir(void *arg, void *h, uint32_t *fileno_return, uint8_t *type_return, 234223828Sneel size_t *namelen_return, char *name) 235223828Sneel{ 236223828Sneel struct cb_file *cf = h; 237223828Sneel struct dirent *dp; 238223828Sneel 239223828Sneel if (!cf->cf_isdir) 240223828Sneel return (EINVAL); 241223828Sneel 242223828Sneel dp = readdir(cf->cf_u.dir); 243223828Sneel if (!dp) 244223828Sneel return (ENOENT); 245223828Sneel 246223828Sneel /* 247223828Sneel * Note: d_namlen is in the range 0..255 and therefore less 248223828Sneel * than PATH_MAX so we don't need to test before copying. 249223828Sneel */ 250223828Sneel *fileno_return = dp->d_fileno; 251223828Sneel *type_return = dp->d_type; 252223828Sneel *namelen_return = dp->d_namlen; 253223828Sneel memcpy(name, dp->d_name, dp->d_namlen); 254223828Sneel name[dp->d_namlen] = 0; 255223828Sneel 256223828Sneel return (0); 257223828Sneel} 258223828Sneel 259223828Sneelstatic int 260223828Sneelcb_seek(void *arg, void *h, uint64_t offset, int whence) 261223828Sneel{ 262223828Sneel struct cb_file *cf = h; 263223828Sneel 264223828Sneel if (cf->cf_isdir) 265223828Sneel return (EINVAL); 266223828Sneel if (lseek(cf->cf_u.fd, offset, whence) < 0) 267223828Sneel return (errno); 268223828Sneel return (0); 269223828Sneel} 270223828Sneel 271223828Sneelstatic int 272223828Sneelcb_stat(void *arg, void *h, int *mode, int *uid, int *gid, uint64_t *size) 273223828Sneel{ 274223828Sneel struct cb_file *cf = h; 275223828Sneel 276223828Sneel *mode = cf->cf_stat.st_mode; 277223828Sneel *uid = cf->cf_stat.st_uid; 278223828Sneel *gid = cf->cf_stat.st_gid; 279223828Sneel *size = cf->cf_stat.st_size; 280223828Sneel return (0); 281223828Sneel} 282223828Sneel 283223828Sneel/* 284223828Sneel * Disk image i/o callbacks 285223828Sneel */ 286223828Sneel 287223828Sneelstatic int 288223828Sneelcb_diskread(void *arg, int unit, uint64_t from, void *to, size_t size, 289223828Sneel size_t *resid) 290223828Sneel{ 291223828Sneel ssize_t n; 292223828Sneel 293268932Sjhb if (unit < 0 || unit >= ndisks ) 294223828Sneel return (EIO); 295268932Sjhb n = pread(disk_fd[unit], to, size, from); 296223828Sneel if (n < 0) 297223828Sneel return (errno); 298223828Sneel *resid = size - n; 299223828Sneel return (0); 300223828Sneel} 301223828Sneel 302242882Sneelstatic int 303242882Sneelcb_diskioctl(void *arg, int unit, u_long cmd, void *data) 304242882Sneel{ 305242882Sneel struct stat sb; 306242882Sneel 307268932Sjhb if (unit < 0 || unit >= ndisks) 308242882Sneel return (EBADF); 309242882Sneel 310242882Sneel switch (cmd) { 311242882Sneel case DIOCGSECTORSIZE: 312242882Sneel *(u_int *)data = 512; 313242882Sneel break; 314242882Sneel case DIOCGMEDIASIZE: 315268932Sjhb if (fstat(disk_fd[unit], &sb) == 0) 316242882Sneel *(off_t *)data = sb.st_size; 317242882Sneel else 318242882Sneel return (ENOTTY); 319242882Sneel break; 320242882Sneel default: 321242882Sneel return (ENOTTY); 322242882Sneel } 323242882Sneel 324242882Sneel return (0); 325242882Sneel} 326242882Sneel 327223828Sneel/* 328223828Sneel * Guest virtual machine i/o callbacks 329223828Sneel */ 330223828Sneelstatic int 331223828Sneelcb_copyin(void *arg, const void *from, uint64_t to, size_t size) 332223828Sneel{ 333248477Sneel char *ptr; 334223828Sneel 335223828Sneel to &= 0x7fffffff; 336248477Sneel 337248477Sneel ptr = vm_map_gpa(ctx, to, size); 338248477Sneel if (ptr == NULL) 339223828Sneel return (EFAULT); 340223828Sneel 341248477Sneel memcpy(ptr, from, size); 342223828Sneel return (0); 343223828Sneel} 344223828Sneel 345223828Sneelstatic int 346223828Sneelcb_copyout(void *arg, uint64_t from, void *to, size_t size) 347223828Sneel{ 348248477Sneel char *ptr; 349223828Sneel 350223828Sneel from &= 0x7fffffff; 351248477Sneel 352248477Sneel ptr = vm_map_gpa(ctx, from, size); 353248477Sneel if (ptr == NULL) 354223828Sneel return (EFAULT); 355223828Sneel 356248477Sneel memcpy(to, ptr, size); 357223828Sneel return (0); 358223828Sneel} 359223828Sneel 360223828Sneelstatic void 361223828Sneelcb_setreg(void *arg, int r, uint64_t v) 362223828Sneel{ 363223828Sneel int error; 364223828Sneel enum vm_reg_name vmreg; 365223828Sneel 366223828Sneel vmreg = VM_REG_LAST; 367223828Sneel 368223828Sneel switch (r) { 369223828Sneel case 4: 370223828Sneel vmreg = VM_REG_GUEST_RSP; 371223828Sneel rsp = v; 372223828Sneel break; 373223828Sneel default: 374223828Sneel break; 375223828Sneel } 376223828Sneel 377223828Sneel if (vmreg == VM_REG_LAST) { 378223828Sneel printf("test_setreg(%d): not implemented\n", r); 379223828Sneel cb_exit(NULL, USERBOOT_EXIT_QUIT); 380223828Sneel } 381223828Sneel 382223828Sneel error = vm_set_register(ctx, BSP, vmreg, v); 383223828Sneel if (error) { 384223828Sneel perror("vm_set_register"); 385223828Sneel cb_exit(NULL, USERBOOT_EXIT_QUIT); 386223828Sneel } 387223828Sneel} 388223828Sneel 389223828Sneelstatic void 390223828Sneelcb_setmsr(void *arg, int r, uint64_t v) 391223828Sneel{ 392223828Sneel int error; 393223828Sneel enum vm_reg_name vmreg; 394223828Sneel 395223828Sneel vmreg = VM_REG_LAST; 396223828Sneel 397223828Sneel switch (r) { 398223828Sneel case MSR_EFER: 399223828Sneel vmreg = VM_REG_GUEST_EFER; 400223828Sneel break; 401223828Sneel default: 402223828Sneel break; 403223828Sneel } 404223828Sneel 405223828Sneel if (vmreg == VM_REG_LAST) { 406223828Sneel printf("test_setmsr(%d): not implemented\n", r); 407223828Sneel cb_exit(NULL, USERBOOT_EXIT_QUIT); 408223828Sneel } 409223828Sneel 410223828Sneel error = vm_set_register(ctx, BSP, vmreg, v); 411223828Sneel if (error) { 412223828Sneel perror("vm_set_msr"); 413223828Sneel cb_exit(NULL, USERBOOT_EXIT_QUIT); 414223828Sneel } 415223828Sneel} 416223828Sneel 417223828Sneelstatic void 418223828Sneelcb_setcr(void *arg, int r, uint64_t v) 419223828Sneel{ 420223828Sneel int error; 421223828Sneel enum vm_reg_name vmreg; 422223828Sneel 423223828Sneel vmreg = VM_REG_LAST; 424223828Sneel 425223828Sneel switch (r) { 426223828Sneel case 0: 427223828Sneel vmreg = VM_REG_GUEST_CR0; 428223828Sneel break; 429223828Sneel case 3: 430223828Sneel vmreg = VM_REG_GUEST_CR3; 431223828Sneel cr3 = v; 432223828Sneel break; 433223828Sneel case 4: 434223828Sneel vmreg = VM_REG_GUEST_CR4; 435223828Sneel break; 436223828Sneel default: 437223828Sneel break; 438223828Sneel } 439223828Sneel 440223828Sneel if (vmreg == VM_REG_LAST) { 441223828Sneel printf("test_setcr(%d): not implemented\n", r); 442223828Sneel cb_exit(NULL, USERBOOT_EXIT_QUIT); 443223828Sneel } 444223828Sneel 445223828Sneel error = vm_set_register(ctx, BSP, vmreg, v); 446223828Sneel if (error) { 447223828Sneel perror("vm_set_cr"); 448223828Sneel cb_exit(NULL, USERBOOT_EXIT_QUIT); 449223828Sneel } 450223828Sneel} 451223828Sneel 452223828Sneelstatic void 453223828Sneelcb_setgdt(void *arg, uint64_t base, size_t size) 454223828Sneel{ 455223828Sneel int error; 456223828Sneel 457223828Sneel error = vm_set_desc(ctx, BSP, VM_REG_GUEST_GDTR, base, size - 1, 0); 458223828Sneel if (error != 0) { 459223828Sneel perror("vm_set_desc(gdt)"); 460223828Sneel cb_exit(NULL, USERBOOT_EXIT_QUIT); 461223828Sneel } 462223828Sneel 463223828Sneel gdtbase = base; 464223828Sneel} 465223828Sneel 466223828Sneelstatic void 467223828Sneelcb_exec(void *arg, uint64_t rip) 468223828Sneel{ 469223828Sneel int error; 470223828Sneel 471267399Sjhb if (cr3 == 0) 472267399Sjhb error = vm_setup_freebsd_registers_i386(ctx, BSP, rip, gdtbase, 473267399Sjhb rsp); 474267399Sjhb else 475267399Sjhb error = vm_setup_freebsd_registers(ctx, BSP, rip, cr3, gdtbase, 476267399Sjhb rsp); 477223828Sneel if (error) { 478223828Sneel perror("vm_setup_freebsd_registers"); 479223828Sneel cb_exit(NULL, USERBOOT_EXIT_QUIT); 480223828Sneel } 481223828Sneel 482223828Sneel cb_exit(NULL, 0); 483223828Sneel} 484223828Sneel 485223828Sneel/* 486223828Sneel * Misc 487223828Sneel */ 488223828Sneel 489223828Sneelstatic void 490223828Sneelcb_delay(void *arg, int usec) 491223828Sneel{ 492223828Sneel 493223828Sneel usleep(usec); 494223828Sneel} 495223828Sneel 496223828Sneelstatic void 497223828Sneelcb_exit(void *arg, int v) 498223828Sneel{ 499223828Sneel 500259301Sgrehan tcsetattr(consout_fd, TCSAFLUSH, &oldterm); 501223828Sneel exit(v); 502223828Sneel} 503223828Sneel 504223828Sneelstatic void 505223828Sneelcb_getmem(void *arg, uint64_t *ret_lowmem, uint64_t *ret_highmem) 506223828Sneel{ 507223828Sneel 508270074Sgrehan *ret_lowmem = vm_get_lowmem_size(ctx); 509270074Sgrehan *ret_highmem = vm_get_highmem_size(ctx); 510223828Sneel} 511223828Sneel 512259301Sgrehanstruct env { 513259301Sgrehan const char *str; /* name=value */ 514259301Sgrehan SLIST_ENTRY(env) next; 515259301Sgrehan}; 516259301Sgrehan 517259301Sgrehanstatic SLIST_HEAD(envhead, env) envhead; 518259301Sgrehan 519259301Sgrehanstatic void 520259301Sgrehanaddenv(const char *str) 521259301Sgrehan{ 522259301Sgrehan struct env *env; 523259301Sgrehan 524259301Sgrehan env = malloc(sizeof(struct env)); 525259301Sgrehan env->str = str; 526259301Sgrehan SLIST_INSERT_HEAD(&envhead, env, next); 527259301Sgrehan} 528259301Sgrehan 529242676Sneelstatic const char * 530242676Sneelcb_getenv(void *arg, int num) 531242676Sneel{ 532259301Sgrehan int i; 533259301Sgrehan struct env *env; 534242676Sneel 535259301Sgrehan i = 0; 536259301Sgrehan SLIST_FOREACH(env, &envhead, next) { 537259301Sgrehan if (i == num) 538259301Sgrehan return (env->str); 539259301Sgrehan i++; 540259301Sgrehan } 541242676Sneel 542259301Sgrehan return (NULL); 543242676Sneel} 544242676Sneel 545242882Sneelstatic struct loader_callbacks cb = { 546223828Sneel .getc = cb_getc, 547223828Sneel .putc = cb_putc, 548223828Sneel .poll = cb_poll, 549223828Sneel 550223828Sneel .open = cb_open, 551223828Sneel .close = cb_close, 552223828Sneel .isdir = cb_isdir, 553223828Sneel .read = cb_read, 554223828Sneel .readdir = cb_readdir, 555223828Sneel .seek = cb_seek, 556223828Sneel .stat = cb_stat, 557223828Sneel 558223828Sneel .diskread = cb_diskread, 559242882Sneel .diskioctl = cb_diskioctl, 560223828Sneel 561223828Sneel .copyin = cb_copyin, 562223828Sneel .copyout = cb_copyout, 563223828Sneel .setreg = cb_setreg, 564223828Sneel .setmsr = cb_setmsr, 565223828Sneel .setcr = cb_setcr, 566223828Sneel .setgdt = cb_setgdt, 567223828Sneel .exec = cb_exec, 568223828Sneel 569223828Sneel .delay = cb_delay, 570223828Sneel .exit = cb_exit, 571223828Sneel .getmem = cb_getmem, 572242676Sneel 573242676Sneel .getenv = cb_getenv, 574223828Sneel}; 575223828Sneel 576259301Sgrehanstatic int 577259301Sgrehanaltcons_open(char *path) 578259301Sgrehan{ 579259301Sgrehan struct stat sb; 580259301Sgrehan int err; 581259301Sgrehan int fd; 582259301Sgrehan 583259301Sgrehan /* 584259301Sgrehan * Allow stdio to be passed in so that the same string 585259301Sgrehan * can be used for the bhyveload console and bhyve com-port 586259301Sgrehan * parameters 587259301Sgrehan */ 588259301Sgrehan if (!strcmp(path, "stdio")) 589259301Sgrehan return (0); 590259301Sgrehan 591259301Sgrehan err = stat(path, &sb); 592259301Sgrehan if (err == 0) { 593259301Sgrehan if (!S_ISCHR(sb.st_mode)) 594259301Sgrehan err = ENOTSUP; 595259301Sgrehan else { 596259301Sgrehan fd = open(path, O_RDWR | O_NONBLOCK); 597259301Sgrehan if (fd < 0) 598259301Sgrehan err = errno; 599259301Sgrehan else 600259301Sgrehan consin_fd = consout_fd = fd; 601259301Sgrehan } 602259301Sgrehan } 603259301Sgrehan 604259301Sgrehan return (err); 605259301Sgrehan} 606259301Sgrehan 607268932Sjhbstatic int 608268932Sjhbdisk_open(char *path) 609268932Sjhb{ 610268932Sjhb int err, fd; 611268932Sjhb 612268932Sjhb if (ndisks > NDISKS) 613268932Sjhb return (ERANGE); 614268932Sjhb 615268932Sjhb err = 0; 616268932Sjhb fd = open(path, O_RDONLY); 617268932Sjhb 618268932Sjhb if (fd > 0) { 619268932Sjhb disk_fd[ndisks] = fd; 620268932Sjhb ndisks++; 621268932Sjhb } else 622268932Sjhb err = errno; 623268932Sjhb 624268932Sjhb return (err); 625268932Sjhb} 626268932Sjhb 627223828Sneelstatic void 628223828Sneelusage(void) 629223828Sneel{ 630223828Sneel 631248477Sneel fprintf(stderr, 632270159Sgrehan "usage: %s [-c <console-device>] [-d <disk-path>] [-e <name=value>]\n" 633270159Sgrehan " %*s [-h <host-path>] [-m mem-size] <vmname>\n", 634259301Sgrehan progname, 635259301Sgrehan (int)strlen(progname), ""); 636223828Sneel exit(1); 637223828Sneel} 638223828Sneel 639223828Sneelint 640223828Sneelmain(int argc, char** argv) 641223828Sneel{ 642223828Sneel void *h; 643242882Sneel void (*func)(struct loader_callbacks *, void *, int, int); 644248477Sneel uint64_t mem_size; 645270071Sgrehan int opt, error, need_reinit; 646223828Sneel 647259301Sgrehan progname = basename(argv[0]); 648223828Sneel 649248477Sneel mem_size = 256 * MB; 650223828Sneel 651259301Sgrehan consin_fd = STDIN_FILENO; 652259301Sgrehan consout_fd = STDOUT_FILENO; 653259301Sgrehan 654259301Sgrehan while ((opt = getopt(argc, argv, "c:d:e:h:m:")) != -1) { 655223828Sneel switch (opt) { 656259301Sgrehan case 'c': 657259301Sgrehan error = altcons_open(optarg); 658259301Sgrehan if (error != 0) 659259301Sgrehan errx(EX_USAGE, "Could not open '%s'", optarg); 660259301Sgrehan break; 661268932Sjhb 662223828Sneel case 'd': 663268932Sjhb error = disk_open(optarg); 664268932Sjhb if (error != 0) 665268932Sjhb errx(EX_USAGE, "Could not open '%s'", optarg); 666223828Sneel break; 667223828Sneel 668259301Sgrehan case 'e': 669259301Sgrehan addenv(optarg); 670259301Sgrehan break; 671259301Sgrehan 672223828Sneel case 'h': 673223828Sneel host_base = optarg; 674223828Sneel break; 675223828Sneel 676223828Sneel case 'm': 677256176Sneel error = vm_parse_memsize(optarg, &mem_size); 678256176Sneel if (error != 0) 679256176Sneel errx(EX_USAGE, "Invalid memsize '%s'", optarg); 680223828Sneel break; 681223828Sneel case '?': 682223828Sneel usage(); 683223828Sneel } 684223828Sneel } 685223828Sneel 686223828Sneel argc -= optind; 687223828Sneel argv += optind; 688223828Sneel 689223828Sneel if (argc != 1) 690223828Sneel usage(); 691223828Sneel 692223828Sneel vmname = argv[0]; 693223828Sneel 694270071Sgrehan need_reinit = 0; 695223828Sneel error = vm_create(vmname); 696270071Sgrehan if (error) { 697270071Sgrehan if (errno != EEXIST) { 698270071Sgrehan perror("vm_create"); 699270071Sgrehan exit(1); 700270071Sgrehan } 701270071Sgrehan need_reinit = 1; 702223828Sneel } 703223828Sneel 704223828Sneel ctx = vm_open(vmname); 705223828Sneel if (ctx == NULL) { 706223828Sneel perror("vm_open"); 707223828Sneel exit(1); 708223828Sneel } 709223828Sneel 710270071Sgrehan if (need_reinit) { 711270071Sgrehan error = vm_reinit(ctx); 712270071Sgrehan if (error) { 713270071Sgrehan perror("vm_reinit"); 714270071Sgrehan exit(1); 715270071Sgrehan } 716270071Sgrehan } 717270071Sgrehan 718248477Sneel error = vm_setup_memory(ctx, mem_size, VM_MMAP_ALL); 719223828Sneel if (error) { 720248477Sneel perror("vm_setup_memory"); 721223828Sneel exit(1); 722223828Sneel } 723223828Sneel 724259301Sgrehan tcgetattr(consout_fd, &term); 725223828Sneel oldterm = term; 726259301Sgrehan cfmakeraw(&term); 727259301Sgrehan term.c_cflag |= CLOCAL; 728259301Sgrehan 729259301Sgrehan tcsetattr(consout_fd, TCSAFLUSH, &term); 730259301Sgrehan 731234695Sgrehan h = dlopen("/boot/userboot.so", RTLD_LOCAL); 732223828Sneel if (!h) { 733223828Sneel printf("%s\n", dlerror()); 734223828Sneel return (1); 735223828Sneel } 736223828Sneel func = dlsym(h, "loader_main"); 737223828Sneel if (!func) { 738223828Sneel printf("%s\n", dlerror()); 739223828Sneel return (1); 740223828Sneel } 741223828Sneel 742259301Sgrehan addenv("smbios.bios.vendor=BHYVE"); 743259301Sgrehan addenv("boot_serial=1"); 744259301Sgrehan 745268932Sjhb func(&cb, NULL, USERBOOT_VERSION_3, ndisks); 746223828Sneel} 747