@@ -597,13 +597,24 @@ DeviceState *cpu_get_current_apic(void)
void gsi_handler(void *opaque, int n, int level)
{
GSIState *s = opaque;
-
+ int i8259_pin = n;
trace_x86_gsi_interrupt(n, level);
switch (n) {
- case 0 ... ISA_NUM_IRQS - 1:
- if (s->i8259_irq[n]) {
+ case 2:
+ /*
+ * Special case for HPET legacy mode, which is defined as routing HPET
+ * timer 0 to IRQ2 of the I/O APIC and IRQ0 of the i8259 PIC. Since
+ * IRQ2 on the i8259 is the cascade, it isn't otherwise valid so we
+ * handle it via this special case.
+ */
+ i8259_pin = 0;
+ /* fall through */
+ case 0:
+ case 1:
+ case 3 ... ISA_NUM_IRQS - 1:
+ if (s->i8259_irq[i8259_pin]) {
/* Under KVM, Kernel will forward to both PIC and IOAPIC */
- qemu_set_irq(s->i8259_irq[n], level);
+ qemu_set_irq(s->i8259_irq[i8259_pin], level);
}
/* fall through */
case ISA_NUM_IRQS ... IOAPIC_NUM_PINS - 1:
@@ -196,8 +196,11 @@ static void update_irq(struct HPETTimer *timer, int set)
/* if LegacyReplacementRoute bit is set, HPET specification requires
* timer0 be routed to IRQ0 in NON-APIC or IRQ2 in the I/O APIC,
* timer1 be routed to IRQ8 in NON-APIC or IRQ8 in the I/O APIC.
+ *
+ * There is a special case in the x86 gsi_handler() which converts
+ * IRQ2 into IRQ0 for the i8259 PIC and makes this work correctly.
*/
- route = (timer->tn == 0) ? 0 : RTC_ISA_IRQ;
+ route = (timer->tn == 0) ? 2 : RTC_ISA_IRQ;
} else {
route = timer_int_route(timer);
}