From f130ef89aa8ad4a1aa189bc1aecc3548781f526c Mon Sep 17 00:00:00 2001 From: John Starks Date: Thu, 14 Nov 2024 10:11:21 -0800 Subject: [PATCH] virt_support_apic: scan IRR for self IPIs and timers (#331) When an interrupt is delivered locally (for self IPIs and timers), we don't notify the partition to wake the processor, and so we never scan IRR to find and deliver these interrupts. Fix this. --- vmm_core/virt_support_apic/src/lib.rs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/vmm_core/virt_support_apic/src/lib.rs b/vmm_core/virt_support_apic/src/lib.rs index 7bd0572f7a..c58c311c6e 100644 --- a/vmm_core/virt_support_apic/src/lib.rs +++ b/vmm_core/virt_support_apic/src/lib.rs @@ -111,6 +111,7 @@ pub struct LocalApic { active_auto_eoi: bool, is_offloaded: bool, needs_offload_reeval: bool, + scan_irr: bool, stats: Stats, } @@ -397,6 +398,7 @@ impl LocalApicSet { active_auto_eoi: false, needs_offload_reeval: false, is_offloaded: false, + scan_irr: false, stats: Stats::default(), }; apic.reset(); @@ -1029,7 +1031,7 @@ impl LocalApicAccess<'_, T> { } ApicRegister::SELF_IPI if self.apic.x2apic_enabled() => { self.apic.stats.self_ipi.increment(); - self.apic.shared.request_interrupt( + self.apic.scan_irr |= self.apic.shared.request_interrupt( self.apic.software_enabled(), DeliveryMode::FIXED, value as u8, @@ -1108,7 +1110,7 @@ impl LocalApicAccess<'_, T> { } DestinationShorthand::SELF => { self.apic.stats.self_ipi.increment(); - self.apic.shared.request_interrupt( + self.apic.scan_irr |= self.apic.shared.request_interrupt( self.apic.software_enabled(), delivery_mode, icr.vector(), @@ -1143,6 +1145,7 @@ impl LocalApicAccess<'_, T> { impl SharedState { /// Returns true if the VP should be woken up to scan the APIC. + #[must_use] fn request_interrupt( &self, software_enabled: bool, @@ -1457,7 +1460,7 @@ impl LocalApic { } let mut r = self.flush(); - if scan_irr { + if scan_irr || self.scan_irr { self.pull_irr(); } if !self.is_offloaded { @@ -1649,7 +1652,7 @@ impl LocalApic { let lvt = Lvt::from(self.lvt_timer); if counts >= self.timer_ccr as u64 { if !lvt.masked() { - self.shared.request_interrupt( + self.scan_irr |= self.shared.request_interrupt( self.software_enabled(), DeliveryMode::FIXED, lvt.vector(), @@ -1734,6 +1737,7 @@ impl LocalApic { timer_dcr, active_auto_eoi, needs_offload_reeval, + scan_irr, is_offloaded: _, stats: _, } = self; @@ -1750,6 +1754,7 @@ impl LocalApic { // disabled state. *irr = [0; 8]; *needs_offload_reeval = false; + *scan_irr = false; *tmr = [0; 8]; *auto_eoi = [0; 8]; *active_auto_eoi = false; @@ -1974,6 +1979,7 @@ impl LocalApic { } } self.recompute_next_irr(); + self.scan_irr = false; } fn id_register(&self) -> u32 {