aboutsummaryrefslogtreecommitdiffstats
path: root/virt
diff options
context:
space:
mode:
authorMarcelo Tosatti <mtosatti@redhat.com>2008-06-04 23:08:11 -0400
committerAvi Kivity <avi@qumranet.com>2008-06-06 14:32:39 -0400
commitff4b9df877b30b8a371d706d3552999dee450738 (patch)
treef2195b2d4305643b59b78be266e98215a31bdcf4 /virt
parent8d2d73b9a5c35f2c6abf427afba7888cfc4cc65d (diff)
KVM: IOAPIC: only set remote_irr if interrupt was injected
There's a bug in the IOAPIC code for level-triggered interrupts. Its relatively easy to trigger by sharing (virtio-blk + usbtablet was the testcase, initially reported by Gerd von Egidy). The "remote_irr" variable is used to indicate accepted but not yet acked interrupts. Its cleared from the EOI handler. Problem is that the EOI handler clears remote_irr unconditionally, even if it reinjected another pending interrupt. In that case, kvm_ioapic_set_irq() proceeds to ioapic_service() which sets remote_irr even if it failed to inject (since the IRR was high due to EOI reinjection). Since the TMR bit has been cleared by the first EOI, the second one fails to clear remote_irr. End result is interrupt line dead. Fix it by setting remote_irr only if a new pending interrupt has been generated (and the TMR bit for vector in question set). Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com> Signed-off-by: Avi Kivity <avi@qumranet.com>
Diffstat (limited to 'virt')
-rw-r--r--virt/kvm/ioapic.c21
1 files changed, 11 insertions, 10 deletions
diff --git a/virt/kvm/ioapic.c b/virt/kvm/ioapic.c
index 4232fd75dd2..98778cb69c6 100644
--- a/virt/kvm/ioapic.c
+++ b/virt/kvm/ioapic.c
@@ -45,7 +45,7 @@
45#else 45#else
46#define ioapic_debug(fmt, arg...) 46#define ioapic_debug(fmt, arg...)
47#endif 47#endif
48static void ioapic_deliver(struct kvm_ioapic *vioapic, int irq); 48static int ioapic_deliver(struct kvm_ioapic *vioapic, int irq);
49 49
50static unsigned long ioapic_read_indirect(struct kvm_ioapic *ioapic, 50static unsigned long ioapic_read_indirect(struct kvm_ioapic *ioapic,
51 unsigned long addr, 51 unsigned long addr,
@@ -89,8 +89,8 @@ static void ioapic_service(struct kvm_ioapic *ioapic, unsigned int idx)
89 pent = &ioapic->redirtbl[idx]; 89 pent = &ioapic->redirtbl[idx];
90 90
91 if (!pent->fields.mask) { 91 if (!pent->fields.mask) {
92 ioapic_deliver(ioapic, idx); 92 int injected = ioapic_deliver(ioapic, idx);
93 if (pent->fields.trig_mode == IOAPIC_LEVEL_TRIG) 93 if (injected && pent->fields.trig_mode == IOAPIC_LEVEL_TRIG)
94 pent->fields.remote_irr = 1; 94 pent->fields.remote_irr = 1;
95 } 95 }
96 if (!pent->fields.trig_mode) 96 if (!pent->fields.trig_mode)
@@ -133,7 +133,7 @@ static void ioapic_write_indirect(struct kvm_ioapic *ioapic, u32 val)
133 } 133 }
134} 134}
135 135
136static void ioapic_inj_irq(struct kvm_ioapic *ioapic, 136static int ioapic_inj_irq(struct kvm_ioapic *ioapic,
137 struct kvm_vcpu *vcpu, 137 struct kvm_vcpu *vcpu,
138 u8 vector, u8 trig_mode, u8 delivery_mode) 138 u8 vector, u8 trig_mode, u8 delivery_mode)
139{ 139{
@@ -143,7 +143,7 @@ static void ioapic_inj_irq(struct kvm_ioapic *ioapic,
143 ASSERT((delivery_mode == IOAPIC_FIXED) || 143 ASSERT((delivery_mode == IOAPIC_FIXED) ||
144 (delivery_mode == IOAPIC_LOWEST_PRIORITY)); 144 (delivery_mode == IOAPIC_LOWEST_PRIORITY));
145 145
146 kvm_apic_set_irq(vcpu, vector, trig_mode); 146 return kvm_apic_set_irq(vcpu, vector, trig_mode);
147} 147}
148 148
149static u32 ioapic_get_delivery_bitmask(struct kvm_ioapic *ioapic, u8 dest, 149static u32 ioapic_get_delivery_bitmask(struct kvm_ioapic *ioapic, u8 dest,
@@ -186,7 +186,7 @@ static u32 ioapic_get_delivery_bitmask(struct kvm_ioapic *ioapic, u8 dest,
186 return mask; 186 return mask;
187} 187}
188 188
189static void ioapic_deliver(struct kvm_ioapic *ioapic, int irq) 189static int ioapic_deliver(struct kvm_ioapic *ioapic, int irq)
190{ 190{
191 u8 dest = ioapic->redirtbl[irq].fields.dest_id; 191 u8 dest = ioapic->redirtbl[irq].fields.dest_id;
192 u8 dest_mode = ioapic->redirtbl[irq].fields.dest_mode; 192 u8 dest_mode = ioapic->redirtbl[irq].fields.dest_mode;
@@ -195,7 +195,7 @@ static void ioapic_deliver(struct kvm_ioapic *ioapic, int irq)
195 u8 trig_mode = ioapic->redirtbl[irq].fields.trig_mode; 195 u8 trig_mode = ioapic->redirtbl[irq].fields.trig_mode;
196 u32 deliver_bitmask; 196 u32 deliver_bitmask;
197 struct kvm_vcpu *vcpu; 197 struct kvm_vcpu *vcpu;
198 int vcpu_id; 198 int vcpu_id, r = 0;
199 199
200 ioapic_debug("dest=%x dest_mode=%x delivery_mode=%x " 200 ioapic_debug("dest=%x dest_mode=%x delivery_mode=%x "
201 "vector=%x trig_mode=%x\n", 201 "vector=%x trig_mode=%x\n",
@@ -204,7 +204,7 @@ static void ioapic_deliver(struct kvm_ioapic *ioapic, int irq)
204 deliver_bitmask = ioapic_get_delivery_bitmask(ioapic, dest, dest_mode); 204 deliver_bitmask = ioapic_get_delivery_bitmask(ioapic, dest, dest_mode);
205 if (!deliver_bitmask) { 205 if (!deliver_bitmask) {
206 ioapic_debug("no target on destination\n"); 206 ioapic_debug("no target on destination\n");
207 return; 207 return 0;
208 } 208 }
209 209
210 switch (delivery_mode) { 210 switch (delivery_mode) {
@@ -216,7 +216,7 @@ static void ioapic_deliver(struct kvm_ioapic *ioapic, int irq)
216 vcpu = ioapic->kvm->vcpus[0]; 216 vcpu = ioapic->kvm->vcpus[0];
217#endif 217#endif
218 if (vcpu != NULL) 218 if (vcpu != NULL)
219 ioapic_inj_irq(ioapic, vcpu, vector, 219 r = ioapic_inj_irq(ioapic, vcpu, vector,
220 trig_mode, delivery_mode); 220 trig_mode, delivery_mode);
221 else 221 else
222 ioapic_debug("null lowest prio vcpu: " 222 ioapic_debug("null lowest prio vcpu: "
@@ -234,7 +234,7 @@ static void ioapic_deliver(struct kvm_ioapic *ioapic, int irq)
234 deliver_bitmask &= ~(1 << vcpu_id); 234 deliver_bitmask &= ~(1 << vcpu_id);
235 vcpu = ioapic->kvm->vcpus[vcpu_id]; 235 vcpu = ioapic->kvm->vcpus[vcpu_id];
236 if (vcpu) { 236 if (vcpu) {
237 ioapic_inj_irq(ioapic, vcpu, vector, 237 r = ioapic_inj_irq(ioapic, vcpu, vector,
238 trig_mode, delivery_mode); 238 trig_mode, delivery_mode);
239 } 239 }
240 } 240 }
@@ -246,6 +246,7 @@ static void ioapic_deliver(struct kvm_ioapic *ioapic, int irq)
246 delivery_mode); 246 delivery_mode);
247 break; 247 break;
248 } 248 }
249 return r;
249} 250}
250 251
251void kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level) 252void kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level)