|  | #include <stdio.h> | 
|  | #include <pthread.h> | 
|  | #include <sys/types.h> | 
|  | #include <sys/stat.h> | 
|  | #include <fcntl.h> | 
|  | #include <parlib/arch/arch.h> | 
|  | #include <parlib/ros_debug.h> | 
|  | #include <unistd.h> | 
|  | #include <gelf.h> | 
|  | #include <errno.h> | 
|  | #include <libelf.h> | 
|  | #include <dirent.h> | 
|  | #include <stdlib.h> | 
|  | #include <string.h> | 
|  | #include <ros/syscall.h> | 
|  | #include <sys/mman.h> | 
|  | #include <vmm/vmm.h> | 
|  | #include <vmm/acpi/acpi.h> | 
|  | #include <vmm/acpi/vmm_simple_dsdt.h> | 
|  | #include <ros/arch/mmu.h> | 
|  | #include <ros/arch/membar.h> | 
|  | #include <ros/vmm.h> | 
|  | #include <parlib/uthread.h> | 
|  | #include <vmm/linux_bootparam.h> | 
|  | #include <getopt.h> | 
|  | #include <iplib/iplib.h> | 
|  | #include <vmm/sched.h> | 
|  | #include <sys/eventfd.h> | 
|  | #include <sys/uio.h> | 
|  | #include <err.h> | 
|  | #include <vmm/linuxemu.h> | 
|  | #include <vmm/vmm.h> | 
|  | #include <vmm/vthread.h> | 
|  |  | 
|  | struct vmm_gpcore_init gpci; | 
|  | bool linuxemu(struct guest_thread *gth, struct vm_trapframe *tf); | 
|  |  | 
|  |  | 
|  | extern char **environ; | 
|  |  | 
|  | static struct virtual_machine vm = {.halt_exit = true, | 
|  | .mtx = UTH_MUTEX_INIT, | 
|  | .vmcall = linuxemu}; | 
|  |  | 
|  | static unsigned long long memsize = GiB; | 
|  | static uintptr_t memstart = MinMemory; | 
|  |  | 
|  | static int dune_debug; | 
|  |  | 
|  | static void hlt(void) | 
|  | { | 
|  | __asm__ __volatile__("\thlt\n\t"); | 
|  | } | 
|  |  | 
|  | static int pc(char *c) | 
|  | { | 
|  | __asm__ __volatile__("movq $1, %%rax\n" | 
|  | "movq $1, %%rdi\n" | 
|  | "movq %0, %%rsi\n" | 
|  | "movq $1, %%rdx\n" | 
|  | "vmcall\n" :: | 
|  | "m"(c) : "rdi", "rax", "rsi", "rdx"); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static void xnum(uint64_t x) | 
|  | { | 
|  | static char *hex = "0123456789abcdef"; | 
|  |  | 
|  | for (int i = 0; i < 8; i++) { | 
|  | uint8_t v = ((uint8_t*)&x)[7 - i]; | 
|  | pc(&hex[v >> 4]); | 
|  | pc(&hex[v & 0xf]); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void show(char *s) | 
|  | { | 
|  | static char *showedoff = "NULL POINTER: That's bad.\n"; | 
|  |  | 
|  | if (!s) { | 
|  | show(showedoff); | 
|  | return; | 
|  | } | 
|  | while (*s) { | 
|  | pc(s); | 
|  | s++; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* This is a small test that runs in gr0 and tests our argument setup. | 
|  | * This test can grow in capability as we find more broken bits in our | 
|  | * dune-like environment. */ | 
|  |  | 
|  | void dune_test(void *stack) | 
|  | { | 
|  | show("Hello this is dune's test\n"); | 
|  |  | 
|  | int argc; | 
|  | char **argv; | 
|  | struct elf_aux *auxv; | 
|  |  | 
|  | show("dune_test: dumping argv, env, and aux\n"); | 
|  |  | 
|  | argc = *((uint64_t*)stack); | 
|  | argv = &((char**)stack)[1]; | 
|  | show("argc: "); xnum(argc); show("\n"); | 
|  | show("argv: "); xnum((uint64_t)argv); show("\n"); | 
|  |  | 
|  | for (int i = 0; i < argc; i++, argv++) { | 
|  | show("arg["); xnum(i); show("]:"); | 
|  | show(argv[0]); | 
|  | show("\n"); | 
|  | } | 
|  | // skip the null and move on to envp. | 
|  | argv++; | 
|  | for (int i = 0; argv[0]; i++, argv++) { | 
|  | show("env["); xnum(i); show("]:"); | 
|  | show(argv[0]); | 
|  | show("\n"); | 
|  | } | 
|  | // skip the null and move on to auxv. | 
|  | argv++; | 
|  | auxv = (void *)argv; | 
|  | for (int i = 0; auxv[i].v[0]; i++) { | 
|  | show("auxv["); xnum(i); show("]:"); | 
|  | xnum(auxv[i].v[0]); show(":"); | 
|  | xnum(auxv[i].v[1]); show("\n"); | 
|  | } | 
|  | show("Done dumping [argv, env, auxv]\n"); | 
|  | show("Testing syscall extensions\n"); | 
|  | __asm__ __volatile__("movq $400, %%rax\n" | 
|  | "vmcall\n" :: ); | 
|  | hlt(); | 
|  | } | 
|  |  | 
|  | static struct option long_options[] = { | 
|  | {"aux",           required_argument, 0, 'a'}, | 
|  | {"debug",         no_argument,       0, 'd'}, | 
|  | {"memsize",       required_argument, 0, 'm'}, | 
|  | {"memstart",      required_argument, 0, 'M'}, | 
|  | {"cmdline_extra", required_argument, 0, 'c'}, | 
|  | {"greedy",        no_argument,       0, 'g'}, | 
|  | {"scp",           no_argument,       0, 's'}, | 
|  | {"test",          no_argument,       0, 't'}, | 
|  | {"help",          no_argument,       0, 'h'}, | 
|  | {0, 0, 0, 0} | 
|  | }; | 
|  |  | 
|  | static void usage(void) | 
|  | { | 
|  | // Sadly, the getopt_long struct does | 
|  | // not have a pointer to help text. | 
|  | fprintf(stderr, | 
|  | "Usage: dune [options] <ELF file] [<ELF file>...]\n"); | 
|  | fprintf(stderr, | 
|  | "Or for testing: dune -t [options]\nOptions are:\n"); | 
|  | for (int i = 0; | 
|  | i < COUNT_OF(long_options) - 1; | 
|  | i++) { | 
|  | struct option *l = &long_options[i]; | 
|  |  | 
|  | fprintf(stderr, "%s or %c%s\n", l->name, l->val, | 
|  | l->has_arg ? " <arg>" : ""); | 
|  | } | 
|  | exit(0); | 
|  | } | 
|  |  | 
|  | static struct elf_aux *getextra(int *auxc, char *_s) | 
|  | { | 
|  | struct elf_aux *auxv; | 
|  | char *s = strdup(_s); | 
|  | // icky hardcode, but realistic. | 
|  | char *auxpairs[32]; | 
|  |  | 
|  | *auxc = gettokens(s, auxpairs, 32, ","); | 
|  | if (dune_debug) | 
|  | fprintf(stderr, "Found %d extra aux pairs\n", *auxc); | 
|  | if (*auxc < 1) | 
|  | return NULL; | 
|  | auxv = malloc(sizeof(*auxv) * *auxc); | 
|  | if (!auxv) | 
|  | errx(1, "auxv malloc: %r"); | 
|  | for (int i = 0; i < *auxc; i++) { | 
|  | char *aux[2]; | 
|  | int j; | 
|  | uint32_t t, v; | 
|  |  | 
|  | j = gettokens(auxpairs[i], aux, 2, "="); | 
|  | if (j < 2) { | 
|  | fprintf(stderr, "%s: should be in the form type=val\n", | 
|  | auxpairs[i]); | 
|  | free(auxv); | 
|  | return NULL; | 
|  | } | 
|  | t = strtoul(aux[0], 0, 0); | 
|  | v = strtoul(aux[1], 0, 0); | 
|  | auxv[i].v[0] = t; | 
|  | auxv[i].v[1] = v; | 
|  | if (dune_debug) | 
|  | fprintf(stderr, "Adding aux pair 0x%x:0x%x\n", | 
|  | auxv[i].v[0], auxv[i].v[1]); | 
|  | } | 
|  | return auxv; | 
|  |  | 
|  | } | 
|  |  | 
|  | static struct elf_aux *buildaux(struct elf_aux *base, int basec, | 
|  | struct elf_aux *extra, int extrac) | 
|  | { | 
|  | int total = basec + extrac; | 
|  | struct elf_aux *ret; | 
|  |  | 
|  | ret = realloc(extra, total * sizeof(*ret)); | 
|  | if (!ret) | 
|  | return NULL; | 
|  |  | 
|  | if (dune_debug) | 
|  | fprintf(stderr, "buildaux: consolidating %d aux and %d extra\n", | 
|  | basec, extrac); | 
|  | /* TOOD: check for dups. */ | 
|  | if (basec) | 
|  | memmove(&ret[extrac], base, sizeof(*base)*basec); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | int main(int argc, char **argv) | 
|  | { | 
|  | void *tos; | 
|  | int envc, auxc, extrac = 0; | 
|  | struct elf_aux *auxv, *extra = NULL; | 
|  | uint64_t entry = 0; | 
|  | struct vthread *vth; | 
|  | struct vmm_gpcore_init gpci[1]; | 
|  | int c; | 
|  | int test = 0; | 
|  | int option_index; | 
|  | int ac = argc; | 
|  | char **av = argv; | 
|  |  | 
|  | fprintf(stderr, "%p %p %p %p\n", PGSIZE, PGSHIFT, PML1_SHIFT, | 
|  | PML1_PTE_REACH); | 
|  |  | 
|  | if ((uintptr_t)__procinfo.program_end >= MinMemory) { | 
|  | fprintf(stderr, | 
|  | "Panic: vmrunkernel binary extends into guest memory\n"); | 
|  | exit(1); | 
|  | } | 
|  |  | 
|  | while ((c = getopt_long(argc, argv, "a:dv:m:M:gsth", long_options, | 
|  | &option_index)) != -1) { | 
|  | switch (c) { | 
|  | case 'a': | 
|  | extra = getextra(&extrac, optarg); | 
|  | if (dune_debug) | 
|  | fprintf(stderr, "Added %d aux items\n", extrac); | 
|  | break; | 
|  | case 'd': | 
|  | fprintf(stderr, "SET DEBUG\n"); | 
|  | dune_debug++; | 
|  | break; | 
|  | case 'm': | 
|  | memsize = strtoull(optarg, 0, 0); | 
|  | break; | 
|  | case 'M': | 
|  | memstart = strtoull(optarg, 0, 0); | 
|  | break; | 
|  | case 'g':	/* greedy */ | 
|  | parlib_never_yield = TRUE; | 
|  | break; | 
|  | case 's':	/* scp */ | 
|  | parlib_wants_to_be_mcp = FALSE; | 
|  | break; | 
|  | case 't': | 
|  | test = 1; | 
|  | break; | 
|  | case 'h': | 
|  | default: | 
|  | usage(); | 
|  | break; | 
|  | } | 
|  | } | 
|  | argc -= optind; | 
|  | argv += optind; | 
|  | if ((!test) && (argc < 1)) { | 
|  | usage(); | 
|  | } | 
|  |  | 
|  | init_lemu_logging(dune_debug); | 
|  | init_linuxemu(); | 
|  |  | 
|  | if ((uintptr_t)(memstart + memsize) >= (uintptr_t)BRK_START) { | 
|  | fprintf(stderr, | 
|  | "memstart 0x%lx memsize 0x%lx -> 0x%lx is too large; overlaps BRK_START at %p\n", | 
|  | memstart, memsize, memstart + memsize, BRK_START); | 
|  | exit(1); | 
|  | } | 
|  |  | 
|  | mmap_memory(&vm, memstart, memsize); | 
|  |  | 
|  | if (dune_debug) | 
|  | fprintf(stderr, | 
|  | "mmap guest physical memory at %p for 0x%lx bytes\n", | 
|  | memstart, memsize); | 
|  |  | 
|  | // TODO: find out why we can't use memstart + memsize as TOS. | 
|  | tos = (void *)(memstart + 0x800000); | 
|  |  | 
|  | for (envc = 0; environ[envc]; envc++) | 
|  | ; | 
|  | auxv = (struct elf_aux *)&environ[envc+1]; | 
|  | for (auxc = 0; auxv[auxc].v[0]; auxc++) | 
|  | ; | 
|  | auxv = buildaux(auxv, auxc, extra, extrac); | 
|  | if (!auxv) { | 
|  | fprintf(stderr, "Can't build auxv: %r"); | 
|  | exit(1); | 
|  | } | 
|  | auxc = auxc + extrac; | 
|  |  | 
|  | if (!test) { | 
|  | entry = load_elf(argv[0], MinMemory, NULL, NULL); | 
|  | if (entry == 0) { | 
|  | fprintf(stderr, "Unable to load kernel %s\n", argv[0]); | 
|  | exit(1); | 
|  | } | 
|  | } else { | 
|  | fprintf(stderr, "Running dune test\n"); | 
|  | entry = (uintptr_t) dune_test; | 
|  | } | 
|  | if (dune_debug) | 
|  | fprintf(stderr, "Test: Populate stack at %p\n", tos); | 
|  | tos = populate_stack(tos, ac, av, envc, environ, auxc, auxv); | 
|  | if (dune_debug) | 
|  | fprintf(stderr, | 
|  | "populated stack at %p; argc %d, envc %d, auxc %d\n", | 
|  | tos, ac, envc, auxc); | 
|  |  | 
|  | if (dune_debug) | 
|  | fprintf(stderr, "stack is %p\n", tos); | 
|  |  | 
|  | gpci_init(gpci); | 
|  | vth = vthread_alloc(&vm, gpci); | 
|  | vthread_init_ctx(vth, entry, (uintptr_t)tos, (uintptr_t)tos); | 
|  | vthread_run(vth); | 
|  |  | 
|  | uthread_sleep_forever(); | 
|  | return 0; | 
|  | } |