diff mbox

[1/4] BIOS changes for configuring irq0->inti2 override (v2)

Message ID 1241708222-11101-1-git-send-email-eak@us.ibm.com (mailing list archive)
State New, archived
Headers show

Commit Message

Beth Kon May 7, 2009, 2:56 p.m. UTC
These patches resolve the irq0->inti2 override issue, and get the hpet working
on kvm. 

They are dependent on Jes Sorensen's recent 0006-qemu-kvm-irq-routing.patch.

Override and HPET changes are sent as a series because HPET depends on the 
override. Win2k8 expects the HPET interrupt on inti2, regardless of whether 
an override exists in the BIOS. And the HPET spec states that in legacy mode, 
timer interrupt is on inti2.

The irq0->inti2 override will always be used unless the kernel cannot do irq 
routing (i.e., compatibility with old kernels). So if the kernel is capable, 
userspace sets up irq0->inti2 via the irq routing interface, and adds the 
irq0->inti2 override to the MADT interrupt source override table, 
and the mp table (for the no-acpi case).

A couple of months ago, Marcelo was seeing RHEL5 guests complain of invalid
checksum with these patches, but later he couldn't reproduce it, and I'm not 
seeing it now. While all guests still need to be fully tested, everything 
appears to be in order.  I've tested on win2k864, win2k832, RHEL5.3 32 bit, 
and ubuntu 8.10 64 bit. 

Signed-off-by: Beth Kon <eak@us.ibm.com>

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Comments

Avi Kivity May 7, 2009, 3:56 p.m. UTC | #1
Beth Kon wrote:
> These patches resolve the irq0->inti2 override issue, and get the hpet working
> on kvm. 
>
> They are dependent on Jes Sorensen's recent 0006-qemu-kvm-irq-routing.patch.
>
> Override and HPET changes are sent as a series because HPET depends on the 
> override. Win2k8 expects the HPET interrupt on inti2, regardless of whether 
> an override exists in the BIOS. And the HPET spec states that in legacy mode, 
> timer interrupt is on inti2.
>
> The irq0->inti2 override will always be used unless the kernel cannot do irq 
> routing (i.e., compatibility with old kernels). So if the kernel is capable, 
> userspace sets up irq0->inti2 via the irq routing interface, and adds the 
> irq0->inti2 override to the MADT interrupt source override table, 
> and the mp table (for the no-acpi case).
>
> A couple of months ago, Marcelo was seeing RHEL5 guests complain of invalid
> checksum with these patches, but later he couldn't reproduce it, and I'm not 
> seeing it now. While all guests still need to be fully tested, everything 
> appears to be in order.  I've tested on win2k864, win2k832, RHEL5.3 32 bit, 
> and ubuntu 8.10 64 bit. 
>
>   

What are the changes relative to v1?

> @@ -477,6 +480,7 @@ void wrmsr_smp(uint32_t index, uint64_t val)
>  #define QEMU_CFG_SIGNATURE  0x00
>  #define QEMU_CFG_ID         0x01
>  #define QEMU_CFG_UUID       0x02
> +#define QEMU_CFG_IRQ0_OVERRIDE 0x0e
>   

As noted, this should be in the arch local space.
Beth Kon May 7, 2009, 4:30 p.m. UTC | #2
Avi Kivity wrote:
> Beth Kon wrote:
>> These patches resolve the irq0->inti2 override issue, and get the 
>> hpet working
>> on kvm.
>> They are dependent on Jes Sorensen's recent 
>> 0006-qemu-kvm-irq-routing.patch.
>>
>> Override and HPET changes are sent as a series because HPET depends 
>> on the override. Win2k8 expects the HPET interrupt on inti2, 
>> regardless of whether an override exists in the BIOS. And the HPET 
>> spec states that in legacy mode, timer interrupt is on inti2.
>>
>> The irq0->inti2 override will always be used unless the kernel cannot 
>> do irq routing (i.e., compatibility with old kernels). So if the 
>> kernel is capable, userspace sets up irq0->inti2 via the irq routing 
>> interface, and adds the irq0->inti2 override to the MADT interrupt 
>> source override table, and the mp table (for the no-acpi case).
>>
>> A couple of months ago, Marcelo was seeing RHEL5 guests complain of 
>> invalid
>> checksum with these patches, but later he couldn't reproduce it, and 
>> I'm not seeing it now. While all guests still need to be fully 
>> tested, everything appears to be in order.  I've tested on win2k864, 
>> win2k832, RHEL5.3 32 bit, and ubuntu 8.10 64 bit.
>>   
>
> What are the changes relative to v1?
Just merge issues with the changes you put in when moving to the newer 
bios. I submitted prematurely, incorrectly thinking I was done testing. 
When I finished, some problems surfaced.
>
>> @@ -477,6 +480,7 @@ void wrmsr_smp(uint32_t index, uint64_t val)
>>  #define QEMU_CFG_SIGNATURE  0x00
>>  #define QEMU_CFG_ID         0x01
>>  #define QEMU_CFG_UUID       0x02
>> +#define QEMU_CFG_IRQ0_OVERRIDE 0x0e
>>   
>
> As noted, this should be in the arch local space.
>
The base changes were not in the code yet. As we discussed on IRC, I'll 
resubmit once they're there.

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/kvm/bios/rombios32.c b/kvm/bios/rombios32.c
index 8684987..07dda73 100755
--- a/kvm/bios/rombios32.c
+++ b/kvm/bios/rombios32.c
@@ -445,6 +445,9 @@  uint32_t cpuid_ext_features;
 unsigned long ram_size;
 uint64_t ram_end;
 uint8_t bios_uuid[16];
