6 #include <parlib/arch/arch.h>
7 #include <parlib/ros_debug.h>
15 #include <ros/syscall.h>
18 #include <vmm/acpi/acpi.h>
19 #include <vmm/acpi/vmm_simple_dsdt.h>
20 #include <ros/arch/mmu.h>
21 #include <ros/arch/membar.h>
23 #include <parlib/uthread.h>
24 #include <vmm/linux_bootparam.h>
26 #include <iplib/iplib.h>
27 #include <vmm/sched.h>
28 #include <sys/eventfd.h>
31 #include <vmm/linuxemu.h>
33 #include <vmm/vthread.h>
35 struct vmm_gpcore_init gpci;
36 bool linuxemu(struct guest_thread *gth, struct vm_trapframe *tf);
39 extern char **environ;
41 static struct virtual_machine vm = {.halt_exit = true,
42 .mtx = UTH_MUTEX_INIT,
45 static unsigned long long memsize = GiB;
46 static uintptr_t memstart = MinMemory;
48 static int dune_debug;
52 __asm__ __volatile__("\thlt\n\t");
55 static int pc(char *c)
57 __asm__ __volatile__("movq $1, %%rax\n"
62 "m"(c) : "rdi", "rax", "rsi", "rdx");
66 static void xnum(uint64_t x)
68 static char *hex = "0123456789abcdef";
70 for (int i = 0; i < 8; i++) {
71 uint8_t v = ((uint8_t*)&x)[7 - i];
77 static void show(char *s)
79 static char *showedoff = "NULL POINTER: That's bad.\n";
91 /* This is a small test that runs in gr0 and tests our argument setup.
92 * This test can grow in capability as we find more broken bits in our
93 * dune-like environment. */
95 void dune_test(void *stack)
97 show("Hello this is dune's test\n");
101 struct elf_aux *auxv;
103 show("dune_test: dumping argv, env, and aux\n");
105 argc = *((uint64_t*)stack);
106 argv = &((char**)stack)[1];
107 show("argc: "); xnum(argc); show("\n");
108 show("argv: "); xnum((uint64_t)argv); show("\n");
110 for (int i = 0; i < argc; i++, argv++) {
111 show("arg["); xnum(i); show("]:");
115 // skip the null and move on to envp.
117 for (int i = 0; argv[0]; i++, argv++) {
118 show("env["); xnum(i); show("]:");
122 // skip the null and move on to auxv.
125 for (int i = 0; auxv[i].v[0]; i++) {
126 show("auxv["); xnum(i); show("]:");
127 xnum(auxv[i].v[0]); show(":");
128 xnum(auxv[i].v[1]); show("\n");
130 show("Done dumping [argv, env, auxv]\n");
131 show("Testing syscall extensions\n");
132 __asm__ __volatile__("movq $400, %%rax\n"
137 static struct option long_options[] = {
138 {"aux", required_argument, 0, 'a'},
139 {"debug", no_argument, 0, 'd'},
140 {"memsize", required_argument, 0, 'm'},
141 {"memstart", required_argument, 0, 'M'},
142 {"cmdline_extra", required_argument, 0, 'c'},
143 {"greedy", no_argument, 0, 'g'},
144 {"scp", no_argument, 0, 's'},
145 {"test", no_argument, 0, 't'},
146 {"help", no_argument, 0, 'h'},
153 // Sadly, the getopt_long struct does
154 // not have a pointer to help text.
156 "Usage: dune [options] <ELF file] [<ELF file>...]\n");
158 "Or for testing: dune -t [options]\nOptions are:\n");
160 i < COUNT_OF(long_options) - 1;
162 struct option *l = &long_options[i];
164 fprintf(stderr, "%s or %c%s\n", l->name, l->val,
165 l->has_arg ? " <arg>" : "");
170 static struct elf_aux *
171 getextra(int *auxc, char *_s)
173 struct elf_aux *auxv;
174 char *s = strdup(_s);
175 // icky hardcode, but realistic.
178 *auxc = gettokens(s, auxpairs, 32, ",");
180 fprintf(stderr, "Found %d extra aux pairs\n", *auxc);
183 auxv = malloc(sizeof(*auxv) * *auxc);
185 errx(1, "auxv malloc: %r");
186 for (int i = 0; i < *auxc; i++) {
191 j = gettokens(auxpairs[i], aux, 2, "=");
193 fprintf(stderr, "%s: should be in the form type=val\n",
198 t = strtoul(aux[0], 0, 0);
199 v = strtoul(aux[1], 0, 0);
203 fprintf(stderr, "Adding aux pair 0x%x:0x%x\n", auxv[i].v[0],
210 static struct elf_aux *
211 buildaux(struct elf_aux *base, int basec, struct elf_aux *extra, int extrac)
213 int total = basec + extrac;
216 ret = realloc(extra, total * sizeof(*ret));
221 fprintf(stderr, "buildaux: consolidating %d aux and %d extra\n",
223 /* TOOD: check for dups. */
225 memmove(&ret[extrac], base, sizeof(*base)*basec);
229 int main(int argc, char **argv)
232 int envc, auxc, extrac = 0;
233 struct elf_aux *auxv, *extra = NULL;
236 struct vmm_gpcore_init gpci[1];
243 fprintf(stderr, "%p %p %p %p\n", PGSIZE, PGSHIFT, PML1_SHIFT,
246 if ((uintptr_t)__procinfo.program_end >= MinMemory) {
248 "Panic: vmrunkernel binary extends into guest memory\n");
252 while ((c = getopt_long(argc, argv, "a:dv:m:M:gsth", long_options,
253 &option_index)) != -1) {
256 extra = getextra(&extrac, optarg);
258 fprintf(stderr, "Added %d aux items\n", extrac);
261 fprintf(stderr, "SET DEBUG\n");
265 memsize = strtoull(optarg, 0, 0);
268 memstart = strtoull(optarg, 0, 0);
270 case 'g': /* greedy */
271 parlib_never_yield = TRUE;
274 parlib_wants_to_be_mcp = FALSE;
287 if ((!test) && (argc < 1)) {
291 init_lemu_logging(dune_debug);
292 init_syscall_table();
294 if ((uintptr_t)(memstart + memsize) >= (uintptr_t)BRK_START) {
296 "memstart 0x%lx memsize 0x%lx -> 0x%lx is too large; overlaps BRK_START at %p\n",
297 memstart, memsize, memstart + memsize, BRK_START);
301 mmap_memory(&vm, memstart, memsize);
304 fprintf(stderr, "mmap guest physical memory at %p for 0x%lx bytes\n",
307 // TODO: find out why we can't use memstart + memsize as TOS.
308 tos = (void *)(memstart + 0x800000);
310 for (envc = 0; environ[envc]; envc++)
312 auxv = (struct elf_aux *)&environ[envc+1];
313 for (auxc = 0; auxv[auxc].v[0]; auxc++)
315 auxv = buildaux(auxv, auxc, extra, extrac);
317 fprintf(stderr, "Can't build auxv: %r");
320 auxc = auxc + extrac;
323 entry = load_elf(argv[0], MinMemory, NULL, NULL);
325 fprintf(stderr, "Unable to load kernel %s\n", argv[0]);
329 fprintf(stderr, "Running dune test\n");
330 entry = (uintptr_t) dune_test;
333 fprintf(stderr, "Test: Populate stack at %p\n", tos);
334 tos = populate_stack(tos, ac, av, envc, environ, auxc, auxv);
336 fprintf(stderr, "populated stack at %p; argc %d, envc %d, auxc %d\n",
337 tos, ac, envc, auxc);
340 fprintf(stderr, "stack is %p\n", tos);
343 vth = vthread_alloc(&vm, gpci);
344 vthread_init_ctx(vth, entry, (uintptr_t)tos, (uintptr_t)tos);
347 uthread_sleep_forever();