Skip to main content

virt_mshv/x86_64/
vm_state.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! VM-level state access for mshv.
5//!
6//! VM-level HV registers (GuestOsId, Hypercall, ReferenceTsc) are accessed
7//! via the VP register interface using the BSP's VcpuFd, which is retained
8//! in `MshvPartitionInner`. These accessors must only be called while VPs
9//! are stopped (e.g., during reset or save/restore).
10
11use crate::Error;
12use crate::ErrorInner;
13use crate::MshvPartition;
14use crate::VcpuFdExt;
15use hvdef::HvPartitionPropertyCode;
16use hvdef::HvX64RegisterName;
17use hvdef::hypercall::HvRegisterAssoc;
18use virt::state::HvRegisterState;
19use virt::x86::vm;
20use virt::x86::vm::AccessVmState;
21use zerocopy::FromZeros;
22
23impl MshvPartition {
24    fn get_vm_register_state<T, const N: usize>(&self) -> Result<T, Error>
25    where
26        T: HvRegisterState<HvX64RegisterName, N>,
27    {
28        let mut regs = T::default();
29        let mut assoc = regs.names().map(|name| HvRegisterAssoc {
30            name: name.into(),
31            pad: [0; 3],
32            value: FromZeros::new_zeroed(),
33        });
34
35        self.inner
36            .bsp_vcpufd
37            .get_hvdef_regs(&mut assoc[..])
38            .map_err(ErrorInner::Register)?;
39
40        regs.set_values(assoc.iter().map(|assoc| assoc.value));
41        Ok(regs)
42    }
43
44    fn set_vm_register_state<T, const N: usize>(&self, regs: &T) -> Result<(), Error>
45    where
46        T: HvRegisterState<HvX64RegisterName, N>,
47    {
48        let mut assoc = regs.names().map(|name| HvRegisterAssoc {
49            name: name.into(),
50            pad: [0; 3],
51            value: FromZeros::new_zeroed(),
52        });
53
54        regs.get_values(assoc.iter_mut().map(|assoc| &mut assoc.value));
55
56        self.inner
57            .bsp_vcpufd
58            .set_hvdef_regs(&assoc[..])
59            .map_err(ErrorInner::Register)?;
60        Ok(())
61    }
62}
63
64impl AccessVmState for &'_ MshvPartition {
65    type Error = Error;
66
67    fn caps(&self) -> &virt::PartitionCapabilities {
68        &self.inner.caps
69    }
70
71    fn commit(&mut self) -> Result<(), Self::Error> {
72        Ok(())
73    }
74
75    fn hypercall(&mut self) -> Result<vm::HypercallMsrs, Self::Error> {
76        self.get_vm_register_state()
77    }
78
79    fn set_hypercall(&mut self, value: &vm::HypercallMsrs) -> Result<(), Self::Error> {
80        self.set_vm_register_state(value)
81    }
82
83    fn reftime(&mut self) -> Result<vm::ReferenceTime, Self::Error> {
84        let ref_time = self
85            .inner
86            .vmfd
87            .get_partition_property(HvPartitionPropertyCode::ReferenceTime.0)
88            .map_err(|e| ErrorInner::GetPartitionProperty(e.into()))?;
89        Ok(vm::ReferenceTime { value: ref_time })
90    }
91
92    fn set_reftime(&mut self, value: &vm::ReferenceTime) -> Result<(), Self::Error> {
93        self.inner
94            .vmfd
95            .set_partition_property(HvPartitionPropertyCode::ReferenceTime.0, value.value)
96            .map_err(|e| ErrorInner::SetPartitionProperty(e.into()))?;
97        Ok(())
98    }
99
100    fn reference_tsc_page(&mut self) -> Result<vm::ReferenceTscPage, Self::Error> {
101        self.get_vm_register_state()
102    }
103
104    fn set_reference_tsc_page(&mut self, value: &vm::ReferenceTscPage) -> Result<(), Self::Error> {
105        self.set_vm_register_state(value)
106    }
107}