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> 62*a10c6f55SNeel Natu #include <sys/disk.h> 63c487da1eSNeel Natu 64c487da1eSNeel Natu #include <machine/specialreg.h> 65c487da1eSNeel Natu #include <machine/vmm.h> 66c487da1eSNeel Natu 67c487da1eSNeel Natu #include <dirent.h> 68c487da1eSNeel Natu #include <dlfcn.h> 69c487da1eSNeel Natu #include <errno.h> 70c487da1eSNeel Natu #include <fcntl.h> 71c487da1eSNeel Natu #include <getopt.h> 72c487da1eSNeel Natu #include <limits.h> 73c487da1eSNeel Natu #include <stdio.h> 74c487da1eSNeel Natu #include <stdlib.h> 75c487da1eSNeel Natu #include <string.h> 76c487da1eSNeel Natu #include <termios.h> 77c487da1eSNeel Natu #include <unistd.h> 78c487da1eSNeel Natu 79c487da1eSNeel Natu #include <vmmapi.h> 80c487da1eSNeel Natu 81c487da1eSNeel Natu #include "userboot.h" 82c487da1eSNeel Natu 83c487da1eSNeel Natu #define MB (1024 * 1024UL) 84c487da1eSNeel Natu #define GB (1024 * 1024 * 1024UL) 85c487da1eSNeel Natu #define BSP 0 86c487da1eSNeel Natu 87c487da1eSNeel Natu static char *host_base = "/"; 88c487da1eSNeel Natu static struct termios term, oldterm; 89c487da1eSNeel Natu static int disk_fd = -1; 90c487da1eSNeel Natu 91c487da1eSNeel Natu static char *vmname, *progname, *membase; 92c487da1eSNeel Natu static uint64_t lowmem, highmem; 93c487da1eSNeel Natu static struct vmctx *ctx; 94c487da1eSNeel Natu 95c487da1eSNeel Natu static uint64_t gdtbase, cr3, rsp; 96c487da1eSNeel Natu 97c487da1eSNeel Natu static void cb_exit(void *arg, int v); 98c487da1eSNeel Natu 99c487da1eSNeel Natu /* 100c487da1eSNeel Natu * Console i/o callbacks 101c487da1eSNeel Natu */ 102c487da1eSNeel Natu 103c487da1eSNeel Natu static void 104c487da1eSNeel Natu cb_putc(void *arg, int ch) 105c487da1eSNeel Natu { 106c487da1eSNeel Natu char c = ch; 107c487da1eSNeel Natu 108c487da1eSNeel Natu write(1, &c, 1); 109c487da1eSNeel Natu } 110c487da1eSNeel Natu 111c487da1eSNeel Natu static int 112c487da1eSNeel Natu cb_getc(void *arg) 113c487da1eSNeel Natu { 114c487da1eSNeel Natu char c; 115c487da1eSNeel Natu 116c487da1eSNeel Natu if (read(0, &c, 1) == 1) 117c487da1eSNeel Natu return (c); 118c487da1eSNeel Natu return (-1); 119c487da1eSNeel Natu } 120c487da1eSNeel Natu 121c487da1eSNeel Natu static int 122c487da1eSNeel Natu cb_poll(void *arg) 123c487da1eSNeel Natu { 124c487da1eSNeel Natu int n; 125c487da1eSNeel Natu 126c487da1eSNeel Natu if (ioctl(0, FIONREAD, &n) >= 0) 127c487da1eSNeel Natu return (n > 0); 128c487da1eSNeel Natu return (0); 129c487da1eSNeel Natu } 130c487da1eSNeel Natu 131c487da1eSNeel Natu /* 132c487da1eSNeel Natu * Host filesystem i/o callbacks 133c487da1eSNeel Natu */ 134c487da1eSNeel Natu 135c487da1eSNeel Natu struct cb_file { 136c487da1eSNeel Natu int cf_isdir; 137c487da1eSNeel Natu size_t cf_size; 138c487da1eSNeel Natu struct stat cf_stat; 139c487da1eSNeel Natu union { 140c487da1eSNeel Natu int fd; 141c487da1eSNeel Natu DIR *dir; 142c487da1eSNeel Natu } cf_u; 143c487da1eSNeel Natu }; 144c487da1eSNeel Natu 145c487da1eSNeel Natu static int 146c487da1eSNeel Natu cb_open(void *arg, const char *filename, void **hp) 147c487da1eSNeel Natu { 148c487da1eSNeel Natu struct stat st; 149c487da1eSNeel Natu struct cb_file *cf; 150c487da1eSNeel Natu char path[PATH_MAX]; 151c487da1eSNeel Natu 152c487da1eSNeel Natu if (!host_base) 153c487da1eSNeel Natu return (ENOENT); 154c487da1eSNeel Natu 155c487da1eSNeel Natu strlcpy(path, host_base, PATH_MAX); 156c487da1eSNeel Natu if (path[strlen(path) - 1] == '/') 157c487da1eSNeel Natu path[strlen(path) - 1] = 0; 158c487da1eSNeel Natu strlcat(path, filename, PATH_MAX); 159c487da1eSNeel Natu cf = malloc(sizeof(struct cb_file)); 160c487da1eSNeel Natu if (stat(path, &cf->cf_stat) < 0) { 161c487da1eSNeel Natu free(cf); 162c487da1eSNeel Natu return (errno); 163c487da1eSNeel Natu } 164c487da1eSNeel Natu 165c487da1eSNeel Natu cf->cf_size = st.st_size; 166c487da1eSNeel Natu if (S_ISDIR(cf->cf_stat.st_mode)) { 167c487da1eSNeel Natu cf->cf_isdir = 1; 168c487da1eSNeel Natu cf->cf_u.dir = opendir(path); 169c487da1eSNeel Natu if (!cf->cf_u.dir) 170c487da1eSNeel Natu goto out; 171c487da1eSNeel Natu *hp = cf; 172c487da1eSNeel Natu return (0); 173c487da1eSNeel Natu } 174c487da1eSNeel Natu if (S_ISREG(cf->cf_stat.st_mode)) { 175c487da1eSNeel Natu cf->cf_isdir = 0; 176c487da1eSNeel Natu cf->cf_u.fd = open(path, O_RDONLY); 177c487da1eSNeel Natu if (cf->cf_u.fd < 0) 178c487da1eSNeel Natu goto out; 179c487da1eSNeel Natu *hp = cf; 180c487da1eSNeel Natu return (0); 181c487da1eSNeel Natu } 182c487da1eSNeel Natu 183c487da1eSNeel Natu out: 184c487da1eSNeel Natu free(cf); 185c487da1eSNeel Natu return (EINVAL); 186c487da1eSNeel Natu } 187c487da1eSNeel Natu 188c487da1eSNeel Natu static int 189c487da1eSNeel Natu cb_close(void *arg, void *h) 190c487da1eSNeel Natu { 191c487da1eSNeel Natu struct cb_file *cf = h; 192c487da1eSNeel Natu 193c487da1eSNeel Natu if (cf->cf_isdir) 194c487da1eSNeel Natu closedir(cf->cf_u.dir); 195c487da1eSNeel Natu else 196c487da1eSNeel Natu close(cf->cf_u.fd); 197c487da1eSNeel Natu free(cf); 198c487da1eSNeel Natu 199c487da1eSNeel Natu return (0); 200c487da1eSNeel Natu } 201c487da1eSNeel Natu 202c487da1eSNeel Natu static int 203c487da1eSNeel Natu cb_isdir(void *arg, void *h) 204c487da1eSNeel Natu { 205c487da1eSNeel Natu struct cb_file *cf = h; 206c487da1eSNeel Natu 207c487da1eSNeel Natu return (cf->cf_isdir); 208c487da1eSNeel Natu } 209c487da1eSNeel Natu 210c487da1eSNeel Natu static int 211c487da1eSNeel Natu cb_read(void *arg, void *h, void *buf, size_t size, size_t *resid) 212c487da1eSNeel Natu { 213c487da1eSNeel Natu struct cb_file *cf = h; 214c487da1eSNeel Natu ssize_t sz; 215c487da1eSNeel Natu 216c487da1eSNeel Natu if (cf->cf_isdir) 217c487da1eSNeel Natu return (EINVAL); 218c487da1eSNeel Natu sz = read(cf->cf_u.fd, buf, size); 219c487da1eSNeel Natu if (sz < 0) 220c487da1eSNeel Natu return (EINVAL); 221c487da1eSNeel Natu *resid = size - sz; 222c487da1eSNeel Natu return (0); 223c487da1eSNeel Natu } 224c487da1eSNeel Natu 225c487da1eSNeel Natu static int 226c487da1eSNeel Natu cb_readdir(void *arg, void *h, uint32_t *fileno_return, uint8_t *type_return, 227c487da1eSNeel Natu size_t *namelen_return, char *name) 228c487da1eSNeel Natu { 229c487da1eSNeel Natu struct cb_file *cf = h; 230c487da1eSNeel Natu struct dirent *dp; 231c487da1eSNeel Natu 232c487da1eSNeel Natu if (!cf->cf_isdir) 233c487da1eSNeel Natu return (EINVAL); 234c487da1eSNeel Natu 235c487da1eSNeel Natu dp = readdir(cf->cf_u.dir); 236c487da1eSNeel Natu if (!dp) 237c487da1eSNeel Natu return (ENOENT); 238c487da1eSNeel Natu 239c487da1eSNeel Natu /* 240c487da1eSNeel Natu * Note: d_namlen is in the range 0..255 and therefore less 241c487da1eSNeel Natu * than PATH_MAX so we don't need to test before copying. 242c487da1eSNeel Natu */ 243c487da1eSNeel Natu *fileno_return = dp->d_fileno; 244c487da1eSNeel Natu *type_return = dp->d_type; 245c487da1eSNeel Natu *namelen_return = dp->d_namlen; 246c487da1eSNeel Natu memcpy(name, dp->d_name, dp->d_namlen); 247c487da1eSNeel Natu name[dp->d_namlen] = 0; 248c487da1eSNeel Natu 249c487da1eSNeel Natu return (0); 250c487da1eSNeel Natu } 251c487da1eSNeel Natu 252c487da1eSNeel Natu static int 253c487da1eSNeel Natu cb_seek(void *arg, void *h, uint64_t offset, int whence) 254c487da1eSNeel Natu { 255c487da1eSNeel Natu struct cb_file *cf = h; 256c487da1eSNeel Natu 257c487da1eSNeel Natu if (cf->cf_isdir) 258c487da1eSNeel Natu return (EINVAL); 259c487da1eSNeel Natu if (lseek(cf->cf_u.fd, offset, whence) < 0) 260c487da1eSNeel Natu return (errno); 261c487da1eSNeel Natu return (0); 262c487da1eSNeel Natu } 263c487da1eSNeel Natu 264c487da1eSNeel Natu static int 265c487da1eSNeel Natu cb_stat(void *arg, void *h, int *mode, int *uid, int *gid, uint64_t *size) 266c487da1eSNeel Natu { 267c487da1eSNeel Natu struct cb_file *cf = h; 268c487da1eSNeel Natu 269c487da1eSNeel Natu *mode = cf->cf_stat.st_mode; 270c487da1eSNeel Natu *uid = cf->cf_stat.st_uid; 271c487da1eSNeel Natu *gid = cf->cf_stat.st_gid; 272c487da1eSNeel Natu *size = cf->cf_stat.st_size; 273c487da1eSNeel Natu return (0); 274c487da1eSNeel Natu } 275c487da1eSNeel Natu 276c487da1eSNeel Natu /* 277c487da1eSNeel Natu * Disk image i/o callbacks 278c487da1eSNeel Natu */ 279c487da1eSNeel Natu 280c487da1eSNeel Natu static int 281c487da1eSNeel Natu cb_diskread(void *arg, int unit, uint64_t from, void *to, size_t size, 282c487da1eSNeel Natu size_t *resid) 283c487da1eSNeel Natu { 284c487da1eSNeel Natu ssize_t n; 285c487da1eSNeel Natu 286c487da1eSNeel Natu if (unit != 0 || disk_fd == -1) 287c487da1eSNeel Natu return (EIO); 288c487da1eSNeel Natu n = pread(disk_fd, to, size, from); 289c487da1eSNeel Natu if (n < 0) 290c487da1eSNeel Natu return (errno); 291c487da1eSNeel Natu *resid = size - n; 292c487da1eSNeel Natu return (0); 293c487da1eSNeel Natu } 294c487da1eSNeel Natu 295*a10c6f55SNeel Natu static int 296*a10c6f55SNeel Natu cb_diskioctl(void *arg, int unit, u_long cmd, void *data) 297*a10c6f55SNeel Natu { 298*a10c6f55SNeel Natu struct stat sb; 299*a10c6f55SNeel Natu 300*a10c6f55SNeel Natu if (unit != 0 || disk_fd == -1) 301*a10c6f55SNeel Natu return (EBADF); 302*a10c6f55SNeel Natu 303*a10c6f55SNeel Natu switch (cmd) { 304*a10c6f55SNeel Natu case DIOCGSECTORSIZE: 305*a10c6f55SNeel Natu *(u_int *)data = 512; 306*a10c6f55SNeel Natu break; 307*a10c6f55SNeel Natu case DIOCGMEDIASIZE: 308*a10c6f55SNeel Natu if (fstat(disk_fd, &sb) == 0) 309*a10c6f55SNeel Natu *(off_t *)data = sb.st_size; 310*a10c6f55SNeel Natu else 311*a10c6f55SNeel Natu return (ENOTTY); 312*a10c6f55SNeel Natu break; 313*a10c6f55SNeel Natu default: 314*a10c6f55SNeel Natu return (ENOTTY); 315*a10c6f55SNeel Natu } 316*a10c6f55SNeel Natu 317*a10c6f55SNeel Natu return (0); 318*a10c6f55SNeel Natu } 319*a10c6f55SNeel Natu 320c487da1eSNeel Natu /* 321c487da1eSNeel Natu * Guest virtual machine i/o callbacks 322c487da1eSNeel Natu */ 323c487da1eSNeel Natu static int 324c487da1eSNeel Natu cb_copyin(void *arg, const void *from, uint64_t to, size_t size) 325c487da1eSNeel Natu { 326c487da1eSNeel Natu 327c487da1eSNeel Natu to &= 0x7fffffff; 328c487da1eSNeel Natu if (to > lowmem) 329c487da1eSNeel Natu return (EFAULT); 330c487da1eSNeel Natu if (to + size > lowmem) 331c487da1eSNeel Natu size = lowmem - to; 332c487da1eSNeel Natu 333c487da1eSNeel Natu memcpy(&membase[to], from, size); 334c487da1eSNeel Natu 335c487da1eSNeel Natu return (0); 336c487da1eSNeel Natu } 337c487da1eSNeel Natu 338c487da1eSNeel Natu static int 339c487da1eSNeel Natu cb_copyout(void *arg, uint64_t from, void *to, size_t size) 340c487da1eSNeel Natu { 341c487da1eSNeel Natu 342c487da1eSNeel Natu from &= 0x7fffffff; 343c487da1eSNeel Natu if (from > lowmem) 344c487da1eSNeel Natu return (EFAULT); 345c487da1eSNeel Natu if (from + size > lowmem) 346c487da1eSNeel Natu size = lowmem - from; 347c487da1eSNeel Natu 348c487da1eSNeel Natu memcpy(to, &membase[from], size); 349c487da1eSNeel Natu 350c487da1eSNeel Natu return (0); 351c487da1eSNeel Natu } 352c487da1eSNeel Natu 353c487da1eSNeel Natu static void 354c487da1eSNeel Natu cb_setreg(void *arg, int r, uint64_t v) 355c487da1eSNeel Natu { 356c487da1eSNeel Natu int error; 357c487da1eSNeel Natu enum vm_reg_name vmreg; 358c487da1eSNeel Natu 359c487da1eSNeel Natu vmreg = VM_REG_LAST; 360c487da1eSNeel Natu 361c487da1eSNeel Natu switch (r) { 362c487da1eSNeel Natu case 4: 363c487da1eSNeel Natu vmreg = VM_REG_GUEST_RSP; 364c487da1eSNeel Natu rsp = v; 365c487da1eSNeel Natu break; 366c487da1eSNeel Natu default: 367c487da1eSNeel Natu break; 368c487da1eSNeel Natu } 369c487da1eSNeel Natu 370c487da1eSNeel Natu if (vmreg == VM_REG_LAST) { 371c487da1eSNeel Natu printf("test_setreg(%d): not implemented\n", r); 372c487da1eSNeel Natu cb_exit(NULL, USERBOOT_EXIT_QUIT); 373c487da1eSNeel Natu } 374c487da1eSNeel Natu 375c487da1eSNeel Natu error = vm_set_register(ctx, BSP, vmreg, v); 376c487da1eSNeel Natu if (error) { 377c487da1eSNeel Natu perror("vm_set_register"); 378c487da1eSNeel Natu cb_exit(NULL, USERBOOT_EXIT_QUIT); 379c487da1eSNeel Natu } 380c487da1eSNeel Natu } 381c487da1eSNeel Natu 382c487da1eSNeel Natu static void 383c487da1eSNeel Natu cb_setmsr(void *arg, int r, uint64_t v) 384c487da1eSNeel Natu { 385c487da1eSNeel Natu int error; 386c487da1eSNeel Natu enum vm_reg_name vmreg; 387c487da1eSNeel Natu 388c487da1eSNeel Natu vmreg = VM_REG_LAST; 389c487da1eSNeel Natu 390c487da1eSNeel Natu switch (r) { 391c487da1eSNeel Natu case MSR_EFER: 392c487da1eSNeel Natu vmreg = VM_REG_GUEST_EFER; 393c487da1eSNeel Natu break; 394c487da1eSNeel Natu default: 395c487da1eSNeel Natu break; 396c487da1eSNeel Natu } 397c487da1eSNeel Natu 398c487da1eSNeel Natu if (vmreg == VM_REG_LAST) { 399c487da1eSNeel Natu printf("test_setmsr(%d): not implemented\n", r); 400c487da1eSNeel Natu cb_exit(NULL, USERBOOT_EXIT_QUIT); 401c487da1eSNeel Natu } 402c487da1eSNeel Natu 403c487da1eSNeel Natu error = vm_set_register(ctx, BSP, vmreg, v); 404c487da1eSNeel Natu if (error) { 405c487da1eSNeel Natu perror("vm_set_msr"); 406c487da1eSNeel Natu cb_exit(NULL, USERBOOT_EXIT_QUIT); 407c487da1eSNeel Natu } 408c487da1eSNeel Natu } 409c487da1eSNeel Natu 410c487da1eSNeel Natu static void 411c487da1eSNeel Natu cb_setcr(void *arg, int r, uint64_t v) 412c487da1eSNeel Natu { 413c487da1eSNeel Natu int error; 414c487da1eSNeel Natu enum vm_reg_name vmreg; 415c487da1eSNeel Natu 416c487da1eSNeel Natu vmreg = VM_REG_LAST; 417c487da1eSNeel Natu 418c487da1eSNeel Natu switch (r) { 419c487da1eSNeel Natu case 0: 420c487da1eSNeel Natu vmreg = VM_REG_GUEST_CR0; 421c487da1eSNeel Natu break; 422c487da1eSNeel Natu case 3: 423c487da1eSNeel Natu vmreg = VM_REG_GUEST_CR3; 424c487da1eSNeel Natu cr3 = v; 425c487da1eSNeel Natu break; 426c487da1eSNeel Natu case 4: 427c487da1eSNeel Natu vmreg = VM_REG_GUEST_CR4; 428c487da1eSNeel Natu break; 429c487da1eSNeel Natu default: 430c487da1eSNeel Natu break; 431c487da1eSNeel Natu } 432c487da1eSNeel Natu 433c487da1eSNeel Natu if (vmreg == VM_REG_LAST) { 434c487da1eSNeel Natu printf("test_setcr(%d): not implemented\n", r); 435c487da1eSNeel Natu cb_exit(NULL, USERBOOT_EXIT_QUIT); 436c487da1eSNeel Natu } 437c487da1eSNeel Natu 438c487da1eSNeel Natu error = vm_set_register(ctx, BSP, vmreg, v); 439c487da1eSNeel Natu if (error) { 440c487da1eSNeel Natu perror("vm_set_cr"); 441c487da1eSNeel Natu cb_exit(NULL, USERBOOT_EXIT_QUIT); 442c487da1eSNeel Natu } 443c487da1eSNeel Natu } 444c487da1eSNeel Natu 445c487da1eSNeel Natu static void 446c487da1eSNeel Natu cb_setgdt(void *arg, uint64_t base, size_t size) 447c487da1eSNeel Natu { 448c487da1eSNeel Natu int error; 449c487da1eSNeel Natu 450c487da1eSNeel Natu error = vm_set_desc(ctx, BSP, VM_REG_GUEST_GDTR, base, size - 1, 0); 451c487da1eSNeel Natu if (error != 0) { 452c487da1eSNeel Natu perror("vm_set_desc(gdt)"); 453c487da1eSNeel Natu cb_exit(NULL, USERBOOT_EXIT_QUIT); 454c487da1eSNeel Natu } 455c487da1eSNeel Natu 456c487da1eSNeel Natu gdtbase = base; 457c487da1eSNeel Natu } 458c487da1eSNeel Natu 459c487da1eSNeel Natu static void 460c487da1eSNeel Natu cb_exec(void *arg, uint64_t rip) 461c487da1eSNeel Natu { 462c487da1eSNeel Natu int error; 463c487da1eSNeel Natu 464c487da1eSNeel Natu error = vm_setup_freebsd_registers(ctx, BSP, rip, cr3, gdtbase, rsp); 465c487da1eSNeel Natu if (error) { 466c487da1eSNeel Natu perror("vm_setup_freebsd_registers"); 467c487da1eSNeel Natu cb_exit(NULL, USERBOOT_EXIT_QUIT); 468c487da1eSNeel Natu } 469c487da1eSNeel Natu 470c487da1eSNeel Natu cb_exit(NULL, 0); 471c487da1eSNeel Natu } 472c487da1eSNeel Natu 473c487da1eSNeel Natu /* 474c487da1eSNeel Natu * Misc 475c487da1eSNeel Natu */ 476c487da1eSNeel Natu 477c487da1eSNeel Natu static void 478c487da1eSNeel Natu cb_delay(void *arg, int usec) 479c487da1eSNeel Natu { 480c487da1eSNeel Natu 481c487da1eSNeel Natu usleep(usec); 482c487da1eSNeel Natu } 483c487da1eSNeel Natu 484c487da1eSNeel Natu static void 485c487da1eSNeel Natu cb_exit(void *arg, int v) 486c487da1eSNeel Natu { 487c487da1eSNeel Natu 488c487da1eSNeel Natu tcsetattr(0, TCSAFLUSH, &oldterm); 489c487da1eSNeel Natu exit(v); 490c487da1eSNeel Natu } 491c487da1eSNeel Natu 492c487da1eSNeel Natu static void 493c487da1eSNeel Natu cb_getmem(void *arg, uint64_t *ret_lowmem, uint64_t *ret_highmem) 494c487da1eSNeel Natu { 495c487da1eSNeel Natu 496c487da1eSNeel Natu *ret_lowmem = lowmem; 497c487da1eSNeel Natu *ret_highmem = highmem; 498c487da1eSNeel Natu } 499c487da1eSNeel Natu 500c3e9ce33SNeel Natu static const char * 501c3e9ce33SNeel Natu cb_getenv(void *arg, int num) 502c3e9ce33SNeel Natu { 503c3e9ce33SNeel Natu int max; 504c3e9ce33SNeel Natu 505c3e9ce33SNeel Natu static const char * var[] = { 506c3e9ce33SNeel Natu "smbios.bios.vendor=BHYVE", 507c3e9ce33SNeel Natu "boot_serial=1", 508c3e9ce33SNeel Natu NULL 509c3e9ce33SNeel Natu }; 510c3e9ce33SNeel Natu 511c3e9ce33SNeel Natu max = sizeof(var) / sizeof(var[0]); 512c3e9ce33SNeel Natu 513c3e9ce33SNeel Natu if (num < max) 514c3e9ce33SNeel Natu return (var[num]); 515c3e9ce33SNeel Natu else 516c3e9ce33SNeel Natu return (NULL); 517c3e9ce33SNeel Natu } 518c3e9ce33SNeel Natu 519*a10c6f55SNeel Natu static struct loader_callbacks cb = { 520c487da1eSNeel Natu .getc = cb_getc, 521c487da1eSNeel Natu .putc = cb_putc, 522c487da1eSNeel Natu .poll = cb_poll, 523c487da1eSNeel Natu 524c487da1eSNeel Natu .open = cb_open, 525c487da1eSNeel Natu .close = cb_close, 526c487da1eSNeel Natu .isdir = cb_isdir, 527c487da1eSNeel Natu .read = cb_read, 528c487da1eSNeel Natu .readdir = cb_readdir, 529c487da1eSNeel Natu .seek = cb_seek, 530c487da1eSNeel Natu .stat = cb_stat, 531c487da1eSNeel Natu 532c487da1eSNeel Natu .diskread = cb_diskread, 533*a10c6f55SNeel Natu .diskioctl = cb_diskioctl, 534c487da1eSNeel Natu 535c487da1eSNeel Natu .copyin = cb_copyin, 536c487da1eSNeel Natu .copyout = cb_copyout, 537c487da1eSNeel Natu .setreg = cb_setreg, 538c487da1eSNeel Natu .setmsr = cb_setmsr, 539c487da1eSNeel Natu .setcr = cb_setcr, 540c487da1eSNeel Natu .setgdt = cb_setgdt, 541c487da1eSNeel Natu .exec = cb_exec, 542c487da1eSNeel Natu 543c487da1eSNeel Natu .delay = cb_delay, 544c487da1eSNeel Natu .exit = cb_exit, 545c487da1eSNeel Natu .getmem = cb_getmem, 546c3e9ce33SNeel Natu 547c3e9ce33SNeel Natu .getenv = cb_getenv, 548c487da1eSNeel Natu }; 549c487da1eSNeel Natu 550c487da1eSNeel Natu static void 551c487da1eSNeel Natu usage(void) 552c487da1eSNeel Natu { 553c487da1eSNeel Natu 554c487da1eSNeel Natu printf("usage: %s [-d <disk image path>] [-h <host filesystem path>] " 555c487da1eSNeel Natu "[-m <lowmem>][-M <highmem>] " 556c487da1eSNeel Natu "<vmname>\n", progname); 557c487da1eSNeel Natu exit(1); 558c487da1eSNeel Natu } 559c487da1eSNeel Natu 560c487da1eSNeel Natu int 561c487da1eSNeel Natu main(int argc, char** argv) 562c487da1eSNeel Natu { 563c487da1eSNeel Natu void *h; 564*a10c6f55SNeel Natu void (*func)(struct loader_callbacks *, void *, int, int); 565c487da1eSNeel Natu int opt, error; 566c487da1eSNeel Natu char *disk_image; 567c487da1eSNeel Natu 568c487da1eSNeel Natu progname = argv[0]; 569c487da1eSNeel Natu 570c487da1eSNeel Natu lowmem = 768 * MB; 571c487da1eSNeel Natu highmem = 0; 572c487da1eSNeel Natu disk_image = NULL; 573c487da1eSNeel Natu 574c487da1eSNeel Natu while ((opt = getopt(argc, argv, "d:h:m:M:")) != -1) { 575c487da1eSNeel Natu switch (opt) { 576c487da1eSNeel Natu case 'd': 577c487da1eSNeel Natu disk_image = optarg; 578c487da1eSNeel Natu break; 579c487da1eSNeel Natu 580c487da1eSNeel Natu case 'h': 581c487da1eSNeel Natu host_base = optarg; 582c487da1eSNeel Natu break; 583c487da1eSNeel Natu 584c487da1eSNeel Natu case 'm': 585c487da1eSNeel Natu lowmem = strtoul(optarg, NULL, 0) * MB; 586c487da1eSNeel Natu break; 587c487da1eSNeel Natu 588c487da1eSNeel Natu case 'M': 589c487da1eSNeel Natu highmem = strtoul(optarg, NULL, 0) * MB; 590c487da1eSNeel Natu break; 591c487da1eSNeel Natu 592c487da1eSNeel Natu case '?': 593c487da1eSNeel Natu usage(); 594c487da1eSNeel Natu } 595c487da1eSNeel Natu } 596c487da1eSNeel Natu 597c487da1eSNeel Natu argc -= optind; 598c487da1eSNeel Natu argv += optind; 599c487da1eSNeel Natu 600c487da1eSNeel Natu if (argc != 1) 601c487da1eSNeel Natu usage(); 602c487da1eSNeel Natu 603c487da1eSNeel Natu vmname = argv[0]; 604c487da1eSNeel Natu 605c487da1eSNeel Natu error = vm_create(vmname); 606c487da1eSNeel Natu if (error != 0 && errno != EEXIST) { 607c487da1eSNeel Natu perror("vm_create"); 608c487da1eSNeel Natu exit(1); 609c487da1eSNeel Natu 610c487da1eSNeel Natu } 611c487da1eSNeel Natu 612c487da1eSNeel Natu ctx = vm_open(vmname); 613c487da1eSNeel Natu if (ctx == NULL) { 614c487da1eSNeel Natu perror("vm_open"); 615c487da1eSNeel Natu exit(1); 616c487da1eSNeel Natu } 617c487da1eSNeel Natu 618c487da1eSNeel Natu error = vm_setup_memory(ctx, 0, lowmem, &membase); 619c487da1eSNeel Natu if (error) { 620c487da1eSNeel Natu perror("vm_setup_memory(lowmem)"); 621c487da1eSNeel Natu exit(1); 622c487da1eSNeel Natu } 623c487da1eSNeel Natu 624c487da1eSNeel Natu if (highmem != 0) { 625c487da1eSNeel Natu error = vm_setup_memory(ctx, 4 * GB, highmem, NULL); 626c487da1eSNeel Natu if (error) { 627c487da1eSNeel Natu perror("vm_setup_memory(highmem)"); 628c487da1eSNeel Natu exit(1); 629c487da1eSNeel Natu } 630c487da1eSNeel Natu } 631c487da1eSNeel Natu 632c487da1eSNeel Natu tcgetattr(0, &term); 633c487da1eSNeel Natu oldterm = term; 634c487da1eSNeel Natu term.c_lflag &= ~(ICANON|ECHO); 635c487da1eSNeel Natu term.c_iflag &= ~ICRNL; 636c487da1eSNeel Natu tcsetattr(0, TCSAFLUSH, &term); 63738f1b189SPeter Grehan h = dlopen("/boot/userboot.so", RTLD_LOCAL); 638c487da1eSNeel Natu if (!h) { 639c487da1eSNeel Natu printf("%s\n", dlerror()); 640c487da1eSNeel Natu return (1); 641c487da1eSNeel Natu } 642c487da1eSNeel Natu func = dlsym(h, "loader_main"); 643c487da1eSNeel Natu if (!func) { 644c487da1eSNeel Natu printf("%s\n", dlerror()); 645c487da1eSNeel Natu return (1); 646c487da1eSNeel Natu } 647c487da1eSNeel Natu 648c487da1eSNeel Natu if (disk_image) { 649c487da1eSNeel Natu disk_fd = open(disk_image, O_RDONLY); 650c487da1eSNeel Natu } 651c3e9ce33SNeel Natu func(&cb, NULL, USERBOOT_VERSION_3, disk_fd >= 0); 652c487da1eSNeel Natu } 653