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: stable/11/stand/userboot/test/test.c 329175 2018-02-12 17:44:35Z kevans $ 27223695Sdfr */ 28223695Sdfr 29239058Sae#include <sys/types.h> 30239058Sae#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> 39268978Ssbruno#include <inttypes.h> 40223695Sdfr#include <limits.h> 41223695Sdfr#include <stdio.h> 42223695Sdfr#include <stdlib.h> 43223695Sdfr#include <string.h> 44223695Sdfr#include <termios.h> 45223695Sdfr#include <unistd.h> 46223695Sdfr 47329140Skevans#include <userboot.h> 48223695Sdfr 49223695Sdfrchar *host_base = NULL; 50223695Sdfrstruct termios term, oldterm; 51223695Sdfrchar *image; 52223695Sdfrsize_t image_size; 53223695Sdfrint disk_fd = -1; 54223695Sdfr 55223695Sdfruint64_t regs[16]; 56223695Sdfruint64_t pc; 57223695Sdfr 58223695Sdfrvoid test_exit(void *arg, int v); 59223695Sdfr 60223695Sdfr/* 61223695Sdfr * Console i/o 62223695Sdfr */ 63223695Sdfr 64223695Sdfrvoid 65223695Sdfrtest_putc(void *arg, int ch) 66223695Sdfr{ 67223695Sdfr char c = ch; 68223695Sdfr 69223695Sdfr write(1, &c, 1); 70223695Sdfr} 71223695Sdfr 72223695Sdfrint 73223695Sdfrtest_getc(void *arg) 74223695Sdfr{ 75223695Sdfr char c; 76223695Sdfr 77223695Sdfr if (read(0, &c, 1) == 1) 78223695Sdfr return c; 79223695Sdfr return -1; 80223695Sdfr} 81223695Sdfr 82223695Sdfrint 83223695Sdfrtest_poll(void *arg) 84223695Sdfr{ 85223695Sdfr int n; 86223695Sdfr 87223695Sdfr if (ioctl(0, FIONREAD, &n) >= 0) 88223695Sdfr return (n > 0); 89223695Sdfr return (0); 90223695Sdfr} 91223695Sdfr 92223695Sdfr/* 93223695Sdfr * Host filesystem i/o 94223695Sdfr */ 95223695Sdfr 96223695Sdfrstruct test_file { 97223695Sdfr int tf_isdir; 98223695Sdfr size_t tf_size; 99223695Sdfr struct stat tf_stat; 100223695Sdfr union { 101223695Sdfr int fd; 102223695Sdfr DIR *dir; 103223695Sdfr } tf_u; 104223695Sdfr}; 105223695Sdfr 106223695Sdfrint 107223695Sdfrtest_open(void *arg, const char *filename, void **h_return) 108223695Sdfr{ 109223695Sdfr struct stat st; 110223695Sdfr struct test_file *tf; 111223695Sdfr char path[PATH_MAX]; 112223695Sdfr 113223695Sdfr if (!host_base) 114223695Sdfr return (ENOENT); 115223695Sdfr 116223695Sdfr strlcpy(path, host_base, PATH_MAX); 117223695Sdfr if (path[strlen(path) - 1] == '/') 118223695Sdfr path[strlen(path) - 1] = 0; 119223695Sdfr strlcat(path, filename, PATH_MAX); 120223695Sdfr tf = malloc(sizeof(struct test_file)); 121223695Sdfr if (stat(path, &tf->tf_stat) < 0) { 122223695Sdfr free(tf); 123223695Sdfr return (errno); 124223695Sdfr } 125223695Sdfr 126223695Sdfr tf->tf_size = st.st_size; 127223695Sdfr if (S_ISDIR(tf->tf_stat.st_mode)) { 128223695Sdfr tf->tf_isdir = 1; 129223695Sdfr tf->tf_u.dir = opendir(path); 130223695Sdfr if (!tf->tf_u.dir) 131223695Sdfr goto out; 132223695Sdfr *h_return = tf; 133223695Sdfr return (0); 134223695Sdfr } 135223695Sdfr if (S_ISREG(tf->tf_stat.st_mode)) { 136223695Sdfr tf->tf_isdir = 0; 137223695Sdfr tf->tf_u.fd = open(path, O_RDONLY); 138223695Sdfr if (tf->tf_u.fd < 0) 139223695Sdfr goto out; 140223695Sdfr *h_return = tf; 141223695Sdfr return (0); 142223695Sdfr } 143223695Sdfr 144223695Sdfrout: 145223695Sdfr free(tf); 146223695Sdfr return (EINVAL); 147223695Sdfr} 148223695Sdfr 149223695Sdfrint 150223695Sdfrtest_close(void *arg, void *h) 151223695Sdfr{ 152223695Sdfr struct test_file *tf = h; 153223695Sdfr 154223695Sdfr if (tf->tf_isdir) 155223695Sdfr closedir(tf->tf_u.dir); 156223695Sdfr else 157223695Sdfr close(tf->tf_u.fd); 158223695Sdfr free(tf); 159223695Sdfr 160223695Sdfr return (0); 161223695Sdfr} 162223695Sdfr 163223695Sdfrint 164223695Sdfrtest_isdir(void *arg, void *h) 165223695Sdfr{ 166223695Sdfr struct test_file *tf = h; 167223695Sdfr 168223695Sdfr return (tf->tf_isdir); 169223695Sdfr} 170223695Sdfr 171223695Sdfrint 172223695Sdfrtest_read(void *arg, void *h, void *dst, size_t size, size_t *resid_return) 173223695Sdfr{ 174223695Sdfr struct test_file *tf = h; 175223695Sdfr ssize_t sz; 176223695Sdfr 177223695Sdfr if (tf->tf_isdir) 178223695Sdfr return (EINVAL); 179223695Sdfr sz = read(tf->tf_u.fd, dst, size); 180223695Sdfr if (sz < 0) 181223695Sdfr return (EINVAL); 182223695Sdfr *resid_return = size - sz; 183223695Sdfr return (0); 184223695Sdfr} 185223695Sdfr 186223695Sdfrint 187223695Sdfrtest_readdir(void *arg, void *h, uint32_t *fileno_return, uint8_t *type_return, 188223695Sdfr size_t *namelen_return, char *name) 189223695Sdfr{ 190223695Sdfr struct test_file *tf = h; 191223695Sdfr struct dirent *dp; 192223695Sdfr 193223695Sdfr if (!tf->tf_isdir) 194223695Sdfr return (EINVAL); 195223695Sdfr 196223695Sdfr dp = readdir(tf->tf_u.dir); 197223695Sdfr if (!dp) 198223695Sdfr return (ENOENT); 199223695Sdfr 200223695Sdfr /* 201223695Sdfr * Note: d_namlen is in the range 0..255 and therefore less 202223695Sdfr * than PATH_MAX so we don't need to test before copying. 203223695Sdfr */ 204223695Sdfr *fileno_return = dp->d_fileno; 205223695Sdfr *type_return = dp->d_type; 206223695Sdfr *namelen_return = dp->d_namlen; 207223695Sdfr memcpy(name, dp->d_name, dp->d_namlen); 208223695Sdfr name[dp->d_namlen] = 0; 209223695Sdfr 210223695Sdfr return (0); 211223695Sdfr} 212223695Sdfr 213223695Sdfrint 214223695Sdfrtest_seek(void *arg, void *h, uint64_t offset, int whence) 215223695Sdfr{ 216223695Sdfr struct test_file *tf = h; 217223695Sdfr 218223695Sdfr if (tf->tf_isdir) 219223695Sdfr return (EINVAL); 220223695Sdfr if (lseek(tf->tf_u.fd, offset, whence) < 0) 221223695Sdfr return (errno); 222223695Sdfr return (0); 223223695Sdfr} 224223695Sdfr 225223695Sdfrint 226223695Sdfrtest_stat(void *arg, void *h, int *mode_return, int *uid_return, int *gid_return, 227223695Sdfr uint64_t *size_return) 228223695Sdfr{ 229223695Sdfr struct test_file *tf = h; 230223695Sdfr 231223695Sdfr *mode_return = tf->tf_stat.st_mode; 232223695Sdfr *uid_return = tf->tf_stat.st_uid; 233223695Sdfr *gid_return = tf->tf_stat.st_gid; 234223695Sdfr *size_return = tf->tf_stat.st_size; 235223695Sdfr return (0); 236223695Sdfr} 237223695Sdfr 238223695Sdfr/* 239223695Sdfr * Disk image i/o 240223695Sdfr */ 241223695Sdfr 242223695Sdfrint 243223695Sdfrtest_diskread(void *arg, int unit, uint64_t offset, void *dst, size_t size, 244223695Sdfr size_t *resid_return) 245223695Sdfr{ 246223695Sdfr ssize_t n; 247223695Sdfr 248223695Sdfr if (unit != 0 || disk_fd == -1) 249223695Sdfr return (EIO); 250223695Sdfr n = pread(disk_fd, dst, size, offset); 251223695Sdfr if (n < 0) 252223695Sdfr return (errno); 253223695Sdfr *resid_return = size - n; 254223695Sdfr return (0); 255223695Sdfr} 256223695Sdfr 257239058Saeint 258239058Saetest_diskioctl(void *arg, int unit, u_long cmd, void *data) 259239058Sae{ 260239058Sae struct stat sb; 261239058Sae 262239058Sae if (unit != 0 || disk_fd == -1) 263239058Sae return (EBADF); 264239058Sae switch (cmd) { 265239058Sae case DIOCGSECTORSIZE: 266239058Sae *(u_int *)data = 512; 267239058Sae break; 268239058Sae case DIOCGMEDIASIZE: 269239058Sae if (fstat(disk_fd, &sb) == 0) 270239058Sae *(off_t *)data = sb.st_size; 271239058Sae else 272239058Sae return (ENOTTY); 273239058Sae break; 274239058Sae default: 275239058Sae return (ENOTTY); 276297793Spfg } 277239058Sae return (0); 278239058Sae} 279239058Sae 280223695Sdfr/* 281223695Sdfr * Guest virtual machine i/o 282223695Sdfr * 283223695Sdfr * Note: guest addresses are kernel virtual 284223695Sdfr */ 285223695Sdfr 286223695Sdfrint 287223695Sdfrtest_copyin(void *arg, const void *from, uint64_t to, size_t size) 288223695Sdfr{ 289223695Sdfr 290223695Sdfr to &= 0x7fffffff; 291223695Sdfr if (to > image_size) 292223695Sdfr return (EFAULT); 293223695Sdfr if (to + size > image_size) 294223695Sdfr size = image_size - to; 295223695Sdfr memcpy(&image[to], from, size); 296268978Ssbruno return(0); 297223695Sdfr} 298223695Sdfr 299223695Sdfrint 300223695Sdfrtest_copyout(void *arg, uint64_t from, void *to, size_t size) 301223695Sdfr{ 302223695Sdfr 303223695Sdfr from &= 0x7fffffff; 304223695Sdfr if (from > image_size) 305223695Sdfr return (EFAULT); 306223695Sdfr if (from + size > image_size) 307223695Sdfr size = image_size - from; 308223695Sdfr memcpy(to, &image[from], size); 309268978Ssbruno return(0); 310223695Sdfr} 311223695Sdfr 312223695Sdfrvoid 313223695Sdfrtest_setreg(void *arg, int r, uint64_t v) 314223695Sdfr{ 315223695Sdfr 316223695Sdfr if (r < 0 || r >= 16) 317223695Sdfr return; 318223695Sdfr regs[r] = v; 319223695Sdfr} 320223695Sdfr 321223695Sdfrvoid 322223695Sdfrtest_setmsr(void *arg, int r, uint64_t v) 323223695Sdfr{ 324223695Sdfr} 325223695Sdfr 326223695Sdfrvoid 327223695Sdfrtest_setcr(void *arg, int r, uint64_t v) 328223695Sdfr{ 329223695Sdfr} 330223695Sdfr 331223695Sdfrvoid 332223695Sdfrtest_setgdt(void *arg, uint64_t v, size_t sz) 333223695Sdfr{ 334223695Sdfr} 335223695Sdfr 336223695Sdfrvoid 337223695Sdfrtest_exec(void *arg, uint64_t pc) 338223695Sdfr{ 339268978Ssbruno printf("Execute at 0x%"PRIu64"\n", pc); 340223695Sdfr test_exit(arg, 0); 341223695Sdfr} 342223695Sdfr 343223695Sdfr/* 344223695Sdfr * Misc 345223695Sdfr */ 346223695Sdfr 347223695Sdfrvoid 348223695Sdfrtest_delay(void *arg, int usec) 349223695Sdfr{ 350223695Sdfr 351223695Sdfr usleep(usec); 352223695Sdfr} 353223695Sdfr 354223695Sdfrvoid 355223695Sdfrtest_exit(void *arg, int v) 356223695Sdfr{ 357223695Sdfr 358223695Sdfr tcsetattr(0, TCSAFLUSH, &oldterm); 359223695Sdfr exit(v); 360223695Sdfr} 361223695Sdfr 362223695Sdfrvoid 363223695Sdfrtest_getmem(void *arg, uint64_t *lowmem, uint64_t *highmem) 364223695Sdfr{ 365223695Sdfr 366223695Sdfr *lowmem = 128*1024*1024; 367223695Sdfr *highmem = 0; 368223695Sdfr} 369223695Sdfr 370329114Skevanschar * 371242935Sneeltest_getenv(void *arg, int idx) 372242935Sneel{ 373329114Skevans static char *vars[] = { 374242935Sneel "foo=bar", 375242935Sneel "bar=barbar", 376242935Sneel NULL 377242935Sneel }; 378242935Sneel 379242935Sneel return (vars[idx]); 380242935Sneel} 381242935Sneel 382241164Saestruct loader_callbacks cb = { 383223695Sdfr .putc = test_putc, 384223695Sdfr .getc = test_getc, 385223695Sdfr .poll = test_poll, 386223695Sdfr 387223695Sdfr .open = test_open, 388223695Sdfr .close = test_close, 389223695Sdfr .isdir = test_isdir, 390223695Sdfr .read = test_read, 391223695Sdfr .readdir = test_readdir, 392223695Sdfr .seek = test_seek, 393223695Sdfr .stat = test_stat, 394223695Sdfr 395223695Sdfr .diskread = test_diskread, 396239058Sae .diskioctl = test_diskioctl, 397223695Sdfr 398223695Sdfr .copyin = test_copyin, 399223695Sdfr .copyout = test_copyout, 400223695Sdfr .setreg = test_setreg, 401223695Sdfr .setmsr = test_setmsr, 402223695Sdfr .setcr = test_setcr, 403223695Sdfr .setgdt = test_setgdt, 404223695Sdfr .exec = test_exec, 405223695Sdfr 406223695Sdfr .delay = test_delay, 407223695Sdfr .exit = test_exit, 408223695Sdfr .getmem = test_getmem, 409242935Sneel 410242935Sneel .getenv = test_getenv, 411223695Sdfr}; 412223695Sdfr 413223695Sdfrvoid 414223695Sdfrusage() 415223695Sdfr{ 416223695Sdfr 417294047Sjmallett printf("usage: [-b <userboot shared object>] [-d <disk image path>] [-h <host filesystem path>\n"); 418223695Sdfr exit(1); 419223695Sdfr} 420223695Sdfr 421223695Sdfrint 422223695Sdfrmain(int argc, char** argv) 423223695Sdfr{ 424223695Sdfr void *h; 425329175Skevans void (*func)(struct loader_callbacks *, void *, int, int) __dead2; 426223695Sdfr int opt; 427223695Sdfr char *disk_image = NULL; 428294047Sjmallett const char *userboot_obj = "/boot/userboot.so"; 429223695Sdfr 430294047Sjmallett while ((opt = getopt(argc, argv, "b:d:h:")) != -1) { 431223695Sdfr switch (opt) { 432294047Sjmallett case 'b': 433294047Sjmallett userboot_obj = optarg; 434294047Sjmallett break; 435294047Sjmallett 436223695Sdfr case 'd': 437223695Sdfr disk_image = optarg; 438223695Sdfr break; 439223695Sdfr 440223695Sdfr case 'h': 441223695Sdfr host_base = optarg; 442223695Sdfr break; 443223695Sdfr 444223695Sdfr case '?': 445223695Sdfr usage(); 446223695Sdfr } 447223695Sdfr } 448223695Sdfr 449294047Sjmallett h = dlopen(userboot_obj, RTLD_LOCAL); 450223695Sdfr if (!h) { 451223695Sdfr printf("%s\n", dlerror()); 452223695Sdfr return (1); 453223695Sdfr } 454223695Sdfr func = dlsym(h, "loader_main"); 455223695Sdfr if (!func) { 456223695Sdfr printf("%s\n", dlerror()); 457223695Sdfr return (1); 458223695Sdfr } 459223695Sdfr 460223695Sdfr image_size = 128*1024*1024; 461223695Sdfr image = malloc(image_size); 462223695Sdfr if (disk_image) { 463223695Sdfr disk_fd = open(disk_image, O_RDONLY); 464223695Sdfr if (disk_fd < 0) 465223695Sdfr err(1, "Can't open disk image '%s'", disk_image); 466223695Sdfr } 467223695Sdfr 468223695Sdfr tcgetattr(0, &term); 469223695Sdfr oldterm = term; 470223695Sdfr term.c_iflag &= ~(ICRNL); 471223695Sdfr term.c_lflag &= ~(ICANON|ECHO); 472223695Sdfr tcsetattr(0, TCSAFLUSH, &term); 473223695Sdfr 474242935Sneel func(&cb, NULL, USERBOOT_VERSION_3, disk_fd >= 0); 475223695Sdfr} 476