vmmcp/APIC: the empire strikes back.
authorRonald G. Minnich <rminnich@gmail.com>
Wed, 16 Sep 2015 19:31:13 +0000 (12:31 -0700)
committerBarret Rhoden <brho@cs.berkeley.edu>
Mon, 2 Nov 2015 23:53:50 +0000 (18:53 -0500)
Some folks think we should be able to get along without these, but I've given up

Signed-off-by: Ronald G. Minnich <rminnich@gmail.com>
Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
tests/vmm/vmrunkernel.c
user/vmm/apic.c
user/vmm/ioapic.c

index 2859e26..46dd95a 100644 (file)
@@ -14,7 +14,7 @@
 #include <sys/mman.h>
 #include <vmm/coreboot_tables.h>
 #include <vmm/vmm.h>
-#include <acpi/acpi.h>
+#include <vmm/acpi/acpi.h>
 #include <ros/arch/mmu.h>
 #include <ros/vmx.h>
 #include <parlib/uthread.h>
@@ -24,7 +24,6 @@
 #include <vmm/virtio_config.h>
 
 int msrio(struct vmctl *vcpu, uint32_t opcode);
-#if 0
 /* Kind of sad what a total clusterf the pc world is. By 1999, you could just scan the hardware 
  * and work it out. But 2005, that was no longer possible. How sad. 
  * so we have to fake acpi to make it all work. !@#$!@#$#.
@@ -84,7 +83,42 @@ struct acpi_madt_local_apic Apic0 = {.header = {.type = ACPI_MADT_TYPE_LOCAL_API
                                     .processor_id = 0, .id = 0};
 struct acpi_madt_io_apic Apic1 = {.header = {.type = ACPI_MADT_TYPE_IO_APIC, .length = sizeof(struct acpi_madt_io_apic)},
                                  .id = 1, .address = 0xfec00000, .global_irq_base = 0};
-#endif
+struct acpi_madt_interrupt_override isor[] = {
+       /* I have no idea if it should be source irq 2, global 0, or global 2, source 0. Shit. */
+       {.header = {.type = ACPI_MADT_TYPE_INTERRUPT_OVERRIDE, .length = sizeof(struct acpi_madt_interrupt_override)},
+        .bus = 0, .source_irq = 2, .global_irq = 0, .inti_flags = 0},
+       {.header = {.type = ACPI_MADT_TYPE_INTERRUPT_OVERRIDE, .length = sizeof(struct acpi_madt_interrupt_override)},
+        .bus = 0, .source_irq = 1, .global_irq = 1, .inti_flags = 0},
+       //{.header = {.type = ACPI_MADT_TYPE_INTERRUPT_OVERRIDE, .length = sizeof(struct acpi_madt_interrupt_override)},
+        //.bus = 0, .source_irq = 2, .global_irq = 2, .inti_flags = 0},
+       {.header = {.type = ACPI_MADT_TYPE_INTERRUPT_OVERRIDE, .length = sizeof(struct acpi_madt_interrupt_override)},
+        .bus = 0, .source_irq = 3, .global_irq = 3, .inti_flags = 0},
+       {.header = {.type = ACPI_MADT_TYPE_INTERRUPT_OVERRIDE, .length = sizeof(struct acpi_madt_interrupt_override)},
+        .bus = 0, .source_irq = 4, .global_irq = 4, .inti_flags = 0},
+       {.header = {.type = ACPI_MADT_TYPE_INTERRUPT_OVERRIDE, .length = sizeof(struct acpi_madt_interrupt_override)},
+        .bus = 0, .source_irq = 5, .global_irq = 5, .inti_flags = 0},
+       {.header = {.type = ACPI_MADT_TYPE_INTERRUPT_OVERRIDE, .length = sizeof(struct acpi_madt_interrupt_override)},
+        .bus = 0, .source_irq = 6, .global_irq = 6, .inti_flags = 0},
+       {.header = {.type = ACPI_MADT_TYPE_INTERRUPT_OVERRIDE, .length = sizeof(struct acpi_madt_interrupt_override)},
+        .bus = 0, .source_irq = 7, .global_irq = 7, .inti_flags = 0},
+       {.header = {.type = ACPI_MADT_TYPE_INTERRUPT_OVERRIDE, .length = sizeof(struct acpi_madt_interrupt_override)},
+        .bus = 0, .source_irq = 8, .global_irq = 8, .inti_flags = 0},
+       {.header = {.type = ACPI_MADT_TYPE_INTERRUPT_OVERRIDE, .length = sizeof(struct acpi_madt_interrupt_override)},
+        .bus = 0, .source_irq = 9, .global_irq = 9, .inti_flags = 0},
+       {.header = {.type = ACPI_MADT_TYPE_INTERRUPT_OVERRIDE, .length = sizeof(struct acpi_madt_interrupt_override)},
+        .bus = 0, .source_irq = 10, .global_irq = 10, .inti_flags = 0},
+       {.header = {.type = ACPI_MADT_TYPE_INTERRUPT_OVERRIDE, .length = sizeof(struct acpi_madt_interrupt_override)},
+        .bus = 0, .source_irq = 11, .global_irq = 11, .inti_flags = 0},
+       {.header = {.type = ACPI_MADT_TYPE_INTERRUPT_OVERRIDE, .length = sizeof(struct acpi_madt_interrupt_override)},
+        .bus = 0, .source_irq = 12, .global_irq = 12, .inti_flags = 0},
+       {.header = {.type = ACPI_MADT_TYPE_INTERRUPT_OVERRIDE, .length = sizeof(struct acpi_madt_interrupt_override)},
+        .bus = 0, .source_irq = 13, .global_irq = 13, .inti_flags = 0},
+       {.header = {.type = ACPI_MADT_TYPE_INTERRUPT_OVERRIDE, .length = sizeof(struct acpi_madt_interrupt_override)},
+        .bus = 0, .source_irq = 14, .global_irq = 14, .inti_flags = 0},
+       {.header = {.type = ACPI_MADT_TYPE_INTERRUPT_OVERRIDE, .length = sizeof(struct acpi_madt_interrupt_override)},
+        .bus = 0, .source_irq = 15, .global_irq = 15, .inti_flags = 0},
+};
+
 
 /* this test will run the "kernel" in the negative address space. We hope. */
 void *low1m;
