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: stable/10/usr.sbin/bhyveload/bhyveload.c 323739 2017-09-19 08:19:20Z avg $ 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: stable/10/usr.sbin/bhyveload/bhyveload.c 323739 2017-09-19 08:19:20Z avg $ 55223828Sneel */ 56223828Sneel 57223828Sneel#include <sys/cdefs.h> 58223828Sneel__FBSDID("$FreeBSD: stable/10/usr.sbin/bhyveload/bhyveload.c 323739 2017-09-19 08:19:20Z avg $"); 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: 315323739Savg if (fstat(disk_fd[unit], &sb) != 0) 316242882Sneel return (ENOTTY); 317323739Savg if (S_ISCHR(sb.st_mode) && 318323739Savg ioctl(disk_fd[unit], DIOCGMEDIASIZE, &sb.st_size) != 0) 319323739Savg return (ENOTTY); 320323739Savg *(off_t *)data = sb.st_size; 321242882Sneel break; 322242882Sneel default: 323242882Sneel return (ENOTTY); 324242882Sneel } 325242882Sneel 326242882Sneel return (0); 327242882Sneel} 328242882Sneel 329223828Sneel/* 330223828Sneel * Guest virtual machine i/o callbacks 331223828Sneel */ 332223828Sneelstatic int 333223828Sneelcb_copyin(void *arg, const void *from, uint64_t to, size_t size) 334223828Sneel{ 335248477Sneel char *ptr; 336223828Sneel 337223828Sneel to &= 0x7fffffff; 338248477Sneel 339248477Sneel ptr = vm_map_gpa(ctx, to, size); 340248477Sneel if (ptr == NULL) 341223828Sneel return (EFAULT); 342223828Sneel 343248477Sneel memcpy(ptr, from, size); 344223828Sneel return (0); 345223828Sneel} 346223828Sneel 347223828Sneelstatic int 348223828Sneelcb_copyout(void *arg, uint64_t from, void *to, size_t size) 349223828Sneel{ 350248477Sneel char *ptr; 351223828Sneel 352223828Sneel from &= 0x7fffffff; 353248477Sneel 354248477Sneel ptr = vm_map_gpa(ctx, from, size); 355248477Sneel if (ptr == NULL) 356223828Sneel return (EFAULT); 357223828Sneel 358248477Sneel memcpy(to, ptr, size); 359223828Sneel return (0); 360223828Sneel} 361223828Sneel 362223828Sneelstatic void 363223828Sneelcb_setreg(void *arg, int r, uint64_t v) 364223828Sneel{ 365223828Sneel int error; 366223828Sneel enum vm_reg_name vmreg; 367223828Sneel 368223828Sneel vmreg = VM_REG_LAST; 369223828Sneel 370223828Sneel switch (r) { 371223828Sneel case 4: 372223828Sneel vmreg = VM_REG_GUEST_RSP; 373223828Sneel rsp = v; 374223828Sneel break; 375223828Sneel default: 376223828Sneel break; 377223828Sneel } 378223828Sneel 379223828Sneel if (vmreg == VM_REG_LAST) { 380223828Sneel printf("test_setreg(%d): not implemented\n", r); 381223828Sneel cb_exit(NULL, USERBOOT_EXIT_QUIT); 382223828Sneel } 383223828Sneel 384223828Sneel error = vm_set_register(ctx, BSP, vmreg, v); 385223828Sneel if (error) { 386223828Sneel perror("vm_set_register"); 387223828Sneel cb_exit(NULL, USERBOOT_EXIT_QUIT); 388223828Sneel } 389223828Sneel} 390223828Sneel 391223828Sneelstatic void 392223828Sneelcb_setmsr(void *arg, int r, uint64_t v) 393223828Sneel{ 394223828Sneel int error; 395223828Sneel enum vm_reg_name vmreg; 396223828Sneel 397223828Sneel vmreg = VM_REG_LAST; 398223828Sneel 399223828Sneel switch (r) { 400223828Sneel case MSR_EFER: 401223828Sneel vmreg = VM_REG_GUEST_EFER; 402223828Sneel break; 403223828Sneel default: 404223828Sneel break; 405223828Sneel } 406223828Sneel 407223828Sneel if (vmreg == VM_REG_LAST) { 408223828Sneel printf("test_setmsr(%d): not implemented\n", r); 409223828Sneel cb_exit(NULL, USERBOOT_EXIT_QUIT); 410223828Sneel } 411223828Sneel 412223828Sneel error = vm_set_register(ctx, BSP, vmreg, v); 413223828Sneel if (error) { 414223828Sneel perror("vm_set_msr"); 415223828Sneel cb_exit(NULL, USERBOOT_EXIT_QUIT); 416223828Sneel } 417223828Sneel} 418223828Sneel 419223828Sneelstatic void 420223828Sneelcb_setcr(void *arg, int r, uint64_t v) 421223828Sneel{ 422223828Sneel int error; 423223828Sneel enum vm_reg_name vmreg; 424223828Sneel 425223828Sneel vmreg = VM_REG_LAST; 426223828Sneel 427223828Sneel switch (r) { 428223828Sneel case 0: 429223828Sneel vmreg = VM_REG_GUEST_CR0; 430223828Sneel break; 431223828Sneel case 3: 432223828Sneel vmreg = VM_REG_GUEST_CR3; 433223828Sneel cr3 = v; 434223828Sneel break; 435223828Sneel case 4: 436223828Sneel vmreg = VM_REG_GUEST_CR4; 437223828Sneel break; 438223828Sneel default: 439223828Sneel break; 440223828Sneel } 441223828Sneel 442223828Sneel if (vmreg == VM_REG_LAST) { 443223828Sneel printf("test_setcr(%d): not implemented\n", r); 444223828Sneel cb_exit(NULL, USERBOOT_EXIT_QUIT); 445223828Sneel } 446223828Sneel 447223828Sneel error = vm_set_register(ctx, BSP, vmreg, v); 448223828Sneel if (error) { 449223828Sneel perror("vm_set_cr"); 450223828Sneel cb_exit(NULL, USERBOOT_EXIT_QUIT); 451223828Sneel } 452223828Sneel} 453223828Sneel 454223828Sneelstatic void 455223828Sneelcb_setgdt(void *arg, uint64_t base, size_t size) 456223828Sneel{ 457223828Sneel int error; 458223828Sneel 459223828Sneel error = vm_set_desc(ctx, BSP, VM_REG_GUEST_GDTR, base, size - 1, 0); 460223828Sneel if (error != 0) { 461223828Sneel perror("vm_set_desc(gdt)"); 462223828Sneel cb_exit(NULL, USERBOOT_EXIT_QUIT); 463223828Sneel } 464223828Sneel 465223828Sneel gdtbase = base; 466223828Sneel} 467223828Sneel 468223828Sneelstatic void 469223828Sneelcb_exec(void *arg, uint64_t rip) 470223828Sneel{ 471223828Sneel int error; 472223828Sneel 473267399Sjhb if (cr3 == 0) 474267399Sjhb error = vm_setup_freebsd_registers_i386(ctx, BSP, rip, gdtbase, 475267399Sjhb rsp); 476267399Sjhb else 477267399Sjhb error = vm_setup_freebsd_registers(ctx, BSP, rip, cr3, gdtbase, 478267399Sjhb rsp); 479223828Sneel if (error) { 480223828Sneel perror("vm_setup_freebsd_registers"); 481223828Sneel cb_exit(NULL, USERBOOT_EXIT_QUIT); 482223828Sneel } 483223828Sneel 484223828Sneel cb_exit(NULL, 0); 485223828Sneel} 486223828Sneel 487223828Sneel/* 488223828Sneel * Misc 489223828Sneel */ 490223828Sneel 491223828Sneelstatic void 492223828Sneelcb_delay(void *arg, int usec) 493223828Sneel{ 494223828Sneel 495223828Sneel usleep(usec); 496223828Sneel} 497223828Sneel 498223828Sneelstatic void 499223828Sneelcb_exit(void *arg, int v) 500223828Sneel{ 501223828Sneel 502259301Sgrehan tcsetattr(consout_fd, TCSAFLUSH, &oldterm); 503223828Sneel exit(v); 504223828Sneel} 505223828Sneel 506223828Sneelstatic void 507223828Sneelcb_getmem(void *arg, uint64_t *ret_lowmem, uint64_t *ret_highmem) 508223828Sneel{ 509223828Sneel 510270074Sgrehan *ret_lowmem = vm_get_lowmem_size(ctx); 511270074Sgrehan *ret_highmem = vm_get_highmem_size(ctx); 512223828Sneel} 513223828Sneel 514259301Sgrehanstruct env { 515259301Sgrehan const char *str; /* name=value */ 516259301Sgrehan SLIST_ENTRY(env) next; 517259301Sgrehan}; 518259301Sgrehan 519259301Sgrehanstatic SLIST_HEAD(envhead, env) envhead; 520259301Sgrehan 521259301Sgrehanstatic void 522259301Sgrehanaddenv(const char *str) 523259301Sgrehan{ 524259301Sgrehan struct env *env; 525259301Sgrehan 526259301Sgrehan env = malloc(sizeof(struct env)); 527259301Sgrehan env->str = str; 528259301Sgrehan SLIST_INSERT_HEAD(&envhead, env, next); 529259301Sgrehan} 530259301Sgrehan 531242676Sneelstatic const char * 532242676Sneelcb_getenv(void *arg, int num) 533242676Sneel{ 534259301Sgrehan int i; 535259301Sgrehan struct env *env; 536242676Sneel 537259301Sgrehan i = 0; 538259301Sgrehan SLIST_FOREACH(env, &envhead, next) { 539259301Sgrehan if (i == num) 540259301Sgrehan return (env->str); 541259301Sgrehan i++; 542259301Sgrehan } 543242676Sneel 544259301Sgrehan return (NULL); 545242676Sneel} 546242676Sneel 547242882Sneelstatic struct loader_callbacks cb = { 548223828Sneel .getc = cb_getc, 549223828Sneel .putc = cb_putc, 550223828Sneel .poll = cb_poll, 551223828Sneel 552223828Sneel .open = cb_open, 553223828Sneel .close = cb_close, 554223828Sneel .isdir = cb_isdir, 555223828Sneel .read = cb_read, 556223828Sneel .readdir = cb_readdir, 557223828Sneel .seek = cb_seek, 558223828Sneel .stat = cb_stat, 559223828Sneel 560223828Sneel .diskread = cb_diskread, 561242882Sneel .diskioctl = cb_diskioctl, 562223828Sneel 563223828Sneel .copyin = cb_copyin, 564223828Sneel .copyout = cb_copyout, 565223828Sneel .setreg = cb_setreg, 566223828Sneel .setmsr = cb_setmsr, 567223828Sneel .setcr = cb_setcr, 568223828Sneel .setgdt = cb_setgdt, 569223828Sneel .exec = cb_exec, 570223828Sneel 571223828Sneel .delay = cb_delay, 572223828Sneel .exit = cb_exit, 573223828Sneel .getmem = cb_getmem, 574242676Sneel 575242676Sneel .getenv = cb_getenv, 576223828Sneel}; 577223828Sneel 578259301Sgrehanstatic int 579259301Sgrehanaltcons_open(char *path) 580259301Sgrehan{ 581259301Sgrehan struct stat sb; 582259301Sgrehan int err; 583259301Sgrehan int fd; 584259301Sgrehan 585259301Sgrehan /* 586259301Sgrehan * Allow stdio to be passed in so that the same string 587259301Sgrehan * can be used for the bhyveload console and bhyve com-port 588259301Sgrehan * parameters 589259301Sgrehan */ 590259301Sgrehan if (!strcmp(path, "stdio")) 591259301Sgrehan return (0); 592259301Sgrehan 593259301Sgrehan err = stat(path, &sb); 594259301Sgrehan if (err == 0) { 595259301Sgrehan if (!S_ISCHR(sb.st_mode)) 596259301Sgrehan err = ENOTSUP; 597259301Sgrehan else { 598259301Sgrehan fd = open(path, O_RDWR | O_NONBLOCK); 599259301Sgrehan if (fd < 0) 600259301Sgrehan err = errno; 601259301Sgrehan else 602259301Sgrehan consin_fd = consout_fd = fd; 603259301Sgrehan } 604259301Sgrehan } 605259301Sgrehan 606259301Sgrehan return (err); 607259301Sgrehan} 608259301Sgrehan 609268932Sjhbstatic int 610268932Sjhbdisk_open(char *path) 611268932Sjhb{ 612268932Sjhb int err, fd; 613268932Sjhb 614284900Sneel if (ndisks >= NDISKS) 615268932Sjhb return (ERANGE); 616268932Sjhb 617268932Sjhb err = 0; 618268932Sjhb fd = open(path, O_RDONLY); 619268932Sjhb 620268932Sjhb if (fd > 0) { 621268932Sjhb disk_fd[ndisks] = fd; 622268932Sjhb ndisks++; 623268932Sjhb } else 624268932Sjhb err = errno; 625268932Sjhb 626268932Sjhb return (err); 627268932Sjhb} 628268932Sjhb 629223828Sneelstatic void 630223828Sneelusage(void) 631223828Sneel{ 632223828Sneel 633248477Sneel fprintf(stderr, 634295124Sgrehan "usage: %s [-S][-c <console-device>] [-d <disk-path>] [-e <name=value>]\n" 635270159Sgrehan " %*s [-h <host-path>] [-m mem-size] <vmname>\n", 636259301Sgrehan progname, 637259301Sgrehan (int)strlen(progname), ""); 638223828Sneel exit(1); 639223828Sneel} 640223828Sneel 641223828Sneelint 642223828Sneelmain(int argc, char** argv) 643223828Sneel{ 644295124Sgrehan char *loader; 645223828Sneel void *h; 646242882Sneel void (*func)(struct loader_callbacks *, void *, int, int); 647248477Sneel uint64_t mem_size; 648295124Sgrehan int opt, error, need_reinit, memflags; 649223828Sneel 650259301Sgrehan progname = basename(argv[0]); 651223828Sneel 652295124Sgrehan loader = NULL; 653295124Sgrehan 654295124Sgrehan memflags = 0; 655248477Sneel mem_size = 256 * MB; 656223828Sneel 657259301Sgrehan consin_fd = STDIN_FILENO; 658259301Sgrehan consout_fd = STDOUT_FILENO; 659259301Sgrehan 660295124Sgrehan while ((opt = getopt(argc, argv, "Sc:d:e:h:l:m:")) != -1) { 661223828Sneel switch (opt) { 662259301Sgrehan case 'c': 663259301Sgrehan error = altcons_open(optarg); 664259301Sgrehan if (error != 0) 665259301Sgrehan errx(EX_USAGE, "Could not open '%s'", optarg); 666259301Sgrehan break; 667268932Sjhb 668223828Sneel case 'd': 669268932Sjhb error = disk_open(optarg); 670268932Sjhb if (error != 0) 671268932Sjhb errx(EX_USAGE, "Could not open '%s'", optarg); 672223828Sneel break; 673223828Sneel 674259301Sgrehan case 'e': 675259301Sgrehan addenv(optarg); 676259301Sgrehan break; 677259301Sgrehan 678223828Sneel case 'h': 679223828Sneel host_base = optarg; 680223828Sneel break; 681223828Sneel 682295124Sgrehan case 'l': 683295124Sgrehan if (loader != NULL) 684295124Sgrehan errx(EX_USAGE, "-l can only be given once"); 685295124Sgrehan loader = strdup(optarg); 686295124Sgrehan if (loader == NULL) 687295124Sgrehan err(EX_OSERR, "malloc"); 688295124Sgrehan break; 689295124Sgrehan 690223828Sneel case 'm': 691256176Sneel error = vm_parse_memsize(optarg, &mem_size); 692256176Sneel if (error != 0) 693256176Sneel errx(EX_USAGE, "Invalid memsize '%s'", optarg); 694223828Sneel break; 695295124Sgrehan case 'S': 696295124Sgrehan memflags |= VM_MEM_F_WIRED; 697295124Sgrehan break; 698223828Sneel case '?': 699223828Sneel usage(); 700223828Sneel } 701223828Sneel } 702223828Sneel 703223828Sneel argc -= optind; 704223828Sneel argv += optind; 705223828Sneel 706223828Sneel if (argc != 1) 707223828Sneel usage(); 708223828Sneel 709223828Sneel vmname = argv[0]; 710223828Sneel 711270071Sgrehan need_reinit = 0; 712223828Sneel error = vm_create(vmname); 713270071Sgrehan if (error) { 714270071Sgrehan if (errno != EEXIST) { 715270071Sgrehan perror("vm_create"); 716270071Sgrehan exit(1); 717270071Sgrehan } 718270071Sgrehan need_reinit = 1; 719223828Sneel } 720223828Sneel 721223828Sneel ctx = vm_open(vmname); 722223828Sneel if (ctx == NULL) { 723223828Sneel perror("vm_open"); 724223828Sneel exit(1); 725223828Sneel } 726223828Sneel 727270071Sgrehan if (need_reinit) { 728270071Sgrehan error = vm_reinit(ctx); 729270071Sgrehan if (error) { 730270071Sgrehan perror("vm_reinit"); 731270071Sgrehan exit(1); 732270071Sgrehan } 733270071Sgrehan } 734270071Sgrehan 735295124Sgrehan vm_set_memflags(ctx, memflags); 736248477Sneel error = vm_setup_memory(ctx, mem_size, VM_MMAP_ALL); 737223828Sneel if (error) { 738248477Sneel perror("vm_setup_memory"); 739223828Sneel exit(1); 740223828Sneel } 741223828Sneel 742295124Sgrehan if (loader == NULL) { 743295124Sgrehan loader = strdup("/boot/userboot.so"); 744295124Sgrehan if (loader == NULL) 745295124Sgrehan err(EX_OSERR, "malloc"); 746295124Sgrehan } 747295124Sgrehan h = dlopen(loader, RTLD_LOCAL); 748223828Sneel if (!h) { 749223828Sneel printf("%s\n", dlerror()); 750295124Sgrehan free(loader); 751223828Sneel return (1); 752223828Sneel } 753223828Sneel func = dlsym(h, "loader_main"); 754223828Sneel if (!func) { 755223828Sneel printf("%s\n", dlerror()); 756295124Sgrehan free(loader); 757223828Sneel return (1); 758223828Sneel } 759223828Sneel 760295124Sgrehan tcgetattr(consout_fd, &term); 761295124Sgrehan oldterm = term; 762295124Sgrehan cfmakeraw(&term); 763295124Sgrehan term.c_cflag |= CLOCAL; 764295124Sgrehan 765295124Sgrehan tcsetattr(consout_fd, TCSAFLUSH, &term); 766295124Sgrehan 767259301Sgrehan addenv("smbios.bios.vendor=BHYVE"); 768259301Sgrehan addenv("boot_serial=1"); 769259301Sgrehan 770268932Sjhb func(&cb, NULL, USERBOOT_VERSION_3, ndisks); 771295124Sgrehan 772295124Sgrehan free(loader); 773295124Sgrehan return (0); 774223828Sneel} 775