X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?p=palacios.git;a=blobdiff_plain;f=palacios%2Fsrc%2Fdevices%2Fmptable.c;h=cca7a44667a07349162cbc00054f4f9de7d6b375;hp=3b6a4631b923180e2934922f4c6e9894426f1812;hb=eb2dd607efd35a1521ae6a707e0a2178dd1f74ee;hpb=4dd1b9b1f155688a8196c1bc9f32f74275511718 diff --git a/palacios/src/devices/mptable.c b/palacios/src/devices/mptable.c index 3b6a463..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); @@ -364,10 +393,19 @@ static int write_mptable(void * target, uint32_t numcores) { 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; @@ -384,7 +422,7 @@ 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 = dst_irq; @@ -392,10 +430,55 @@ static int write_mptable(void * target, uint32_t numcores) { 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; @@ -403,8 +486,6 @@ static int write_mptable(void * target, uint32_t numcores) { sum += ((uint8_t *)target)[i]; } header->checksum = (255 - sum) + 1; - - return 0; }