diff --git a/openhcl/virt_mshv_vtl/src/processor/hardware_cvm/mod.rs b/openhcl/virt_mshv_vtl/src/processor/hardware_cvm/mod.rs index 37b9b883a4..0f17142a6d 100644 --- a/openhcl/virt_mshv_vtl/src/processor/hardware_cvm/mod.rs +++ b/openhcl/virt_mshv_vtl/src/processor/hardware_cvm/mod.rs @@ -1745,14 +1745,8 @@ impl UhProcessor<'_, B> { } /// Handle checking for cross-VTL interrupts, preempting VTL 0, and setting - /// VINA when appropriate. The `is_interrupt_pending` function should return - /// true if an interrupt of appropriate priority, or an NMI, is pending for - /// the given VTL. The boolean specifies whether RFLAGS.IF should be checked. - /// Returns true if interrupt reprocessing is required. - pub(crate) fn cvm_handle_cross_vtl_interrupts( - &mut self, - is_interrupt_pending: impl Fn(&mut Self, GuestVtl, bool) -> bool, - ) -> Result { + /// VINA when appropriate. Returns true if interrupt reprocessing is required. + fn cvm_handle_cross_vtl_interrupts(&mut self, dev: &impl CpuIo) -> Result { let cvm_state = self.backing.cvm_state(); // If VTL1 is not yet enabled, there is nothing to do. @@ -1761,7 +1755,8 @@ impl UhProcessor<'_, B> { } // Check for VTL preemption - which ignores RFLAGS.IF - if cvm_state.exit_vtl == GuestVtl::Vtl0 && is_interrupt_pending(self, GuestVtl::Vtl1, false) + if cvm_state.exit_vtl == GuestVtl::Vtl0 + && B::is_interrupt_pending(self, GuestVtl::Vtl1, false, dev) { self.raise_vtl(GuestVtl::Vtl0, GuestVtl::Vtl1, HvVtlEntryReason::INTERRUPT); } @@ -1770,7 +1765,7 @@ impl UhProcessor<'_, B> { // Check for VINA if self.backing.cvm_state().exit_vtl == GuestVtl::Vtl1 - && is_interrupt_pending(self, GuestVtl::Vtl0, true) + && B::is_interrupt_pending(self, GuestVtl::Vtl0, true, dev) { let hv = &mut self.backing.cvm_state_mut().hv[GuestVtl::Vtl1]; let vina = hv.synic.vina(); @@ -2342,7 +2337,8 @@ impl UhProcessor<'_, B> { } *first_scan_irr = false; - B::handle_cross_vtl_interrupts(self, dev).map_err(VpHaltReason::InvalidVmState) + self.cvm_handle_cross_vtl_interrupts(dev) + .map_err(VpHaltReason::InvalidVmState) } fn update_synic(&mut self, vtl: GuestVtl, untrusted_synic: bool) { diff --git a/openhcl/virt_mshv_vtl/src/processor/mod.rs b/openhcl/virt_mshv_vtl/src/processor/mod.rs index 3d79c73986..703d1fbaa3 100644 --- a/openhcl/virt_mshv_vtl/src/processor/mod.rs +++ b/openhcl/virt_mshv_vtl/src/processor/mod.rs @@ -446,12 +446,14 @@ trait HardwareIsolatedBacking: Backing { /// Vector of the event that is pending injection into the guest state, if /// valid. fn pending_event_vector(this: &UhProcessor<'_, Self>, vtl: GuestVtl) -> Option; - /// Checks interrupt status for all VTLs, and handles cross VTL interrupt preemption and VINA. - /// Returns whether interrupt reprocessing is required. - fn handle_cross_vtl_interrupts( + /// Check if an interrupt of appropriate priority, or an NMI, is pending for + /// the given VTL. `check_rflags` specifies whether RFLAGS.IF should be checked. + fn is_interrupt_pending( this: &mut UhProcessor<'_, Self>, + vtl: GuestVtl, + check_rflags: bool, dev: &impl CpuIo, - ) -> Result; + ) -> bool; /// Sets the pending exception for the guest state. /// /// Note that this will overwrite any existing pending exception. It will diff --git a/openhcl/virt_mshv_vtl/src/processor/snp/mod.rs b/openhcl/virt_mshv_vtl/src/processor/snp/mod.rs index b9bb582587..5db4a155fe 100644 --- a/openhcl/virt_mshv_vtl/src/processor/snp/mod.rs +++ b/openhcl/virt_mshv_vtl/src/processor/snp/mod.rs @@ -320,44 +320,44 @@ impl HardwareIsolatedBacking for SnpBacked { .expect("setting intercept control succeeds"); } - fn handle_cross_vtl_interrupts( + fn is_interrupt_pending( this: &mut UhProcessor<'_, Self>, + vtl: GuestVtl, + check_rflags: bool, dev: &impl CpuIo, - ) -> Result { - this.cvm_handle_cross_vtl_interrupts(|this, vtl, check_rflags| { - let vmsa = this.runner.vmsa_mut(vtl); - if vmsa.event_inject().valid() - && vmsa.event_inject().interruption_type() == x86defs::snp::SEV_INTR_TYPE_NMI - { - return true; - } + ) -> bool { + let vmsa = this.runner.vmsa_mut(vtl); + if vmsa.event_inject().valid() + && vmsa.event_inject().interruption_type() == x86defs::snp::SEV_INTR_TYPE_NMI + { + return true; + } - let vmsa_priority = vmsa.v_intr_cntrl().priority() as u32; - let lapic = &mut this.backing.cvm.lapics[vtl].lapic; - let ppr = lapic - .access(&mut SnpApicClient { - partition: this.partition, - vmsa, - dev, - vmtime: &this.vmtime, - vtl, - }) - .get_ppr(); - let ppr_priority = ppr >> 4; - if vmsa_priority <= ppr_priority { - return false; - } + let vmsa_priority = vmsa.v_intr_cntrl().priority() as u32; + let lapic = &mut this.backing.cvm.lapics[vtl].lapic; + let ppr = lapic + .access(&mut SnpApicClient { + partition: this.partition, + vmsa, + dev, + vmtime: &this.vmtime, + vtl, + }) + .get_ppr(); + let ppr_priority = ppr >> 4; + if vmsa_priority <= ppr_priority { + return false; + } - let vmsa = this.runner.vmsa_mut(vtl); - if (check_rflags && !RFlags::from_bits(vmsa.rflags()).interrupt_enable()) - || vmsa.v_intr_cntrl().intr_shadow() - || !vmsa.v_intr_cntrl().irq() - { - return false; - } + let vmsa = this.runner.vmsa_mut(vtl); + if (check_rflags && !RFlags::from_bits(vmsa.rflags()).interrupt_enable()) + || vmsa.v_intr_cntrl().intr_shadow() + || !vmsa.v_intr_cntrl().irq() + { + return false; + } - true - }) + true } } diff --git a/openhcl/virt_mshv_vtl/src/processor/tdx/mod.rs b/openhcl/virt_mshv_vtl/src/processor/tdx/mod.rs index 41cd2fa718..03758b88a6 100644 --- a/openhcl/virt_mshv_vtl/src/processor/tdx/mod.rs +++ b/openhcl/virt_mshv_vtl/src/processor/tdx/mod.rs @@ -657,63 +657,61 @@ impl HardwareIsolatedBacking for TdxBacked { ); } - fn handle_cross_vtl_interrupts( + fn is_interrupt_pending( this: &mut UhProcessor<'_, Self>, + vtl: GuestVtl, + check_rflags: bool, dev: &impl CpuIo, - ) -> Result { - this.cvm_handle_cross_vtl_interrupts(|this, vtl, check_rflags| { - let backing_vtl = &this.backing.vtls[vtl]; - if backing_vtl.interruption_information.valid() - && backing_vtl.interruption_information.interruption_type() == INTERRUPT_TYPE_NMI - { - return true; - } + ) -> bool { + let backing_vtl = &this.backing.vtls[vtl]; + if backing_vtl.interruption_information.valid() + && backing_vtl.interruption_information.interruption_type() == INTERRUPT_TYPE_NMI + { + return true; + } - let (vector, ppr) = if this.backing.cvm.lapics[vtl].lapic.is_offloaded() { - let vector = backing_vtl.private_regs.rvi; - let ppr = std::cmp::max( - backing_vtl.private_regs.svi.into(), - this.runner.tdx_apic_page(vtl).tpr.value, - ); - (vector, ppr) - } else { - let lapic = &mut this.backing.cvm.lapics[vtl].lapic; - let vector = lapic.next_irr().unwrap_or(0); - let ppr = lapic - .access(&mut TdxApicClient { - partition: this.partition, - apic_page: this.runner.tdx_apic_page_mut(vtl), - dev, - vmtime: &this.vmtime, - vtl, - }) - .get_ppr(); - (vector, ppr) - }; - let vector_priority = (vector as u32) >> 4; - let ppr_priority = ppr >> 4; + let (vector, ppr) = if this.backing.cvm.lapics[vtl].lapic.is_offloaded() { + let vector = backing_vtl.private_regs.rvi; + let ppr = std::cmp::max( + backing_vtl.private_regs.svi.into(), + this.runner.tdx_apic_page(vtl).tpr.value, + ); + (vector, ppr) + } else { + let lapic = &mut this.backing.cvm.lapics[vtl].lapic; + let vector = lapic.next_irr().unwrap_or(0); + let ppr = lapic + .access(&mut TdxApicClient { + partition: this.partition, + apic_page: this.runner.tdx_apic_page_mut(vtl), + dev, + vmtime: &this.vmtime, + vtl, + }) + .get_ppr(); + (vector, ppr) + }; + let vector_priority = (vector as u32) >> 4; + let ppr_priority = ppr >> 4; - if vector_priority <= ppr_priority { - return false; - } + if vector_priority <= ppr_priority { + return false; + } - if check_rflags - && !RFlags::from_bits(backing_vtl.private_regs.rflags).interrupt_enable() - { - return false; - } + if check_rflags && !RFlags::from_bits(backing_vtl.private_regs.rflags).interrupt_enable() { + return false; + } - let interruptibility: Interruptibility = this - .runner - .read_vmcs32(vtl, VmcsField::VMX_VMCS_GUEST_INTERRUPTIBILITY) - .into(); + let interruptibility: Interruptibility = this + .runner + .read_vmcs32(vtl, VmcsField::VMX_VMCS_GUEST_INTERRUPTIBILITY) + .into(); - if interruptibility.blocked_by_sti() || interruptibility.blocked_by_movss() { - return false; - } + if interruptibility.blocked_by_sti() || interruptibility.blocked_by_movss() { + return false; + } - true - }) + true } }