X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?a=blobdiff_plain;f=palacios%2Fsrc%2Fdevices%2Fmptable.c;h=cca7a44667a07349162cbc00054f4f9de7d6b375;hb=eb2dd607efd35a1521ae6a707e0a2178dd1f74ee;hp=64cf96f65a053610551075c8aa71f3b532e4dcc5;hpb=9d406e84682878859284200ae00251d27c53c845;p=palacios.releases.git diff --git a/palacios/src/devices/mptable.c b/palacios/src/devices/mptable.c index 64cf96f..cca7a44 100644 --- a/palacios/src/devices/mptable.c +++ b/palacios/src/devices/mptable.c @@ -30,7 +30,10 @@ Currently, we set up n identical processors (based on number of cores in guest info), with apics 0..n-1, and - ioapic as n. + ioapic as n. The ISA interrupt lines map to pins 0..15 + of the first ioapic. PCI bus lines map to pins 16..19 + of the first ioapic. The system supports virtual wire + compability mode and symmetric mode. PIC mode is not supported. The expectation is that the target will have 8 bytes (for ___HVMMP signature) followed by 896 bytes of space @@ -72,6 +75,7 @@ #define BUS_ISA "ISA " +#define BUS_PCI "PCI " #define INT_TYPE_INT 0 #define INT_TYPE_NMI 1 @@ -214,6 +218,8 @@ struct mp_table_local_interrupt_assignment { +#define PCI 1 +#define NUM_PCI_SLOTS 8 static inline int check_for_cookie(void * target) { @@ -275,6 +281,11 @@ static int write_pointer(void * target, uint32_t mptable_gpa) { p->pointer = mptable_gpa; p->length = 1; // length in 16 byte chunks p->spec_rev = SPEC_REV; + + // The remaining zeros indicate that an MP config table is present + // and that virtual wire mode is implemented (not PIC mode) + // Either virtual wire or PIC must be implemented in addition to + // symmetric I/O mode // checksum calculation p->checksum = 0; @@ -315,8 +326,14 @@ static int write_mptable(void * target, uint32_t numcores) { memcpy(header->oem_id, OEM_ID, 8); memcpy(header->prod_id, PROD_ID, 12); - // n processors, 1 ioapic, 1 isa bus, 16 IRQs = 18+n +#if PCI + // n processors, 1 ioapic, 1 pci bus, 1 isa bus, 16 IRQ, 4*NUM_SLOTS = 19 + 4*numslots+ n + header->entry_count = numcores + 19 + 4 * NUM_PCI_SLOTS; +#else + // n processors, 1 ioapic, 1 isa bus, 16 IRQ INTs = 18+n header->entry_count = numcores + 18; +#endif + header->lapic_addr = LAPIC_ADDR; // now we arrange the processors; @@ -343,15 +360,27 @@ static int write_mptable(void * target, uint32_t numcores) { cur += sizeof(struct mp_table_processor); } - // next comes the ISA bas +#if PCI + // PCI bus is always zero bus = (struct mp_table_bus *)cur; cur += sizeof(struct mp_table_bus); memset((void *)bus, 0, sizeof(struct mp_table_bus)); bus->entry_type = ENTRY_BUS; bus->bus_id = 0; + memcpy(bus->bus_type, BUS_PCI, 6); +#endif + + // next comes the ISA bus (bus one) + bus = (struct mp_table_bus *)cur; + cur += sizeof(struct mp_table_bus); + + memset((void *)bus, 0, sizeof(struct mp_table_bus)); + bus->entry_type = ENTRY_BUS; + bus->bus_id = 1; memcpy(bus->bus_type, BUS_ISA, 6); + // next comes the IOAPIC ioapic = (struct mp_table_ioapic *)cur; cur += sizeof(struct mp_table_ioapic); @@ -363,7 +392,29 @@ static int write_mptable(void * target, uint32_t numcores) { ioapic->ioapic_flags.en = 1; ioapic->ioapic_address = IOAPIC_ADDR; + + + // LEGACY ISA IRQ mappings + // The MPTABLE IRQ mappings are kind of odd. + // We don't include a bus IRQ 2, and instead remap Bus IRQ 0 to dest irq 2 + // The idea here is that the timer hooks to 2, while the PIC hooks + // to zero in ExtInt mode. This makes it possible to do virtual wire + // mode via the ioapic. + // + // Note that the timer connects to pin 2 of the IOAPIC. Sadly, + // the timer is unaware of this and just raises irq 0. The ioapic + // transforms this to a pin 2 interrupt. If we want the PIC + // to be able to channel interrupts via pin 0, we need a separate + // path. for (irq = 0; irq < 16; irq++) { + uint8_t dst_irq = irq; + + if (irq == 0) { + dst_irq = 2; + } else if (irq == 2) { + continue; + } + interrupt = (struct mp_table_io_interrupt_assignment *)cur; memset((void *)interrupt, 0, sizeof(struct mp_table_io_interrupt_assignment)); @@ -371,18 +422,63 @@ static int write_mptable(void * target, uint32_t numcores) { interrupt->interrupt_type = INT_TYPE_INT; interrupt->flags.po = INT_POLARITY_DEFAULT; interrupt->flags.el = INT_TRIGGER_DEFAULT; - interrupt->source_bus_id = 0; + interrupt->source_bus_id = 1; interrupt->source_bus_irq = irq; interrupt->dest_ioapic_id = numcores; - interrupt->dest_ioapic_intn = irq; + interrupt->dest_ioapic_intn = dst_irq; cur += sizeof(struct mp_table_io_interrupt_assignment); } +#if PCI + { + // Interrupt redirection entries for PCI bus + // + // We need an entry for each slot+pci interrupt + // There can be 32 slots, each of which can use 4 interrupts + // Thus there are 128 entries + // + // In this simple setup, we map + // slot i, intr j (both zero based) to pci_irq[(i+j)%4] + + int slot, intr; + static uint8_t pci_irq[4] = {16,17,18,19}; + + for (slot=0;slotentry_type = ENTRY_IOINT; + interrupt->interrupt_type = INT_TYPE_INT; + interrupt->flags.po = INT_POLARITY_DEFAULT; + interrupt->flags.el = INT_TRIGGER_DEFAULT; + interrupt->source_bus_id = 0; + // Yes, this is how you encode the slot and pin of a PCI device + // As we all know, bits are expensive + // We can have as many as 32 slots, but to get that large, + // we would need to tweak the bios's landing zone for the mptable + interrupt->source_bus_irq = (slot<<2) | intr ; + interrupt->dest_ioapic_id = numcores; + interrupt->dest_ioapic_intn = dst_irq; + + cur += sizeof(struct mp_table_io_interrupt_assignment); + + //V3_Print("PCI0, slot %d, irq %d maps to irq %d\n",slot,intr,dst_irq); + } + } + } +#endif + // now we can set the length; header->base_table_length = (cur - (uint8_t *)header); + V3_Print("MPtable size: %u\n",header->base_table_length); + // checksum calculation header->checksum = 0; sum = 0; @@ -390,8 +486,6 @@ static int write_mptable(void * target, uint32_t numcores) { sum += ((uint8_t *)target)[i]; } header->checksum = (255 - sum) + 1; - - return 0; }