1223695Sdfr/*- 2223695Sdfr * Copyright (c) 2011 Google, Inc. 3223695Sdfr * All rights reserved. 4223695Sdfr * 5223695Sdfr * Redistribution and use in source and binary forms, with or without 6223695Sdfr * modification, are permitted provided that the following conditions 7223695Sdfr * are met: 8223695Sdfr * 1. Redistributions of source code must retain the above copyright 9223695Sdfr * notice, this list of conditions and the following disclaimer. 10223695Sdfr * 2. Redistributions in binary form must reproduce the above copyright 11223695Sdfr * notice, this list of conditions and the following disclaimer in the 12223695Sdfr * documentation and/or other materials provided with the distribution. 13223695Sdfr * 14223695Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15223695Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16223695Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17223695Sdfr * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18223695Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19223695Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20223695Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21223695Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22223695Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23223695Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24223695Sdfr * SUCH DAMAGE. 25223695Sdfr * 26223695Sdfr * $FreeBSD$ 27223695Sdfr */ 28223695Sdfr 29243243Sae#include <sys/types.h> 30243243Sae#include <sys/disk.h> 31223695Sdfr#include <sys/ioctl.h> 32223695Sdfr#include <sys/stat.h> 33223695Sdfr#include <dirent.h> 34223695Sdfr#include <dlfcn.h> 35223695Sdfr#include <err.h> 36223695Sdfr#include <errno.h> 37223695Sdfr#include <fcntl.h> 38223695Sdfr#include <getopt.h> 39223695Sdfr#include <limits.h> 40223695Sdfr#include <stdio.h> 41223695Sdfr#include <stdlib.h> 42223695Sdfr#include <string.h> 43223695Sdfr#include <termios.h> 44223695Sdfr#include <unistd.h> 45223695Sdfr 46223695Sdfr#include <boot/userboot/userboot.h> 47223695Sdfr 48223695Sdfrchar *host_base = NULL; 49223695Sdfrstruct termios term, oldterm; 50223695Sdfrchar *image; 51223695Sdfrsize_t image_size; 52223695Sdfrint disk_fd = -1; 53223695Sdfr 54223695Sdfruint64_t regs[16]; 55223695Sdfruint64_t pc; 56223695Sdfr 57223695Sdfrvoid test_exit(void *arg, int v); 58223695Sdfr 59223695Sdfr/* 60223695Sdfr * Console i/o 61223695Sdfr */ 62223695Sdfr 63223695Sdfrvoid 64223695Sdfrtest_putc(void *arg, int ch) 65223695Sdfr{ 66223695Sdfr char c = ch; 67223695Sdfr 68223695Sdfr write(1, &c, 1); 69223695Sdfr} 70223695Sdfr 71223695Sdfrint 72223695Sdfrtest_getc(void *arg) 73223695Sdfr{ 74223695Sdfr char c; 75223695Sdfr 76223695Sdfr if (read(0, &c, 1) == 1) 77223695Sdfr return c; 78223695Sdfr return -1; 79223695Sdfr} 80223695Sdfr 81223695Sdfrint 82223695Sdfrtest_poll(void *arg) 83223695Sdfr{ 84223695Sdfr int n; 85223695Sdfr 86223695Sdfr if (ioctl(0, FIONREAD, &n) >= 0) 87223695Sdfr return (n > 0); 88223695Sdfr return (0); 89223695Sdfr} 90223695Sdfr 91223695Sdfr/* 92223695Sdfr * Host filesystem i/o 93223695Sdfr */ 94223695Sdfr 95223695Sdfrstruct test_file { 96223695Sdfr int tf_isdir; 97223695Sdfr size_t tf_size; 98223695Sdfr struct stat tf_stat; 99223695Sdfr union { 100223695Sdfr int fd; 101223695Sdfr DIR *dir; 102223695Sdfr } tf_u; 103223695Sdfr}; 104223695Sdfr 105223695Sdfrint 106223695Sdfrtest_open(void *arg, const char *filename, void **h_return) 107223695Sdfr{ 108223695Sdfr struct stat st; 109223695Sdfr struct test_file *tf; 110223695Sdfr char path[PATH_MAX]; 111223695Sdfr 112223695Sdfr if (!host_base) 113223695Sdfr return (ENOENT); 114223695Sdfr 115223695Sdfr strlcpy(path, host_base, PATH_MAX); 116223695Sdfr if (path[strlen(path) - 1] == '/') 117223695Sdfr path[strlen(path) - 1] = 0; 118223695Sdfr strlcat(path, filename, PATH_MAX); 119223695Sdfr tf = malloc(sizeof(struct test_file)); 120223695Sdfr if (stat(path, &tf->tf_stat) < 0) { 121223695Sdfr free(tf); 122223695Sdfr return (errno); 123223695Sdfr } 124223695Sdfr 125223695Sdfr tf->tf_size = st.st_size; 126223695Sdfr if (S_ISDIR(tf->tf_stat.st_mode)) { 127223695Sdfr tf->tf_isdir = 1; 128223695Sdfr tf->tf_u.dir = opendir(path); 129223695Sdfr if (!tf->tf_u.dir) 130223695Sdfr goto out; 131223695Sdfr *h_return = tf; 132223695Sdfr return (0); 133223695Sdfr } 134223695Sdfr if (S_ISREG(tf->tf_stat.st_mode)) { 135223695Sdfr tf->tf_isdir = 0; 136223695Sdfr tf->tf_u.fd = open(path, O_RDONLY); 137223695Sdfr if (tf->tf_u.fd < 0) 138223695Sdfr goto out; 139223695Sdfr *h_return = tf; 140223695Sdfr return (0); 141223695Sdfr } 142223695Sdfr 143223695Sdfrout: 144223695Sdfr free(tf); 145223695Sdfr return (EINVAL); 146223695Sdfr} 147223695Sdfr 148223695Sdfrint 149223695Sdfrtest_close(void *arg, void *h) 150223695Sdfr{ 151223695Sdfr struct test_file *tf = h; 152223695Sdfr 153223695Sdfr if (tf->tf_isdir) 154223695Sdfr closedir(tf->tf_u.dir); 155223695Sdfr else 156223695Sdfr close(tf->tf_u.fd); 157223695Sdfr free(tf); 158223695Sdfr 159223695Sdfr return (0); 160223695Sdfr} 161223695Sdfr 162223695Sdfrint 163223695Sdfrtest_isdir(void *arg, void *h) 164223695Sdfr{ 165223695Sdfr struct test_file *tf = h; 166223695Sdfr 167223695Sdfr return (tf->tf_isdir); 168223695Sdfr} 169223695Sdfr 170223695Sdfrint 171223695Sdfrtest_read(void *arg, void *h, void *dst, size_t size, size_t *resid_return) 172223695Sdfr{ 173223695Sdfr struct test_file *tf = h; 174223695Sdfr ssize_t sz; 175223695Sdfr 176223695Sdfr if (tf->tf_isdir) 177223695Sdfr return (EINVAL); 178223695Sdfr sz = read(tf->tf_u.fd, dst, size); 179223695Sdfr if (sz < 0) 180223695Sdfr return (EINVAL); 181223695Sdfr *resid_return = size - sz; 182223695Sdfr return (0); 183223695Sdfr} 184223695Sdfr 185223695Sdfrint 186223695Sdfrtest_readdir(void *arg, void *h, uint32_t *fileno_return, uint8_t *type_return, 187223695Sdfr size_t *namelen_return, char *name) 188223695Sdfr{ 189223695Sdfr struct test_file *tf = h; 190223695Sdfr struct dirent *dp; 191223695Sdfr 192223695Sdfr if (!tf->tf_isdir) 193223695Sdfr return (EINVAL); 194223695Sdfr 195223695Sdfr dp = readdir(tf->tf_u.dir); 196223695Sdfr if (!dp) 197223695Sdfr return (ENOENT); 198223695Sdfr 199223695Sdfr /* 200223695Sdfr * Note: d_namlen is in the range 0..255 and therefore less 201223695Sdfr * than PATH_MAX so we don't need to test before copying. 202223695Sdfr */ 203223695Sdfr *fileno_return = dp->d_fileno; 204223695Sdfr *type_return = dp->d_type; 205223695Sdfr *namelen_return = dp->d_namlen; 206223695Sdfr memcpy(name, dp->d_name, dp->d_namlen); 207223695Sdfr name[dp->d_namlen] = 0; 208223695Sdfr 209223695Sdfr return (0); 210223695Sdfr} 211223695Sdfr 212223695Sdfrint 213223695Sdfrtest_seek(void *arg, void *h, uint64_t offset, int whence) 214223695Sdfr{ 215223695Sdfr struct test_file *tf = h; 216223695Sdfr 217223695Sdfr if (tf->tf_isdir) 218223695Sdfr return (EINVAL); 219223695Sdfr if (lseek(tf->tf_u.fd, offset, whence) < 0) 220223695Sdfr return (errno); 221223695Sdfr return (0); 222223695Sdfr} 223223695Sdfr 224223695Sdfrint 225223695Sdfrtest_stat(void *arg, void *h, int *mode_return, int *uid_return, int *gid_return, 226223695Sdfr uint64_t *size_return) 227223695Sdfr{ 228223695Sdfr struct test_file *tf = h; 229223695Sdfr 230223695Sdfr *mode_return = tf->tf_stat.st_mode; 231223695Sdfr *uid_return = tf->tf_stat.st_uid; 232223695Sdfr *gid_return = tf->tf_stat.st_gid; 233223695Sdfr *size_return = tf->tf_stat.st_size; 234223695Sdfr return (0); 235223695Sdfr} 236223695Sdfr 237223695Sdfr/* 238223695Sdfr * Disk image i/o 239223695Sdfr */ 240223695Sdfr 241223695Sdfrint 242223695Sdfrtest_diskread(void *arg, int unit, uint64_t offset, void *dst, size_t size, 243223695Sdfr size_t *resid_return) 244223695Sdfr{ 245223695Sdfr ssize_t n; 246223695Sdfr 247223695Sdfr if (unit != 0 || disk_fd == -1) 248223695Sdfr return (EIO); 249223695Sdfr n = pread(disk_fd, dst, size, offset); 250223695Sdfr if (n < 0) 251223695Sdfr return (errno); 252223695Sdfr *resid_return = size - n; 253223695Sdfr return (0); 254223695Sdfr} 255223695Sdfr 256243243Saeint 257243243Saetest_diskioctl(void *arg, int unit, u_long cmd, void *data) 258243243Sae{ 259243243Sae struct stat sb; 260243243Sae 261243243Sae if (unit != 0 || disk_fd == -1) 262243243Sae return (EBADF); 263243243Sae switch (cmd) { 264243243Sae case DIOCGSECTORSIZE: 265243243Sae *(u_int *)data = 512; 266243243Sae break; 267243243Sae case DIOCGMEDIASIZE: 268243243Sae if (fstat(disk_fd, &sb) == 0) 269243243Sae *(off_t *)data = sb.st_size; 270243243Sae else 271243243Sae return (ENOTTY); 272243243Sae break; 273243243Sae default: 274243243Sae return (ENOTTY); 275243243Sae }; 276243243Sae return (0); 277243243Sae} 278243243Sae 279223695Sdfr/* 280223695Sdfr * Guest virtual machine i/o 281223695Sdfr * 282223695Sdfr * Note: guest addresses are kernel virtual 283223695Sdfr */ 284223695Sdfr 285223695Sdfrint 286223695Sdfrtest_copyin(void *arg, const void *from, uint64_t to, size_t size) 287223695Sdfr{ 288223695Sdfr 289223695Sdfr to &= 0x7fffffff; 290223695Sdfr if (to > image_size) 291223695Sdfr return (EFAULT); 292223695Sdfr if (to + size > image_size) 293223695Sdfr size = image_size - to; 294223695Sdfr memcpy(&image[to], from, size); 295223695Sdfr} 296223695Sdfr 297223695Sdfrint 298223695Sdfrtest_copyout(void *arg, uint64_t from, void *to, size_t size) 299223695Sdfr{ 300223695Sdfr 301223695Sdfr from &= 0x7fffffff; 302223695Sdfr if (from > image_size) 303223695Sdfr return (EFAULT); 304223695Sdfr if (from + size > image_size) 305223695Sdfr size = image_size - from; 306223695Sdfr memcpy(to, &image[from], size); 307223695Sdfr} 308223695Sdfr 309223695Sdfrvoid 310223695Sdfrtest_setreg(void *arg, int r, uint64_t v) 311223695Sdfr{ 312223695Sdfr 313223695Sdfr if (r < 0 || r >= 16) 314223695Sdfr return; 315223695Sdfr regs[r] = v; 316223695Sdfr} 317223695Sdfr 318223695Sdfrvoid 319223695Sdfrtest_setmsr(void *arg, int r, uint64_t v) 320223695Sdfr{ 321223695Sdfr} 322223695Sdfr 323223695Sdfrvoid 324223695Sdfrtest_setcr(void *arg, int r, uint64_t v) 325223695Sdfr{ 326223695Sdfr} 327223695Sdfr 328223695Sdfrvoid 329223695Sdfrtest_setgdt(void *arg, uint64_t v, size_t sz) 330223695Sdfr{ 331223695Sdfr} 332223695Sdfr 333223695Sdfrvoid 334223695Sdfrtest_exec(void *arg, uint64_t pc) 335223695Sdfr{ 336223695Sdfr printf("Execute at 0x%llx\n", pc); 337223695Sdfr test_exit(arg, 0); 338223695Sdfr} 339223695Sdfr 340223695Sdfr/* 341223695Sdfr * Misc 342223695Sdfr */ 343223695Sdfr 344223695Sdfrvoid 345223695Sdfrtest_delay(void *arg, int usec) 346223695Sdfr{ 347223695Sdfr 348223695Sdfr usleep(usec); 349223695Sdfr} 350223695Sdfr 351223695Sdfrvoid 352223695Sdfrtest_exit(void *arg, int v) 353223695Sdfr{ 354223695Sdfr 355223695Sdfr tcsetattr(0, TCSAFLUSH, &oldterm); 356223695Sdfr exit(v); 357223695Sdfr} 358223695Sdfr 359223695Sdfrvoid 360223695Sdfrtest_getmem(void *arg, uint64_t *lowmem, uint64_t *highmem) 361223695Sdfr{ 362223695Sdfr 363223695Sdfr *lowmem = 128*1024*1024; 364223695Sdfr *highmem = 0; 365223695Sdfr} 366223695Sdfr 367243243Saestruct loader_callbacks cb = { 368223695Sdfr .putc = test_putc, 369223695Sdfr .getc = test_getc, 370223695Sdfr .poll = test_poll, 371223695Sdfr 372223695Sdfr .open = test_open, 373223695Sdfr .close = test_close, 374223695Sdfr .isdir = test_isdir, 375223695Sdfr .read = test_read, 376223695Sdfr .readdir = test_readdir, 377223695Sdfr .seek = test_seek, 378223695Sdfr .stat = test_stat, 379223695Sdfr 380223695Sdfr .diskread = test_diskread, 381243243Sae .diskioctl = test_diskioctl, 382223695Sdfr 383223695Sdfr .copyin = test_copyin, 384223695Sdfr .copyout = test_copyout, 385223695Sdfr .setreg = test_setreg, 386223695Sdfr .setmsr = test_setmsr, 387223695Sdfr .setcr = test_setcr, 388223695Sdfr .setgdt = test_setgdt, 389223695Sdfr .exec = test_exec, 390223695Sdfr 391223695Sdfr .delay = test_delay, 392223695Sdfr .exit = test_exit, 393223695Sdfr .getmem = test_getmem, 394223695Sdfr}; 395223695Sdfr 396223695Sdfrvoid 397223695Sdfrusage() 398223695Sdfr{ 399223695Sdfr 400223695Sdfr printf("usage: %s [-d <disk image path>] [-h <host filesystem path>\n"); 401223695Sdfr exit(1); 402223695Sdfr} 403223695Sdfr 404223695Sdfrint 405223695Sdfrmain(int argc, char** argv) 406223695Sdfr{ 407223695Sdfr void *h; 408243243Sae void (*func)(struct loader_callbacks *, void *, int, int); 409223695Sdfr int opt; 410223695Sdfr char *disk_image = NULL; 411223695Sdfr 412223695Sdfr while ((opt = getopt(argc, argv, "d:h:")) != -1) { 413223695Sdfr switch (opt) { 414223695Sdfr case 'd': 415223695Sdfr disk_image = optarg; 416223695Sdfr break; 417223695Sdfr 418223695Sdfr case 'h': 419223695Sdfr host_base = optarg; 420223695Sdfr break; 421223695Sdfr 422223695Sdfr case '?': 423223695Sdfr usage(); 424223695Sdfr } 425223695Sdfr } 426223695Sdfr 427223695Sdfr h = dlopen("/boot/userboot.so", 428223695Sdfr RTLD_LOCAL); 429223695Sdfr if (!h) { 430223695Sdfr printf("%s\n", dlerror()); 431223695Sdfr return (1); 432223695Sdfr } 433223695Sdfr func = dlsym(h, "loader_main"); 434223695Sdfr if (!func) { 435223695Sdfr printf("%s\n", dlerror()); 436223695Sdfr return (1); 437223695Sdfr } 438223695Sdfr 439223695Sdfr image_size = 128*1024*1024; 440223695Sdfr image = malloc(image_size); 441223695Sdfr if (disk_image) { 442223695Sdfr disk_fd = open(disk_image, O_RDONLY); 443223695Sdfr if (disk_fd < 0) 444223695Sdfr err(1, "Can't open disk image '%s'", disk_image); 445223695Sdfr } 446223695Sdfr 447223695Sdfr tcgetattr(0, &term); 448223695Sdfr oldterm = term; 449223695Sdfr term.c_iflag &= ~(ICRNL); 450223695Sdfr term.c_lflag &= ~(ICANON|ECHO); 451223695Sdfr tcsetattr(0, TCSAFLUSH, &term); 452223695Sdfr 453243243Sae func(&cb, NULL, USERBOOT_VERSION_2, disk_fd >= 0); 454223695Sdfr} 455