aboutsummaryrefslogtreecommitdiff
path: root/target-i386
diff options
context:
space:
mode:
authorJan Kiszka <jan.kiszka@siemens.com>2012-07-09 16:42:32 +0200
committerMichael Roth <mdroth@linux.vnet.ibm.com>2012-08-21 15:36:35 -0500
commita47343957489b9fafdb438351e8fa9d58d7fd30b (patch)
treefcf5b78d3c4b264a2b0190f0eb217a8dafcf6cc6 /target-i386
parent2a93a8940093560686fdcda24776ff265d6bcba7 (diff)
apic: Defer interrupt updates to VCPU thread
KVM performs TPR raising asynchronously to QEMU, specifically outside QEMU's global lock. When an interrupt is injected into the APIC and TPR is checked to decide if this can be delivered, a stale TPR value may be used, causing spurious interrupts in the end. Fix this by deferring apic_update_irq to the context of the target VCPU. We introduce a new interrupt flag for this, CPU_INTERRUPT_POLL. When it is set, the VCPU calls apic_poll_irq before checking for further pending interrupts. To avoid special-casing KVM, we also implement this logic for TCG mode. Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com> Signed-off-by: Avi Kivity <avi@redhat.com> (cherry picked from commit 5d62c43a17edaa7f6a88821c9086e6c8e0e5327d) Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
Diffstat (limited to 'target-i386')
-rw-r--r--target-i386/cpu.h4
-rw-r--r--target-i386/kvm.c4
2 files changed, 7 insertions, 1 deletions
diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index 2460f6348b..8ff3f304c1 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -477,6 +477,7 @@
for syscall instruction */
/* i386-specific interrupt pending bits. */
+#define CPU_INTERRUPT_POLL CPU_INTERRUPT_TGT_EXT_1
#define CPU_INTERRUPT_SMI CPU_INTERRUPT_TGT_EXT_2
#define CPU_INTERRUPT_NMI CPU_INTERRUPT_TGT_EXT_3
#define CPU_INTERRUPT_MCE CPU_INTERRUPT_TGT_EXT_4
@@ -1029,7 +1030,8 @@ static inline void cpu_clone_regs(CPUX86State *env, target_ulong newsp)
static inline bool cpu_has_work(CPUX86State *env)
{
- return ((env->interrupt_request & CPU_INTERRUPT_HARD) &&
+ return ((env->interrupt_request & (CPU_INTERRUPT_HARD |
+ CPU_INTERRUPT_POLL)) &&
(env->eflags & IF_MASK)) ||
(env->interrupt_request & (CPU_INTERRUPT_NMI |
CPU_INTERRUPT_INIT |
diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index e74a9e4641..d8bbe4ff6a 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -1725,6 +1725,10 @@ int kvm_arch_process_async_events(CPUX86State *env)
return 0;
}
+ if (env->interrupt_request & CPU_INTERRUPT_POLL) {
+ env->interrupt_request &= ~CPU_INTERRUPT_POLL;
+ apic_poll_irq(env->apic_state);
+ }
if (((env->interrupt_request & CPU_INTERRUPT_HARD) &&
(env->eflags & IF_MASK)) ||
(env->interrupt_request & CPU_INTERRUPT_NMI)) {