1#![cfg(guest_arch = "x86_64")]
8
9use hvdef::HvEnlightenmentInformation;
10use hvdef::HvFeatures;
11use hvdef::HvHardwareFeatures;
12use hvdef::HvIsolationConfiguration;
13use hvdef::HvPartitionPrivilege;
14use std::arch::x86_64::CpuidResult;
15use virt::CpuidLeaf;
16use x86defs::cpuid::CpuidFunction;
17
18pub const SUPPORTED_PRIVILEGES: HvPartitionPrivilege = HvPartitionPrivilege::new()
20 .with_access_partition_reference_counter(true)
21 .with_access_hypercall_msrs(true)
22 .with_access_vp_index(true)
23 .with_access_synic_msrs(true)
24 .with_access_synthetic_timer_msrs(true)
25 .with_access_partition_reference_tsc(true);
26
27pub const SUPPORTED_FEATURES: HvFeatures = HvFeatures::new()
29 .with_privileges(SUPPORTED_PRIVILEGES)
30 .with_direct_synthetic_timers(true);
31
32const fn split_u128(x: u128) -> CpuidResult {
33 let bytes: [u32; 4] = zerocopy::transmute!(x);
34 CpuidResult {
35 eax: bytes[0],
36 ebx: bytes[1],
37 ecx: bytes[2],
38 edx: bytes[3],
39 }
40}
41
42pub fn make_hv_cpuid_leaves(
45 features: HvFeatures,
46 enlightenments: HvEnlightenmentInformation,
47 max_cpus: u32,
48) -> [(CpuidFunction, CpuidResult); 3] {
49 const fn split_u128(x: u128) -> CpuidResult {
50 let bytes: [u32; 4] = zerocopy::transmute!(x);
51 CpuidResult {
52 eax: bytes[0],
53 ebx: bytes[1],
54 ecx: bytes[2],
55 edx: bytes[3],
56 }
57 }
58
59 [
60 (CpuidFunction(hvdef::HV_CPUID_FUNCTION_MS_HV_FEATURES), {
61 split_u128(features.into_bits())
62 }),
63 (
64 CpuidFunction(hvdef::HV_CPUID_FUNCTION_MS_HV_ENLIGHTENMENT_INFORMATION),
65 split_u128(enlightenments.into_bits()),
66 ),
67 (
68 CpuidFunction(hvdef::HV_CPUID_FUNCTION_MS_HV_IMPLEMENTATION_LIMITS),
69 CpuidResult {
70 eax: max_cpus,
71 ebx: max_cpus,
72 ecx: 0,
73 edx: 0,
74 },
75 ),
76 ]
77}
78
79pub fn make_isolated_hv_cpuid_leaves(
82 hardware_features: HvHardwareFeatures,
83 isolation_config: HvIsolationConfiguration,
84) -> [(CpuidFunction, CpuidResult); 2] {
85 [
86 (
87 CpuidFunction(hvdef::HV_CPUID_FUNCTION_MS_HV_HARDWARE_FEATURES),
88 split_u128(hardware_features.into_bits()),
89 ),
90 (
91 CpuidFunction(hvdef::HV_CPUID_FUNCTION_MS_HV_ISOLATION_CONFIGURATION),
92 split_u128(isolation_config.into_bits()),
93 ),
94 ]
95}
96
97pub fn process_hv_cpuid_leaves(
100 leaves: &mut Vec<CpuidLeaf>,
101 hide_isolation: bool,
102 hv_version: [u32; 4],
103) {
104 leaves.push(CpuidLeaf::new(
106 hvdef::HV_CPUID_FUNCTION_HV_VENDOR_AND_MAX_FUNCTION,
107 [
108 if hide_isolation {
109 hvdef::HV_CPUID_FUNCTION_MS_HV_IMPLEMENTATION_LIMITS
110 } else {
111 hvdef::HV_CPUID_FUNCTION_MS_HV_ISOLATION_CONFIGURATION
112 },
113 u32::from_le_bytes(*b"Micr"),
114 u32::from_le_bytes(*b"osof"),
115 u32::from_le_bytes(*b"t Hv"),
116 ],
117 ));
118 leaves.push(CpuidLeaf::new(
119 hvdef::HV_CPUID_FUNCTION_HV_INTERFACE,
120 [u32::from_le_bytes(*b"Hv#1"), 0, 0, 0],
121 ));
122 leaves.push(CpuidLeaf::new(
123 hvdef::HV_CPUID_FUNCTION_MS_HV_VERSION,
124 hv_version,
125 ));
126
127 if hide_isolation {
129 leaves.retain(|leaf| {
130 if leaf.function & 0xF0000000 == hvdef::HV_CPUID_FUNCTION_HV_VENDOR_AND_MAX_FUNCTION {
131 leaf.function <= hvdef::HV_CPUID_FUNCTION_MS_HV_IMPLEMENTATION_LIMITS
132 } else {
133 true
134 }
135 });
136
137 let isolated_mask =
139 HvFeatures::new().with_privileges(HvPartitionPrivilege::new().with_isolation(true));
140 leaves.push(
141 CpuidLeaf::new(hvdef::HV_CPUID_FUNCTION_MS_HV_FEATURES, [0, 0, 0, 0])
142 .masked(zerocopy::transmute!(isolated_mask)),
143 );
144 }
145}