EOI virtualization and virtual APIC success.
[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/vmx.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 = 0x100000000;
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                 
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         
246         if (debug) fprintf(stderr, "Spin on console being read, print num queues, halt\n");
247
248         for(num = 0;! quit;num++) {
249                 int debug = 1;
250                 /* host: use any buffers we should have been sent. */
251                 head = wait_for_vq_desc(v, iov, &outlen, &inlen);
252                 if (debug)
253                         fprintf(stderr, "vq desc head %d, gaveit %d gotitback %d\n", head, gaveit, gotitback);
254                 for(i = 0; debug && i < outlen + inlen; i++)
255                         fprintf(stderr, "v[%d/%d] v %p len %d\n", i, outlen + inlen, iov[i].v, iov[i].length);
256                 if (debug)
257                         fprintf(stderr, "outlen is %d; inlen is %d\n", outlen, inlen);
258                 /* host: fill in the writeable buffers. */
259                 for (i = outlen; i < outlen + inlen; i++) {
260                         /* host: read a line. */
261                         memset(consline, 0, 128);
262                         if (fgets(consline, 4096-256, stdin) == NULL) {
263                                 exit(0);
264                         } 
265                         if (debug) fprintf(stderr, "CONSIN: GOT A LINE:%s:\n", consline);
266                         if (debug) fprintf(stderr, "CONSIN: OUTLEN:%d:\n", outlen);
267                         if (strlen(consline) < 3 && consline[0] == 'q' ) {
268                                 quit = 1;
269                                 break;
270                         }
271
272                         memmove(iov[i].v, consline, strlen(consline)+ 1);
273                         iov[i].length = strlen(consline) + 1;
274                 }
275                 if (debug) fprintf(stderr, "call add_used\n");
276                 /* host: now ack that we used them all. */
277                 add_used(v, head, outlen+inlen);
278                 consdata = 1;
279                 if (debug) fprintf(stderr, "DONE call add_used\n");
280
281                 // Send spurious for testing (Gan)
282                 set_posted_interrupt(0xE5);
283                 virtio_mmio_set_vring_irq();
284         }
285         fprintf(stderr, "All done\n");
286         return NULL;
287 }
288
289 static struct vqdev vqdev= {
290 name: "console",
291 dev: VIRTIO_ID_CONSOLE,
292 device_features: 0, /* Can't do it: linux console device does not support it. VIRTIO_F_VERSION_1*/
293 numvqs: 2,
294 vqs: {
295                 {name: "consin", maxqnum: 64, f: consin, arg: (void *)0},
296                 {name: "consout", maxqnum: 64, f: consout, arg: (void *)0},
297         }
298 };
299
300 void lowmem() {
301         __asm__ __volatile__ (".section .lowmem, \"aw\"\n\tlow: \n\t.=0x1000\n\t.align 0x100000\n\t.previous\n");
302 }
303
304 static uint8_t acpi_tb_checksum(uint8_t *buffer, uint32_t length)
305 {
306         uint8_t sum = 0;
307         uint8_t *end = buffer + length;
308         fprintf(stderr, "tbchecksum %p for %d", buffer, length);
309         while (buffer < end) {
310                 if (end - buffer < 2)
311                         fprintf(stderr, "%02x\n", sum);
312                 sum = (uint8_t)(sum + *(buffer++));
313         }
314         fprintf(stderr, " is %02x\n", sum);
315         return (sum);
316 }
317
318 static void gencsum(uint8_t *target, void *data, int len)
319 {
320         uint8_t csum;
321         // blast target to zero so it does not get counted (it might be in the struct we checksum) 
322         // And, yes, it is, goodness.
323         fprintf(stderr, "gencsum %p target %p source %d bytes\n", target, data, len);
324         *target = 0;
325         csum  = acpi_tb_checksum((uint8_t *)data, len);
326         *target = ~csum + 1;
327         fprintf(stderr, "Cmoputed is %02x\n", *target);
328 }
329
330 static inline int test_and_set_bit(int nr, volatile unsigned long *addr)
331 {
332         int oldbit;
333
334         asm volatile(LOCK_PREFIX "bts %2,%1\n\t"
335                      "sbb %0,%0" : "=r" (oldbit), ADDR : "Ir" (nr) : "memory");
336
337         return oldbit;
338 }
339
340 static void pir_dump()
341 {
342         unsigned long *pir_ptr = (unsigned long *)vmctl.pir;
343         int i;
344         fprintf(stderr, "-------Begin PIR dump-------\n");
345         for (i = 0; i < 8; i++){
346                 fprintf(stderr, "Byte %d: 0x%016x\n", i, pir_ptr[i]);
347         }
348         fprintf(stderr, "-------End PIR dump-------\n");
349 }
350
351 static void set_posted_interrupt(int vector)
352 {
353         unsigned long *bit_vec;
354         int bit_offset;
355         int i, j;
356         unsigned long *pir = (unsigned long *)vmctl.pir;
357         // Move to the correct location to set our bit.
358         bit_vec = pir + vector/(sizeof(unsigned long)*8);
359         bit_offset = vector%(sizeof(unsigned long)*8);
360         fprintf(stderr, "%s: Pre set PIR dump", __func__);
361         pir_dump();
362         vapic_status_dump(stderr, (void *)vmctl.vapic);
363         fprintf(stderr, "%s: Setting pir bit offset %d at 0x%p", __func__,
364                         bit_offset, bit_vec);
365         test_and_set_bit(bit_offset, bit_vec);
366
367         // Set outstanding notification bit
368         /*bit_vec = pir + 4;
369         fprintf(stderr, "%s: Setting pir bit offset 0 at 0x%p", __func__,
370                         bit_vec);
371         test_and_set_bit(0, bit_vec);*/
372
373         pir_dump();
374 }
375
376 int main(int argc, char **argv)
377 {
378         uint64_t *p64;
379         void *a = (void *)0xe0000;
380         struct acpi_table_rsdp *r;
381         struct acpi_table_fadt *f;
382         struct acpi_table_madt *m;
383         struct acpi_table_xsdt *x;
384         uint64_t virtiobase = 0x100000000ULL;
385         // lowmem is a bump allocated pointer to 2M at the "physbase" of memory 
386         void *lowmem = (void *) 0x1000000;
387         //struct vmctl vmctl;
388         int amt;
389         int vmmflags = 0; // Disabled probably forever. VMM_VMCALL_PRINTF;
390         uint64_t entry = 0x1200000, kerneladdress = 0x1200000;
391         int nr_gpcs = 1;
392         int fd = open("#cons/vmctl", O_RDWR), ret;
393         void * xp;
394         int kfd = -1;
395         static char cmd[512];
396         int i;
397         uint8_t csum;
398         void *coreboot_tables = (void *) 0x1165000;
399         void *a_page;
400 fprintf(stderr, "%p %p %p %p\n", PGSIZE, PGSHIFT, PML1_SHIFT, PML1_PTE_REACH);
401
402         // mmap is not working for us at present.
403         if ((uint64_t)_kernel > GKERNBASE) {
404                 fprintf(stderr, "kernel array @%p is above , GKERNBASE@%p sucks\n", _kernel, GKERNBASE);
405                 exit(1);
406         }
407         memset(_kernel, 0, sizeof(_kernel));
408         memset(lowmem, 0xff, 2*1048576);
409         memset(low4k, 0xff, 4096);
410         // avoid at all costs, requires too much instruction emulation.
411         //low4k[0x40e] = 0;
412         //low4k[0x40f] = 0xe0;
413
414         //Place mmap(Gan)
415         a_page = mmap((void *)0xfee00000, PGSIZE, PROT_READ | PROT_WRITE,
416                               MAP_POPULATE | MAP_ANONYMOUS, -1, 0);
417         fprintf(stderr, "a_page mmap pointer %p", a_page);
418
419         if (a_page == (void *) -1) {
420                 perror("Could not mmap APIC");
421                 exit(1);
422         }
423         if (((uint64_t)a_page & 0xfff) != 0) {
424                 perror("APIC page mapping is not page aligned");
425                 exit(1);
426         }
427
428         memset(a_page, 0, 4096);
429         ((uint32_t *)a_page)[0x30/4] = 0x01060015;
430
431         if (fd < 0) {
432                 perror("#cons/sysctl");
433                 exit(1);
434         }
435         argc--,argv++;
436         // switches ...
437         // Sorry, I don't much like the gnu opt parsing code.
438         while (1) {
439                 if (*argv[0] != '-')
440                         break;
441                 switch(argv[0][1]) {
442                 case 'd':
443                         debug++;
444                         break;
445                 case 'v':
446                         vmmflags |= VMM_VMCALL_PRINTF;
447                         break;
448                 case 'm':
449                         argc--,argv++;
450                         maxresume = strtoull(argv[0], 0, 0);
451                         break;
452                 case 'i':
453                         argc--,argv++;
454                         virtioirq = strtoull(argv[0], 0, 0);
455                         break;
456                 default:
457                         fprintf(stderr, "BMAFR\n");
458                         break;
459                 }
460                 argc--,argv++;
461         }
462         if (argc < 1) {
463                 fprintf(stderr, "Usage: %s vmimage [-n (no vmcall printf)] [coreboot_tables [loadaddress [entrypoint]]]\n", argv[0]);
464                 exit(1);
465         }
466         if (argc > 1)
467                 coreboot_tables = (void *) strtoull(argv[1], 0, 0);
468         if (argc > 2)
469                 kerneladdress = strtoull(argv[2], 0, 0);
470         if (argc > 3)
471                 entry = strtoull(argv[3], 0, 0);
472         kfd = open(argv[0], O_RDONLY);
473         if (kfd < 0) {
474                 perror(argv[0]);
475                 exit(1);
476         }
477         // read in the kernel.
478         xp = (void *)kerneladdress;
479         for(;;) {
480                 amt = read(kfd, xp, 1048576);
481                 if (amt < 0) {
482                         perror("read");
483                         exit(1);
484                 }
485                 if (amt == 0) {
486                         break;
487                 }
488                 xp += amt;
489         }
490         fprintf(stderr, "Read in %d bytes\n", xp-kerneladdress);
491         close(kfd);
492
493         // The low 1m so we can fill in bullshit like ACPI. */
494         // And, sorry, due to the STUPID format of the RSDP for now we need the low 1M.
495         low1m = mmap((int*)4096, MiB-4096, PROT_READ | PROT_WRITE,
496                          MAP_ANONYMOUS, -1, 0);
497         if (low1m != (void *)4096) {
498                 perror("Unable to mmap low 1m");
499                 exit(1);
500         }
501         memset(low1m, 0xff, MiB-4096);
502         r = a;
503         fprintf(stderr, "install rsdp to %p\n", r);
504         *r = rsdp;
505         a += sizeof(*r);
506         memmove(&r->xsdt_physical_address, &a, sizeof(a));
507         gencsum(&r->checksum, r, ACPI_RSDP_CHECKSUM_LENGTH);
508         if ((csum = acpi_tb_checksum((uint8_t *) r, ACPI_RSDP_CHECKSUM_LENGTH)) != 0) {
509                 fprintf(stderr, "RSDP has bad checksum; summed to %x\n", csum);
510                 exit(1);
511         }
512
513         /* Check extended checksum if table version >= 2 */
514         gencsum(&r->extended_checksum, r, ACPI_RSDP_XCHECKSUM_LENGTH);
515         if ((rsdp.revision >= 2) &&
516             (acpi_tb_checksum((uint8_t *) r, ACPI_RSDP_XCHECKSUM_LENGTH) != 0)) {
517                 fprintf(stderr, "RSDP has bad checksum v2\n");
518                 exit(1);
519         }
520
521         /* just leave a bunch of space for the xsdt. */
522         /* we need to zero the area since it has pointers. */
523         x = a;
524         a += sizeof(*x) + 8*sizeof(void *);
525         memset(x, 0, a - (void *)x);
526         fprintf(stderr, "install xsdt to %p\n", x);
527         *x = xsdt;
528         x->table_offset_entry[0] = 0;
529         x->table_offset_entry[1] = 0;
530         x->header.length = a - (void *)x;
531
532         f = a;
533         fprintf(stderr, "install fadt to %p\n", f);
534         *f = fadt;
535         x->table_offset_entry[2] = (uint64_t) f;
536         a += sizeof(*f);
537         f->header.length = a - (void *)f;
538         gencsum(&f->header.checksum, f, f->header.length);
539         if (acpi_tb_checksum((uint8_t *)f, f->header.length) != 0) {
540                 fprintf(stderr, "ffadt has bad checksum v2\n");
541                 exit(1);
542         }
543
544         m = a;
545         *m = madt;
546         x->table_offset_entry[3] = (uint64_t) m;
547         a += sizeof(*m);
548         fprintf(stderr, "install madt to %p\n", m);
549         memmove(a, &Apic0, sizeof(Apic0));
550         a += sizeof(Apic0);
551         memmove(a, &Apic1, sizeof(Apic1));
552         a += sizeof(Apic1);
553         memmove(a, &isor, sizeof(isor));
554         a += sizeof(isor);
555         m->header.length = a - (void *)m;
556         gencsum(&m->header.checksum, m, m->header.length);
557         if (acpi_tb_checksum((uint8_t *) m, m->header.length) != 0) {
558                 fprintf(stderr, "madt has bad checksum v2\n");
559                 exit(1);
560         }
561         fprintf(stderr, "allchecksums ok\n");
562
563         gencsum(&x->header.checksum, x, x->header.length);
564         if ((csum = acpi_tb_checksum((uint8_t *) x, x->header.length)) != 0) {
565                 fprintf(stderr, "XSDT has bad checksum; summed to %x\n", csum);
566                 exit(1);
567         }
568
569         hexdump(stdout, r, a-(void *)r);
570
571         a = (void *)(((unsigned long)a + 0xfff) & ~0xfff);
572         vmctl.pir = (uint64_t) a;
573         memset(a, 0, 4096);
574         a += 4096;
575         vmctl.vapic = (uint64_t) a;
576         //vmctl.vapic = (uint64_t) a_page;      
577         memset(a, 0, 4096);
578         ((uint32_t *)a)[0x30/4] = 0x01060014;
579         p64 = a;
580         // set up apic values? do we need to?
581         // qemu does this.
582         //((uint8_t *)a)[4] = 1;
583         a += 4096;
584
585         if (ros_syscall(SYS_setup_vmm, nr_gpcs, vmmflags, 0, 0, 0, 0) != nr_gpcs) {
586                 perror("Guest pcore setup failed");
587                 exit(1);
588         }
589
590         fprintf(stderr, "Run with %d cores and vmmflags 0x%x\n", nr_gpcs, vmmflags);
591         mcp = 1;
592         if (mcp) {
593                 my_retvals = malloc(sizeof(void*) * nr_threads);
594                 if (!my_retvals)
595                         perror("Init threads/malloc");
596
597                 pthread_can_vcore_request(FALSE);       /* 2LS won't manage vcores */
598                 pthread_need_tls(FALSE);
599                 pthread_mcp_init();                                     /* gives us one vcore */
600                 vcore_request(nr_threads - 1);          /* ghetto incremental interface */
601                 for (int i = 0; i < nr_threads; i++) {
602                         xp = __procinfo.vcoremap;
603                         fprintf(stderr, "%p\n", __procinfo.vcoremap);
604                         fprintf(stderr, "Vcore %d mapped to pcore %d\n", i,
605                                 __procinfo.vcoremap[i].pcoreid);
606                 }
607         }
608
609         ret = syscall(33, 1);
610         if (ret < 0) {
611                 perror("vm setup");
612                 exit(1);
613         }
614         ret = posix_memalign((void **)&p512, 4096, 3*4096);
615         fprintf(stderr, "memalign is %p\n", p512);
616         if (ret) {
617                 perror("ptp alloc");
618                 exit(1);
619         }
620         p1 = &p512[512];
621         p2m = &p512[1024];
622         uint64_t kernbase = 0; //0xffffffff80000000;
623         uint64_t highkernbase = 0xffffffff80000000;
624         p512[PML4(kernbase)] = (unsigned long long)p1 | 7;
625         p1[PML3(kernbase)] = /*0x87; */(unsigned long long)p2m | 7;
626         p512[PML4(highkernbase)] = (unsigned long long)p1 | 7;
627         p1[PML3(highkernbase)] = /*0x87; */(unsigned long long)p2m | 7;
628 #define _2MiB (0x200000)
629
630         for (i = 0; i < 512; i++) {
631                 p2m[PML2(kernbase + i * _2MiB)] = 0x87 | i * _2MiB;
632         }
633
634         kernbase >>= (0+12);
635         kernbase <<= (0 + 12);
636         uint8_t *kernel = (void *)GKERNBASE;
637         //write_coreboot_table(coreboot_tables, ((void *)VIRTIOBASE) /*kernel*/, KERNSIZE + 1048576);
638         hexdump(stdout, coreboot_tables, 512);
639         fprintf(stderr, "kernbase for pml4 is 0x%llx and entry is %llx\n", kernbase, entry);
640         fprintf(stderr, "p512 %p p512[0] is 0x%lx p1 %p p1[0] is 0x%x\n", p512, p512[0], p1, p1[0]);
641         vmctl.interrupt = 0;
642         vmctl.command = REG_RSP_RIP_CR3;
643         vmctl.cr3 = (uint64_t) p512;
644         vmctl.regs.tf_rip = entry;
645         vmctl.regs.tf_rsp = (uint64_t) &stack[1024];
646         if (mcp) {
647                 /* set up virtio bits, which depend on threads being enabled. */
648                 register_virtio_mmio(&vqdev, virtio_mmio_base);
649         }
650         fprintf(stderr, "threads started\n");
651         fprintf(stderr, "Writing command :%s:\n", cmd);
652         
653         vapic_status_dump(stderr, (void *)vmctl.vapic);
654
655         ret = write(fd, &vmctl, sizeof(vmctl));
656
657         vapic_status_dump(stderr, (void *)vmctl.vapic);
658
659         if (ret != sizeof(vmctl)) {
660                 perror(cmd);
661         }
662         while (1) {
663                 void showstatus(FILE *f, struct vmctl *v);
664                 int c;
665                 uint8_t byte;
666                 vmctl.command = REG_RIP;
667                 if (maxresume-- == 0) {
668                         debug = 1;
669                         resumeprompt = 1;
670                 }
671                 if (debug) {
672                         fprintf(stderr, "RIP %p, shutdown 0x%x\n", vmctl.regs.tf_rip, vmctl.shutdown);
673                         showstatus(stderr, &vmctl);
674                 }
675                 if (resumeprompt) {
676                         fprintf(stderr, "RESUME?\n");
677                         c = getchar();
678                         if (c == 'q')
679                                 break;
680                 }
681                 if (vmctl.shutdown == SHUTDOWN_EPT_VIOLATION) {
682                         uint64_t gpa, *regp, val;
683                         uint8_t regx;
684                         int store, size;
685                         int advance;
686                         if (decode(&vmctl, &gpa, &regx, &regp, &store, &size, &advance)) {
687                                 fprintf(stderr, "RIP %p, shutdown 0x%x\n", vmctl.regs.tf_rip, vmctl.shutdown);
688                                 showstatus(stderr, &vmctl);
689                                 quit = 1;
690                                 break;
691                         }
692                         if (debug) fprintf(stderr, "%p %p %p %p %p %p\n", gpa, regx, regp, store, size, advance);
693                         if ((gpa & ~0xfffULL) == virtiobase) {
694                                 if (debug) fprintf(stderr, "DO SOME VIRTIO\n");
695                                 // Lucky for us the various virtio ops are well-defined.
696                                 virtio_mmio(&vmctl, gpa, regx, regp, store);
697                                 if (debug) fprintf(stderr, "store is %d:\n", store);
698                                 if (debug) fprintf(stderr, "REGP IS %16x:\n", *regp);
699                         } else if ((gpa & 0xfee00000) == 0xfee00000) {
700                                 // until we fix our include mess, just put the proto here.
701                                 //int apic(struct vmctl *v, uint64_t gpa, int destreg, uint64_t *regp, int store);
702                                 //apic(&vmctl, gpa, regx, regp, store);
703                         } else if ((gpa & 0xfec00000) == 0xfec00000) {
704                                 // until we fix our include mess, just put the proto here.
705                                 int do_ioapic(struct vmctl *v, uint64_t gpa, int destreg, uint64_t *regp, int store);
706                                 do_ioapic(&vmctl, gpa, regx, regp, store);
707                         } else if (gpa < 4096) {
708                                 uint64_t val = 0;
709                                 memmove(&val, &low4k[gpa], size);
710                                 hexdump(stdout, &low4k[gpa], size);
711                                 fprintf(stderr, "Low 1m, code %p read @ %p, size %d, val %p\n", vmctl.regs.tf_rip, gpa, size, val);
712                                 memmove(regp, &low4k[gpa], size);
713                                 hexdump(stdout, regp, size);
714                         } else {
715                                 fprintf(stderr, "EPT violation: can't handle %p\n", gpa);
716                                 fprintf(stderr, "RIP %p, shutdown 0x%x\n", vmctl.regs.tf_rip, vmctl.shutdown);
717                                 fprintf(stderr, "Returning 0xffffffff\n");
718                                 showstatus(stderr, &vmctl);
719                                 // Just fill the whole register for now.
720                                 *regp = (uint64_t) -1;
721                         }
722                         vmctl.regs.tf_rip += advance;
723                         if (debug) fprintf(stderr, "Advance rip by %d bytes to %p\n", advance, vmctl.regs.tf_rip);
724                         vmctl.shutdown = 0;
725                         vmctl.gpa = 0;
726                         vmctl.command = REG_ALL;
727                 } else if (vmctl.shutdown == SHUTDOWN_UNHANDLED_EXIT_REASON) {
728                         switch(vmctl.ret_code){
729                         case  EXIT_REASON_VMCALL:
730                                 byte = vmctl.regs.tf_rdi;
731                                 printf("%c", byte);
732                                 if (byte == '\n') printf("%c", 'V');
733                                 vmctl.regs.tf_rip += 3;
734                                 break;
735                         case EXIT_REASON_EXTERNAL_INTERRUPT:
736                                 //debug = 1;
737                                 fprintf(stderr, "XINT 0x%x 0x%x\n", vmctl.intrinfo1, vmctl.intrinfo2);
738                                 pir_dump();
739                                 vmctl.command = RESUME;
740                                 break;
741                         case EXIT_REASON_IO_INSTRUCTION:
742                                 fprintf(stderr, "IO @ %p\n", vmctl.regs.tf_rip);
743                                 io(&vmctl);
744                                 vmctl.shutdown = 0;
745                                 vmctl.gpa = 0;
746                                 vmctl.command = REG_ALL;
747                                 break;
748                         case EXIT_REASON_INTERRUPT_WINDOW:
749                                 if (consdata) {
750                                         if (debug) fprintf(stderr, "inject an interrupt\n");
751                                         virtio_mmio_set_vring_irq();
752                                         vmctl.interrupt = 0x80000000 | virtioirq;
753                                         vmctl.command = RESUME;
754                                         consdata = 0;
755                                 }
756                                 break;
757                         case EXIT_REASON_MSR_WRITE:
758                         case EXIT_REASON_MSR_READ:
759                                 fprintf(stderr, "Do an msr\n");
760                                 quit = msrio(&vmctl, vmctl.ret_code);
761                                 if (quit) {
762                                         fprintf(stderr, "MSR FAILED: RIP %p, shutdown 0x%x\n", vmctl.regs.tf_rip, vmctl.shutdown);
763                                         showstatus(stderr, &vmctl);
764                                 }
765                                 break;
766                         case EXIT_REASON_MWAIT_INSTRUCTION:
767                           fflush(stdout);
768                                 if (debug)fprintf(stderr, "\n================== Guest MWAIT. =======================\n");
769                                 if (debug)fprintf(stderr, "Wait for cons data\n");
770                                 while (!consdata)
771                                         ;
772                                 //debug = 1;
773                                 vapic_status_dump(stderr, (void *)vmctl.vapic);
774                                 if (debug)fprintf(stderr, "Resume with consdata ...\n");
775                                 vmctl.regs.tf_rip += 3;
776                                 ret = write(fd, &vmctl, sizeof(vmctl));
777                                 if (ret != sizeof(vmctl)) {
778                                         perror(cmd);
779                                 }
780                                 //fprintf(stderr, "RIP %p, shutdown 0x%x\n", vmctl.regs.tf_rip, vmctl.shutdown);
781                                 //showstatus(stderr, &vmctl);
782                                 break;
783                         case EXIT_REASON_HLT:
784                                 fflush(stdout);
785                                 if (debug)fprintf(stderr, "\n================== Guest halted. =======================\n");
786                                 if (debug)fprintf(stderr, "Wait for cons data\n");
787                                 while (!consdata)
788                                         ;
789                                 //debug = 1;
790                                 if (debug)fprintf(stderr, "Resume with consdata ...\n");
791                                 vmctl.regs.tf_rip += 1;
792                                 ret = write(fd, &vmctl, sizeof(vmctl));
793                                 if (ret != sizeof(vmctl)) {
794                                         perror(cmd);
795                                 }
796                                 //fprintf(stderr, "RIP %p, shutdown 0x%x\n", vmctl.regs.tf_rip, vmctl.shutdown);
797                                 //showstatus(stderr, &vmctl);
798                                 break;
799                         case EXIT_REASON_APIC_ACCESS:                           
800                                 if (1 || debug)fprintf(stderr, "APIC READ EXIT\n");
801                                 
802                                 uint64_t gpa, *regp, val;
803                                 uint8_t regx;
804                                 int store, size;
805                                 int advance;
806                                 if (decode(&vmctl, &gpa, &regx, &regp, &store, &size, &advance)) {
807                                         fprintf(stderr, "RIP %p, shutdown 0x%x\n", vmctl.regs.tf_rip, vmctl.shutdown);
808                                         showstatus(stderr, &vmctl);
809                                         quit = 1;
810                                         break;
811                                 }
812
813                                 int apic(struct vmctl *v, uint64_t gpa, int destreg, uint64_t *regp, int store);
814                                 apic(&vmctl, gpa, regx, regp, store);
815                                 vmctl.regs.tf_rip += advance;
816                                 if (debug) fprintf(stderr, "Advance rip by %d bytes to %p\n", advance, vmctl.regs.tf_rip);
817                                 vmctl.shutdown = 0;
818                                 vmctl.gpa = 0;
819                                 vmctl.command = REG_ALL;
820                                 break;
821                         case EXIT_REASON_APIC_WRITE:
822                                 if (1 || debug)fprintf(stderr, "APIC WRITE EXIT\n");
823                                 break;
824                         default:
825                                 fprintf(stderr, "Don't know how to handle exit %d\n", vmctl.ret_code);
826                                 fprintf(stderr, "RIP %p, shutdown 0x%x\n", vmctl.regs.tf_rip, vmctl.shutdown);
827                                 showstatus(stderr, &vmctl);
828                                 quit = 1;
829                                 break;
830                         }
831                 }
832                 if (debug) fprintf(stderr, "at bottom of switch, quit is %d\n", quit);
833                 if (quit)
834                         break;
835                 if (consdata) {
836                         if (debug) fprintf(stderr, "inject an interrupt\n");
837                         fprintf(stderr, "XINT 0x%x 0x%x\n", vmctl.intrinfo1, vmctl.intrinfo2);
838                         vmctl.interrupt = 0x80000000 | virtioirq;
839                         virtio_mmio_set_vring_irq();
840                         consdata = 0;
841                         //debug = 1;
842                         vmctl.command = RESUME;
843                 }
844                 if (debug) fprintf(stderr, "NOW DO A RESUME\n");
845                 ret = write(fd, &vmctl, sizeof(vmctl));
846                 if (ret != sizeof(vmctl)) {
847                         perror(cmd);
848                 }
849         }
850
851         /* later. 
852         for (int i = 0; i < nr_threads-1; i++) {
853                 int ret;
854                 if (pthread_join(my_threads[i], &my_retvals[i]))
855                         perror("pth_join failed");
856                 fprintf(stderr, "%d %d\n", i, ret);
857         }
858  */
859
860         fflush(stdout);
861         exit(0);
862 }