We dynamically get the interrupt vector from ioapic_write to the relevant irq in virtio_console. The poke_guest function now posts the interrupt vector for a specific device.
We now no longer need Ron's vroom patch for linux. Fixes: b/29243001 Change-Id: I222f33582c013dc730412d28881a184d0ae31fb1 Signed-off-by: Kyle Milka <[email protected]> --- tests/vmm/vmrunkernel.c | 66 +++++++++++++++----------------------- user/vmm/include/vmm/virtio_mmio.h | 8 ++++- user/vmm/ioapic.c | 34 ++++++++++++++++---- user/vmm/virtio_lguest_console.c | 16 +++++---- user/vmm/virtio_mmio.c | 2 +- 5 files changed, 71 insertions(+), 55 deletions(-) diff --git a/tests/vmm/vmrunkernel.c b/tests/vmm/vmrunkernel.c index 9074f83..0a928b8 100644 --- a/tests/vmm/vmrunkernel.c +++ b/tests/vmm/vmrunkernel.c @@ -97,7 +97,7 @@ struct acpi_table_madt madt = { struct acpi_madt_local_apic Apic0 = {.header = {.type = ACPI_MADT_TYPE_LOCAL_APIC, .length = sizeof(struct acpi_madt_local_apic)}, .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}; + .id = 0, .address = 0xfec00000, .global_irq_base = 0}; struct acpi_madt_local_x2apic X2Apic0 = { .header = { .type = ACPI_MADT_TYPE_LOCAL_X2APIC, @@ -108,42 +108,24 @@ struct acpi_madt_local_x2apic X2Apic0 = { }; 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)}, + /* From the ACPI Specification Version 6.1: + * For example, if your machine has the ISA Programmable Interrupt Timer + * (PIT) connected to ISA IRQ 0, but in APIC mode, it is connected to I/O + * APIC interrupt input 2, then you would need an Interrupt Source Override + * where the source entry is ‘0’ and the Global System Interrupt is ‘2.’ + */ + {.header = {.type = ACPI_MADT_TYPE_INTERRUPT_OVERRIDE, + .length = sizeof(struct acpi_madt_interrupt_override)}, + .bus = 0, .source_irq = 0, .global_irq = 2, .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)}, + {.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)}, + {.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}, - // VMMCP routes irq 32 to gsi 17 - {.header = {.type = ACPI_MADT_TYPE_INTERRUPT_OVERRIDE, .length = sizeof(struct acpi_madt_interrupt_override)}, - .bus = 0, .source_irq = 32, .global_irq = 17, .inti_flags = 5}, }; @@ -206,14 +188,17 @@ void timer_thread(void *arg) // FIXME. volatile int consdata = 0; -static void virtio_poke_guest(void) +static void virtio_poke_guest(uint8_t vec) { - set_posted_interrupt(0xE5); + set_posted_interrupt(vec); ros_syscall(SYS_vmm_poke_guest, 0, 0, 0, 0, 0, 0); } static struct virtio_mmio_dev cons_mmio_dev = { - .poke_guest = virtio_poke_guest + .poke_guest = virtio_poke_guest, + /* At the moment irq numbers cannot be below 24; this is a problem with + * the IOAPIC and Interrupt Source Override Structure. */ + .irq = 26, }; static struct virtio_console_config cons_cfg; @@ -246,7 +231,6 @@ static struct virtio_vq_dev cons_vqdev = { } }; - void lowmem() { __asm__ __volatile__ (".section .lowmem, \"aw\"\n\tlow: \n\t.=0x1000\n\t.align 0x100000\n\t.previous\n"); } @@ -613,8 +597,10 @@ int main(int argc, char **argv) if (vm->virtio_mmio_devices[i] == NULL) continue; /* Append all the virtio mmio base addresses. */ - len = snprintf(cmdlinep, cmdlinesz, " virtio_mmio.device=1K@0x%llx:32", - vm->virtio_mmio_devices[i]->addr); + len = snprintf(cmdlinep, cmdlinesz, + " virtio_mmio.device=1K@0x%llx:%lld", + vm->virtio_mmio_devices[i]->addr, + vm->virtio_mmio_devices[i]->irq); if (len >= cmdlinesz) { fprintf(stderr, "Too many arguments to the linux command line."); exit(1); diff --git a/user/vmm/include/vmm/virtio_mmio.h b/user/vmm/include/vmm/virtio_mmio.h index f0b8979..54471da 100644 --- a/user/vmm/include/vmm/virtio_mmio.h +++ b/user/vmm/include/vmm/virtio_mmio.h @@ -201,7 +201,7 @@ struct virtio_mmio_dev { // This utility function will be called when the device needs to interrupt // the guest. You can have it do whatever you want, but it is required. - void (*poke_guest)(void); + void (*poke_guest)(uint8_t vec); // Status flags for the device uint8_t status; @@ -212,6 +212,12 @@ struct virtio_mmio_dev { // The generic vq device contained by this mmio transport struct virtio_vq_dev *vqdev; + + // The specific irq number for this device. + uint64_t irq; + + // Actual vector the device will inject. + uint8_t vec; }; // Sets the VIRTIO_MMIO_INT_VRING bit in the interrupt status diff --git a/user/vmm/ioapic.c b/user/vmm/ioapic.c index 00c9819..651008e 100644 --- a/user/vmm/ioapic.c +++ b/user/vmm/ioapic.c @@ -31,6 +31,10 @@ #define IOAPIC_CONFIG 0x100 #define IOAPIC_NUM_PINS 24 +/* The problem with the IOAPIC and ISOR Structure means all irq numbers + * must be at least 24, so this is used to correct that offset. */ +#define IOAPIC_LAST_IRQ 23 + int debug_ioapic = 1; int apic_id_mask = 0xf0; @@ -47,12 +51,12 @@ struct ioapic { static struct ioapic ioapic[1]; -static uint32_t ioapic_read(int ix, uint64_t offset) +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; - if (offset == 0) { DPRINTF("ioapic_read ix %x return 0x%x\n", ix, reg); return reg; @@ -85,10 +89,13 @@ static uint32_t ioapic_read(int ix, uint64_t offset) return 0; } -static void ioapic_write(int ix, uint64_t offset, uint32_t value) +static void ioapic_write(struct guest_thread *vm_thread, int ix, + uint64_t offset, uint32_t value) { 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); @@ -96,6 +103,21 @@ static void ioapic_write(int ix, uint64_t offset, uint32_t 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 - IOAPIC_LAST_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); + } + } + switch (reg) { case 0: DPRINTF("IOAPIC_WRITE: Set %d ID to %d\n", ix, value); @@ -119,7 +141,7 @@ static void ioapic_write(int ix, uint64_t offset, uint32_t value) int do_ioapic(struct guest_thread *vm_thread, uint64_t gpa, int destreg, uint64_t *regp, int store) { - // TODO: compute an index for the ioapic array. + /* TODO(ganshun): compute an index for the ioapic array. */ int ix = 0; uint32_t offset = gpa & 0xfffff; /* basic sanity tests. */ @@ -131,9 +153,9 @@ int do_ioapic(struct guest_thread *vm_thread, uint64_t gpa, int destreg, } if (store) { - ioapic_write(ix, offset, *regp); + ioapic_write(vm_thread, ix, offset, *regp); } else { - *regp = ioapic_read(ix, offset); + *regp = ioapic_read(vm_thread, ix, offset); } } diff --git a/user/vmm/virtio_lguest_console.c b/user/vmm/virtio_lguest_console.c index 0303a0f..ffc0787 100644 --- a/user/vmm/virtio_lguest_console.c +++ b/user/vmm/virtio_lguest_console.c @@ -40,6 +40,7 @@ void cons_receiveq_fn(void *_vq) // host -> guest uint32_t i, j; int num_read; struct iovec *iov; + struct virtio_mmio_dev *dev = vq->vqdev->transport_dev; if (!vq) errx(1, @@ -85,10 +86,10 @@ void cons_receiveq_fn(void *_vq) // host -> guest virtio_add_used_desc(vq, head, num_read); // Poke the guest however the mmio transport prefers - // NOTE: assuming that the mmio transport was used for now - virtio_mmio_set_vring_irq(vq->vqdev->transport_dev); - if (((struct virtio_mmio_dev*)vq->vqdev->transport_dev)->poke_guest) - ((struct virtio_mmio_dev*)vq->vqdev->transport_dev)->poke_guest(); + // NOTE: assuming that the mmio transport was used for now. + virtio_mmio_set_vring_irq(dev); + if (dev->poke_guest) + dev->poke_guest(dev->vec); else VIRTIO_DEV_ERRX(vq->vqdev, "The host MUST provide a way for device interrupts to be sent to the guest. The 'poke_guest' function pointer on the vq->vqdev->transport_dev (assumed to be a struct virtio_mmio_dev) was not set."); @@ -103,6 +104,7 @@ void cons_transmitq_fn(void *_vq) // guest -> host uint32_t olen, ilen; uint32_t i, j; struct iovec *iov; + struct virtio_mmio_dev *dev = vq->vqdev->transport_dev; if (!vq) errx(1, @@ -146,9 +148,9 @@ void cons_transmitq_fn(void *_vq) // guest -> host // Poke the guest however the mmio transport prefers // NOTE: assuming that the mmio transport was used for now - virtio_mmio_set_vring_irq(vq->vqdev->transport_dev); - if (((struct virtio_mmio_dev*)vq->vqdev->transport_dev)->poke_guest) - ((struct virtio_mmio_dev*)vq->vqdev->transport_dev)->poke_guest(); + virtio_mmio_set_vring_irq(dev); + if (dev->poke_guest) + dev->poke_guest(dev->vec); else VIRTIO_DEV_ERRX(vq->vqdev, "The host MUST provide a way for device interrupts to be sent to the guest. The 'poke_guest' function pointer on the vq->vqdev->transport_dev (assumed to be a struct virtio_mmio_dev) was not set."); diff --git a/user/vmm/virtio_mmio.c b/user/vmm/virtio_mmio.c index 5cef438..9be52fe 100644 --- a/user/vmm/virtio_mmio.c +++ b/user/vmm/virtio_mmio.c @@ -451,7 +451,7 @@ void virtio_mmio_wr(struct virtual_machine *vm, // Notify the driver that the device-specific config changed virtio_mmio_set_cfg_irq(mmio_dev); if (mmio_dev->poke_guest) - mmio_dev->poke_guest(); + mmio_dev->poke_guest(mmio_dev->vec); return; } -- 2.8.0.rc3.226.g39d4020 -- You received this message because you are subscribed to the Google Groups "Akaros" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To post to this group, send email to [email protected]. For more options, visit https://groups.google.com/d/optout.
