Commit b4a2f5e7 authored by Gleb Natapov's avatar Gleb Natapov Committed by Avi Kivity

KVM: Avoid redelivery of edge interrupt before next edge

The check for an edge is broken in current ioapic code. ioapic->irr is
cleared on each edge interrupt by ioapic_service() and this makes
old_irr != ioapic->irr condition in kvm_ioapic_set_irq() to be always
true. The patch fixes the code to properly recognise edge.

Some HW emulation calls set_irq() without level change. If each such
call is propagated to an OS it may confuse a device driver. This is the
case with keyboard device emulation and Windows XP x64  installer on SMP VM.
Each keystroke produce two interrupts (down/up) one interrupt is
submitted to CPU0 and another to CPU1. This confuses Windows somehow
and it ignores keystrokes.
Signed-off-by: default avatarGleb Natapov <gleb@redhat.com>
Signed-off-by: default avatarAvi Kivity <avi@redhat.com>
parent 53a27b39
...@@ -95,8 +95,6 @@ static int ioapic_service(struct kvm_ioapic *ioapic, unsigned int idx) ...@@ -95,8 +95,6 @@ static int ioapic_service(struct kvm_ioapic *ioapic, unsigned int idx)
if (injected && pent->fields.trig_mode == IOAPIC_LEVEL_TRIG) if (injected && pent->fields.trig_mode == IOAPIC_LEVEL_TRIG)
pent->fields.remote_irr = 1; pent->fields.remote_irr = 1;
} }
if (!pent->fields.trig_mode)
ioapic->irr &= ~(1 << idx);
return injected; return injected;
} }
...@@ -136,7 +134,8 @@ static void ioapic_write_indirect(struct kvm_ioapic *ioapic, u32 val) ...@@ -136,7 +134,8 @@ static void ioapic_write_indirect(struct kvm_ioapic *ioapic, u32 val)
mask_after = ioapic->redirtbl[index].fields.mask; mask_after = ioapic->redirtbl[index].fields.mask;
if (mask_before != mask_after) if (mask_before != mask_after)
kvm_fire_mask_notifiers(ioapic->kvm, index, mask_after); kvm_fire_mask_notifiers(ioapic->kvm, index, mask_after);
if (ioapic->irr & (1 << index)) if (ioapic->redirtbl[index].fields.trig_mode == IOAPIC_LEVEL_TRIG
&& ioapic->irr & (1 << index))
ioapic_service(ioapic, index); ioapic_service(ioapic, index);
break; break;
} }
...@@ -184,9 +183,10 @@ int kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level) ...@@ -184,9 +183,10 @@ int kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level)
if (!level) if (!level)
ioapic->irr &= ~mask; ioapic->irr &= ~mask;
else { else {
int edge = (entry.fields.trig_mode == IOAPIC_EDGE_TRIG);
ioapic->irr |= mask; ioapic->irr |= mask;
if ((!entry.fields.trig_mode && old_irr != ioapic->irr) if ((edge && old_irr != ioapic->irr) ||
|| !entry.fields.remote_irr) (!edge && !entry.fields.remote_irr))
ret = ioapic_service(ioapic, irq); ret = ioapic_service(ioapic, irq);
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment