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 c4a969571d..9680d8aa4d 100644 --- a/openhcl/virt_mshv_vtl/src/processor/hardware_cvm/mod.rs +++ b/openhcl/virt_mshv_vtl/src/processor/hardware_cvm/mod.rs @@ -1448,7 +1448,7 @@ impl hv1_hypercall::EnablePartitionVtl GuestVsmState::NotGuestEnabled => (), GuestVsmState::Enabled { vtl1: _ } => { // VTL 1 cannot be already enabled - return Err(HvError::VtlAlreadyEnabled); + return Err(HvError::InvalidVtlState); } } diff --git a/opentmk/src/platform/hyperv/arch/hypercall.rs b/opentmk/src/platform/hyperv/arch/hypercall.rs index d3a3193ecf..d1a63fc395 100644 --- a/opentmk/src/platform/hyperv/arch/hypercall.rs +++ b/opentmk/src/platform/hyperv/arch/hypercall.rs @@ -142,7 +142,7 @@ impl HvCall { let output = self.dispatch_hvcall(hvdef::HypercallCode::HvCallEnablePartitionVtl, None); match output.result() { - Ok(()) | Err(hvdef::HvError::VtlAlreadyEnabled) => Ok(()), + Ok(()) | Err(hvdef::HvError::InvalidVtlState) => Ok(()), err => err, } } diff --git a/vmm_core/virt_whp/src/lib.rs b/vmm_core/virt_whp/src/lib.rs index 7611128055..6657b6d17f 100644 --- a/vmm_core/virt_whp/src/lib.rs +++ b/vmm_core/virt_whp/src/lib.rs @@ -388,6 +388,26 @@ impl Vplc { start_vp_context: Default::default(), } } + + /// Resets the pending per-VTL VP signals to the initial state from `Vplc::new`. + /// + /// This is used when resetting the partition or scrubbing a VTL, so that + /// the freshly-reinitialized VTL does not observe stale events queued + /// before the reset. + fn reset(&self) { + let Self { + message_queues, + check_queues, + extint_pending, + start_vp_context, + start_vp, + } = self; + message_queues.clear(); + check_queues.store(false, Ordering::Relaxed); + extint_pending.store(false, Ordering::Relaxed); + *start_vp_context.lock() = None; + start_vp.store(false, Ordering::Relaxed); + } } impl<'a> WhpVpRef<'a> { @@ -1642,13 +1662,18 @@ impl<'p> virt::Processor for WhpProcessor<'p> { let is_bsp = self.inner.vp_info.base.is_bsp(); self.state.reset(false, is_bsp); + // For each enabled VTL: apply arch fixups that WHP doesn't handle + // and clear any pending `start_vp_context` (via `finish_reset`), + // then clear stale pending per-VTL VP signal flags (via + // `Vplc::reset`). // VTL0 is always present. self.finish_reset(Vtl::Vtl0); - self.vplc(Vtl::Vtl0).message_queues.clear(); + self.vplc(Vtl::Vtl0).reset(); if self.state.vtls.vtl2.is_some() { self.finish_reset(Vtl::Vtl2); - self.vplc(Vtl::Vtl2).message_queues.clear(); + self.vplc(Vtl::Vtl2).reset(); } + self.inner.vtl2_wake.store(false, Ordering::Relaxed); if cfg!(debug_assertions) { let vp_info = &self.inner.vp_info; @@ -1663,11 +1688,29 @@ impl<'p> virt::Processor for WhpProcessor<'p> { fn scrub(&mut self, vtl: Vtl) -> Result<(), impl std::error::Error + Send + Sync + 'static> { assert_eq!(vtl, Vtl::Vtl2); let is_bsp = self.inner.vp_info.base.is_bsp(); + + // Reset per-VP VTL2-enable state on non-BSP VPs. The new VTL2 + // will re-issue `HvCallEnableVpVtl` on each AP to program its startup + // context (RIP/RSP/CR3/GDT/IDT). Clear VTL2 from `enabled_vtls` + // before `state.reset` so that `runnable_vtls` and `active_vtl` are + // derived from the post-scrub set rather than the pre-scrub one. + if !is_bsp { + self.inner.vtl2_enable.store(false, Ordering::Relaxed); + self.state.enabled_vtls.clear(Vtl::Vtl2); + } + self.state.reset(true, is_bsp); - // Scrub only resets VTL2. + // Scrub only resets VTL2. Reset the Vplc to clear any stale pending + // signals (message queue notifications, external interrupts, start-VP + // requests, etc.) -- the hypervisor zeroes the equivalent per-VTL + // activity flags during a VTL scrub. self.finish_reset(Vtl::Vtl2); - self.vplc(Vtl::Vtl2).message_queues.clear(); + self.vplc(Vtl::Vtl2).reset(); + + // Clear any pending VTL2 wake signal, since VTL2 is now back in + // startup suspend and any prior wake request is stale. + self.inner.vtl2_wake.store(false, Ordering::Relaxed); if cfg!(debug_assertions) { let vp_info = &self.inner.vp_info;