Under certain conditions, PIC interrupts should not be passed through by
the local APIC. This is usually when the guest uses the IOAPIC instead
of the PIC.
Currently qemu does not block PIC interrupts when the local APIC is
configured to do so; this results in interrupts begin received twice and
time running at double speed on Linux x86_64 guest.
The attached patch, from Qing He and myself, fixes the problem.
--
error compiling committee.c: too many arguments to function
Index: vl.h
===================================================================
RCS file: /sources/qemu/qemu/vl.h,v
retrieving revision 1.273
diff -u -u -r1.273 vl.h
--- vl.h 30 Sep 2007 14:44:52 -0000 1.273
+++ vl.h 2 Oct 2007 10:28:55 -0000
@@ -1138,6 +1138,7 @@
typedef struct IOAPICState IOAPICState;
int apic_init(CPUState *env);
+int apic_accept_pic_intr(CPUState *env);
int apic_get_interrupt(CPUState *env);
IOAPICState *ioapic_init(void);
void ioapic_set_irq(void *opaque, int vector, int level);
Index: hw/apic.c
===================================================================
RCS file: /sources/qemu/qemu/hw/apic.c,v
retrieving revision 1.16
diff -u -u -r1.16 apic.c
--- hw/apic.c 17 Sep 2007 08:09:46 -0000 1.16
+++ hw/apic.c 2 Oct 2007 10:28:55 -0000
@@ -484,6 +484,25 @@
return intno;
}
+int apic_accept_pic_intr(CPUState *env)
+{
+ APICState *s = env->apic_state;
+ uint32_t lvt0;
+
+ if (!s)
+ return -1;
+
+ lvt0 = s->lvt[APIC_LVT_LINT0];
+
+ if (s->id == 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;
@@ -790,6 +809,13 @@
{
APICState *s = opaque;
apic_init_ipi(s);
+
+ /*
+ * LINT0 delivery mode is set to ExtInt at initialization time
+ * typically by BIOS, so PIC interrupt can be delivered to the
+ * processor when local APIC is enabled.
+ */
+ s->lvt[APIC_LVT_LINT0] = 0x700;
}
static CPUReadMemoryFunc *apic_mem_read[3] = {
@@ -821,6 +847,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
+ * typically by BIOS, 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
Index: hw/pc.c
===================================================================
RCS file: /sources/qemu/qemu/hw/pc.c,v
retrieving revision 1.85
diff -u -u -r1.85 pc.c
--- hw/pc.c 17 Sep 2007 08:09:47 -0000 1.85
+++ hw/pc.c 2 Oct 2007 10:28:55 -0000
@@ -93,6 +93,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;
}
@@ -100,10 +103,8 @@
static void pic_irq_request(void *opaque, int irq, int level)
{
CPUState *env = opaque;
- if (level)
+ if (level && apic_accept_pic_intr(env))
cpu_interrupt(env, CPU_INTERRUPT_HARD);
- else
- cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
}
/* PC cmos mappings */
-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2005.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
_______________________________________________
kvm-devel mailing list
kvm-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/kvm-devel