mptable and madt irq override

Implement irq override support for timer interrupts. This matches what
QEMU+BOCHS has been doing for the latest 8 months, and is also what
real hardware does.

Windows expects this according to Beth Kon.

Based on patch by Jes Sorensen <jes@sgi.com>
diff --git a/src/acpi.c b/src/acpi.c
index bafdd6b..ef4eaf9 100644
--- a/src/acpi.c
+++ b/src/acpi.c
@@ -331,7 +331,16 @@
     io_apic->interrupt = cpu_to_le32(0);
 
     struct madt_intsrcovr *intsrcovr = (void*)&io_apic[1];
-    for (i = 0; i < 16; i++) {
+    if (irq0override) {
+        memset(intsrcovr, 0, sizeof(*intsrcovr));
+        intsrcovr->type   = APIC_XRUPT_OVERRIDE;
+        intsrcovr->length = sizeof(*intsrcovr);
+        intsrcovr->source = 0;
+        intsrcovr->gsi    = 2;
+        intsrcovr->flags  = 0; /* conforms to bus specifications */
+        intsrcovr++;
+    }
+    for (i = 1; i < 16; i++) {
         if (!(PCI_ISA_IRQ_MASK & (1 << i)))
             /* No need for a INT source override structure. */
             continue;
diff --git a/src/mptable.c b/src/mptable.c
index 5758b28..dd3b10a 100644
--- a/src/mptable.c
+++ b/src/mptable.c
@@ -10,6 +10,12 @@
 #include "config.h" // CONFIG_*
 #include "mptable.h" // MPTABLE_SIGNATURE
 
+#if CONFIG_KVM
+int irq0override = 1;
+#else
+int irq0override = 0;
+#endif
+
 void
 mptable_init(void)
 {
@@ -48,7 +54,6 @@
     // Config structure.
     memset(config, 0, sizeof(*config));
     config->signature = MPCONFIG_SIGNATURE;
-    config->length = length - sizeof(*floating);
     config->spec = 4;
     memcpy(config->oemid, CONFIG_CPUNAME8, sizeof(config->oemid));
     memcpy(config->productid, "0.1         ", sizeof(config->productid));
@@ -94,19 +99,28 @@
     ioapic->apicaddr = BUILD_IOAPIC_ADDR;
 
     /* irqs */
-    struct mpt_intsrc *intsrcs = (void *)&ioapic[1];
-    for(i = 0; i < 16; i++) {
-        struct mpt_intsrc *isrc = &intsrcs[i];
-        memset(isrc, 0, sizeof(*isrc));
-        isrc->type = MPT_TYPE_INTSRC;
-        isrc->srcbusirq = i;
-        isrc->dstapic = ioapic_id;
-        isrc->dstirq = i;
+    struct mpt_intsrc *intsrc = (void*)&ioapic[1];
+    for (i = 0; i < 16; i++) {
+        memset(intsrc, 0, sizeof(*intsrc));
+        intsrc->type = MPT_TYPE_INTSRC;
+        intsrc->srcbusirq = i;
+        intsrc->dstapic = ioapic_id;
+        intsrc->dstirq = i;
+        if (irq0override) {
+            /* Destination 2 is covered by irq0->inti2 override (i ==
+               0). Source IRQ 2 is unused */
+            if (i == 0)
+                intsrc->dstirq = 2;
+            else if (i == 2)
+                intsrc--;
+        }
+        intsrc++;
     }
 
     // Set checksum.
+    config->length = (void*)intsrc - (void*)config;
     config->checksum -= checksum(config, config->length);
 
     dprintf(1, "MP table addr=%p MPC table addr=%p size=%d\n",
-            floating, config, length);
+            floating, config, config->length);
 }
diff --git a/src/util.h b/src/util.h
index 22b58bc..6cdcffe 100644
--- a/src/util.h
+++ b/src/util.h
@@ -244,4 +244,7 @@
 // misc.c
 extern u8 BiosChecksum;
 
+// mptable.c
+extern int irq0override;
+
 #endif // util.h