@@ -263,12 +297,10 @@ static void gencsum(uint8_t *target, void *data, int len)
 int main(int argc, char **argv)
 {
        void *a = (void *)0xe0000;
-#if 0
        struct acpi_table_rsdp *r;
        struct acpi_table_fadt *f;
        struct acpi_table_madt *m;
        struct acpi_table_xsdt *x;
-#endif
        uint64_t virtiobase = 0x100000000ULL;
        // lowmem is a bump allocated pointer to 2M at the "physbase" of memory 
        void *lowmem = (void *) 0x1000000;
@@ -364,7 +396,6 @@ printf("%p %p %p %p\n", PGSIZE, PGSHIFT, PML1_SHIFT, PML1_PTE_REACH);
                exit(1);
        }
        memset(low1m, 0xff, MiB-4096);
-#if 0
        r = a;
        fprintf(stderr, "install rsdp to %p\n", r);
        *r = rsdp;
@@ -416,6 +447,8 @@ printf("%p %p %p %p\n", PGSIZE, PGSHIFT, PML1_SHIFT, PML1_PTE_REACH);
        a += sizeof(Apic0);
        memmove(a, &Apic1, sizeof(Apic1));
        a += sizeof(Apic1);
+       memmove(a, &isor, sizeof(isor));
+       a += sizeof(isor);
        m->header.length = a - (void *)m;
        gencsum(&m->header.checksum, m, m->header.length);
        if (acpi_tb_checksum((uint8_t *) m, m->header.length) != 0) {
@@ -431,7 +464,6 @@ printf("%p %p %p %p\n", PGSIZE, PGSHIFT, PML1_SHIFT, PML1_PTE_REACH);
        }
 
        hexdump(stdout, r, a-(void *)r);