+#ifdef BX_QEMU
+uint8_t irq0_override;
+#endif
 #ifdef BX_USE_EBDA_TABLES
 unsigned long ebda_cur_addr;
 #endif
@@ -477,6 +480,7 @@  void wrmsr_smp(uint32_t index, uint64_t val)
 #define QEMU_CFG_SIGNATURE  0x00
 #define QEMU_CFG_ID         0x01
 #define QEMU_CFG_UUID       0x02
+#define QEMU_CFG_IRQ0_OVERRIDE 0x0e
 
 int qemu_cfg_port;
 
@@ -518,6 +522,18 @@  void uuid_probe(void)
     memset(bios_uuid, 0, 16);
 }
 
+#ifdef BX_QEMU
+void irq0_override_probe(void)
+{
+    if(qemu_cfg_port) {
+        qemu_cfg_select(QEMU_CFG_IRQ0_OVERRIDE);
+        qemu_cfg_read(&irq0_override, 1);
+        return;
+    }
+    memset(&irq0_override, 0, 1);
+}
+#endif
+
 void cpu_probe(void)
 {
     uint32_t eax, ebx, ecx, edx;
@@ -1160,6 +1176,13 @@  static void mptable_init(void)
 
     /* irqs */
     for(i = 0; i < 16; i++) {
+#ifdef BX_QEMU
+        /* One entry per ioapic interrupt destination. Destination 2 is covered
+         * by irq0->inti2 override (i == 0). Source IRQ 2 is unused 
+         */
+        if (irq0_override && i == 2)
+            continue;
+#endif
         putb(&q, 3); /* entry type = I/O interrupt */
         putb(&q, 0); /* interrupt type = vectored interrupt */
         putb(&q, 0); /* flags: po=0, el=0 */
@@ -1167,7 +1190,12 @@  static void mptable_init(void)
         putb(&q, 0); /* source bus ID = ISA */
         putb(&q, i); /* source bus IRQ */
         putb(&q, ioapic_id); /* dest I/O APIC ID */
-        putb(&q, i); /* dest I/O APIC interrupt in */
+#ifdef BX_QEMU
+        if (irq0_override && i == 0)
+            putb(&q, 2); /* dest I/O APIC interrupt in */
+        else
+#endif
+            putb(&q, i); /* dest I/O APIC interrupt in */
     }
     /* patch length */
     len = q - mp_config_table;
@@ -1550,16 +1578,18 @@  void acpi_bios_init(void)
 
     addr = (addr + 7) & ~7;
     madt_addr = addr;
+    madt = (void *)(addr);
     madt_size = sizeof(*madt) +
         sizeof(struct madt_processor_apic) * MAX_CPUS +
-#ifdef BX_QEMU
-        sizeof(struct madt_io_apic) /* + sizeof(struct madt_int_override) */;
-#else
         sizeof(struct madt_io_apic);
+#ifdef BX_QEMU
+    for (i = 0; i < 16; i++)
+        if (PCI_ISA_IRQ_MASK & (1U << i))
+            madt_size += sizeof(struct madt_int_override);
+    if (irq0_override)
+        madt_size += sizeof(struct madt_int_override);
 #endif
-    madt = (void *)(addr);
     addr += madt_size;
-
 #ifdef BX_QEMU
 #ifdef HPET_WORKS_IN_KVM
     addr = (addr + 7) & ~7;
@@ -1660,23 +1690,20 @@  void acpi_bios_init(void)
         io_apic->io_apic_id = smp_cpus;
         io_apic->address = cpu_to_le32(0xfec00000);
         io_apic->interrupt = cpu_to_le32(0);
+        int_override = (struct madt_int_override*)(io_apic + 1);
 #ifdef BX_QEMU
-#ifdef HPET_WORKS_IN_KVM
-        io_apic++;
-
-        int_override = (void *)io_apic;
-        int_override->type = APIC_XRUPT_OVERRIDE;
-        int_override->length = sizeof(*int_override);
-        int_override->bus = cpu_to_le32(0);
-        int_override->source = cpu_to_le32(0);
-        int_override->gsi = cpu_to_le32(2);
-        int_override->flags = cpu_to_le32(0);
-#endif
+        if (irq0_override) {
+            memset(int_override, 0, sizeof(*int_override));
+            int_override->type = APIC_XRUPT_OVERRIDE;
+            int_override->length = sizeof(*int_override);
+            int_override->source = 0;
+            int_override->gsi = 2;
+            int_override->flags = 0; /* conforms to bus specifications */
+            int_override++;
+        }
 #endif
-
-        int_override = (struct madt_int_override*)(io_apic + 1);
         for ( i = 0; i < 16; i++ ) {
-            if ( PCI_ISA_IRQ_MASK & (1U << i) ) {
+            if (PCI_ISA_IRQ_MASK & (1U << i)) {
                 memset(int_override, 0, sizeof(*int_override));
                 int_override->type   = APIC_XRUPT_OVERRIDE;
                 int_override->length = sizeof(*int_override);
@@ -1688,7 +1715,6 @@  void acpi_bios_init(void)
                 continue;
             }
             int_override++;
-            madt_size += sizeof(struct madt_int_override);
         }
         acpi_build_table_header((struct acpi_table_header *)madt,
                                 "APIC", madt_size, 1);
@@ -2325,6 +2351,9 @@  void rombios32_init(uint32_t *s3_resume_vector, uint8_t *shutdown_flag)
 
     if (bios_table_cur_addr != 0) {
 
+#ifdef BX_QEMU
+        irq0_override_probe();
+#endif        
         mptable_init();
 
         uuid_probe();