diff --git a/openhcl/hcl/src/ioctl.rs b/openhcl/hcl/src/ioctl.rs index f463d906b..0b953a7b5 100644 --- a/openhcl/hcl/src/ioctl.rs +++ b/openhcl/hcl/src/ioctl.rs @@ -121,6 +121,8 @@ pub enum Error { TranslateGvaToGpa(#[source] TranslateGvaToGpaError), #[error("gpa failed vtl access check")] CheckVtlAccess(#[source] HvError), + #[error("failed to set registers")] + SetRegisters(#[source] HvError), #[error("Unknown register name: {0:x}")] UnknownRegisterName(u32), #[error("Invalid register value")] @@ -445,10 +447,6 @@ mod ioctls { mshv_vp_registers ); - // The kernel has a bug where it only supports one register at a time. - // Increase this when this is fixed. - pub const MSHV_VP_MAX_REGISTERS: usize = 1; - ioctl_write_ptr!( /// Adds the VTL0 memory as a ZONE_DEVICE memory (I/O) to support /// DMA from the guest. @@ -1269,7 +1267,10 @@ impl MshvHvcall { todo!(); } Some(Vtl::Vtl0) => { - assert!(matches!(name, HvArm64RegisterName::GuestOsId)); + assert!(matches!( + name, + HvArm64RegisterName::GuestOsId | HvArm64RegisterName::XPc + )); } } @@ -1498,57 +1499,154 @@ impl Drop for ProcessorRunner<'_, T> { } impl<'a, T: Backing> ProcessorRunner<'a, T> { - fn set_reg(&mut self, regs: &[HvRegisterAssoc]) -> Result<(), Error> { + // These registers are handled specially by the kernel through a dedicated + // ioctl. is_special_register is arch-specific to guard against an into() on an + // HvArmRegisterName that overlaps one of these x86-specific values. + #[cfg(guest_arch = "x86_64")] + fn is_special_register(&self, name: HvX64RegisterName) -> bool { + if name == HvX64RegisterName::Xfem { + if let Some(IsolationType::Tdx) = self.hcl.isolation() { + return true; + } + } + + matches!( + name, + HvX64RegisterName::MsrMtrrCap + | HvX64RegisterName::MsrMtrrDefType + | HvX64RegisterName::MsrMtrrPhysBase0 + | HvX64RegisterName::MsrMtrrPhysBase1 + | HvX64RegisterName::MsrMtrrPhysBase2 + | HvX64RegisterName::MsrMtrrPhysBase3 + | HvX64RegisterName::MsrMtrrPhysBase4 + | HvX64RegisterName::MsrMtrrPhysBase5 + | HvX64RegisterName::MsrMtrrPhysBase6 + | HvX64RegisterName::MsrMtrrPhysBase7 + | HvX64RegisterName::MsrMtrrPhysBase8 + | HvX64RegisterName::MsrMtrrPhysBase9 + | HvX64RegisterName::MsrMtrrPhysBaseA + | HvX64RegisterName::MsrMtrrPhysBaseB + | HvX64RegisterName::MsrMtrrPhysBaseC + | HvX64RegisterName::MsrMtrrPhysBaseD + | HvX64RegisterName::MsrMtrrPhysBaseE + | HvX64RegisterName::MsrMtrrPhysBaseF + | HvX64RegisterName::MsrMtrrPhysMask0 + | HvX64RegisterName::MsrMtrrPhysMask1 + | HvX64RegisterName::MsrMtrrPhysMask2 + | HvX64RegisterName::MsrMtrrPhysMask3 + | HvX64RegisterName::MsrMtrrPhysMask4 + | HvX64RegisterName::MsrMtrrPhysMask5 + | HvX64RegisterName::MsrMtrrPhysMask6 + | HvX64RegisterName::MsrMtrrPhysMask7 + | HvX64RegisterName::MsrMtrrPhysMask8 + | HvX64RegisterName::MsrMtrrPhysMask9 + | HvX64RegisterName::MsrMtrrPhysMaskA + | HvX64RegisterName::MsrMtrrPhysMaskB + | HvX64RegisterName::MsrMtrrPhysMaskC + | HvX64RegisterName::MsrMtrrPhysMaskD + | HvX64RegisterName::MsrMtrrPhysMaskE + | HvX64RegisterName::MsrMtrrPhysMaskF + | HvX64RegisterName::MsrMtrrFix64k00000 + | HvX64RegisterName::MsrMtrrFix16k80000 + | HvX64RegisterName::MsrMtrrFix16kA0000 + | HvX64RegisterName::MsrMtrrFix4kC0000 + | HvX64RegisterName::MsrMtrrFix4kC8000 + | HvX64RegisterName::MsrMtrrFix4kD0000 + | HvX64RegisterName::MsrMtrrFix4kD8000 + | HvX64RegisterName::MsrMtrrFix4kE0000 + | HvX64RegisterName::MsrMtrrFix4kE8000 + | HvX64RegisterName::MsrMtrrFix4kF0000 + | HvX64RegisterName::MsrMtrrFix4kF8000 + | HvX64RegisterName::Dr0 + | HvX64RegisterName::Dr1 + | HvX64RegisterName::Dr2 + | HvX64RegisterName::Dr3 + | HvX64RegisterName::Dr6 + ) + } + + #[cfg(guest_arch = "aarch64")] + fn is_special_register(&self, _name: HvArm64RegisterName) -> bool { + false + } + + fn set_reg(&mut self, regs: &[HvRegisterAssoc], vtl: Vtl) -> Result<(), Error> { if regs.is_empty() { return Ok(()); } - // TODO GUEST_VSM - let vtl = Vtl::Vtl0; + if let Some(sidecar) = &mut self.sidecar { sidecar .set_vp_registers(vtl.into(), regs) .map_err(Error::Sidecar)?; } else { - for regs in regs.chunks(MSHV_VP_MAX_REGISTERS) { - let hv_vp_register_args = mshv_vp_registers { - count: regs.len() as i32, - regs: regs.as_ptr().cast_mut(), - }; - // SAFETY: IOCTL call with correct types. - unsafe { - hcl_set_vp_register(self.hcl.mshv_vtl.file.as_raw_fd(), &hv_vp_register_args) + // TODO: group up to MSHV_VP_MAX_REGISTERS regs + for reg in regs { + let hc_regs = &mut [HvRegisterAssoc { + name: reg.name, + pad: [0; 3], + value: reg.value, + }]; + + if self.is_special_register(reg.name.into()) { + let hv_vp_register_args = mshv_vp_registers { + count: 1, + regs: hc_regs.as_mut_ptr(), + }; + // SAFETY: ioctl call with correct types. + unsafe { + hcl_set_vp_register( + self.hcl.mshv_vtl.file.as_raw_fd(), + &hv_vp_register_args, + ) .map_err(Error::SetVpRegister)?; + } + } else { + let hc_regs = [HvRegisterAssoc { + name: reg.name, + pad: [0; 3], + value: reg.value, + }]; + self.set_vp_registers_hvcall_inner(vtl, &hc_regs) + .map_err(Error::SetRegisters)?; } } } Ok(()) } - fn get_reg(&mut self, regs: &mut [HvRegisterAssoc]) -> Result<(), Error> { + fn get_reg(&mut self, regs: &mut [HvRegisterAssoc], vtl: Vtl) -> Result<(), Error> { if regs.is_empty() { return Ok(()); } - // TODO GUEST_VSM - let vtl = Vtl::Vtl0; + if let Some(sidecar) = &mut self.sidecar { sidecar .get_vp_registers(vtl.into(), regs) .map_err(Error::Sidecar)?; } else { - for reg_names in regs.chunks_mut(MSHV_VP_MAX_REGISTERS) { - let mut mshv_vp_register_args = mshv_vp_registers { - count: reg_names.len() as i32, - regs: reg_names.as_mut_ptr(), - }; - // SAFETY: we know that our file is a vCPU fd, we know the kernel will only read the - // correct amount of memory from our pointer, and we verify the return result. - unsafe { - hcl_get_vp_register( - self.hcl.mshv_vtl.file.as_raw_fd(), - &mut mshv_vp_register_args, - ) - .map_err(Error::GetVpRegister)?; - }; + // TODO: group up to MSHV_VP_MAX_REGISTERS regs + for reg in regs { + if self.is_special_register(reg.name.into()) { + let mut mshv_vp_register_args = mshv_vp_registers { + count: 1, + regs: reg, + }; + // SAFETY: we know that our file is a vCPU fd, we know the kernel will only read the + // correct amount of memory from our pointer, and we verify the return result. + unsafe { + hcl_get_vp_register( + self.hcl.mshv_vtl.file.as_raw_fd(), + &mut mshv_vp_register_args, + ) + .map_err(Error::GetVpRegister)?; + } + } else { + reg.value = self + .hcl + .mshv_hvcall + .get_vp_register_for_vtl(reg.name.into(), vtl.into()); + } } } Ok(()) @@ -1668,98 +1766,81 @@ impl<'a, T: Backing> ProcessorRunner<'a, T> { } impl ProcessorRunner<'_, T> { - fn set_vp_register_inner( + fn get_vp_registers_inner>( &mut self, - name: HvRegisterName, - value: HvRegisterValue, + names: &[R], + values: &mut [HvRegisterValue], + vtl: Vtl, ) -> Result<(), Error> { - let set = T::try_set_reg(self, name, value)?; - if set { - return Ok(()); + assert_eq!(names.len(), values.len()); + let mut assoc = Vec::new(); + let mut offset = Vec::new(); + for (i, (&name, value)) in names.iter().zip(values.iter_mut()).enumerate() { + if let Some(v) = T::try_get_reg(self, name.into())? { + *value = v; + } else { + assoc.push(HvRegisterAssoc { + name: name.into(), + pad: Default::default(), + value: FromZeroes::new_zeroed(), + }); + offset.push(i); + } } - // Set the register via a hypercall. - let info = [HvRegisterAssoc { - name, - pad: Default::default(), - value, - }]; - - self.set_reg(&info)?; - + self.get_reg(&mut assoc, vtl)?; + for (&i, assoc) in offset.iter().zip(&assoc) { + values[i] = assoc.value; + } Ok(()) } - /// Set the following register on the given VP, x86_64 + /// Get the following register on the current VP. /// /// This will fail for registers that are in the mmapped CPU context, i.e. /// registers that are shared between VTL0 and VTL2. + pub fn get_vp_register( + &mut self, + #[cfg(guest_arch = "x86_64")] name: HvX64RegisterName, + #[cfg(guest_arch = "aarch64")] name: HvArm64RegisterName, + vtl: Vtl, + ) -> Result { + let mut value = [0u64.into(); 1]; + self.get_vp_registers_inner(&[name], &mut value, vtl)?; + Ok(value[0]) + } + + /// Get the following VP registers on the current VP. /// - /// Can only set registers for VTL 0. - #[cfg(guest_arch = "x86_64")] - pub fn set_vp_register( + /// # Panics + /// Panics if `names.len() != values.len()`. + + pub fn get_vp_registers( &mut self, - name: HvX64RegisterName, - value: HvRegisterValue, + #[cfg(guest_arch = "x86_64")] names: &[HvX64RegisterName], + #[cfg(guest_arch = "aarch64")] names: &[HvArm64RegisterName], + values: &mut [HvRegisterValue], + vtl: Vtl, ) -> Result<(), Error> { - tracing::trace!(?name, ?value, "set_vp_register"); - self.set_vp_register_inner(name.into(), value) + self.get_vp_registers_inner(names, values, vtl) } - /// Set the following register on the given VP, aarch64 + /// Set the following register on the current VP. /// /// This will fail for registers that are in the mmapped CPU context, i.e. /// registers that are shared between VTL0 and VTL2. - /// - /// Can only set registers for VTL 0. - #[cfg(guest_arch = "aarch64")] pub fn set_vp_register( &mut self, - name: HvArm64RegisterName, + #[cfg(guest_arch = "x86_64")] name: HvX64RegisterName, + #[cfg(guest_arch = "aarch64")] name: HvArm64RegisterName, value: HvRegisterValue, + vtl: Vtl, ) -> Result<(), Error> { - tracing::trace!(?name, ?value, "set_vp_register"); - self.set_vp_register_inner(name.into(), value) - } - - fn get_vp_register_inner(&mut self, name: HvRegisterName) -> Result { - if let Some(value) = T::try_get_reg(self, name)? { - return Ok(value); - } - let mut info = [HvRegisterAssoc { - name, - pad: Default::default(), - value: FromZeroes::new_zeroed(), - }]; - self.get_reg(&mut info)?; - Ok(info[0].value) + self.set_vp_registers([(name, value)], vtl) } - /// Get the following register on the current VP, x86_64. - /// - /// This will fail for registers that are in the mmapped CPU context, i.e. - /// registers that are shared between VTL0 and VTL2. - /// - /// Can only get registers for VTL 0. - #[cfg(guest_arch = "x86_64")] - pub fn get_vp_register(&mut self, name: HvX64RegisterName) -> Result { - self.get_vp_register_inner(name.into()) - } - - /// Get the following register on the current VP, aarch64. - /// - /// This will fail for registers that are in the mmapped CPU context, i.e. - /// registers that are shared between VTL0 and VTL2. - /// - /// Can only get registers for VTL 0. - #[cfg(guest_arch = "aarch64")] - pub fn get_vp_register(&mut self, name: HvArm64RegisterName) -> Result { - tracing::trace!(?name, "get_vp_register"); - self.get_vp_register_inner(name.into()) - } - - /// Sets a set of VP registers on the last intercepting VTL. - pub fn set_vp_registers(&mut self, values: I) -> Result<(), Error> + /// Sets a set of VP registers. + pub fn set_vp_registers(&mut self, values: I, vtl: Vtl) -> Result<(), Error> where I: IntoIterator, I::Item: Into + Clone, @@ -1767,7 +1848,7 @@ impl ProcessorRunner<'_, T> { let mut assoc = Vec::new(); for HvRegisterAssoc { name, value, .. } in values.into_iter().map(Into::into) { if !assoc.is_empty() && T::must_flush_regs_on(self, name) { - self.set_reg(&assoc)?; + self.set_reg(&assoc, vtl)?; assoc.clear(); } if !T::try_set_reg(self, name, value)? { @@ -1776,63 +1857,50 @@ impl ProcessorRunner<'_, T> { pad: Default::default(), value, }); - } - } - self.set_reg(&assoc) - } - fn get_vp_registers_inner>( - &mut self, - names: &[R], - values: &mut [HvRegisterValue], - ) -> Result<(), Error> { - assert_eq!(names.len(), values.len()); - let mut assoc = Vec::new(); - let mut offset = Vec::new(); - for (i, (&name, value)) in names.iter().zip(values.iter_mut()).enumerate() { - if let Some(v) = T::try_get_reg(self, name.into())? { - *value = v; - } else { - assoc.push(HvRegisterAssoc { - name: name.into(), - pad: Default::default(), - value: FromZeroes::new_zeroed(), - }); - offset.push(i); + if T::must_flush_regs_on(self, name) { + self.set_reg(&assoc, vtl)?; + assoc.clear(); + } } } - - self.get_reg(&mut assoc)?; - for (&i, assoc) in offset.iter().zip(&assoc) { - values[i] = assoc.value; + if !assoc.is_empty() { + self.set_reg(&assoc, vtl)?; } Ok(()) } - /// Get the following VP registers on the current VP. - /// - /// # Panics - /// Panics if `names.len() != values.len()`. - #[cfg(guest_arch = "x86_64")] - pub fn get_vp_registers( + fn set_vp_registers_hvcall_inner( &mut self, - names: &[HvX64RegisterName], - values: &mut [HvRegisterValue], - ) -> Result<(), Error> { - self.get_vp_registers_inner(names, values) - } + vtl: Vtl, + registers: &[HvRegisterAssoc], + ) -> Result<(), HvError> { + let header = hvdef::hypercall::GetSetVpRegisters { + partition_id: HV_PARTITION_ID_SELF, + vp_index: HV_VP_INDEX_SELF, + target_vtl: vtl.into(), + rsvd: [0; 3], + }; - /// Get the following VP registers on the current VP. - /// - /// # Panics - /// Panics if `names.len() != values.len()`. - #[cfg(guest_arch = "aarch64")] - pub fn get_vp_registers( - &mut self, - names: &[HvArm64RegisterName], - values: &mut [HvRegisterValue], - ) -> Result<(), Error> { - self.get_vp_registers_inner(names, values) + tracing::trace!(?registers, "HvCallSetVpRegisters rep"); + + // SAFETY: The input header and rep slice are the correct types for this hypercall. + // The hypercall output is validated right after the hypercall is issued. + let status = unsafe { + self.hcl + .mshv_hvcall + .hvcall_rep::( + HypercallCode::HvCallSetVpRegisters, + &header, + HvcallRepInput::Elements(registers), + None, + ) + .expect("set_vp_registers hypercall should not fail") + }; + + // Status must be success + status.result()?; + Ok(()) } /// Sets the following registers on the current VP and given VTL using a @@ -1865,34 +1933,7 @@ impl ProcessorRunner<'_, T> { | HvX64RegisterName::VsmVpSecureConfigVtl1 ) )); - - let header = hvdef::hypercall::GetSetVpRegisters { - partition_id: HV_PARTITION_ID_SELF, - vp_index: HV_VP_INDEX_SELF, - target_vtl: vtl.into(), - rsvd: [0; 3], - }; - - tracing::trace!(?registers, "HvCallSetVpRegisters rep"); - - // SAFETY: The input header and rep slice are the correct types for this hypercall. - // The hypercall output is validated right after the hypercall is issued. - let status = unsafe { - self.hcl - .mshv_hvcall - .hvcall_rep::( - HypercallCode::HvCallSetVpRegisters, - &header, - HvcallRepInput::Elements(registers.as_slice()), - None, - ) - .expect("set_vp_registers hypercall should not fail") - }; - - // Status must be success - status.result()?; - - Ok(()) + self.set_vp_registers_hvcall_inner(vtl, ®isters) } /// Sets the VTL that should be returned to when underhill exits diff --git a/openhcl/virt_mshv_vtl/src/processor/mod.rs b/openhcl/virt_mshv_vtl/src/processor/mod.rs index 8e9adbb2b..e77d9a9c1 100644 --- a/openhcl/virt_mshv_vtl/src/processor/mod.rs +++ b/openhcl/virt_mshv_vtl/src/processor/mod.rs @@ -224,7 +224,7 @@ mod private { /// message slot. /// /// This is used for hypervisor-managed and untrusted SINTs. - fn request_untrusted_sint_readiness(this: &mut UhProcessor<'_, Self>, sints: u16); + fn request_untrusted_sint_readiness(this: &mut UhProcessor<'_, Self>, vtl: Vtl, sints: u16); /// The VTL that was running when the VP exited into VTL2, with the /// exception of a successful vtl switch, where it will return the VTL @@ -836,7 +836,7 @@ impl<'a, T: Backing> UhProcessor<'a, T> { #[cfg(guest_arch = "aarch64")] let sint_reg = HvArm64RegisterName(HvArm64RegisterName::Sint0.0 + sint as u32); - self.runner.get_vp_register(sint_reg).unwrap().as_u64() + self.runner.get_vp_register(sint_reg, vtl).unwrap().as_u64() }; masked_sints |= (HvSynicSint::from(sint_msr).masked() as u16) << sint; } @@ -911,7 +911,7 @@ impl<'a, T: Backing> UhProcessor<'a, T> { }; if sints & untrusted_sints != 0 { - T::request_untrusted_sint_readiness(self, sints & untrusted_sints); + T::request_untrusted_sint_readiness(self, vtl, sints & untrusted_sints); } } @@ -1202,7 +1202,7 @@ impl Arm64RegisterState for UhHypercallHandler<'_, '_, T, fn pc(&mut self) -> u64 { self.vp .runner - .get_vp_register(HvArm64RegisterName::XPc) + .get_vp_register(HvArm64RegisterName::XPc, self.vp.last_vtl()) .expect("get vp register cannot fail") .as_u64() } @@ -1210,14 +1210,17 @@ impl Arm64RegisterState for UhHypercallHandler<'_, '_, T, fn set_pc(&mut self, pc: u64) { self.vp .runner - .set_vp_register(HvArm64RegisterName::XPc, pc.into()) + .set_vp_register(HvArm64RegisterName::XPc, pc.into(), self.vp.last_vtl()) .expect("set vp register cannot fail"); } fn x(&mut self, n: u8) -> u64 { self.vp .runner - .get_vp_register(HvArm64RegisterName(HvArm64RegisterName::X0.0 + n as u32)) + .get_vp_register( + HvArm64RegisterName(HvArm64RegisterName::X0.0 + n as u32), + self.vp.last_vtl(), + ) .expect("get vp register cannot fail") .as_u64() } @@ -1228,6 +1231,7 @@ impl Arm64RegisterState for UhHypercallHandler<'_, '_, T, .set_vp_register( HvArm64RegisterName(HvArm64RegisterName::X0.0 + n as u32), v.into(), + self.vp.last_vtl(), ) .expect("set vp register cannot fail") } diff --git a/openhcl/virt_mshv_vtl/src/processor/mshv/apic.rs b/openhcl/virt_mshv_vtl/src/processor/mshv/apic.rs index 27c8b316d..d04d0cc1b 100644 --- a/openhcl/virt_mshv_vtl/src/processor/mshv/apic.rs +++ b/openhcl/virt_mshv_vtl/src/processor/mshv/apic.rs @@ -155,7 +155,7 @@ impl UhApicState { ]; let mut values = [0u32.into(); NAMES.len()]; runner - .get_vp_registers(NAMES, &mut values) + .get_vp_registers(NAMES, &mut values, self.vtl) .map_err(UhRunVpError::EmulationState)?; let &[rflags, cr8, interrupt_state, pending_interruption, pending_event] = &values; @@ -194,6 +194,7 @@ impl UhApicState { .set_vp_register( HvX64RegisterName::PendingInterruption, u64::from(interruption).into(), + self.vtl, ) .map_err(UhRunVpError::EmulationState)?; @@ -217,7 +218,7 @@ impl UhApicState { ]; let mut values = [0u32.into(); NAMES.len()]; runner - .get_vp_registers(NAMES, &mut values) + .get_vp_registers(NAMES, &mut values, self.vtl) .map_err(UhRunVpError::EmulationState)?; let &[interrupt_state, pending_interruption, pending_event] = &values; @@ -247,6 +248,7 @@ impl UhApicState { .set_vp_register( HvX64RegisterName::PendingInterruption, u64::from(interruption).into(), + self.vtl, ) .map_err(UhRunVpError::EmulationState)?; @@ -329,10 +331,13 @@ impl UhProcessor<'_, HypervisorBackedX86> { attributes: 0x9b, }; self.runner - .set_vp_registers([ - (HvX64RegisterName::Cs, HvRegisterValue::from(cs)), - (HvX64RegisterName::Rip, 0u64.into()), - ]) + .set_vp_registers( + [ + (HvX64RegisterName::Cs, HvRegisterValue::from(cs)), + (HvX64RegisterName::Rip, 0u64.into()), + ], + vtl, + ) .map_err(UhRunVpError::EmulationState)?; lapic.startup_suspend = false; lapic.halted = false; @@ -352,20 +357,20 @@ struct UhApicClient<'a, 'b, T> { impl ApicClient for UhApicClient<'_, '_, T> { fn cr8(&mut self) -> u32 { self.runner - .get_vp_register(HvX64RegisterName::Cr8) + .get_vp_register(HvX64RegisterName::Cr8, self.vtl) .unwrap() .as_u32() } fn set_cr8(&mut self, value: u32) { self.runner - .set_vp_register(HvX64RegisterName::Cr8, value.into()) + .set_vp_register(HvX64RegisterName::Cr8, value.into(), self.vtl) .unwrap(); } fn set_apic_base(&mut self, value: u64) { self.runner - .set_vp_register(HvX64RegisterName::ApicBase, value.into()) + .set_vp_register(HvX64RegisterName::ApicBase, value.into(), self.vtl) .unwrap(); } diff --git a/openhcl/virt_mshv_vtl/src/processor/mshv/arm64.rs b/openhcl/virt_mshv_vtl/src/processor/mshv/arm64.rs index 4edd7d4d5..85afe0215 100644 --- a/openhcl/virt_mshv_vtl/src/processor/mshv/arm64.rs +++ b/openhcl/virt_mshv_vtl/src/processor/mshv/arm64.rs @@ -146,6 +146,7 @@ impl BackingPrivate for HypervisorBackedArm64 { .set_vp_register( VpRegisterName::DeliverabilityNotifications, u64::from(notifications).into(), + Vtl::Vtl0, ) .expect("requesting deliverability is not a fallable operation"); this.backing.deliverability_notifications = @@ -208,7 +209,7 @@ impl BackingPrivate for HypervisorBackedArm64 { .set_interrupt_notification(true); } - fn request_untrusted_sint_readiness(this: &mut UhProcessor<'_, Self>, sints: u16) { + fn request_untrusted_sint_readiness(this: &mut UhProcessor<'_, Self>, _vtl: Vtl, sints: u16) { this.backing .next_deliverability_notifications .set_sints(this.backing.next_deliverability_notifications.sints() | sints); @@ -346,7 +347,9 @@ impl AccessCpuState for UhProcessor<'_, HypervisorBackedArm64> { if self.backing.cpu_state.sp.is_some() { expensive_regs.push((HvArm64RegisterName::XSp, self.sp())); } - self.runner.set_vp_registers(expensive_regs).unwrap(); + self.runner + .set_vp_registers(expensive_regs, Vtl::Vtl0) + .unwrap(); self.runner.cpu_context_mut().x = self.backing.cpu_state.x; self.runner.cpu_context_mut().q = self.backing.cpu_state.q; } @@ -356,7 +359,7 @@ impl AccessCpuState for UhProcessor<'_, HypervisorBackedArm64> { if index == 18 && !self.backing.cpu_state.x18_valid { let reg_val = self .runner - .get_vp_register(HvArm64RegisterName::X18) + .get_vp_register(HvArm64RegisterName::X18, Vtl::Vtl0) .expect("register query should not fail"); self.backing.cpu_state.x[18] = reg_val.as_u64(); self.backing.cpu_state.x18_valid = true; @@ -418,7 +421,7 @@ impl AccessCpuState for UhProcessor<'_, HypervisorBackedArm64> { if self.backing.cpu_state.sp.is_none() { let reg_val = self .runner - .get_vp_register(HvArm64RegisterName::XSp) + .get_vp_register(HvArm64RegisterName::XSp, Vtl::Vtl0) .expect("register query should not fail"); self.backing.cpu_state.sp = Some(reg_val.as_u64()); } @@ -449,7 +452,7 @@ impl AccessCpuState for UhProcessor<'_, HypervisorBackedArm64> { if self.backing.cpu_state.pc.is_none() { let reg_val = self .runner - .get_vp_register(HvArm64RegisterName::XPc) + .get_vp_register(HvArm64RegisterName::XPc, Vtl::Vtl0) .expect("register query should not fail"); self.backing.cpu_state.pc = Some(reg_val.as_u64()); } @@ -464,7 +467,7 @@ impl AccessCpuState for UhProcessor<'_, HypervisorBackedArm64> { if self.backing.cpu_state.cpsr.is_none() { let reg_val = self .runner - .get_vp_register(HvArm64RegisterName::Cpsr) + .get_vp_register(HvArm64RegisterName::Cpsr, Vtl::Vtl0) .expect("register query should not fail"); self.backing.cpu_state.cpsr = Some(reg_val.as_u64()); } @@ -554,7 +557,7 @@ impl EmulatorSupport for UhEmulationState<'_, '_, T, HypervisorBacked> let cpsr: Cpsr64 = self .vp .runner - .get_vp_register(HvArm64RegisterName::SpsrEl2) + .get_vp_register(HvArm64RegisterName::SpsrEl2, Vtl::Vtl0) .map_err(UhRunVpError::EmulationState)? .as_u64() .into(); @@ -788,7 +791,7 @@ impl UhVpStateAccess<'_, '_, HypervisorBackedArm64> { regs.get_values(values.iter_mut()); self.vp .runner - .set_vp_registers(names.iter().copied().zip(values)) + .set_vp_registers(names.iter().copied().zip(values), self.vtl) .map_err(vp_state::Error::SetRegisters)?; Ok(()) } @@ -804,7 +807,7 @@ impl UhVpStateAccess<'_, '_, HypervisorBackedArm64> { let mut values = [HvRegisterValue::new_zeroed(); N]; self.vp .runner - .get_vp_registers(&names, &mut values) + .get_vp_registers(&names, &mut values, self.vtl) .map_err(vp_state::Error::GetRegisters)?; regs.set_values(values.into_iter()); @@ -859,6 +862,7 @@ mod save_restore { use anyhow::anyhow; use hvdef::HvArm64RegisterName; use hvdef::HvInternalActivityRegister; + use hvdef::Vtl; use virt::Processor; use vmcore::save_restore::RestoreError; use vmcore::save_restore::SaveError; @@ -890,7 +894,7 @@ mod save_restore { let internal_activity = self .runner - .get_vp_register(HvArm64RegisterName::InternalActivityState) + .get_vp_register(HvArm64RegisterName::InternalActivityState, Vtl::Vtl0) .map_err(|err| { SaveError::Other(anyhow!("unable to query startup suspend: {}", err)) })?; @@ -911,7 +915,10 @@ mod save_restore { if state.startup_suspend { let reg = u64::from(HvInternalActivityRegister::new().with_startup_suspend(true)); self.runner - .set_vp_registers([(HvArm64RegisterName::InternalActivityState, reg)]) + .set_vp_registers( + [(HvArm64RegisterName::InternalActivityState, reg)], + Vtl::Vtl0, + ) .map_err(|err| { RestoreError::Other(anyhow!( "unable to set internal activity register: {}", diff --git a/openhcl/virt_mshv_vtl/src/processor/mshv/x64.rs b/openhcl/virt_mshv_vtl/src/processor/mshv/x64.rs index 4442a8d5f..5b069ca55 100644 --- a/openhcl/virt_mshv_vtl/src/processor/mshv/x64.rs +++ b/openhcl/virt_mshv_vtl/src/processor/mshv/x64.rs @@ -133,11 +133,12 @@ impl BackingPrivate for HypervisorBackedX86 { // Initialize APIC base to match the current VM state. let apic_base = params .runner - .get_vp_register(HvX64RegisterName::ApicBase) + .get_vp_register(HvX64RegisterName::ApicBase, Vtl::Vtl0) .unwrap() .as_u64(); let mut lapic0 = arr[Vtl::Vtl0].add_apic(params.vp_info); lapic0.set_apic_base(apic_base).unwrap(); + // TODO WHP GUEST VSM is this the right base? let mut lapic1 = arr[Vtl::Vtl1].add_apic(params.vp_info); lapic1.set_apic_base(apic_base).unwrap(); @@ -182,6 +183,7 @@ impl BackingPrivate for HypervisorBackedX86 { .set_vp_register( VpRegisterName::DeliverabilityNotifications, u64::from(notifications).into(), + Vtl::Vtl0, ) .expect("requesting deliverability is not a fallable operation"); this.backing.deliverability_notifications = @@ -300,7 +302,7 @@ impl BackingPrivate for HypervisorBackedX86 { .set_interrupt_notification(true); } - fn request_untrusted_sint_readiness(this: &mut UhProcessor<'_, Self>, sints: u16) { + fn request_untrusted_sint_readiness(this: &mut UhProcessor<'_, Self>, _vtl: Vtl, sints: u16) { this.backing .next_deliverability_notifications .set_sints(this.backing.next_deliverability_notifications.sints() | sints); @@ -376,7 +378,7 @@ fn next_rip(value: &HvX64InterceptMessageHeader) -> u64 { impl UhProcessor<'_, HypervisorBackedX86> { fn set_rip(&mut self, rip: u64) -> Result<(), VpHaltReason> { self.runner - .set_vp_register(HvX64RegisterName::Rip, rip.into()) + .set_vp_register(HvX64RegisterName::Rip, rip.into(), self.last_vtl()) .map_err(|e| VpHaltReason::Hypervisor(UhRunVpError::AdvanceRip(e)))?; Ok(()) @@ -411,7 +413,11 @@ impl UhProcessor<'_, HypervisorBackedX86> { .with_vector(vector); self.runner - .set_vp_register(HvX64RegisterName::PendingEvent0, u128::from(event).into()) + .set_vp_register( + HvX64RegisterName::PendingEvent0, + u128::from(event).into(), + self.last_vtl(), + ) .map_err(|e| VpHaltReason::Hypervisor(UhRunVpError::Event(e)))?; } @@ -687,6 +693,7 @@ impl UhProcessor<'_, HypervisorBackedX86> { .set_vp_register( HvX64RegisterName::PendingEvent0, u128::from(exception_event).into(), + self.last_vtl(), ) .expect("set_vp_register should succeed for pending event"); } @@ -741,7 +748,7 @@ impl UhProcessor<'_, HypervisorBackedX86> { ]; let mut values = [FromZeroes::new_zeroed(); NAMES.len()]; self.runner - .get_vp_registers(NAMES, &mut values) + .get_vp_registers(NAMES, &mut values, self.last_vtl()) .expect("register query should not fail"); let [rsp, es, ds, fs, gs, ss, cr0, efer] = values; @@ -771,11 +778,14 @@ impl UhProcessor<'_, HypervisorBackedX86> { fn set_emulator_state(&mut self, state: &x86emu::CpuState) { self.runner - .set_vp_registers([ - (HvX64RegisterName::Rip, state.rip), - (HvX64RegisterName::Rflags, state.rflags.into()), - (HvX64RegisterName::Rsp, state.gps[x86emu::CpuState::RSP]), - ]) + .set_vp_registers( + [ + (HvX64RegisterName::Rip, state.rip), + (HvX64RegisterName::Rflags, state.rflags.into()), + (HvX64RegisterName::Rsp, state.gps[x86emu::CpuState::RSP]), + ], + self.last_vtl(), + ) .unwrap(); self.runner.cpu_context_mut().gps = state.gps; @@ -1006,7 +1016,10 @@ impl EmulatorSupport for UhEmulationState<'_, '_, T, HypervisorBackedX let mbec_user_execute = self .vp .runner - .get_vp_register(HvX64RegisterName::InstructionEmulationHints) + .get_vp_register( + HvX64RegisterName::InstructionEmulationHints, + self.vp.last_vtl(), + ) .map_err(UhRunVpError::EmulationState)?; let flags = @@ -1281,7 +1294,7 @@ impl UhVpStateAccess<'_, '_, HypervisorBackedX86> { regs.get_values(values.iter_mut()); self.vp .runner - .set_vp_registers(names.iter().copied().zip(values)) + .set_vp_registers(names.iter().copied().zip(values), self.vtl) .map_err(vp_state::Error::SetRegisters)?; Ok(()) } @@ -1297,7 +1310,7 @@ impl UhVpStateAccess<'_, '_, HypervisorBackedX86> { let mut values = [HvRegisterValue::new_zeroed(); N]; self.vp .runner - .get_vp_registers(&names, &mut values) + .get_vp_registers(&names, &mut values, self.vtl) .map_err(vp_state::Error::GetRegisters)?; regs.set_values(values.into_iter()); @@ -1549,12 +1562,14 @@ impl hv1_hypercall::SetVpRegisters for UhHypercallHandler<'_, '_, T, Hypervis } } +// TODO GUEST VSM Audit save state mod save_restore { use super::HypervisorBackedX86; use super::UhProcessor; use anyhow::Context; use hvdef::HvInternalActivityRegister; use hvdef::HvX64RegisterName; + use hvdef::Vtl; use virt::irqcon::MsiRequest; use virt::Processor; use vmcore::save_restore::RestoreError; @@ -1648,13 +1663,13 @@ mod save_restore { }; self.runner - .get_vp_registers(&SHARED_REGISTERS[..len], &mut values[..len]) + .get_vp_registers(&SHARED_REGISTERS[..len], &mut values[..len], Vtl::Vtl0) .context("failed to get shared registers") .map_err(SaveError::Other)?; let startup_suspend = match self .runner - .get_vp_register(HvX64RegisterName::InternalActivityState) + .get_vp_register(HvX64RegisterName::InternalActivityState, Vtl::Vtl0) { Ok(val) => Some(HvInternalActivityRegister::from(val.as_u64()).startup_suspend()), Err(e) => { @@ -1752,7 +1767,10 @@ mod save_restore { let values = [dr0, dr1, dr2, dr3, dr6.unwrap_or(0)]; self.runner - .set_vp_registers(SHARED_REGISTERS[..len].iter().copied().zip(values)) + .set_vp_registers( + SHARED_REGISTERS[..len].iter().copied().zip(values), + Vtl::Vtl0, + ) .context("failed to set shared registers") .map_err(RestoreError::Other)?; @@ -1784,7 +1802,7 @@ mod save_restore { ]; let mut values = [FromZeroes::new_zeroed(); NAMES.len()]; self.runner - .get_vp_registers(&NAMES, &mut values) + .get_vp_registers(&NAMES, &mut values, Vtl::Vtl0) .context("failed to get VP registers for startup suspend log") .map_err(RestoreError::Other)?; let [rip, rflags, cr0, efer] = values.map(|reg| reg.as_u64()); @@ -1807,7 +1825,7 @@ mod save_restore { let reg = u64::from(HvInternalActivityRegister::new().with_startup_suspend(true)); let result = self .runner - .set_vp_registers([(HvX64RegisterName::InternalActivityState, reg)]); + .set_vp_registers([(HvX64RegisterName::InternalActivityState, reg)], Vtl::Vtl0); if let Err(e) = result { // The ioctl set_vp_register path does not tell us hv_status @@ -1818,7 +1836,7 @@ mod save_restore { ); self.partition.request_msi( - hvdef::Vtl::Vtl0, + Vtl::Vtl0, MsiRequest::new_x86( virt::irqcon::DeliveryMode::INIT, self.inner.vp_info.apic_id, diff --git a/openhcl/virt_mshv_vtl/src/processor/snp/mod.rs b/openhcl/virt_mshv_vtl/src/processor/snp/mod.rs index 9c2649bf4..daa2906bc 100644 --- a/openhcl/virt_mshv_vtl/src/processor/snp/mod.rs +++ b/openhcl/virt_mshv_vtl/src/processor/snp/mod.rs @@ -398,7 +398,7 @@ impl BackingPrivate for SnpBacked { unreachable!("extint managed through software apic") } - fn request_untrusted_sint_readiness(this: &mut UhProcessor<'_, Self>, sints: u16) { + fn request_untrusted_sint_readiness(this: &mut UhProcessor<'_, Self>, vtl: Vtl, sints: u16) { if this.backing.hv_sint_notifications & !sints == 0 { return; } @@ -410,6 +410,7 @@ impl BackingPrivate for SnpBacked { .set_vp_register( HvX64RegisterName::DeliverabilityNotifications, u64::from(notifications).into(), + vtl, ) .expect("requesting deliverability is not a fallable operation"); } diff --git a/openhcl/virt_mshv_vtl/src/processor/tdx/mod.rs b/openhcl/virt_mshv_vtl/src/processor/tdx/mod.rs index ee144f808..9aafd4e59 100644 --- a/openhcl/virt_mshv_vtl/src/processor/tdx/mod.rs +++ b/openhcl/virt_mshv_vtl/src/processor/tdx/mod.rs @@ -751,7 +751,7 @@ impl BackingPrivate for TdxBacked { unreachable!("extint managed through software apic") } - fn request_untrusted_sint_readiness(this: &mut UhProcessor<'_, Self>, sints: u16) { + fn request_untrusted_sint_readiness(this: &mut UhProcessor<'_, Self>, _vtl: Vtl, sints: u16) { if let Some(synic) = &mut this.untrusted_synic { synic.request_sint_readiness(sints); } else { @@ -1375,7 +1375,7 @@ impl UhProcessor<'_, TdxBacked> { let subleaf = enter_state.rcx() as u32; let xfem = self .runner - .get_vp_register(HvX64RegisterName::Xfem) + .get_vp_register(HvX64RegisterName::Xfem, Vtl::Vtl0) .map_err(|err| VpHaltReason::Hypervisor(UhRunVpError::EmulationState(err)))? .as_u64(); let guest_state = crate::hardware_cvm::cpuid::CpuidGuestState { @@ -1494,7 +1494,7 @@ impl UhProcessor<'_, TdxBacked> { }) { self.runner - .set_vp_register(HvX64RegisterName::Xfem, value.into()) + .set_vp_register(HvX64RegisterName::Xfem, value.into(), Vtl::Vtl0) .map_err(|err| { VpHaltReason::Hypervisor(UhRunVpError::EmulationState(err)) })?; @@ -1728,6 +1728,7 @@ impl UhProcessor<'_, TdxBacked> { HvX64RegisterName::Sint0.0 + (msr - hvdef::HV_X64_MSR_SINT0), ), value.into(), + Vtl::Vtl0, ) { tracelimit::warn_ratelimited!( error = &err as &dyn std::error::Error, @@ -2708,7 +2709,7 @@ impl AccessVpState for UhVpStateAccess<'_, '_, TdxBacked> { value: self .vp .runner - .get_vp_register(HvX64RegisterName::Xfem) + .get_vp_register(HvX64RegisterName::Xfem, self.vtl) .unwrap() .as_u64(), }) @@ -2837,6 +2838,7 @@ impl AccessVpState for UhVpStateAccess<'_, '_, TdxBacked> { HvX64RegisterName::Dr6, ], &mut values, + self.vtl, ) .map_err(vp_state::Error::GetRegisters)?; @@ -2866,13 +2868,16 @@ impl AccessVpState for UhVpStateAccess<'_, '_, TdxBacked> { } = value; self.vp .runner - .set_vp_registers([ - (HvX64RegisterName::Dr0, dr0), - (HvX64RegisterName::Dr1, dr1), - (HvX64RegisterName::Dr2, dr2), - (HvX64RegisterName::Dr3, dr3), - (HvX64RegisterName::Dr6, dr6), - ]) + .set_vp_registers( + [ + (HvX64RegisterName::Dr0, dr0), + (HvX64RegisterName::Dr1, dr1), + (HvX64RegisterName::Dr2, dr2), + (HvX64RegisterName::Dr3, dr3), + (HvX64RegisterName::Dr6, dr6), + ], + self.vtl, + ) .map_err(vp_state::Error::SetRegisters)?; self.vp