Move ros/vmx.h to an arch-specific location (XCC)
[akaros.git] / tests / vmm / vmrunkernel.c
1 #include <stdio.h> 
2 #include <pthread.h>
3 #include <sys/types.h>
4 #include <sys/stat.h>
5 #include <fcntl.h>
6 #include <parlib/arch/arch.h>
7 #include <parlib/ros_debug.h>
8 #include <unistd.h>
9 #include <errno.h>
10 #include <dirent.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <ros/syscall.h>
14 #include <sys/mman.h>
15 #include <vmm/coreboot_tables.h>
16 #include <vmm/vmm.h>
17 #include <vmm/acpi/acpi.h>
18 #include <ros/arch/mmu.h>
19 #include <ros/vmm.h>
20 #include <parlib/uthread.h>
21 #include <vmm/virtio.h>
22 #include <vmm/virtio_mmio.h>
23 #include <vmm/virtio_ids.h>
24 #include <vmm/virtio_config.h>
25
26 int msrio(struct vmctl *vcpu, uint32_t opcode);
27
28 struct vmctl vmctl;
29
30 /* Kind of sad what a total clusterf the pc world is. By 1999, you could just scan the hardware 
31  * and work it out. But 2005, that was no longer possible. How sad. 
32  * so we have to fake acpi to make it all work. !@#$!@#$#.
33  * This will be copied to memory at 0xe0000, so the kernel can find it.
34  */
35 /* assume they're all 256 bytes long just to make it easy. Just have pointers that point to aligned things. */
36
37 struct acpi_table_rsdp rsdp = {
38         .signature = "RSD PTR ",
39         .oem_id = "AKAROS",
40         .revision = 2,
41         .length = 36,
42 };
43
44 struct acpi_table_xsdt xsdt = {
45         .header = {
46                 .signature= "XSDT",
47                 // This is so stupid. Incredibly stupid.
48                 .revision = 0,
49                 .oem_id = "AKAROS",
50                 .oem_table_id = "ALPHABET",
51                 .oem_revision = 0,
52                 .asl_compiler_id = "RON ",
53                 .asl_compiler_revision = 0,
54         },
55 };
56 struct acpi_table_fadt fadt = {
57         .header = {
58                 .signature= "FADT",
59                 // This is so stupid. Incredibly stupid.
60                 .revision = 0,
61                 .oem_id = "AKAROS",
62                 .oem_table_id = "ALPHABET",
63                 .oem_revision = 0,
64                 .asl_compiler_id = "RON ",
65                 .asl_compiler_revision = 0,
66         },
67 };
68
69 /* This has to be dropped into memory, then the other crap just follows it.
70  */
71 struct acpi_table_madt madt = {
72         .header = {
73                 .signature = "APIC",
74                 .revision = 0,
75                 .oem_id = "AKAROS",
76                 .oem_table_id = "ALPHABET",
77                 .oem_revision = 0,
78                 .asl_compiler_id = "RON ",
79                 .asl_compiler_revision = 0,
80         },
81         
82         .address = 0xfee00000ULL,
83 };
84
85 struct acpi_madt_local_apic Apic0 = {.header = {.type = ACPI_MADT_TYPE_LOCAL_APIC, .length = sizeof(struct acpi_madt_local_apic)},
86                                      .processor_id = 0, .id = 0};
87 struct acpi_madt_io_apic Apic1 = {.header = {.type = ACPI_MADT_TYPE_IO_APIC, .length = sizeof(struct acpi_madt_io_apic)},
88                                   .id = 1, .address = 0xfec00000, .global_irq_base = 0};
89 struct acpi_madt_interrupt_override isor[] = {
90         /* I have no idea if it should be source irq 2, global 0, or global 2, source 0. Shit. */
91         {.header = {.type = ACPI_MADT_TYPE_INTERRUPT_OVERRIDE, .length = sizeof(struct acpi_madt_interrupt_override)},
92          .bus = 0, .source_irq = 2, .global_irq = 0, .inti_flags = 0},
93         {.header = {.type = ACPI_MADT_TYPE_INTERRUPT_OVERRIDE, .length = sizeof(struct acpi_madt_interrupt_override)},
94          .bus = 0, .source_irq = 1, .global_irq = 1, .inti_flags = 0},
95         //{.header = {.type = ACPI_MADT_TYPE_INTERRUPT_OVERRIDE, .length = sizeof(struct acpi_madt_interrupt_override)},
96          //.bus = 0, .source_irq = 2, .global_irq = 2, .inti_flags = 0},
97         {.header = {.type = ACPI_MADT_TYPE_INTERRUPT_OVERRIDE, .length = sizeof(struct acpi_madt_interrupt_override)},
98          .bus = 0, .source_irq = 3, .global_irq = 3, .inti_flags = 0},
99         {.header = {.type = ACPI_MADT_TYPE_INTERRUPT_OVERRIDE, .length = sizeof(struct acpi_madt_interrupt_override)},
100          .bus = 0, .source_irq = 4, .global_irq = 4, .inti_flags = 0},
101         {.header = {.type = ACPI_MADT_TYPE_INTERRUPT_OVERRIDE, .length = sizeof(struct acpi_madt_interrupt_override)},
102          .bus = 0, .source_irq = 5, .global_irq = 5, .inti_flags = 0},
103         {.header = {.type = ACPI_MADT_TYPE_INTERRUPT_OVERRIDE, .length = sizeof(struct acpi_madt_interrupt_override)},
104          .bus = 0, .source_irq = 6, .global_irq = 6, .inti_flags = 0},
105         {.header = {.type = ACPI_MADT_TYPE_INTERRUPT_OVERRIDE, .length = sizeof(struct acpi_madt_interrupt_override)},
106          .bus = 0, .source_irq = 7, .global_irq = 7, .inti_flags = 0},
107         {.header = {.type = ACPI_MADT_TYPE_INTERRUPT_OVERRIDE, .length = sizeof(struct acpi_madt_interrupt_override)},
108          .bus = 0, .source_irq = 8, .global_irq = 8, .inti_flags = 0},
109         {.header = {.type = ACPI_MADT_TYPE_INTERRUPT_OVERRIDE, .length = sizeof(struct acpi_madt_interrupt_override)},
110          .bus = 0, .source_irq = 9, .global_irq = 9, .inti_flags = 0},
111         {.header = {.type = ACPI_MADT_TYPE_INTERRUPT_OVERRIDE, .length = sizeof(struct acpi_madt_interrupt_override)},
112          .bus = 0, .source_irq = 10, .global_irq = 10, .inti_flags = 0},
113         {.header = {.type = ACPI_MADT_TYPE_INTERRUPT_OVERRIDE, .length = sizeof(struct acpi_madt_interrupt_override)},
114          .bus = 0, .source_irq = 11, .global_irq = 11, .inti_flags = 0},
115         {.header = {.type = ACPI_MADT_TYPE_INTERRUPT_OVERRIDE, .length = sizeof(struct acpi_madt_interrupt_override)},
116          .bus = 0, .source_irq = 12, .global_irq = 12, .inti_flags = 0},
117         {.header = {.type = ACPI_MADT_TYPE_INTERRUPT_OVERRIDE, .length = sizeof(struct acpi_madt_interrupt_override)},
118          .bus = 0, .source_irq = 13, .global_irq = 13, .inti_flags = 0},
119         {.header = {.type = ACPI_MADT_TYPE_INTERRUPT_OVERRIDE, .length = sizeof(struct acpi_madt_interrupt_override)},
120          .bus = 0, .source_irq = 14, .global_irq = 14, .inti_flags = 0},
121         {.header = {.type = ACPI_MADT_TYPE_INTERRUPT_OVERRIDE, .length = sizeof(struct acpi_madt_interrupt_override)},
122          .bus = 0, .source_irq = 15, .global_irq = 15, .inti_flags = 0},
123         // VMMCP routes irq 32 to gsi 17
124         {.header = {.type = ACPI_MADT_TYPE_INTERRUPT_OVERRIDE, .length = sizeof(struct acpi_madt_interrupt_override)},
125          .bus = 0, .source_irq = 32, .global_irq = 17, .inti_flags = 5},
126 };
127
128
129 /* this test will run the "kernel" in the negative address space. We hope. */
130 void *low1m;
131 uint8_t low4k[4096];
132 unsigned long long stack[1024];
133 volatile int shared = 0;
134 volatile int quit = 0;
135 int mcp = 1;
136 int virtioirq = 17;
137
138 /* total hack. If the vm runs away we want to get control again. */
139 unsigned int maxresume = (unsigned int) -1;
140
141 #define MiB 0x100000u
142 #define GiB (1u<<30)
143 #define GKERNBASE (16*MiB)
144 #define KERNSIZE (128*MiB+GKERNBASE)
145 uint8_t _kernel[KERNSIZE];
146
147 unsigned long long *p512, *p1, *p2m;
148
149 void **my_retvals;
150 int nr_threads = 3;
151 int debug = 0;
152 int resumeprompt = 0;
153 /* unlike Linux, this shared struct is for both host and guest. */
154 //      struct virtqueue *constoguest = 
155 //              vring_new_virtqueue(0, 512, 8192, 0, inpages, NULL, NULL, "test");
156 uint64_t virtio_mmio_base = 0x100000000ULL;
157
158 void vapic_status_dump(FILE *f, void *vapic);
159 static void set_posted_interrupt(int vector);
160
161 #if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 1)
162 #error "Get a gcc newer than 4.4.0"
163 #else
164 #define BITOP_ADDR(x) "+m" (*(volatile long *) (x))
165 #endif
166
167 #define LOCK_PREFIX "lock "
168 #define ADDR                            BITOP_ADDR(addr)
169 static inline int test_and_set_bit(int nr, volatile unsigned long *addr);
170
171 void *consout(void *arg)
172 {
173         char *line, *consline, *outline;
174         static struct scatterlist out[] = { {NULL, sizeof(outline)}, };
175         static struct scatterlist in[] = { {NULL, sizeof(line)}, };
176         static struct scatterlist iov[32];
177         struct virtio_threadarg *a = arg;
178         static unsigned int inlen, outlen, conslen;
179         struct virtqueue *v = a->arg->virtio;
180         fprintf(stderr, "talk thread ..\n");
181         uint16_t head, gaveit = 0, gotitback = 0;
182         uint32_t vv;
183         int i;
184         int num;
185         if (debug) {
186                 fprintf(stderr, "----------------------- TT a %p\n", a);
187                 fprintf(stderr, "talk thread ttargs %x v %x\n", a, v);
188         }
189         
190         for(num = 0;;num++) {
191                 //int debug = 1;
192                 /* host: use any buffers we should have been sent. */
193                 head = wait_for_vq_desc(v, iov, &outlen, &inlen);
194                 if (debug)
195                         fprintf(stderr, "CCC: vq desc head %d, gaveit %d gotitback %d\n", head, gaveit, gotitback);
196                 for(i = 0; debug && i < outlen + inlen; i++)
197                         fprintf(stderr, "CCC: v[%d/%d] v %p len %d\n", i, outlen + inlen, iov[i].v, iov[i].length);
198                 /* host: if we got an output buffer, just output it. */
199                 for(i = 0; i < outlen; i++) {
200                         num++;
201                         int j;
202                         if (debug) {
203                                 fprintf(stderr, "CCC: IOV length is %d\n", iov[i].length);
204                         }
205                         for (j = 0; j < iov[i].length; j++)
206                                 printf("%c", ((char *)iov[i].v)[j]);
207                 }
208                 fflush(stdout);
209                 if (debug)
210                         fprintf(stderr, "CCC: outlen is %d; inlen is %d\n", outlen, inlen);
211                 /* host: fill in the writeable buffers. */
212                 /* why we're getting these I don't know. */
213                 for (i = outlen; i < outlen + inlen; i++) {
214                         if (debug) fprintf(stderr, "CCC: send back empty writeable");
215                         iov[i].length = 0;
216                 }
217                 if (debug) fprintf(stderr, "CCC: call add_used\n");
218                 /* host: now ack that we used them all. */
219                 add_used(v, head, outlen+inlen);
220                 if (debug) fprintf(stderr, "CCC: DONE call add_used\n");
221         }
222         fprintf(stderr, "All done\n");
223         return NULL;
224 }
225
226 // FIXME. 
227 volatile int consdata = 0;
228
229 void *consin(void *arg)
230 {
231         struct virtio_threadarg *a = arg;
232         char *line, *outline;
233         static char consline[128];
234         static struct scatterlist iov[32];
235         static struct scatterlist out[] = { {NULL, sizeof(outline)}, };
236         static struct scatterlist in[] = { {NULL, sizeof(line)}, };
237
238         static unsigned int inlen, outlen, conslen;
239         struct virtqueue *v = a->arg->virtio;
240         fprintf(stderr, "consin thread ..\n");
241         uint16_t head, gaveit = 0, gotitback = 0;
242         uint32_t vv;
243         int i;
244         int num;
245         //char c[1];
246
247         int fd = open("#cons/vmctl", O_RDWR), ret;
248         
249         if (debug) fprintf(stderr, "Spin on console being read, print num queues, halt\n");
250
251         for(num = 0;! quit;num++) {
252                 //int debug = 1;
253                 /* host: use any buffers we should have been sent. */
254                 head = wait_for_vq_desc(v, iov, &outlen, &inlen);
255                 if (debug)
256                         fprintf(stderr, "vq desc head %d, gaveit %d gotitback %d\n", head, gaveit, gotitback);
257                 for(i = 0; debug && i < outlen + inlen; i++)
258                         fprintf(stderr, "v[%d/%d] v %p len %d\n", i, outlen + inlen, iov[i].v, iov[i].length);
259                 if (debug)
260                         fprintf(stderr, "outlen is %d; inlen is %d\n", outlen, inlen);
261                 /* host: fill in the writeable buffers. */
262                 for (i = outlen; i < outlen + inlen; i++) {
263                         /* host: read a line. */
264                         memset(consline, 0, 128);
265                         if (read(0, consline, 1) < 0) {
266                                 exit(0);
267                         } 
268                         if (debug) fprintf(stderr, "CONSIN: GOT A LINE:%s:\n", consline);
269                         if (debug) fprintf(stderr, "CONSIN: OUTLEN:%d:\n", outlen);
270                         if (strlen(consline) < 3 && consline[0] == 'q' ) {
271                                 quit = 1;
272                                 break;
273                         }
274
275                         memmove(iov[i].v, consline, strlen(consline)+ 1);
276                         iov[i].length = strlen(consline) + 1;
277                 }
278                 if (debug) fprintf(stderr, "call add_used\n");
279                 /* host: now ack that we used them all. */
280                 add_used(v, head, outlen+inlen);
281                 consdata = 1;
282                 if (debug) fprintf(stderr, "DONE call add_used\n");
283
284                 // Send spurious for testing (Gan)
285                 set_posted_interrupt(0xE5);
286                 virtio_mmio_set_vring_irq();
287
288                 pwrite(fd, &vmctl, sizeof(vmctl), 1<<12);
289         }
290         fprintf(stderr, "All done\n");
291         return NULL;
292 }
293
294 static struct vqdev vqdev= {
295 name: "console",
296 dev: VIRTIO_ID_CONSOLE,
297 device_features: 0, /* Can't do it: linux console device does not support it. VIRTIO_F_VERSION_1*/
298 numvqs: 2,
299 vqs: {
300                 {name: "consin", maxqnum: 64, f: consin, arg: (void *)0},
301                 {name: "consout", maxqnum: 64, f: consout, arg: (void *)0},
302         }
303 };
304
305 void lowmem() {
306         __asm__ __volatile__ (".section .lowmem, \"aw\"\n\tlow: \n\t.=0x1000\n\t.align 0x100000\n\t.previous\n");
307 }
308
309 static uint8_t acpi_tb_checksum(uint8_t *buffer, uint32_t length)
310 {
311         uint8_t sum = 0;
312         uint8_t *end = buffer + length;
313         fprintf(stderr, "tbchecksum %p for %d", buffer, length);
314         while (buffer < end) {
315                 if (end - buffer < 2)
316                         fprintf(stderr, "%02x\n", sum);
317                 sum = (uint8_t)(sum + *(buffer++));
318         }
319         fprintf(stderr, " is %02x\n", sum);
320         return (sum);
321 }
322
323 static void gencsum(uint8_t *target, void *data, int len)
324 {
325         uint8_t csum;
326         // blast target to zero so it does not get counted (it might be in the struct we checksum) 
327         // And, yes, it is, goodness.
328         fprintf(stderr, "gencsum %p target %p source %d bytes\n", target, data, len);
329         *target = 0;
330         csum  = acpi_tb_checksum((uint8_t *)data, len);
331         *target = ~csum + 1;
332         fprintf(stderr, "Cmoputed is %02x\n", *target);
333 }
334
335 static inline int test_and_set_bit(int nr, volatile unsigned long *addr)
336 {
337         int oldbit;
338
339         asm volatile(LOCK_PREFIX "bts %2,%1\n\t"
340                      "sbb %0,%0" : "=r" (oldbit), ADDR : "Ir" (nr) : "memory");
341
342         return oldbit;
343 }
344
345 static void pir_dump()
346 {
347         unsigned long *pir_ptr = (unsigned long *)vmctl.pir;
348         int i;
349         fprintf(stderr, "-------Begin PIR dump-------\n");
350         for (i = 0; i < 8; i++){
351                 fprintf(stderr, "Byte %d: 0x%016x\n", i, pir_ptr[i]);
352         }
353         fprintf(stderr, "-------End PIR dump-------\n");
354 }
355
356 static void set_posted_interrupt(int vector)
357 {
358         unsigned long *bit_vec;
359         int bit_offset;
360         int i, j;
361         unsigned long *pir = (unsigned long *)vmctl.pir;
362         // Move to the correct location to set our bit.
363         bit_vec = pir + vector/(sizeof(unsigned long)*8);
364         bit_offset = vector%(sizeof(unsigned long)*8);
365         if(debug) fprintf(stderr, "%s: Pre set PIR dump\n", __func__);
366         if(debug) pir_dump();
367         if(debug) vapic_status_dump(stderr, (void *)vmctl.vapic);
368         if(debug) fprintf(stderr, "%s: Setting pir bit offset %d at 0x%p\n", __func__,
369                         bit_offset, bit_vec);
370         test_and_set_bit(bit_offset, bit_vec);
371
372         // Set outstanding notification bit
373         /*bit_vec = pir + 4;
374         fprintf(stderr, "%s: Setting pir bit offset 0 at 0x%p", __func__,
375                         bit_vec);
376         test_and_set_bit(0, bit_vec);*/
377
378         if(debug) pir_dump();
379 }
380
381 int main(int argc, char **argv)
382 {
383         uint64_t *p64;
384         void *a = (void *)0xe0000;
385         struct acpi_table_rsdp *r;
386         struct acpi_table_fadt *f;
387         struct acpi_table_madt *m;
388         struct acpi_table_xsdt *x;
389         uint64_t virtiobase = 0x100000000ULL;
390         // lowmem is a bump allocated pointer to 2M at the "physbase" of memory 
391         void *lowmem = (void *) 0x1000000;
392         //struct vmctl vmctl;
393         int amt;
394         int vmmflags = 0; // Disabled probably forever. VMM_VMCALL_PRINTF;
395         uint64_t entry = 0x1200000, kerneladdress = 0x1200000;
396         int nr_gpcs = 1;
397         int fd = open("#cons/vmctl", O_RDWR), ret;
398         void * xp;
399         int kfd = -1;
400         static char cmd[512];
401         int i;
402         uint8_t csum;
403         void *coreboot_tables = (void *) 0x1165000;
404         void *a_page;
405 fprintf(stderr, "%p %p %p %p\n", PGSIZE, PGSHIFT, PML1_SHIFT, PML1_PTE_REACH);
406
407         // mmap is not working for us at present.
408         if ((uint64_t)_kernel > GKERNBASE) {
409                 fprintf(stderr, "kernel array @%p is above , GKERNBASE@%p sucks\n", _kernel, GKERNBASE);
410                 exit(1);
411         }
412         memset(_kernel, 0, sizeof(_kernel));
413         memset(lowmem, 0xff, 2*1048576);
414         memset(low4k, 0xff, 4096);
415         // avoid at all costs, requires too much instruction emulation.
416         //low4k[0x40e] = 0;
417         //low4k[0x40f] = 0xe0;
418
419         //Place mmap(Gan)
420         a_page = mmap((void *)0xfee00000, PGSIZE, PROT_READ | PROT_WRITE,
421                               MAP_POPULATE | MAP_ANONYMOUS, -1, 0);
422         fprintf(stderr, "a_page mmap pointer %p", a_page);
423
424         if (a_page == (void *) -1) {
425                 perror("Could not mmap APIC");
426                 exit(1);
427         }
428         if (((uint64_t)a_page & 0xfff) != 0) {
429                 perror("APIC page mapping is not page aligned");
430                 exit(1);
431         }
432
433         memset(a_page, 0, 4096);
434         //((uint32_t *)a_page)[0x30/4] = 0x01060015;
435         ((uint32_t *)a_page)[0x30/4] = 0xDEADBEEF;
436
437
438         if (fd < 0) {
439                 perror("#cons/sysctl");
440                 exit(1);
441         }
442         argc--,argv++;
443         // switches ...
444         // Sorry, I don't much like the gnu opt parsing code.
445         while (1) {
446                 if (*argv[0] != '-')
447                         break;
448                 switch(argv[0][1]) {
449                 case 'd':
450                         debug++;
451                         break;
452                 case 'v':
453                         vmmflags |= VMM_VMCALL_PRINTF;
454                         break;
455                 case 'm':
456                         argc--,argv++;
457                         maxresume = strtoull(argv[0], 0, 0);
458                         break;
459                 case 'i':
460                         argc--,argv++;
461                         virtioirq = strtoull(argv[0], 0, 0);
462                         break;
463                 default:
464                         fprintf(stderr, "BMAFR\n");
465                         break;
466                 }
467                 argc--,argv++;
468         }
469         if (argc < 1) {
470                 fprintf(stderr, "Usage: %s vmimage [-n (no vmcall printf)] [coreboot_tables [loadaddress [entrypoint]]]\n", argv[0]);
471                 exit(1);
472         }
473         if (argc > 1)
474                 coreboot_tables = (void *) strtoull(argv[1], 0, 0);
475         if (argc > 2)
476                 kerneladdress = strtoull(argv[2], 0, 0);
477         if (argc > 3)
478                 entry = strtoull(argv[3], 0, 0);
479         kfd = open(argv[0], O_RDONLY);
480         if (kfd < 0) {
481                 perror(argv[0]);
482                 exit(1);
483         }
484         // read in the kernel.
485         xp = (void *)kerneladdress;
486         for(;;) {
487                 amt = read(kfd, xp, 1048576);
488                 if (amt < 0) {
489                         perror("read");
490                         exit(1);
491                 }
492                 if (amt == 0) {
493                         break;
494                 }
495                 xp += amt;
496         }
497         fprintf(stderr, "Read in %d bytes\n", xp-kerneladdress);
498         close(kfd);
499
500         // The low 1m so we can fill in bullshit like ACPI. */
501         // And, sorry, due to the STUPID format of the RSDP for now we need the low 1M.
502         low1m = mmap((int*)4096, MiB-4096, PROT_READ | PROT_WRITE,
503                          MAP_ANONYMOUS, -1, 0);
504         if (low1m != (void *)4096) {
505                 perror("Unable to mmap low 1m");
506                 exit(1);
507         }
508         memset(low1m, 0xff, MiB-4096);
509         r = a;
510         fprintf(stderr, "install rsdp to %p\n", r);
511         *r = rsdp;
512         a += sizeof(*r);
513         memmove(&r->xsdt_physical_address, &a, sizeof(a));
514         gencsum(&r->checksum, r, ACPI_RSDP_CHECKSUM_LENGTH);
515         if ((csum = acpi_tb_checksum((uint8_t *) r, ACPI_RSDP_CHECKSUM_LENGTH)) != 0) {
516                 fprintf(stderr, "RSDP has bad checksum; summed to %x\n", csum);
517                 exit(1);
518         }
519
520         /* Check extended checksum if table version >= 2 */
521         gencsum(&r->extended_checksum, r, ACPI_RSDP_XCHECKSUM_LENGTH);
522         if ((rsdp.revision >= 2) &&
523             (acpi_tb_checksum((uint8_t *) r, ACPI_RSDP_XCHECKSUM_LENGTH) != 0)) {
524                 fprintf(stderr, "RSDP has bad checksum v2\n");
525                 exit(1);
526         }
527
528         /* just leave a bunch of space for the xsdt. */
529         /* we need to zero the area since it has pointers. */
530         x = a;
531         a += sizeof(*x) + 8*sizeof(void *);
532         memset(x, 0, a - (void *)x);
533         fprintf(stderr, "install xsdt to %p\n", x);
534         *x = xsdt;
535         x->table_offset_entry[0] = 0;
536         x->table_offset_entry[1] = 0;
537         x->header.length = a - (void *)x;
538
539         f = a;
540         fprintf(stderr, "install fadt to %p\n", f);
541         *f = fadt;
542         x->table_offset_entry[2] = (uint64_t) f;
543         a += sizeof(*f);
544         f->header.length = a - (void *)f;
545         gencsum(&f->header.checksum, f, f->header.length);
546         if (acpi_tb_checksum((uint8_t *)f, f->header.length) != 0) {
547                 fprintf(stderr, "ffadt has bad checksum v2\n");
548                 exit(1);
549         }
550
551         m = a;
552         *m = madt;
553         x->table_offset_entry[3] = (uint64_t) m;
554         a += sizeof(*m);
555         fprintf(stderr, "install madt to %p\n", m);
556         memmove(a, &Apic0, sizeof(Apic0));
557         a += sizeof(Apic0);
558         memmove(a, &Apic1, sizeof(Apic1));
559         a += sizeof(Apic1);
560         memmove(a, &isor, sizeof(isor));
561         a += sizeof(isor);
562         m->header.length = a - (void *)m;
563         gencsum(&m->header.checksum, m, m->header.length);
564         if (acpi_tb_checksum((uint8_t *) m, m->header.length) != 0) {
565                 fprintf(stderr, "madt has bad checksum v2\n");
566                 exit(1);
567         }
568         fprintf(stderr, "allchecksums ok\n");
569
570         gencsum(&x->header.checksum, x, x->header.length);
571         if ((csum = acpi_tb_checksum((uint8_t *) x, x->header.length)) != 0) {
572                 fprintf(stderr, "XSDT has bad checksum; summed to %x\n", csum);
573                 exit(1);
574         }
575
576         hexdump(stdout, r, a-(void *)r);
577
578         a = (void *)(((unsigned long)a + 0xfff) & ~0xfff);
579         vmctl.pir = (uint64_t) a;
580         memset(a, 0, 4096);
581         a += 4096;
582         vmctl.vapic = (uint64_t) a;
583         //vmctl.vapic = (uint64_t) a_page;      
584         memset(a, 0, 4096);
585         ((uint32_t *)a)[0x30/4] = 0x01060014;
586         p64 = a;
587         // set up apic values? do we need to?
588         // qemu does this.
589         //((uint8_t *)a)[4] = 1;
590         a += 4096;
591
592         if (ros_syscall(SYS_setup_vmm, nr_gpcs, vmmflags, 0, 0, 0, 0) != nr_gpcs) {
593                 perror("Guest pcore setup failed");
594                 exit(1);
595         }
596
597         fprintf(stderr, "Run with %d cores and vmmflags 0x%x\n", nr_gpcs, vmmflags);
598         mcp = 1;
599         if (mcp) {
600                 my_retvals = malloc(sizeof(void*) * nr_threads);
601                 if (!my_retvals)
602                         perror("Init threads/malloc");
603
604                 pthread_can_vcore_request(FALSE);       /* 2LS won't manage vcores */
605                 pthread_need_tls(FALSE);
606                 pthread_mcp_init();                                     /* gives us one vcore */
607                 vcore_request(nr_threads - 1);          /* ghetto incremental interface */
608                 for (int i = 0; i < nr_threads; i++) {
609                         xp = __procinfo.vcoremap;
610                         fprintf(stderr, "%p\n", __procinfo.vcoremap);
611                         fprintf(stderr, "Vcore %d mapped to pcore %d\n", i,
612                                 __procinfo.vcoremap[i].pcoreid);
613                 }
614         }
615
616         ret = syscall(33, 1);
617         if (ret < 0) {
618                 perror("vm setup");
619                 exit(1);
620         }
621         ret = posix_memalign((void **)&p512, 4096, 3*4096);
622         fprintf(stderr, "memalign is %p\n", p512);
623         if (ret) {
624                 perror("ptp alloc");
625                 exit(1);
626         }
627         p1 = &p512[512];
628         p2m = &p512[1024];
629         uint64_t kernbase = 0; //0xffffffff80000000;
630         uint64_t highkernbase = 0xffffffff80000000;
631         p512[PML4(kernbase)] = (unsigned long long)p1 | 7;
632         p1[PML3(kernbase)] = /*0x87; */(unsigned long long)p2m | 7;
633         p512[PML4(highkernbase)] = (unsigned long long)p1 | 7;
634         p1[PML3(highkernbase)] = /*0x87; */(unsigned long long)p2m | 7;
635 #define _2MiB (0x200000)
636
637         for (i = 0; i < 512; i++) {
638                 p2m[PML2(kernbase + i * _2MiB)] = 0x87 | i * _2MiB;
639         }
640
641         kernbase >>= (0+12);
642         kernbase <<= (0 + 12);
643         uint8_t *kernel = (void *)GKERNBASE;
644         //write_coreboot_table(coreboot_tables, ((void *)VIRTIOBASE) /*kernel*/, KERNSIZE + 1048576);
645         hexdump(stdout, coreboot_tables, 512);
646         fprintf(stderr, "kernbase for pml4 is 0x%llx and entry is %llx\n", kernbase, entry);
647         fprintf(stderr, "p512 %p p512[0] is 0x%lx p1 %p p1[0] is 0x%x\n", p512, p512[0], p1, p1[0]);
648         vmctl.interrupt = 0;
649         vmctl.command = REG_RSP_RIP_CR3;
650         vmctl.cr3 = (uint64_t) p512;
651         vmctl.regs.tf_rip = entry;
652         vmctl.regs.tf_rsp = (uint64_t) &stack[1024];
653         if (mcp) {
654                 /* set up virtio bits, which depend on threads being enabled. */
655                 register_virtio_mmio(&vqdev, virtio_mmio_base);
656         }
657         fprintf(stderr, "threads started\n");
658         fprintf(stderr, "Writing command :%s:\n", cmd);
659         
660         if(debug) vapic_status_dump(stderr, (void *)vmctl.vapic);
661
662         ret = pwrite(fd, &vmctl, sizeof(vmctl), 0);
663
664         if(debug) vapic_status_dump(stderr, (void *)vmctl.vapic);
665
666         if (ret != sizeof(vmctl)) {
667                 perror(cmd);
668         }
669         while (1) {
670                 void showstatus(FILE *f, struct vmctl *v);
671                 int c;
672                 uint8_t byte;
673                 vmctl.command = REG_RIP;
674                 if (maxresume-- == 0) {
675                         debug = 1;
676                         resumeprompt = 1;
677                 }
678                 if (debug) {
679                         fprintf(stderr, "RIP %p, shutdown 0x%x\n", vmctl.regs.tf_rip, vmctl.shutdown);
680                         showstatus(stderr, &vmctl);
681                 }
682                 if (resumeprompt) {
683                         fprintf(stderr, "RESUME?\n");
684                         c = getchar();
685                         if (c == 'q')
686                                 break;
687                 }
688                 if (vmctl.shutdown == SHUTDOWN_EPT_VIOLATION) {
689                         uint64_t gpa, *regp, val;
690                         uint8_t regx;
691                         int store, size;
692                         int advance;
693                         if (decode(&vmctl, &gpa, &regx, &regp, &store, &size, &advance)) {
694                                 fprintf(stderr, "RIP %p, shutdown 0x%x\n", vmctl.regs.tf_rip, vmctl.shutdown);
695                                 showstatus(stderr, &vmctl);
696                                 quit = 1;
697                                 break;
698                         }
699                         if (debug) fprintf(stderr, "%p %p %p %p %p %p\n", gpa, regx, regp, store, size, advance);
700                         if ((gpa & ~0xfffULL) == virtiobase) {
701                                 if (debug) fprintf(stderr, "DO SOME VIRTIO\n");
702                                 // Lucky for us the various virtio ops are well-defined.
703                                 virtio_mmio(&vmctl, gpa, regx, regp, store);
704                                 if (debug) fprintf(stderr, "store is %d:\n", store);
705                                 if (debug) fprintf(stderr, "REGP IS %16x:\n", *regp);
706                         } else if ((gpa & 0xfee00000) == 0xfee00000) {
707                                 // until we fix our include mess, just put the proto here.
708                                 //int apic(struct vmctl *v, uint64_t gpa, int destreg, uint64_t *regp, int store);
709                                 //apic(&vmctl, gpa, regx, regp, store);
710                         } else if ((gpa & 0xfec00000) == 0xfec00000) {
711                                 // until we fix our include mess, just put the proto here.
712                                 int do_ioapic(struct vmctl *v, uint64_t gpa, int destreg, uint64_t *regp, int store);
713                                 do_ioapic(&vmctl, gpa, regx, regp, store);
714                         } else if (gpa < 4096) {
715                                 uint64_t val = 0;
716                                 memmove(&val, &low4k[gpa], size);
717                                 hexdump(stdout, &low4k[gpa], size);
718                                 fprintf(stderr, "Low 1m, code %p read @ %p, size %d, val %p\n", vmctl.regs.tf_rip, gpa, size, val);
719                                 memmove(regp, &low4k[gpa], size);
720                                 hexdump(stdout, regp, size);
721                         } else {
722                                 fprintf(stderr, "EPT violation: can't handle %p\n", gpa);
723                                 fprintf(stderr, "RIP %p, shutdown 0x%x\n", vmctl.regs.tf_rip, vmctl.shutdown);
724                                 fprintf(stderr, "Returning 0xffffffff\n");
725                                 showstatus(stderr, &vmctl);
726                                 // Just fill the whole register for now.
727                                 *regp = (uint64_t) -1;
728                         }
729                         vmctl.regs.tf_rip += advance;
730                         if (debug) fprintf(stderr, "Advance rip by %d bytes to %p\n", advance, vmctl.regs.tf_rip);
731                         vmctl.shutdown = 0;
732                         vmctl.gpa = 0;
733                         vmctl.command = REG_ALL;
734                 } else if (vmctl.shutdown == SHUTDOWN_UNHANDLED_EXIT_REASON) {
735                         switch(vmctl.ret_code){
736                         case  EXIT_REASON_VMCALL:
737                                 byte = vmctl.regs.tf_rdi;
738                                 printf("%c", byte);
739                                 if (byte == '\n') printf("%c", '%');
740                                 vmctl.regs.tf_rip += 3;
741                                 break;
742                         case EXIT_REASON_EXTERNAL_INTERRUPT:
743                                 //debug = 1;
744                                 if (debug) fprintf(stderr, "XINT 0x%x 0x%x\n", vmctl.intrinfo1, vmctl.intrinfo2);
745                                 if (debug) pir_dump();
746                                 vmctl.command = RESUME;
747                                 break;
748                         case EXIT_REASON_IO_INSTRUCTION:
749                                 fprintf(stderr, "IO @ %p\n", vmctl.regs.tf_rip);
750                                 io(&vmctl);
751                                 vmctl.shutdown = 0;
752                                 vmctl.gpa = 0;
753                                 vmctl.command = REG_ALL;
754                                 break;
755                         case EXIT_REASON_INTERRUPT_WINDOW:
756                                 if (consdata) {
757                                         if (debug) fprintf(stderr, "inject an interrupt\n");
758                                         virtio_mmio_set_vring_irq();
759                                         vmctl.interrupt = 0x80000000 | virtioirq;
760                                         vmctl.command = RESUME;
761                                         consdata = 0;
762                                 }
763                                 break;
764                         case EXIT_REASON_MSR_WRITE:
765                         case EXIT_REASON_MSR_READ:
766                                 fprintf(stderr, "Do an msr\n");
767                                 quit = msrio(&vmctl, vmctl.ret_code);
768                                 if (quit) {
769                                         fprintf(stderr, "MSR FAILED: RIP %p, shutdown 0x%x\n", vmctl.regs.tf_rip, vmctl.shutdown);
770                                         showstatus(stderr, &vmctl);
771                                 }
772                                 break;
773                         case EXIT_REASON_MWAIT_INSTRUCTION:
774                           fflush(stdout);
775                                 if (debug)fprintf(stderr, "\n================== Guest MWAIT. =======================\n");
776                                 if (debug)fprintf(stderr, "Wait for cons data\n");
777                                 while (!consdata)
778                                         ;
779                                 //debug = 1;
780                                 if(debug) vapic_status_dump(stderr, (void *)vmctl.vapic);
781                                 if (debug)fprintf(stderr, "Resume with consdata ...\n");
782                                 vmctl.regs.tf_rip += 3;
783                                 ret = pwrite(fd, &vmctl, sizeof(vmctl), 0);
784                                 if (ret != sizeof(vmctl)) {
785                                         perror(cmd);
786                                 }
787                                 //fprintf(stderr, "RIP %p, shutdown 0x%x\n", vmctl.regs.tf_rip, vmctl.shutdown);
788                                 //showstatus(stderr, &vmctl);
789                                 break;
790                         case EXIT_REASON_HLT:
791                                 fflush(stdout);
792                                 if (debug)fprintf(stderr, "\n================== Guest halted. =======================\n");
793                                 if (debug)fprintf(stderr, "Wait for cons data\n");
794                                 while (!consdata)
795                                         ;
796                                 //debug = 1;
797                                 if (debug)fprintf(stderr, "Resume with consdata ...\n");
798                                 vmctl.regs.tf_rip += 1;
799                                 ret = pwrite(fd, &vmctl, sizeof(vmctl), 0);
800                                 if (ret != sizeof(vmctl)) {
801                                         perror(cmd);
802                                 }
803                                 //fprintf(stderr, "RIP %p, shutdown 0x%x\n", vmctl.regs.tf_rip, vmctl.shutdown);
804                                 //showstatus(stderr, &vmctl);
805                                 break;
806                         case EXIT_REASON_APIC_ACCESS:                           
807                                 if (1 || debug)fprintf(stderr, "APIC READ EXIT\n");
808                                 
809                                 uint64_t gpa, *regp, val;
810                                 uint8_t regx;
811                                 int store, size;
812                                 int advance;
813                                 if (decode(&vmctl, &gpa, &regx, &regp, &store, &size, &advance)) {
814                                         fprintf(stderr, "RIP %p, shutdown 0x%x\n", vmctl.regs.tf_rip, vmctl.shutdown);
815                                         showstatus(stderr, &vmctl);
816                                         quit = 1;
817                                         break;
818                                 }
819
820                                 int apic(struct vmctl *v, uint64_t gpa, int destreg, uint64_t *regp, int store);
821                                 apic(&vmctl, gpa, regx, regp, store);
822                                 vmctl.regs.tf_rip += advance;
823                                 if (debug) fprintf(stderr, "Advance rip by %d bytes to %p\n", advance, vmctl.regs.tf_rip);
824                                 vmctl.shutdown = 0;
825                                 vmctl.gpa = 0;
826                                 vmctl.command = REG_ALL;
827                                 break;
828                         case EXIT_REASON_APIC_WRITE:
829                                 if (1 || debug)fprintf(stderr, "APIC WRITE EXIT\n");
830                                 break;
831                         default:
832                                 fprintf(stderr, "Don't know how to handle exit %d\n", vmctl.ret_code);
833                                 fprintf(stderr, "RIP %p, shutdown 0x%x\n", vmctl.regs.tf_rip, vmctl.shutdown);
834                                 showstatus(stderr, &vmctl);
835                                 quit = 1;
836                                 break;
837                         }
838                 }
839                 if (debug) fprintf(stderr, "at bottom of switch, quit is %d\n", quit);
840                 if (quit)
841                         break;
842                 if (consdata) {
843                         if (debug) fprintf(stderr, "inject an interrupt\n");
844                         if (debug) fprintf(stderr, "XINT 0x%x 0x%x\n", vmctl.intrinfo1, vmctl.intrinfo2);
845                         vmctl.interrupt = 0x80000000 | virtioirq;
846                         virtio_mmio_set_vring_irq();
847                         consdata = 0;
848                         //debug = 1;
849                         vmctl.command = RESUME;
850                 }
851                 if (debug) fprintf(stderr, "NOW DO A RESUME\n");
852                 ret = pwrite(fd, &vmctl, sizeof(vmctl), 0);
853                 if (ret != sizeof(vmctl)) {
854                         perror(cmd);
855                 }
856         }
857
858         /* later. 
859         for (int i = 0; i < nr_threads-1; i++) {
860                 int ret;
861                 if (pthread_join(my_threads[i], &my_retvals[i]))
862                         perror("pth_join failed");
863                 fprintf(stderr, "%d %d\n", i, ret);
864         }
865  */
866
867         fflush(stdout);
868         exit(0);
869 }