First, second, and third pass at apic code. Crude
authorRonald G. Minnich <rminnich@gmail.com>
Mon, 31 Aug 2015 04:09:04 +0000 (21:09 -0700)
committerBarret Rhoden <brho@cs.berkeley.edu>
Mon, 2 Nov 2015 23:53:49 +0000 (18:53 -0500)
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 [new file with mode: 0644]
user/vmm/ioapic.c [new file with mode: 0644]
user/vmm/virtio-mmio.c

index 07cc712..422bff8 100644 (file)
@@ -532,6 +532,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);
+                       } 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);
                        } else if (gpa < 4096) {
                                uint64_t val = 0;
                                memmove(&val, &low4k[gpa], size);
diff --git a/user/vmm/apic.c b/user/vmm/apic.c
new file mode 100644 (file)
index 0000000..d77733a
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ * APIC emulation
+ *
+ * Copyright 2015 Google Inc.
+ *
+ * See LICENSE for details.
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <pthread.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <parlib/arch/arch.h>
+#include <parlib/ros_debug.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/uio.h>
+#include <stdint.h>
+#include <err.h>
+#include <sys/mman.h>
+#include <ros/vmm.h>
+#include <vmm/virtio.h>
+#include <vmm/virtio_mmio.h>
+#include <vmm/virtio_ids.h>
+#include <vmm/virtio_config.h>
+
+#define APIC_CONFIG 0x100
+
+int debug_apic = 1;
+#define DPRINTF(fmt, ...) \
+       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 {
+       reserved,
+       readonly = 1,
+       readwrite = 3,
+       writeonly = 2
+};
+
+struct {
+       char *name;
+       int mode;
+       uint32_t value;
+} apicregs[256] = {
+[0x00] {.name = "Reserved", .mode =  reserved},
+[0x01] {.name = "Reserved", .mode =  reserved},
+[0x02] {.name = "Local APIC ID Register Read/Write.", .mode = readwrite},
+[0x03] {.name = "Local APIC Version Register Read Only.", .mode = readonly},
+[0x04] {.name = "Reserved", .mode =  reserved},
+[0x05] {.name = "Reserved", .mode =  reserved},
+[0x06] {.name = "Reserved", .mode =  reserved},
+[0x07] {.name = "Reserved", .mode =  reserved},
+[0x08] {.name = "Task Priority Register (TPR) Read/Write.", .mode = readwrite},
+[0x09] {.name = "Arbitration Priority Register1 (APR) Read Only.", .mode = readonly},
+[0x0A] {.name = "Processor Priority Register (PPR) Read Only.", .mode = readonly},
+[0x0B] {.name = "EOI Register Write Only.", .mode = writeonly},
+[0x0C] {.name = "Remote Read Register1 (RRD) Read Only", .mode = readonly},
+[0x0D] {.name = "Logical Destination Register Read/Write.", .mode = readwrite},
+[0x0E] {.name = "Destination Format Register Read/Write (see Section", .mode = readwrite},
+[0x0F] {.name = "Spurious Interrupt Vector Register Read/Write (see Section 10.9.", .mode = readwrite},
+[0x10] {.name = "In-Service Register (ISR); bits 31:0 Read Only.", .mode = readonly},
+[0x11] {.name = "In-Service Register (ISR); bits 63:32 Read Only.", .mode = readonly},
+[0x12] {.name = "In-Service Register (ISR); bits 95:64 Read Only.", .mode = readonly},
+[0x13] {.name = "In-Service Register (ISR); bits 127:96 Read Only.", .mode = readonly},
+[0x14] {.name = "In-Service Register (ISR); bits 159:128 Read Only.", .mode = readonly},
+[0x15] {.name = "In-Service Register (ISR); bits 191:160 Read Only.", .mode = readonly},
+[0x16] {.name = "In-Service Register (ISR); bits 223:192 Read Only.", .mode = readonly},
+[0x17] {.name = "In-Service Register (ISR); bits 255:224 Read Only.", .mode = readonly},
+[0x18] {.name = "Trigger Mode Register (TMR); bits 31:0 Read Only.", .mode = readonly},
+[0x19] {.name = "Trigger Mode Register (TMR); bits 63:32 Read Only.", .mode = readonly},
+[0x1A] {.name = "Trigger Mode Register (TMR); bits 95:64 Read Only.", .mode = readonly},
+[0x1B] {.name = "Trigger Mode Register (TMR); bits 127:96 Read Only.", .mode = readonly},
+[0x1C] {.name = "Trigger Mode Register (TMR); bits 159:128 Read Only.", .mode = readonly},
+[0x1D] {.name = "Trigger Mode Register (TMR); bits 191:160 Read Only.", .mode = readonly},
+[0x1E] {.name = "Trigger Mode Register (TMR); bits 223:192 Read Only.", .mode = readonly},
+[0x1F] {.name = "Trigger Mode Register (TMR); bits 255:224 Read Only.", .mode = readonly},
+[0x20] {.name = "Interrupt Request Register (IRR); bits 31:0 Read Only.", .mode = readonly},
+[0x21] {.name = "Interrupt Request Register (IRR); bits 63:32 Read Only.", .mode = readonly},
+[0x22] {.name = "Interrupt Request Register (IRR); bits 95:64 Read Only.", .mode = readonly},
+[0x23] {.name = "Interrupt Request Register (IRR); bits 127:96 Read Only.", .mode = readonly},
+[0x24] {.name = "Interrupt Request Register (IRR); bits 159:128 Read Only.", .mode = readonly},
+[0x25] {.name = "Interrupt Request Register (IRR); bits 191:160 Read Only.", .mode = readonly},
+[0x26] {.name = "Interrupt Request Register (IRR); bits 223:192 Read Only.", .mode = readonly},
+[0x27] {.name = "Interrupt Request Register (IRR); bits 255:224 Read Only.", .mode = readonly},
+[0x28] {.name = "Error Status Register Read Only.", .mode = readonly},
+[0x29 ] {.name = "Reserved", .mode =  reserved},
+[0x2a] {.name = "Reserved", .mode =  reserved},
+[0x2b] {.name = "Reserved", .mode =  reserved},
+[0x2c] {.name = "Reserved", .mode =  reserved},
+[0x2d] {.name = "Reserved", .mode =  reserved},
+[0x2E] {.name = "Reserved", .mode =  reserved},
+[0x2F] {.name = "LVT CMCI Register Read/Write.", .mode = readwrite},
+[0x30] {.name = "Interrupt Command Register (ICR); bits 0-31 Read/Write.", .mode = readwrite},
+[0x31] {.name = "Interrupt Command Register (ICR); bits 32-63 Read/Write.", .mode = readwrite},
+[0x32] {.name = "LVT Timer Register Read/Write.", .mode = readwrite},
+[0x33] {.name = "LVT Thermal Sensor Register2 Read/Write.", .mode = readwrite},
+[0x34] {.name = "LVT Performance Monitoring Counters Register3 Read/Write.", .mode = readwrite},
+[0x35] {.name = "LVT LINT0 Register Read/Write.", .mode = readwrite},
+[0x36] {.name = "LVT LINT1 Register Read/Write.", .mode = readwrite},
+[0x37] {.name = "LVT Error Register Read/Write.", .mode = readwrite},
+[0x38] {.name = "Initial Count Register (for Timer) Read/Write.", .mode = readwrite},
+[0x39] {.name = "Current Count Register (for Timer) Read Only.", .mode = readonly},
+[0x3A] {.name = "Reserved", .mode =  reserved},
+[0x3a]{.name = "Reserved", .mode =  reserved},
+[0x3b]{.name = "Reserved", .mode =  reserved},
+[0x3c]{.name = "Reserved", .mode =  reserved},
+[0x3D]{.name = "Reserved", .mode =  reserved},
+[0x3E] {.name = "Divide Configuration Register (for Timer) Read/Write.", .mode = readwrite},
+[0x3F] {.name = "Reserved", .mode =  reserved},
+};
+
+static uint32_t apic_read(uint64_t offset)
+{
+
+       uint32_t low;
+
+       DPRINTF("apic_read offset %s 0x%x\n", apicregs[offset].name, (int)offset);
+
+       if (! apicregs[offset].mode & 1) {
+               fprintf(stderr, "Attempt to read %s, which is %s\n", apicregs[offset].name,
+                       apicregs[offset].mode == 0 ?  "reserved" : "writeonly");
+               // panic? what to do?
+               return (uint32_t) -1;
+       }
+
+       // no special cases yet.
+       switch (offset) {
+       default:
+               DPRINTF("%s: return %08x\n", apicregs[offset].name, apicregs[offset].value);
+               return apicregs[offset].value;
+               break;
+       }
+       return 0;
+}
+
+static void apic_write(uint64_t offset, uint32_t value)
+{
+       uint64_t val64;
+       uint32_t low, high;
+
+       DPRINTF("apic_write offset %s 0x%x value 0x%x\n", apicregs[offset].name, (int)offset, value);
+
+       if (! apicregs[offset].mode & 2) {
+               fprintf(stderr, "Attempt to write %s, which is %s\n", apicregs[offset].name,
+                       apicregs[offset].mode == 0 ?  "reserved" : "readonly");
+               // panic? what to do?
+               return;
+       }
+
+       switch (offset) {
+       default:
+               DPRINTF("%s: Set to %08x\n", apicregs[offset].name, value);
+               apicregs[offset].value = value;
+               break;
+       }
+
+}
+
+int apic(struct vmctl *v, uint64_t gpa, int destreg, uint64_t *regp, int store)
+{
+       uint32_t offset = gpa & 0xfffff;
+       /* basic sanity tests. */
+       // TODO: Should be minus the base but FIXME
+       offset = gpa & 0xfffff;
+       if (offset & 0xf) {
+               DPRINTF("bad register offset; low nibl is non-zero\n");
+               return -1;
+       }
+       offset >>= 4;
+       if (offset > APIC_CONFIG) {
+               DPRINTF("Bad register offset: 0x%x and max is 0x%x\n", gpa, gpa + APIC_CONFIG);
+               return -1;
+       }
+
+       if (store) {
+               apic_write(offset, *regp);
+               DPRINTF("Write: mov %s to %s @%p val %p\n", regname(destreg), apicregs[offset].name, gpa, *regp);
+       } else {
+               *regp = apic_read(offset);
+               DPRINTF("Read: Set %s from %s @%p to %p\n", regname(destreg), apicregs[offset].name, gpa, *regp);
+       }
+
+}
diff --git a/user/vmm/ioapic.c b/user/vmm/ioapic.c
new file mode 100644 (file)
index 0000000..0449173
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * IOAPIC emulation
+ *
+ * Copyright 2015 Google Inc.
+ *
+ * See LICENSE for details.
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <pthread.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <parlib/arch/arch.h>
+#include <parlib/ros_debug.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/uio.h>
+#include <stdint.h>
+#include <err.h>
+#include <sys/mman.h>
+#include <ros/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
+
+int debug_ioapic = 0;
+#define DPRINTF(fmt, ...) \
+       if (debug_ioapic) { printf("ioapic: " fmt , ## __VA_ARGS__); }
+
+
+struct ioapicinfo {
+       int state; // not used yet. */
+       uint64_t ioapicbase;
+};
+
+static struct ioapicinfo ioapicinfo;
+
+char *ioapic_names[256] = {
+       [0] "IOAPICID",
+};
+
+static uint32_t ioapic_read(uint64_t gpa)
+{
+
+       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;
+       }
+
+
+    switch (offset) {
+    case 0x20: 
+           return 0;
+    default:
+           fprintf(stderr, "bad register offset@%p\n", (void *)gpa);
+           return 0;
+    }
+    return 0;
+}
+
+static void ioapic_write(uint64_t gpa, 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);
+    }
+
+}
+
+int ioapic(struct vmctl *v, uint64_t gpa, int destreg, uint64_t *regp, int store)
+{
+       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);
+       } else {
+               *regp = ioapic_read(gpa);
+               DPRINTF("Read: Set %s from %s @%p to %p\n", regname(destreg), ioapic_names[(uint8_t)gpa], gpa, *regp);
+       }
+
+}
index 8a20902..d33d9b6 100644 (file)
@@ -138,7 +138,7 @@ static uint32_t virtio_mmio_read(uint64_t gpa)
 
     // WTF? Does this happen? 
     if (offset >= VIRTIO_MMIO_CONFIG) {
-           fprintf(stderr, "Whoa. Reading past mmio config space? What gives?\n");
+           fprintf(stderr, "Whoa. %p Reading past mmio config space? What gives?\n", gpa);
            return -1;
 #if 0
            offset -= VIRTIO_MMIO_CONFIG;
@@ -211,7 +211,7 @@ static void virtio_mmio_write(uint64_t gpa, uint32_t value)
        DPRINTF("virtio_mmio_write offset %s 0x%x value 0x%x\n", virtio_names[offset], (int)offset, value);
 
     if (offset >= VIRTIO_MMIO_CONFIG) {
-           fprintf(stderr, "Whoa. Writing past mmio config space? What gives?\n");
+           fprintf(stderr, "Whoa. %p Writing past mmio config space? What gives?\n", gpa);
 #if 0
         offset -= VIRTIO_MMIO_CONFIG;
         switch (size) {