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: Gleb Natapov <gleb@redhat.com> Signed-off-by: Avi Kivity <avi@redhat.com>
This commit is contained in:
		
					parent
					
						
							
								53a27b39ff
							
						
					
				
			
			
				commit
				
					
						b4a2f5e723
					
				
			
		
					 1 changed files with 5 additions and 5 deletions
				
			
		|  | @ -95,8 +95,6 @@ static int ioapic_service(struct kvm_ioapic *ioapic, unsigned int idx) | |||
| 		if (injected && pent->fields.trig_mode == IOAPIC_LEVEL_TRIG) | ||||
| 			pent->fields.remote_irr = 1; | ||||
| 	} | ||||
| 	if (!pent->fields.trig_mode) | ||||
| 		ioapic->irr &= ~(1 << idx); | ||||
| 
 | ||||
| 	return injected; | ||||
| } | ||||
|  | @ -136,7 +134,8 @@ static void ioapic_write_indirect(struct kvm_ioapic *ioapic, u32 val) | |||
| 		mask_after = ioapic->redirtbl[index].fields.mask; | ||||
| 		if (mask_before != 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); | ||||
| 		break; | ||||
| 	} | ||||
|  | @ -184,9 +183,10 @@ int kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level) | |||
| 		if (!level) | ||||
| 			ioapic->irr &= ~mask; | ||||
| 		else { | ||||
| 			int edge = (entry.fields.trig_mode == IOAPIC_EDGE_TRIG); | ||||
| 			ioapic->irr |= mask; | ||||
| 			if ((!entry.fields.trig_mode && old_irr != ioapic->irr) | ||||
| 			    || !entry.fields.remote_irr) | ||||
| 			if ((edge && old_irr != ioapic->irr) || | ||||
| 			    (!edge && !entry.fields.remote_irr)) | ||||
| 				ret = ioapic_service(ioapic, irq); | ||||
| 		} | ||||
| 	} | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Gleb Natapov
				Gleb Natapov