-#endif
 
        if (ros_syscall(SYS_setup_vmm, nr_gpcs, vmmflags, 0, 0, 0, 0) != nr_gpcs) {
                perror("Guest pcore setup failed");
@@ -539,16 +571,14 @@ printf("%p %p %p %p\n", PGSIZE, PGSHIFT, PML1_SHIFT, PML1_PTE_REACH);
                                if (debug) printf("DO SOME VIRTIO\n");
                                // Lucky for us the various virtio ops are well-defined.
                                virtio_mmio(&vmctl, gpa, regx, regp, store);
-#if 0
                        } else if ((gpa & 0xfee00000) == 0xfee00000) {
                                // until we fix our include mess, just put the proto here.
                                int apic(struct vmctl *v, uint64_t gpa, int destreg, uint64_t *regp, int store);
                                apic(&vmctl, gpa, regx, regp, store);
                        } else if ((gpa & 0xfec00000) == 0xfec00000) {
                                // until we fix our include mess, just put the proto here.
-                               int ioapic(struct vmctl *v, uint64_t gpa, int destreg, uint64_t *regp, int store);
-                               ioapic(&vmctl, gpa, regx, regp, store);
-#endif
+                               int do_ioapic(struct vmctl *v, uint64_t gpa, int destreg, uint64_t *regp, int store);
+                               do_ioapic(&vmctl, gpa, regx, regp, store);
                        } else if (gpa < 4096) {
                                uint64_t val = 0;
                                memmove(&val, &low4k[gpa], size);
index d77733a..ab6e33b 100644 (file)
@@ -21,7 +21,7 @@
 #include <stdint.h>
 #include <err.h>
 #include <sys/mman.h>
-#include <ros/vmm.h>
+#include <vmm/vmm.h>
 #include <vmm/virtio.h>
 #include <vmm/virtio_mmio.h>
 #include <vmm/virtio_ids.h>
@@ -34,13 +34,6 @@ int debug_apic = 1;
        if (debug_apic) { fprintf(stderr, "apic: " fmt , ## __VA_ARGS__); }
 
 
-struct apicinfo {
-       int state; // not used yet. */
-       int id;
-       uint64_t apicbase;
-       uint64_t ioapicbase;
-};
-
 static struct apicinfo apicinfo;
 
 enum {
index 0449173..5f8fb2a 100644 (file)
 #include <stdint.h>
 #include <err.h>
 #include <sys/mman.h>
-#include <ros/vmm.h>
+#include <vmm/vmm.h>
 #include <vmm/virtio.h>
 #include <vmm/virtio_mmio.h>
 #include <vmm/virtio_ids.h>
 #include <vmm/virtio_config.h>
 
 #define IOAPIC_CONFIG 0x100
+#define IOAPIC_NUM_PINS 24
+
+int debug_ioapic = 1;
+int apic_id_mask = 0xf0;
 
-int debug_ioapic = 0;
 #define DPRINTF(fmt, ...) \
-       if (debug_ioapic) { printf("ioapic: " fmt , ## __VA_ARGS__); }
+       if (debug_ioapic) { fprintf(stderr, "ioapic: " fmt , ## __VA_ARGS__); }
 
 
-struct ioapicinfo {
-       int state; // not used yet. */
-       uint64_t ioapicbase;
+struct ioapic {
+       int id;
+       int reg;
+       uint32_t arbid;
+       uint32_t value[256];
 };
 
-static struct ioapicinfo ioapicinfo;
-
-char *ioapic_names[256] = {
-       [0] "IOAPICID",
-};
+static struct ioapic ioapic[1];
 
-static uint32_t ioapic_read(uint64_t gpa)
+static uint32_t ioapic_read(int ix, uint64_t offset)
 {
+       uint32_t ret = (uint32_t)-1;
+       uint32_t reg = ioapic[ix].reg;
 
-       unsigned int offset = gpa - ioapicinfo.ioapicbase;
-       uint32_t low;
-       
-       DPRINTF("ioapic_read offset %s 0x%x\n", ioapic_names[offset],(int)offset);
 
-       if (offset >= IOAPIC_CONFIG) {
-               fprintf(stderr, "Whoa. %p Reading past ioapic space? What gives?\n", gpa);
-               return -1;
+       if (offset == 0) {
+               DPRINTF("ioapic_read ix %x return 0x%x\n", ix, reg);
+               return reg;
        }
 
-
-    switch (offset) {
-    case 0x20: 
-           return 0;
-    default:
-           fprintf(stderr, "bad register offset@%p\n", (void *)gpa);
-           return 0;
-    }
-    return 0;
+       DPRINTF("ioapic_read %x 0x%x\n", ix, (int)reg);
+       switch (reg) {
+       case 0:
+               return ioapic[ix].id;
+               break;
+       case 1:
+               return 0x170011;
+               break;
+       case 2:
+               return ioapic[ix].arbid;
+               break;
+       default:
+               if (reg >= 0 && reg < (IOAPIC_NUM_PINS*2 + 0x10)) {
+                       //bx_io_redirect_entry_t *entry = ioredtbl + index;
+                       //data = (ioregsel&1) ? entry->get_hi_part() : entry->get_lo_part();
+                       ret = ioapic[ix].value[reg];
+                       DPRINTF("IOAPIC_READ %x: %x return %08x\n", ix, reg, ret);
+                       return ret;
+               } else {
+                       DPRINTF("IOAPIC READ: %x BAD INDEX 0x%x\n", ix, reg);
+               }
+               return ret;
+               break;
+       }
+       return 0;
 }
 
-static void ioapic_write(uint64_t gpa, uint32_t value)
+static void ioapic_write(int ix, uint64_t offset, uint32_t value)
 {
-       uint64_t val64;
-       uint32_t low, high;
-       unsigned int offset = gpa - ioapicinfo.ioapicbase;
-       
-       DPRINTF("ioapic_write offset %s 0x%x value 0x%x\n", ioapic_names[offset], (int)offset, value);
-
-    if (offset >= IOAPIC_CONFIG) {
-           fprintf(stderr, "Whoa. %p Writing past ioapic config space? What gives?\n", gpa);
-           return;
-    }
-
-    switch (offset) {
-    default:
-        DPRINTF("bad register offset 0x%x\n", offset);
-    }
+       uint32_t ret;
+       uint32_t reg = ioapic[ix].reg;
+
+       if (offset == 0) {
+               DPRINTF("ioapic_write ix %x set reg 0x%x\n", ix, value);
+               ioapic[ix].reg = value;
+               return;
+       }
+
+       switch (reg) {
+       case 0:
+               DPRINTF("IOAPIC_WRITE: Set %d ID to %d\n", ix, value);
+               ioapic[ix].id = value;
+               break;
+       case 1:
+       case 2:
+               DPRINTF("IOAPIC_WRITE: Can't write %d\n", reg);
+       default:
+               if (reg >= 0 && reg < (IOAPIC_NUM_PINS*2 + 0x10)) {
+                       ioapic[ix].value[reg] = value;
+                       DPRINTF("IOAPIC %x: set %08x to %016x\n", ix, reg, value);
+               } else {
+                       DPRINTF("IOAPIC WRITE: %x BAD INDEX 0x%x\n", ix, reg);
+               }
+               break;
+       }
 
 }
 
-int ioapic(struct vmctl *v, uint64_t gpa, int destreg, uint64_t *regp, int store)
+int do_ioapic(struct vmctl *v, uint64_t gpa, int destreg, uint64_t *regp, int store)
 {
+       // TODO: compute an index for the ioapic array. 
+       int ix = 0;
+       uint32_t offset = gpa & 0xfffff;
+       /* basic sanity tests. */
+       DPRINTF("%s: %p 0x%x %p %s\n", __func__, (void *)gpa, destreg, regp, store ? "write" : "read");
+
+       if ((offset != 0) && (offset != 0x10)) {
+               DPRINTF("Bad register offset: 0x%x and has to be 0x0 or 0x10\n", offset);
+               return -1;
+       }
+
        if (store) {
-               ioapic_write(gpa, *regp);
-               DPRINTF("Write: mov %s to %s @%p val %p\n", regname(destreg), ioapic_names[(uint8_t)gpa], gpa, *regp);
+               ioapic_write(ix, offset, *regp);
        } else {
-               *regp = ioapic_read(gpa);
-               DPRINTF("Read: Set %s from %s @%p to %p\n", regname(destreg), ioapic_names[(uint8_t)gpa], gpa, *regp);
+               *regp = ioapic_read(ix, offset);
        }
 
 }