qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH] fix PIC irq delivery for x86 target when local APIC


From: He, Qing
Subject: [Qemu-devel] [PATCH] fix PIC irq delivery for x86 target when local APIC is enabled
Date: Sat, 28 Apr 2007 16:31:36 +0800

Current interrupt logic in Qemu unconditionally checks pending irqs on
PIC after checking local APIC, however, this is problematic.
        On x86 platform, PIC is usually connected to the LINT0 of local
APIC. In this way when local APIC is disabled, this pin behaves like
INTR. But when local APIC is enabled, its behavior can be determined by
LVT_LINT0: PIC should only deliver normal irq only when `external
interrupt' delivery mode is set.
        x86_64 Linux kernel uses PIT->PIC->LINT0 as NMI source when
performance counters are not available, but the logic described above
treats the NMI as normal interrupt which yields a 2x faster global timer
because an additional timer interrupt is injected on every tick. This
patch fixes this issue.

Thanks,
Qing

diff -uNra qemu-cvs/hw/apic.c qemu/hw/apic.c
--- qemu-cvs/hw/apic.c  2007-04-04 00:38:34.000000000 +0800
+++ qemu/hw/apic.c      2007-04-28 16:19:36.000000000 +0800
@@ -484,6 +484,20 @@
     return intno;
 }
 
+int apic_accept_pic_intr(CPUState *env)
+{
+    APICState *s = env->apic_state;
+    uint32_t lvt0 = s->lvt[APIC_LVT_LINT0];
+
+    if (env->cpu_index == 0 &&
+        ((s->apicbase & MSR_IA32_APICBASE_ENABLE) == 0 ||
+         ((lvt0 & APIC_LVT_MASKED) == 0 &&
+          ((lvt0 >> 8) & 0x7) == APIC_DM_EXTINT)))
+        return 1;
+
+    return 0;
+}
+
 static uint32_t apic_get_current_count(APICState *s)
 {
     int64_t d;
@@ -821,6 +835,13 @@
     s->apicbase = 0xfee00000 | 
         (s->id ? 0 : MSR_IA32_APICBASE_BSP) | MSR_IA32_APICBASE_ENABLE;
 
+    /*
+     * LINT0 delivery mode is set to ExtInt at initialization time, so
+     * PIC interrupt can be delivered to the processor when local APIC
+     * is enabled.
+     */
+    s->lvt[APIC_LVT_LINT0] = 0x700;
+
     /* XXX: mapping more APICs at the same memory location */
     if (apic_io_memory == 0) {
         /* NOTE: the APIC is directly connected to the CPU - it is not
diff -uNra qemu-cvs/hw/pc.c qemu/hw/pc.c
--- qemu-cvs/hw/pc.c    2007-04-08 02:14:41.000000000 +0800
+++ qemu/hw/pc.c        2007-04-28 16:19:36.000000000 +0800
@@ -98,6 +98,9 @@
         return intno;
     }
     /* read the irq from the PIC */
+    if (!apic_accept_pic_intr(env))
+        return -1;
+
     intno = pic_read_irq(isa_pic);
     return intno;
 }
diff -uNra qemu-cvs/vl.h qemu/vl.h
--- qemu-cvs/vl.h       2007-04-24 15:40:49.000000000 +0800
+++ qemu/vl.h   2007-04-28 16:19:36.000000000 +0800
@@ -1090,6 +1090,7 @@
 
 int apic_init(CPUState *env);
 int apic_get_interrupt(CPUState *env);
+int apic_accept_pic_intr(CPUState *env);
 IOAPICState *ioapic_init(void);
 void ioapic_set_irq(void *opaque, int vector, int level);

Attachment: qemu-pc-pic-apic-mutual-exclusive.patch
Description: qemu-pc-pic-apic-mutual-exclusive.patch


reply via email to

[Prev in Thread] Current Thread [Next in Thread]