1c487da1eSNeel Natu /*- 2c487da1eSNeel Natu * Copyright (c) 2011 NetApp, Inc. 3c487da1eSNeel Natu * All rights reserved. 4c487da1eSNeel Natu * 5c487da1eSNeel Natu * Redistribution and use in source and binary forms, with or without 6c487da1eSNeel Natu * modification, are permitted provided that the following conditions 7c487da1eSNeel Natu * are met: 8c487da1eSNeel Natu * 1. Redistributions of source code must retain the above copyright 9c487da1eSNeel Natu * notice, this list of conditions and the following disclaimer. 10c487da1eSNeel Natu * 2. Redistributions in binary form must reproduce the above copyright 11c487da1eSNeel Natu * notice, this list of conditions and the following disclaimer in the 12c487da1eSNeel Natu * documentation and/or other materials provided with the distribution. 13c487da1eSNeel Natu * 14c487da1eSNeel Natu * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND 15c487da1eSNeel Natu * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16c487da1eSNeel Natu * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17c487da1eSNeel Natu * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE 18c487da1eSNeel Natu * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19c487da1eSNeel Natu * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20c487da1eSNeel Natu * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21c487da1eSNeel Natu * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22c487da1eSNeel Natu * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23c487da1eSNeel Natu * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24c487da1eSNeel Natu * SUCH DAMAGE. 25c487da1eSNeel Natu * 26c487da1eSNeel Natu * $FreeBSD$ 27c487da1eSNeel Natu */ 28c487da1eSNeel Natu 29c487da1eSNeel Natu /*- 30c487da1eSNeel Natu * Copyright (c) 2011 Google, Inc. 31c487da1eSNeel Natu * All rights reserved. 32c487da1eSNeel Natu * 33c487da1eSNeel Natu * Redistribution and use in source and binary forms, with or without 34c487da1eSNeel Natu * modification, are permitted provided that the following conditions 35c487da1eSNeel Natu * are met: 36c487da1eSNeel Natu * 1. Redistributions of source code must retain the above copyright 37c487da1eSNeel Natu * notice, this list of conditions and the following disclaimer. 38c487da1eSNeel Natu * 2. Redistributions in binary form must reproduce the above copyright 39c487da1eSNeel Natu * notice, this list of conditions and the following disclaimer in the 40c487da1eSNeel Natu * documentation and/or other materials provided with the distribution. 41c487da1eSNeel Natu * 42c487da1eSNeel Natu * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 43c487da1eSNeel Natu * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 44c487da1eSNeel Natu * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 45c487da1eSNeel Natu * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 46c487da1eSNeel Natu * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 47c487da1eSNeel Natu * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 48c487da1eSNeel Natu * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 49c487da1eSNeel Natu * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 50c487da1eSNeel Natu * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 51c487da1eSNeel Natu * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 52c487da1eSNeel Natu * SUCH DAMAGE. 53c487da1eSNeel Natu * 54c487da1eSNeel Natu * $FreeBSD$ 55c487da1eSNeel Natu */ 56c487da1eSNeel Natu 57c487da1eSNeel Natu #include <sys/cdefs.h> 58c487da1eSNeel Natu __FBSDID("$FreeBSD$"); 59c487da1eSNeel Natu 60c487da1eSNeel Natu #include <sys/ioctl.h> 61c487da1eSNeel Natu #include <sys/stat.h> 62a10c6f55SNeel Natu #include <sys/disk.h> 63b6afa84bSNeel Natu #include <sys/queue.h> 64c487da1eSNeel Natu 65c487da1eSNeel Natu #include <machine/specialreg.h> 66c487da1eSNeel Natu #include <machine/vmm.h> 67c487da1eSNeel Natu 68c487da1eSNeel Natu #include <dirent.h> 69c487da1eSNeel Natu #include <dlfcn.h> 70c487da1eSNeel Natu #include <errno.h> 71200758f1SNeel Natu #include <err.h> 72c487da1eSNeel Natu #include <fcntl.h> 73c487da1eSNeel Natu #include <getopt.h> 74b5331f4dSNeel Natu #include <libgen.h> 75c487da1eSNeel Natu #include <limits.h> 76c487da1eSNeel Natu #include <stdio.h> 77c487da1eSNeel Natu #include <stdlib.h> 78c487da1eSNeel Natu #include <string.h> 79200758f1SNeel Natu #include <sysexits.h> 80c487da1eSNeel Natu #include <termios.h> 81c487da1eSNeel Natu #include <unistd.h> 82c487da1eSNeel Natu 83c487da1eSNeel Natu #include <vmmapi.h> 84c487da1eSNeel Natu 85c487da1eSNeel Natu #include "userboot.h" 86c487da1eSNeel Natu 87c487da1eSNeel Natu #define MB (1024 * 1024UL) 88c487da1eSNeel Natu #define GB (1024 * 1024 * 1024UL) 89c487da1eSNeel Natu #define BSP 0 90c487da1eSNeel Natu 91cf087c12SPeter Grehan #define NDISKS 32 92cf087c12SPeter Grehan 93384305ffSPeter Grehan static char *host_base; 94c487da1eSNeel Natu static struct termios term, oldterm; 95cf087c12SPeter Grehan static int disk_fd[NDISKS]; 96cf087c12SPeter Grehan static int ndisks; 976380102cSPeter Grehan static int consin_fd, consout_fd; 98c487da1eSNeel Natu 99b060ba50SNeel Natu static char *vmname, *progname; 100c487da1eSNeel Natu static struct vmctx *ctx; 101c487da1eSNeel Natu 102c487da1eSNeel Natu static uint64_t gdtbase, cr3, rsp; 103c487da1eSNeel Natu 104c487da1eSNeel Natu static void cb_exit(void *arg, int v); 105c487da1eSNeel Natu 106c487da1eSNeel Natu /* 107c487da1eSNeel Natu * Console i/o callbacks 108c487da1eSNeel Natu */ 109c487da1eSNeel Natu 110c487da1eSNeel Natu static void 111c487da1eSNeel Natu cb_putc(void *arg, int ch) 112c487da1eSNeel Natu { 113c487da1eSNeel Natu char c = ch; 114c487da1eSNeel Natu 1156380102cSPeter Grehan (void) write(consout_fd, &c, 1); 116c487da1eSNeel Natu } 117c487da1eSNeel Natu 118c487da1eSNeel Natu static int 119c487da1eSNeel Natu cb_getc(void *arg) 120c487da1eSNeel Natu { 121c487da1eSNeel Natu char c; 122c487da1eSNeel Natu 1236380102cSPeter Grehan if (read(consin_fd, &c, 1) == 1) 124c487da1eSNeel Natu return (c); 125c487da1eSNeel Natu return (-1); 126c487da1eSNeel Natu } 127c487da1eSNeel Natu 128c487da1eSNeel Natu static int 129c487da1eSNeel Natu cb_poll(void *arg) 130c487da1eSNeel Natu { 131c487da1eSNeel Natu int n; 132c487da1eSNeel Natu 1336380102cSPeter Grehan if (ioctl(consin_fd, FIONREAD, &n) >= 0) 134c487da1eSNeel Natu return (n > 0); 135c487da1eSNeel Natu return (0); 136c487da1eSNeel Natu } 137c487da1eSNeel Natu 138c487da1eSNeel Natu /* 139c487da1eSNeel Natu * Host filesystem i/o callbacks 140c487da1eSNeel Natu */ 141c487da1eSNeel Natu 142c487da1eSNeel Natu struct cb_file { 143c487da1eSNeel Natu int cf_isdir; 144c487da1eSNeel Natu size_t cf_size; 145c487da1eSNeel Natu struct stat cf_stat; 146c487da1eSNeel Natu union { 147c487da1eSNeel Natu int fd; 148c487da1eSNeel Natu DIR *dir; 149c487da1eSNeel Natu } cf_u; 150c487da1eSNeel Natu }; 151c487da1eSNeel Natu 152c487da1eSNeel Natu static int 153c487da1eSNeel Natu cb_open(void *arg, const char *filename, void **hp) 154c487da1eSNeel Natu { 155c487da1eSNeel Natu struct cb_file *cf; 156c487da1eSNeel Natu char path[PATH_MAX]; 157c487da1eSNeel Natu 158c487da1eSNeel Natu if (!host_base) 159c487da1eSNeel Natu return (ENOENT); 160c487da1eSNeel Natu 161c487da1eSNeel Natu strlcpy(path, host_base, PATH_MAX); 162c487da1eSNeel Natu if (path[strlen(path) - 1] == '/') 163c487da1eSNeel Natu path[strlen(path) - 1] = 0; 164c487da1eSNeel Natu strlcat(path, filename, PATH_MAX); 165c487da1eSNeel Natu cf = malloc(sizeof(struct cb_file)); 166c487da1eSNeel Natu if (stat(path, &cf->cf_stat) < 0) { 167c487da1eSNeel Natu free(cf); 168c487da1eSNeel Natu return (errno); 169c487da1eSNeel Natu } 170c487da1eSNeel Natu 1718f61276dSPedro F. Giffuni cf->cf_size = cf->cf_stat.st_size; 172c487da1eSNeel Natu if (S_ISDIR(cf->cf_stat.st_mode)) { 173c487da1eSNeel Natu cf->cf_isdir = 1; 174c487da1eSNeel Natu cf->cf_u.dir = opendir(path); 175c487da1eSNeel Natu if (!cf->cf_u.dir) 176c487da1eSNeel Natu goto out; 177c487da1eSNeel Natu *hp = cf; 178c487da1eSNeel Natu return (0); 179c487da1eSNeel Natu } 180c487da1eSNeel Natu if (S_ISREG(cf->cf_stat.st_mode)) { 181c487da1eSNeel Natu cf->cf_isdir = 0; 182c487da1eSNeel Natu cf->cf_u.fd = open(path, O_RDONLY); 183c487da1eSNeel Natu if (cf->cf_u.fd < 0) 184c487da1eSNeel Natu goto out; 185c487da1eSNeel Natu *hp = cf; 186c487da1eSNeel Natu return (0); 187c487da1eSNeel Natu } 188c487da1eSNeel Natu 189c487da1eSNeel Natu out: 190c487da1eSNeel Natu free(cf); 191c487da1eSNeel Natu return (EINVAL); 192c487da1eSNeel Natu } 193c487da1eSNeel Natu 194c487da1eSNeel Natu static int 195c487da1eSNeel Natu cb_close(void *arg, void *h) 196c487da1eSNeel Natu { 197c487da1eSNeel Natu struct cb_file *cf = h; 198c487da1eSNeel Natu 199c487da1eSNeel Natu if (cf->cf_isdir) 200c487da1eSNeel Natu closedir(cf->cf_u.dir); 201c487da1eSNeel Natu else 202c487da1eSNeel Natu close(cf->cf_u.fd); 203c487da1eSNeel Natu free(cf); 204c487da1eSNeel Natu 205c487da1eSNeel Natu return (0); 206c487da1eSNeel Natu } 207c487da1eSNeel Natu 208c487da1eSNeel Natu static int 209c487da1eSNeel Natu cb_isdir(void *arg, void *h) 210c487da1eSNeel Natu { 211c487da1eSNeel Natu struct cb_file *cf = h; 212c487da1eSNeel Natu 213c487da1eSNeel Natu return (cf->cf_isdir); 214c487da1eSNeel Natu } 215c487da1eSNeel Natu 216c487da1eSNeel Natu static int 217c487da1eSNeel Natu cb_read(void *arg, void *h, void *buf, size_t size, size_t *resid) 218c487da1eSNeel Natu { 219c487da1eSNeel Natu struct cb_file *cf = h; 220c487da1eSNeel Natu ssize_t sz; 221c487da1eSNeel Natu 222c487da1eSNeel Natu if (cf->cf_isdir) 223c487da1eSNeel Natu return (EINVAL); 224c487da1eSNeel Natu sz = read(cf->cf_u.fd, buf, size); 225c487da1eSNeel Natu if (sz < 0) 226c487da1eSNeel Natu return (EINVAL); 227c487da1eSNeel Natu *resid = size - sz; 228c487da1eSNeel Natu return (0); 229c487da1eSNeel Natu } 230c487da1eSNeel Natu 231c487da1eSNeel Natu static int 232c487da1eSNeel Natu cb_readdir(void *arg, void *h, uint32_t *fileno_return, uint8_t *type_return, 233c487da1eSNeel Natu size_t *namelen_return, char *name) 234c487da1eSNeel Natu { 235c487da1eSNeel Natu struct cb_file *cf = h; 236c487da1eSNeel Natu struct dirent *dp; 237c487da1eSNeel Natu 238c487da1eSNeel Natu if (!cf->cf_isdir) 239c487da1eSNeel Natu return (EINVAL); 240c487da1eSNeel Natu 241c487da1eSNeel Natu dp = readdir(cf->cf_u.dir); 242c487da1eSNeel Natu if (!dp) 243c487da1eSNeel Natu return (ENOENT); 244c487da1eSNeel Natu 245c487da1eSNeel Natu /* 246c487da1eSNeel Natu * Note: d_namlen is in the range 0..255 and therefore less 247c487da1eSNeel Natu * than PATH_MAX so we don't need to test before copying. 248c487da1eSNeel Natu */ 249c487da1eSNeel Natu *fileno_return = dp->d_fileno; 250c487da1eSNeel Natu *type_return = dp->d_type; 251c487da1eSNeel Natu *namelen_return = dp->d_namlen; 252c487da1eSNeel Natu memcpy(name, dp->d_name, dp->d_namlen); 253c487da1eSNeel Natu name[dp->d_namlen] = 0; 254c487da1eSNeel Natu 255c487da1eSNeel Natu return (0); 256c487da1eSNeel Natu } 257c487da1eSNeel Natu 258c487da1eSNeel Natu static int 259c487da1eSNeel Natu cb_seek(void *arg, void *h, uint64_t offset, int whence) 260c487da1eSNeel Natu { 261c487da1eSNeel Natu struct cb_file *cf = h; 262c487da1eSNeel Natu 263c487da1eSNeel Natu if (cf->cf_isdir) 264c487da1eSNeel Natu return (EINVAL); 265c487da1eSNeel Natu if (lseek(cf->cf_u.fd, offset, whence) < 0) 266c487da1eSNeel Natu return (errno); 267c487da1eSNeel Natu return (0); 268c487da1eSNeel Natu } 269c487da1eSNeel Natu 270c487da1eSNeel Natu static int 271c487da1eSNeel Natu cb_stat(void *arg, void *h, int *mode, int *uid, int *gid, uint64_t *size) 272c487da1eSNeel Natu { 273c487da1eSNeel Natu struct cb_file *cf = h; 274c487da1eSNeel Natu 275c487da1eSNeel Natu *mode = cf->cf_stat.st_mode; 276c487da1eSNeel Natu *uid = cf->cf_stat.st_uid; 277c487da1eSNeel Natu *gid = cf->cf_stat.st_gid; 278c487da1eSNeel Natu *size = cf->cf_stat.st_size; 279c487da1eSNeel Natu return (0); 280c487da1eSNeel Natu } 281c487da1eSNeel Natu 282c487da1eSNeel Natu /* 283c487da1eSNeel Natu * Disk image i/o callbacks 284c487da1eSNeel Natu */ 285c487da1eSNeel Natu 286c487da1eSNeel Natu static int 287c487da1eSNeel Natu cb_diskread(void *arg, int unit, uint64_t from, void *to, size_t size, 288c487da1eSNeel Natu size_t *resid) 289c487da1eSNeel Natu { 290c487da1eSNeel Natu ssize_t n; 291c487da1eSNeel Natu 292cf087c12SPeter Grehan if (unit < 0 || unit >= ndisks ) 293c487da1eSNeel Natu return (EIO); 294cf087c12SPeter Grehan n = pread(disk_fd[unit], to, size, from); 295c487da1eSNeel Natu if (n < 0) 296c487da1eSNeel Natu return (errno); 297c487da1eSNeel Natu *resid = size - n; 298c487da1eSNeel Natu return (0); 299c487da1eSNeel Natu } 300c487da1eSNeel Natu 301a10c6f55SNeel Natu static int 302a10c6f55SNeel Natu cb_diskioctl(void *arg, int unit, u_long cmd, void *data) 303a10c6f55SNeel Natu { 304a10c6f55SNeel Natu struct stat sb; 305a10c6f55SNeel Natu 306cf087c12SPeter Grehan if (unit < 0 || unit >= ndisks) 307a10c6f55SNeel Natu return (EBADF); 308a10c6f55SNeel Natu 309a10c6f55SNeel Natu switch (cmd) { 310a10c6f55SNeel Natu case DIOCGSECTORSIZE: 311a10c6f55SNeel Natu *(u_int *)data = 512; 312a10c6f55SNeel Natu break; 313a10c6f55SNeel Natu case DIOCGMEDIASIZE: 314*6589ee29SAndriy Gapon if (fstat(disk_fd[unit], &sb) != 0) 315a10c6f55SNeel Natu return (ENOTTY); 316*6589ee29SAndriy Gapon if (S_ISCHR(sb.st_mode) && 317*6589ee29SAndriy Gapon ioctl(disk_fd[unit], DIOCGMEDIASIZE, &sb.st_size) != 0) 318*6589ee29SAndriy Gapon return (ENOTTY); 319*6589ee29SAndriy Gapon *(off_t *)data = sb.st_size; 320a10c6f55SNeel Natu break; 321a10c6f55SNeel Natu default: 322a10c6f55SNeel Natu return (ENOTTY); 323a10c6f55SNeel Natu } 324a10c6f55SNeel Natu 325a10c6f55SNeel Natu return (0); 326a10c6f55SNeel Natu } 327a10c6f55SNeel Natu 328c487da1eSNeel Natu /* 329c487da1eSNeel Natu * Guest virtual machine i/o callbacks 330c487da1eSNeel Natu */ 331c487da1eSNeel Natu static int 332c487da1eSNeel Natu cb_copyin(void *arg, const void *from, uint64_t to, size_t size) 333c487da1eSNeel Natu { 334b060ba50SNeel Natu char *ptr; 335c487da1eSNeel Natu 336c487da1eSNeel Natu to &= 0x7fffffff; 337b060ba50SNeel Natu 338b060ba50SNeel Natu ptr = vm_map_gpa(ctx, to, size); 339b060ba50SNeel Natu if (ptr == NULL) 340c487da1eSNeel Natu return (EFAULT); 341c487da1eSNeel Natu 342b060ba50SNeel Natu memcpy(ptr, from, size); 343c487da1eSNeel Natu return (0); 344c487da1eSNeel Natu } 345c487da1eSNeel Natu 346c487da1eSNeel Natu static int 347c487da1eSNeel Natu cb_copyout(void *arg, uint64_t from, void *to, size_t size) 348c487da1eSNeel Natu { 349b060ba50SNeel Natu char *ptr; 350c487da1eSNeel Natu 351c487da1eSNeel Natu from &= 0x7fffffff; 352b060ba50SNeel Natu 353b060ba50SNeel Natu ptr = vm_map_gpa(ctx, from, size); 354b060ba50SNeel Natu if (ptr == NULL) 355c487da1eSNeel Natu return (EFAULT); 356c487da1eSNeel Natu 357b060ba50SNeel Natu memcpy(to, ptr, size); 358c487da1eSNeel Natu return (0); 359c487da1eSNeel Natu } 360c487da1eSNeel Natu 361c487da1eSNeel Natu static void 362c487da1eSNeel Natu cb_setreg(void *arg, int r, uint64_t v) 363c487da1eSNeel Natu { 364c487da1eSNeel Natu int error; 365c487da1eSNeel Natu enum vm_reg_name vmreg; 366c487da1eSNeel Natu 367c487da1eSNeel Natu vmreg = VM_REG_LAST; 368c487da1eSNeel Natu 369c487da1eSNeel Natu switch (r) { 370c487da1eSNeel Natu case 4: 371c487da1eSNeel Natu vmreg = VM_REG_GUEST_RSP; 372c487da1eSNeel Natu rsp = v; 373c487da1eSNeel Natu break; 374c487da1eSNeel Natu default: 375c487da1eSNeel Natu break; 376c487da1eSNeel Natu } 377c487da1eSNeel Natu 378c487da1eSNeel Natu if (vmreg == VM_REG_LAST) { 379c487da1eSNeel Natu printf("test_setreg(%d): not implemented\n", r); 380c487da1eSNeel Natu cb_exit(NULL, USERBOOT_EXIT_QUIT); 381c487da1eSNeel Natu } 382c487da1eSNeel Natu 383c487da1eSNeel Natu error = vm_set_register(ctx, BSP, vmreg, v); 384c487da1eSNeel Natu if (error) { 385c487da1eSNeel Natu perror("vm_set_register"); 386c487da1eSNeel Natu cb_exit(NULL, USERBOOT_EXIT_QUIT); 387c487da1eSNeel Natu } 388c487da1eSNeel Natu } 389c487da1eSNeel Natu 390c487da1eSNeel Natu static void 391c487da1eSNeel Natu cb_setmsr(void *arg, int r, uint64_t v) 392c487da1eSNeel Natu { 393c487da1eSNeel Natu int error; 394c487da1eSNeel Natu enum vm_reg_name vmreg; 395c487da1eSNeel Natu 396c487da1eSNeel Natu vmreg = VM_REG_LAST; 397c487da1eSNeel Natu 398c487da1eSNeel Natu switch (r) { 399c487da1eSNeel Natu case MSR_EFER: 400c487da1eSNeel Natu vmreg = VM_REG_GUEST_EFER; 401c487da1eSNeel Natu break; 402c487da1eSNeel Natu default: 403c487da1eSNeel Natu break; 404c487da1eSNeel Natu } 405c487da1eSNeel Natu 406c487da1eSNeel Natu if (vmreg == VM_REG_LAST) { 407c487da1eSNeel Natu printf("test_setmsr(%d): not implemented\n", r); 408c487da1eSNeel Natu cb_exit(NULL, USERBOOT_EXIT_QUIT); 409c487da1eSNeel Natu } 410c487da1eSNeel Natu 411c487da1eSNeel Natu error = vm_set_register(ctx, BSP, vmreg, v); 412c487da1eSNeel Natu if (error) { 413c487da1eSNeel Natu perror("vm_set_msr"); 414c487da1eSNeel Natu cb_exit(NULL, USERBOOT_EXIT_QUIT); 415c487da1eSNeel Natu } 416c487da1eSNeel Natu } 417c487da1eSNeel Natu 418c487da1eSNeel Natu static void 419c487da1eSNeel Natu cb_setcr(void *arg, int r, uint64_t v) 420c487da1eSNeel Natu { 421c487da1eSNeel Natu int error; 422c487da1eSNeel Natu enum vm_reg_name vmreg; 423c487da1eSNeel Natu 424c487da1eSNeel Natu vmreg = VM_REG_LAST; 425c487da1eSNeel Natu 426c487da1eSNeel Natu switch (r) { 427c487da1eSNeel Natu case 0: 428c487da1eSNeel Natu vmreg = VM_REG_GUEST_CR0; 429c487da1eSNeel Natu break; 430c487da1eSNeel Natu case 3: 431c487da1eSNeel Natu vmreg = VM_REG_GUEST_CR3; 432c487da1eSNeel Natu cr3 = v; 433c487da1eSNeel Natu break; 434c487da1eSNeel Natu case 4: 435c487da1eSNeel Natu vmreg = VM_REG_GUEST_CR4; 436c487da1eSNeel Natu break; 437c487da1eSNeel Natu default: 438c487da1eSNeel Natu break; 439c487da1eSNeel Natu } 440c487da1eSNeel Natu 441c487da1eSNeel Natu if (vmreg == VM_REG_LAST) { 442c487da1eSNeel Natu printf("test_setcr(%d): not implemented\n", r); 443c487da1eSNeel Natu cb_exit(NULL, USERBOOT_EXIT_QUIT); 444c487da1eSNeel Natu } 445c487da1eSNeel Natu 446c487da1eSNeel Natu error = vm_set_register(ctx, BSP, vmreg, v); 447c487da1eSNeel Natu if (error) { 448c487da1eSNeel Natu perror("vm_set_cr"); 449c487da1eSNeel Natu cb_exit(NULL, USERBOOT_EXIT_QUIT); 450c487da1eSNeel Natu } 451c487da1eSNeel Natu } 452c487da1eSNeel Natu 453c487da1eSNeel Natu static void 454c487da1eSNeel Natu cb_setgdt(void *arg, uint64_t base, size_t size) 455c487da1eSNeel Natu { 456c487da1eSNeel Natu int error; 457c487da1eSNeel Natu 458c487da1eSNeel Natu error = vm_set_desc(ctx, BSP, VM_REG_GUEST_GDTR, base, size - 1, 0); 459c487da1eSNeel Natu if (error != 0) { 460c487da1eSNeel Natu perror("vm_set_desc(gdt)"); 461c487da1eSNeel Natu cb_exit(NULL, USERBOOT_EXIT_QUIT); 462c487da1eSNeel Natu } 463c487da1eSNeel Natu 464c487da1eSNeel Natu gdtbase = base; 465c487da1eSNeel Natu } 466c487da1eSNeel Natu 467c487da1eSNeel Natu static void 468c487da1eSNeel Natu cb_exec(void *arg, uint64_t rip) 469c487da1eSNeel Natu { 470c487da1eSNeel Natu int error; 471c487da1eSNeel Natu 47200f3efe1SJohn Baldwin if (cr3 == 0) 47300f3efe1SJohn Baldwin error = vm_setup_freebsd_registers_i386(ctx, BSP, rip, gdtbase, 47400f3efe1SJohn Baldwin rsp); 47500f3efe1SJohn Baldwin else 47600f3efe1SJohn Baldwin error = vm_setup_freebsd_registers(ctx, BSP, rip, cr3, gdtbase, 47700f3efe1SJohn Baldwin rsp); 478c487da1eSNeel Natu if (error) { 479c487da1eSNeel Natu perror("vm_setup_freebsd_registers"); 480c487da1eSNeel Natu cb_exit(NULL, USERBOOT_EXIT_QUIT); 481c487da1eSNeel Natu } 482c487da1eSNeel Natu 483c487da1eSNeel Natu cb_exit(NULL, 0); 484c487da1eSNeel Natu } 485c487da1eSNeel Natu 486c487da1eSNeel Natu /* 487c487da1eSNeel Natu * Misc 488c487da1eSNeel Natu */ 489c487da1eSNeel Natu 490c487da1eSNeel Natu static void 491c487da1eSNeel Natu cb_delay(void *arg, int usec) 492c487da1eSNeel Natu { 493c487da1eSNeel Natu 494c487da1eSNeel Natu usleep(usec); 495c487da1eSNeel Natu } 496c487da1eSNeel Natu 497c487da1eSNeel Natu static void 498c487da1eSNeel Natu cb_exit(void *arg, int v) 499c487da1eSNeel Natu { 500c487da1eSNeel Natu 5016380102cSPeter Grehan tcsetattr(consout_fd, TCSAFLUSH, &oldterm); 502c487da1eSNeel Natu exit(v); 503c487da1eSNeel Natu } 504c487da1eSNeel Natu 505c487da1eSNeel Natu static void 506c487da1eSNeel Natu cb_getmem(void *arg, uint64_t *ret_lowmem, uint64_t *ret_highmem) 507c487da1eSNeel Natu { 508c487da1eSNeel Natu 509be679db4SNeel Natu *ret_lowmem = vm_get_lowmem_size(ctx); 510be679db4SNeel Natu *ret_highmem = vm_get_highmem_size(ctx); 511c487da1eSNeel Natu } 512c487da1eSNeel Natu 513b6afa84bSNeel Natu struct env { 514b6afa84bSNeel Natu const char *str; /* name=value */ 515b6afa84bSNeel Natu SLIST_ENTRY(env) next; 516b6afa84bSNeel Natu }; 517b6afa84bSNeel Natu 518b6afa84bSNeel Natu static SLIST_HEAD(envhead, env) envhead; 519b6afa84bSNeel Natu 520b6afa84bSNeel Natu static void 521b6afa84bSNeel Natu addenv(const char *str) 522b6afa84bSNeel Natu { 523b6afa84bSNeel Natu struct env *env; 524b6afa84bSNeel Natu 525b6afa84bSNeel Natu env = malloc(sizeof(struct env)); 526b6afa84bSNeel Natu env->str = str; 527b6afa84bSNeel Natu SLIST_INSERT_HEAD(&envhead, env, next); 528b6afa84bSNeel Natu } 529b6afa84bSNeel Natu 530c3e9ce33SNeel Natu static const char * 531c3e9ce33SNeel Natu cb_getenv(void *arg, int num) 532c3e9ce33SNeel Natu { 533b6afa84bSNeel Natu int i; 534b6afa84bSNeel Natu struct env *env; 535c3e9ce33SNeel Natu 536b6afa84bSNeel Natu i = 0; 537b6afa84bSNeel Natu SLIST_FOREACH(env, &envhead, next) { 538b6afa84bSNeel Natu if (i == num) 539b6afa84bSNeel Natu return (env->str); 540b6afa84bSNeel Natu i++; 541b6afa84bSNeel Natu } 542c3e9ce33SNeel Natu 543c3e9ce33SNeel Natu return (NULL); 544c3e9ce33SNeel Natu } 545c3e9ce33SNeel Natu 54648f337b8SMarcel Moolenaar static int 54748f337b8SMarcel Moolenaar cb_vm_set_register(void *arg, int vcpu, int reg, uint64_t val) 54848f337b8SMarcel Moolenaar { 54948f337b8SMarcel Moolenaar 55048f337b8SMarcel Moolenaar return (vm_set_register(ctx, vcpu, reg, val)); 55148f337b8SMarcel Moolenaar } 55248f337b8SMarcel Moolenaar 55348f337b8SMarcel Moolenaar static int 55448f337b8SMarcel Moolenaar cb_vm_set_desc(void *arg, int vcpu, int reg, uint64_t base, u_int limit, 55548f337b8SMarcel Moolenaar u_int access) 55648f337b8SMarcel Moolenaar { 55748f337b8SMarcel Moolenaar 55848f337b8SMarcel Moolenaar return (vm_set_desc(ctx, vcpu, reg, base, limit, access)); 55948f337b8SMarcel Moolenaar } 56048f337b8SMarcel Moolenaar 561a10c6f55SNeel Natu static struct loader_callbacks cb = { 562c487da1eSNeel Natu .getc = cb_getc, 563c487da1eSNeel Natu .putc = cb_putc, 564c487da1eSNeel Natu .poll = cb_poll, 565c487da1eSNeel Natu 566c487da1eSNeel Natu .open = cb_open, 567c487da1eSNeel Natu .close = cb_close, 568c487da1eSNeel Natu .isdir = cb_isdir, 569c487da1eSNeel Natu .read = cb_read, 570c487da1eSNeel Natu .readdir = cb_readdir, 571c487da1eSNeel Natu .seek = cb_seek, 572c487da1eSNeel Natu .stat = cb_stat, 573c487da1eSNeel Natu 574c487da1eSNeel Natu .diskread = cb_diskread, 575a10c6f55SNeel Natu .diskioctl = cb_diskioctl, 576c487da1eSNeel Natu 577c487da1eSNeel Natu .copyin = cb_copyin, 578c487da1eSNeel Natu .copyout = cb_copyout, 579c487da1eSNeel Natu .setreg = cb_setreg, 580c487da1eSNeel Natu .setmsr = cb_setmsr, 581c487da1eSNeel Natu .setcr = cb_setcr, 582c487da1eSNeel Natu .setgdt = cb_setgdt, 583c487da1eSNeel Natu .exec = cb_exec, 584c487da1eSNeel Natu 585c487da1eSNeel Natu .delay = cb_delay, 586c487da1eSNeel Natu .exit = cb_exit, 587c487da1eSNeel Natu .getmem = cb_getmem, 588c3e9ce33SNeel Natu 589c3e9ce33SNeel Natu .getenv = cb_getenv, 59048f337b8SMarcel Moolenaar 59148f337b8SMarcel Moolenaar /* Version 4 additions */ 59248f337b8SMarcel Moolenaar .vm_set_register = cb_vm_set_register, 59348f337b8SMarcel Moolenaar .vm_set_desc = cb_vm_set_desc, 594c487da1eSNeel Natu }; 595c487da1eSNeel Natu 5966380102cSPeter Grehan static int 5976380102cSPeter Grehan altcons_open(char *path) 5986380102cSPeter Grehan { 5996380102cSPeter Grehan struct stat sb; 6006380102cSPeter Grehan int err; 6016380102cSPeter Grehan int fd; 6026380102cSPeter Grehan 6036380102cSPeter Grehan /* 6046380102cSPeter Grehan * Allow stdio to be passed in so that the same string 6056380102cSPeter Grehan * can be used for the bhyveload console and bhyve com-port 6066380102cSPeter Grehan * parameters 6076380102cSPeter Grehan */ 6086380102cSPeter Grehan if (!strcmp(path, "stdio")) 6096380102cSPeter Grehan return (0); 6106380102cSPeter Grehan 6116380102cSPeter Grehan err = stat(path, &sb); 6126380102cSPeter Grehan if (err == 0) { 6136380102cSPeter Grehan if (!S_ISCHR(sb.st_mode)) 6146380102cSPeter Grehan err = ENOTSUP; 6156380102cSPeter Grehan else { 6166380102cSPeter Grehan fd = open(path, O_RDWR | O_NONBLOCK); 6176380102cSPeter Grehan if (fd < 0) 6186380102cSPeter Grehan err = errno; 6196380102cSPeter Grehan else 6206380102cSPeter Grehan consin_fd = consout_fd = fd; 6216380102cSPeter Grehan } 6226380102cSPeter Grehan } 6236380102cSPeter Grehan 6246380102cSPeter Grehan return (err); 6256380102cSPeter Grehan } 6266380102cSPeter Grehan 627cf087c12SPeter Grehan static int 628cf087c12SPeter Grehan disk_open(char *path) 629cf087c12SPeter Grehan { 630cf087c12SPeter Grehan int err, fd; 631cf087c12SPeter Grehan 6320db293c1SAllan Jude if (ndisks >= NDISKS) 633cf087c12SPeter Grehan return (ERANGE); 634cf087c12SPeter Grehan 635cf087c12SPeter Grehan err = 0; 636cf087c12SPeter Grehan fd = open(path, O_RDONLY); 637cf087c12SPeter Grehan 638cf087c12SPeter Grehan if (fd > 0) { 639cf087c12SPeter Grehan disk_fd[ndisks] = fd; 640cf087c12SPeter Grehan ndisks++; 641cf087c12SPeter Grehan } else 642cf087c12SPeter Grehan err = errno; 643cf087c12SPeter Grehan 644cf087c12SPeter Grehan return (err); 645cf087c12SPeter Grehan } 646cf087c12SPeter Grehan 647c487da1eSNeel Natu static void 648c487da1eSNeel Natu usage(void) 649c487da1eSNeel Natu { 650c487da1eSNeel Natu 651b060ba50SNeel Natu fprintf(stderr, 6529b1aa8d6SNeel Natu "usage: %s [-S][-c <console-device>] [-d <disk-path>] [-e <name=value>]\n" 6536ee52c65SRoman Bogorodskiy " %*s [-h <host-path>] [-m memsize[K|k|M|m|G|g|T|t]] <vmname>\n", 6546380102cSPeter Grehan progname, 655b5331f4dSNeel Natu (int)strlen(progname), ""); 656c487da1eSNeel Natu exit(1); 657c487da1eSNeel Natu } 658c487da1eSNeel Natu 659c487da1eSNeel Natu int 660c487da1eSNeel Natu main(int argc, char** argv) 661c487da1eSNeel Natu { 6628c96dcc1SMarcel Moolenaar char *loader; 663c487da1eSNeel Natu void *h; 664a10c6f55SNeel Natu void (*func)(struct loader_callbacks *, void *, int, int); 665b060ba50SNeel Natu uint64_t mem_size; 6669b1aa8d6SNeel Natu int opt, error, need_reinit, memflags; 667c487da1eSNeel Natu 668b5331f4dSNeel Natu progname = basename(argv[0]); 669c487da1eSNeel Natu 6708c96dcc1SMarcel Moolenaar loader = NULL; 6718c96dcc1SMarcel Moolenaar 6729b1aa8d6SNeel Natu memflags = 0; 673b060ba50SNeel Natu mem_size = 256 * MB; 674c487da1eSNeel Natu 6756380102cSPeter Grehan consin_fd = STDIN_FILENO; 6766380102cSPeter Grehan consout_fd = STDOUT_FILENO; 6776380102cSPeter Grehan 678568e3a8dSMarcel Moolenaar while ((opt = getopt(argc, argv, "CSc:d:e:h:l:m:")) != -1) { 679c487da1eSNeel Natu switch (opt) { 6806380102cSPeter Grehan case 'c': 6816380102cSPeter Grehan error = altcons_open(optarg); 6826380102cSPeter Grehan if (error != 0) 6836380102cSPeter Grehan errx(EX_USAGE, "Could not open '%s'", optarg); 6846380102cSPeter Grehan break; 685cf087c12SPeter Grehan 686c487da1eSNeel Natu case 'd': 687cf087c12SPeter Grehan error = disk_open(optarg); 688cf087c12SPeter Grehan if (error != 0) 689cf087c12SPeter Grehan errx(EX_USAGE, "Could not open '%s'", optarg); 690c487da1eSNeel Natu break; 691c487da1eSNeel Natu 692b6afa84bSNeel Natu case 'e': 693b6afa84bSNeel Natu addenv(optarg); 694b6afa84bSNeel Natu break; 695b6afa84bSNeel Natu 696c487da1eSNeel Natu case 'h': 697c487da1eSNeel Natu host_base = optarg; 698c487da1eSNeel Natu break; 699c487da1eSNeel Natu 7008c96dcc1SMarcel Moolenaar case 'l': 7018c96dcc1SMarcel Moolenaar if (loader != NULL) 7028c96dcc1SMarcel Moolenaar errx(EX_USAGE, "-l can only be given once"); 7038c96dcc1SMarcel Moolenaar loader = strdup(optarg); 7048c96dcc1SMarcel Moolenaar if (loader == NULL) 7058c96dcc1SMarcel Moolenaar err(EX_OSERR, "malloc"); 7068c96dcc1SMarcel Moolenaar break; 7078c96dcc1SMarcel Moolenaar 708c487da1eSNeel Natu case 'm': 709200758f1SNeel Natu error = vm_parse_memsize(optarg, &mem_size); 710200758f1SNeel Natu if (error != 0) 711200758f1SNeel Natu errx(EX_USAGE, "Invalid memsize '%s'", optarg); 712c487da1eSNeel Natu break; 713568e3a8dSMarcel Moolenaar case 'C': 714568e3a8dSMarcel Moolenaar memflags |= VM_MEM_F_INCORE; 715568e3a8dSMarcel Moolenaar break; 7169b1aa8d6SNeel Natu case 'S': 7179b1aa8d6SNeel Natu memflags |= VM_MEM_F_WIRED; 7189b1aa8d6SNeel Natu break; 719c487da1eSNeel Natu case '?': 720c487da1eSNeel Natu usage(); 721c487da1eSNeel Natu } 722c487da1eSNeel Natu } 723c487da1eSNeel Natu 724c487da1eSNeel Natu argc -= optind; 725c487da1eSNeel Natu argv += optind; 726c487da1eSNeel Natu 727c487da1eSNeel Natu if (argc != 1) 728c487da1eSNeel Natu usage(); 729c487da1eSNeel Natu 730c487da1eSNeel Natu vmname = argv[0]; 731c487da1eSNeel Natu 7325fcf252fSNeel Natu need_reinit = 0; 733c487da1eSNeel Natu error = vm_create(vmname); 7345fcf252fSNeel Natu if (error) { 7355fcf252fSNeel Natu if (errno != EEXIST) { 736c487da1eSNeel Natu perror("vm_create"); 737c487da1eSNeel Natu exit(1); 7385fcf252fSNeel Natu } 7395fcf252fSNeel Natu need_reinit = 1; 740c487da1eSNeel Natu } 741c487da1eSNeel Natu 742c487da1eSNeel Natu ctx = vm_open(vmname); 743c487da1eSNeel Natu if (ctx == NULL) { 744c487da1eSNeel Natu perror("vm_open"); 745c487da1eSNeel Natu exit(1); 746c487da1eSNeel Natu } 747c487da1eSNeel Natu 7485fcf252fSNeel Natu if (need_reinit) { 7495fcf252fSNeel Natu error = vm_reinit(ctx); 7505fcf252fSNeel Natu if (error) { 7515fcf252fSNeel Natu perror("vm_reinit"); 7525fcf252fSNeel Natu exit(1); 7535fcf252fSNeel Natu } 7545fcf252fSNeel Natu } 7555fcf252fSNeel Natu 7569b1aa8d6SNeel Natu vm_set_memflags(ctx, memflags); 757b060ba50SNeel Natu error = vm_setup_memory(ctx, mem_size, VM_MMAP_ALL); 758c487da1eSNeel Natu if (error) { 759b060ba50SNeel Natu perror("vm_setup_memory"); 760c487da1eSNeel Natu exit(1); 761c487da1eSNeel Natu } 762c487da1eSNeel Natu 7638c96dcc1SMarcel Moolenaar if (loader == NULL) { 7648c96dcc1SMarcel Moolenaar loader = strdup("/boot/userboot.so"); 7658c96dcc1SMarcel Moolenaar if (loader == NULL) 7668c96dcc1SMarcel Moolenaar err(EX_OSERR, "malloc"); 7678c96dcc1SMarcel Moolenaar } 7688c96dcc1SMarcel Moolenaar h = dlopen(loader, RTLD_LOCAL); 7698c96dcc1SMarcel Moolenaar if (!h) { 7708c96dcc1SMarcel Moolenaar printf("%s\n", dlerror()); 7718c96dcc1SMarcel Moolenaar free(loader); 7728c96dcc1SMarcel Moolenaar return (1); 7738c96dcc1SMarcel Moolenaar } 7748c96dcc1SMarcel Moolenaar func = dlsym(h, "loader_main"); 7758c96dcc1SMarcel Moolenaar if (!func) { 7768c96dcc1SMarcel Moolenaar printf("%s\n", dlerror()); 7778c96dcc1SMarcel Moolenaar free(loader); 7788c96dcc1SMarcel Moolenaar return (1); 7798c96dcc1SMarcel Moolenaar } 7808c96dcc1SMarcel Moolenaar 7816380102cSPeter Grehan tcgetattr(consout_fd, &term); 782c487da1eSNeel Natu oldterm = term; 7836380102cSPeter Grehan cfmakeraw(&term); 7846380102cSPeter Grehan term.c_cflag |= CLOCAL; 7856380102cSPeter Grehan 7866380102cSPeter Grehan tcsetattr(consout_fd, TCSAFLUSH, &term); 7876380102cSPeter Grehan 788b6afa84bSNeel Natu addenv("smbios.bios.vendor=BHYVE"); 789b6afa84bSNeel Natu addenv("boot_serial=1"); 790b6afa84bSNeel Natu 79148f337b8SMarcel Moolenaar func(&cb, NULL, USERBOOT_VERSION_4, ndisks); 7928c96dcc1SMarcel Moolenaar 7938c96dcc1SMarcel Moolenaar free(loader); 7948c96dcc1SMarcel Moolenaar return (0); 795c487da1eSNeel Natu } 796