vmm: Increase the vmthread stack size
[akaros.git] / user / vmm / ioapic.c
index 0449173..bd0ed0e 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>
+#include <vmm/sched.h>
 
 #define IOAPIC_CONFIG 0x100
+#define IOAPIC_NUM_PINS 24
+
+int debug_ioapic;
+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(struct guest_thread *vm_thread, 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(struct guest_thread *vm_thread, 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;
+       struct virtual_machine *vm = gth_to_vm(vm_thread);
+       uint32_t irqreg;
+
+       if (offset == 0) {
+               DPRINTF("ioapic_write ix %x set reg 0x%x\n", ix, value);
+               ioapic[ix].reg = value;
+               return;
+       }
+
+       for (int i = 0; i < VIRTIO_MMIO_MAX_NUM_DEV; i++) {
+               if (vm->virtio_mmio_devices[i] == NULL)
+                       continue;
+
+               /* The first IRQ register starts at 0x10, and there are two 32-bit
+                * registers for each IRQ. The first 8 bits of the value assigned to
+                * 'reg' is the interrupt vector. */
+               irqreg = (vm->virtio_mmio_devices[i]->irq) * 2 + 0x10;
+               if (reg == irqreg && (value & 0xff) != 0) {
+                       vm->virtio_mmio_devices[i]->vec = value & 0xff;
+                       DPRINTF("irq vector for irq number %d is: %lx\n",
+                                vm->virtio_mmio_devices[i]->irq, value & 0xff);
+               } else if (reg == irqreg + 1) {
+                       vm->virtio_mmio_devices[i]->dest = value >> 24;
+                       if (value >> 24 == 0xff)
+                               vm->virtio_mmio_devices[i]->dest = 0xffffffff;
+
+                       DPRINTF("high value for irq number %d is: %lx\n",
+                                vm->virtio_mmio_devices[i]->irq, value);
+                       DPRINTF("irq destination for irq number %d is: %lx\n",
+                                vm->virtio_mmio_devices[i]->irq, value >> 24);
+               }
+       }
+
+       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 guest_thread *vm_thread, uint64_t gpa, int destreg,
+              uint64_t *regp, int store)
 {
+       /* TODO(ganshun): 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(vm_thread, 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(vm_thread, ix, offset);
        }
 
 }