1pub mod apic_software_device;
7pub mod vm;
8pub mod vp;
9
10use crate::state::StateElement;
11use inspect::Inspect;
12use mesh_protobuf::Protobuf;
13use std::fmt::Debug;
14use vm_topology::processor::ProcessorTopology;
15use vm_topology::processor::x86::ApicMode;
16use vm_topology::processor::x86::X86Topology;
17use vm_topology::processor::x86::X86VpInfo;
18use x86defs::cpuid::CpuidFunction;
19use x86defs::cpuid::SgxCpuidSubleafEax;
20use x86defs::cpuid::Vendor;
21use x86defs::xsave::XSAVE_VARIABLE_OFFSET;
22
23#[derive(Debug, PartialEq, Eq, Protobuf)]
25pub struct X86InitialRegs {
26 pub registers: vp::Registers,
28 pub mtrrs: vp::Mtrrs,
30 pub pat: vp::Pat,
32}
33
34impl X86InitialRegs {
35 pub fn at_reset(caps: &X86PartitionCapabilities, bsp: &X86VpInfo) -> Self {
36 Self {
37 registers: vp::Registers::at_reset(caps, bsp),
38 mtrrs: vp::Mtrrs::at_reset(caps, bsp),
39 pat: vp::Pat::at_reset(caps, bsp),
40 }
41 }
42}
43
44#[derive(Debug, Inspect)]
47pub struct X86PartitionCapabilities {
48 #[inspect(display)]
50 pub vendor: Vendor,
51 pub hv1: bool,
53 pub hv1_reference_tsc_page: bool,
55 pub xsave: XsaveCapabilities,
57 pub x2apic: bool,
59 pub x2apic_enabled: bool,
61 #[inspect(hex)]
63 pub reset_rdx: u64,
64 pub cet: bool,
66 pub cet_ss: bool,
68 pub sgx: bool,
70 pub tsc_aux: bool,
72 #[inspect(hex)]
77 pub vtom: Option<u64>,
78 pub physical_address_width: u8,
80
81 pub can_freeze_time: bool,
83 pub xsaves_state_bv_broken: bool,
86 pub dr6_tsx_broken: bool,
89 pub nxe_forced_on: bool,
92}
93
94impl X86PartitionCapabilities {
95 pub fn from_cpuid(
96 processor_topology: &ProcessorTopology<X86Topology>,
97 f: &mut dyn FnMut(u32, u32) -> [u32; 4],
98 ) -> Self {
99 let mut this = Self {
100 vendor: Vendor([0; 12]),
101 hv1: false,
102 hv1_reference_tsc_page: false,
103 xsave: XsaveCapabilities {
104 features: 0,
105 supervisor_features: 0,
106 standard_len: XSAVE_VARIABLE_OFFSET as u32,
107 compact_len: XSAVE_VARIABLE_OFFSET as u32,
108 feature_info: [Default::default(); 63],
109 },
110 x2apic: false,
111 x2apic_enabled: false,
112 reset_rdx: 0,
113 cet: false,
114 cet_ss: false,
115 sgx: false,
116 tsc_aux: false,
117 vtom: None,
118 physical_address_width: max_physical_address_size_from_cpuid(&mut *f),
119 can_freeze_time: false,
120 xsaves_state_bv_broken: false,
121 dr6_tsx_broken: false,
122 nxe_forced_on: false,
123 };
124
125 let max_function = {
126 let [eax, ebx, ecx, edx] = f(CpuidFunction::VendorAndMaxFunction.0, 0);
127 this.vendor = Vendor::from_ebx_ecx_edx(ebx, ecx, edx);
128 eax
129 };
130
131 let mut hypervisor = false;
132 let mut xsave = false;
133 if max_function >= CpuidFunction::VersionAndFeatures.0 {
134 let result = f(CpuidFunction::VersionAndFeatures.0, 0);
135 this.reset_rdx = result[0].into();
136 let features = result[2] as u64 | ((result[3] as u64) << 32);
137 this.x2apic = features & (1 << 21) != 0;
138 xsave = features & (1 << 26) != 0;
139 hypervisor = features & (1 << 31) != 0;
140 }
141
142 let extended_features = if max_function >= CpuidFunction::ExtendedFeatures.0 {
143 f(CpuidFunction::ExtendedFeatures.0, 0)
144 } else {
145 Default::default()
146 };
147
148 if max_function >= CpuidFunction::ExtendedFeatures.0 {
149 if extended_features[2] & (1 << 7) != 0 {
150 this.cet = true;
151 this.cet_ss = true;
152 }
153 if extended_features[3] & (1 << 20) != 0 {
154 this.cet = true;
155 }
156 }
157
158 if max_function >= CpuidFunction::SgxEnumeration.0 {
159 let sgx_result: SgxCpuidSubleafEax =
160 SgxCpuidSubleafEax::from(f(CpuidFunction::SgxEnumeration.0, 2)[0]);
161 if sgx_result.sgx_type() != 0 {
162 this.sgx = true;
163 }
164 }
165
166 if xsave {
167 let result = f(CpuidFunction::ExtendedStateEnumeration.0, 0);
168 this.xsave.features = result[0] as u64 | ((result[3] as u64) << 32);
169 let standard_len = result[2];
170
171 let result = f(CpuidFunction::ExtendedStateEnumeration.0, 1);
172 this.xsave.supervisor_features = result[2] as u64 | ((result[3] as u64) << 32);
173
174 let mut n = (this.xsave.features | this.xsave.supervisor_features) & !3;
175 while n != 0 {
176 let i = n.trailing_zeros();
177 n -= 1 << i;
178 let result = f(CpuidFunction::ExtendedStateEnumeration.0, i);
179 let feature = XsaveFeature {
180 offset: result[1],
181 len: result[0],
182 align: result[2] & 2 != 0,
183 };
184 this.xsave.feature_info[i as usize] = feature;
185 }
186 this.xsave.compact_len = this.xsave.compact_len_for(!0);
187 this.xsave.standard_len = this.xsave.standard_len_for(!0);
188 assert!(
189 this.xsave.standard_len <= standard_len,
190 "advertised xsave length ({}) too small for features, requires ({}) bytes",
191 standard_len,
192 this.xsave.standard_len
193 );
194 }
195
196 if hypervisor {
198 let hv_max = f(hvdef::HV_CPUID_FUNCTION_HV_VENDOR_AND_MAX_FUNCTION, 0)[0];
199 if hv_max >= hvdef::HV_CPUID_FUNCTION_MS_HV_ENLIGHTENMENT_INFORMATION
200 && f(hvdef::HV_CPUID_FUNCTION_HV_INTERFACE, 0)[0] == u32::from_le_bytes(*b"Hv#1")
201 {
202 this.hv1 = true;
203 let result = f(hvdef::HV_CPUID_FUNCTION_MS_HV_FEATURES, 0);
204 let privs = hvdef::HvPartitionPrivilege::from(
205 result[0] as u64 | ((result[1] as u64) << 32),
206 );
207 this.hv1_reference_tsc_page = privs.access_partition_reference_tsc();
208 if privs.isolation()
209 && hv_max >= hvdef::HV_CPUID_FUNCTION_MS_HV_ISOLATION_CONFIGURATION
210 {
211 let [eax, ebx, ecx, edx] =
212 f(hvdef::HV_CPUID_FUNCTION_MS_HV_ISOLATION_CONFIGURATION, 0);
213 let config = hvdef::HvIsolationConfiguration::from(
214 eax as u128
215 | ((ebx as u128) << 32)
216 | ((ecx as u128) << 64)
217 | ((edx as u128) << 96),
218 );
219 if config.shared_gpa_boundary_active() {
220 this.vtom = Some(1 << config.shared_gpa_boundary_bits());
221 }
222 }
223 }
224 }
225
226 match processor_topology.apic_mode() {
227 ApicMode::XApic => assert!(
228 !this.x2apic,
229 "x2apic disabled in topology, enabled in cpuid"
230 ),
231 ApicMode::X2ApicSupported => {
232 assert!(this.x2apic, "x2apic enabled in topology, disabled in cpuid")
233 }
234 ApicMode::X2ApicEnabled => {
235 assert!(this.x2apic, "x2apic enabled in topology, disabled in cpuid");
236 this.x2apic_enabled = true;
237 }
238 }
239
240 this.tsc_aux = {
241 let rdtscp = {
242 let extended_max_function = f(CpuidFunction::ExtendedMaxFunction.0, 0)[0];
243 if extended_max_function >= CpuidFunction::ExtendedVersionAndFeatures.0 {
244 x86defs::cpuid::ExtendedVersionAndFeaturesEdx::from(
245 f(CpuidFunction::ExtendedVersionAndFeatures.0, 0)[3],
246 )
247 .rdtscp()
248 } else {
249 false
250 }
251 };
252
253 let rdpid =
254 x86defs::cpuid::ExtendedFeatureSubleaf0Ecx::from(extended_features[2]).rd_pid();
255
256 rdtscp || rdpid
257 };
258
259 this
260 }
261}
262
263#[derive(Debug, Copy, Clone, Inspect)]
264pub struct XsaveCapabilities {
265 pub features: u64,
266 pub supervisor_features: u64,
267 pub standard_len: u32,
268 pub compact_len: u32,
269 #[inspect(skip)] pub feature_info: [XsaveFeature; 63],
271}
272
273#[derive(Default, Debug, Copy, Clone)]
274pub struct XsaveFeature {
275 pub offset: u32,
276 pub len: u32,
277 pub align: bool,
278}
279
280impl XsaveCapabilities {
281 pub fn standard_len_for(&self, xfem: u64) -> u32 {
282 let mut len = XSAVE_VARIABLE_OFFSET as u32;
283 for i in 2..63 {
284 if xfem & (1 << i) != 0 {
285 let feature = &self.feature_info[i as usize];
286 len = len.max(feature.offset + feature.len);
287 }
288 }
289 len
290 }
291
292 pub fn compact_len_for(&self, xfem: u64) -> u32 {
293 let mut len = XSAVE_VARIABLE_OFFSET as u32;
294 for i in 2..63 {
295 if xfem & (1 << i) != 0 {
296 let feature = &self.feature_info[i as usize];
297 if feature.align {
298 len = (len + 63) & !63;
299 }
300 len += feature.len;
301 }
302 }
303 len
304 }
305}
306
307#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Protobuf, Inspect)]
308#[mesh(package = "virt.x86")]
309pub struct TableRegister {
310 #[inspect(hex)]
311 #[mesh(1)]
312 pub base: u64,
313 #[inspect(hex)]
314 #[mesh(2)]
315 pub limit: u16,
316}
317
318impl From<hvdef::HvX64TableRegister> for TableRegister {
319 fn from(table: hvdef::HvX64TableRegister) -> Self {
320 Self {
321 base: table.base,
322 limit: table.limit,
323 }
324 }
325}
326
327impl From<TableRegister> for hvdef::HvX64TableRegister {
328 fn from(table: TableRegister) -> Self {
329 Self {
330 base: table.base,
331 limit: table.limit,
332 pad: [0; 3],
333 }
334 }
335}
336
337#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Protobuf, Inspect)]
338#[mesh(package = "virt.x86")]
339pub struct SegmentRegister {
340 #[inspect(hex)]
341 #[mesh(1)]
342 pub base: u64,
343 #[inspect(hex)]
344 #[mesh(2)]
345 pub limit: u32,
346 #[inspect(hex)]
347 #[mesh(3)]
348 pub selector: u16,
349 #[inspect(hex)]
350 #[mesh(4)]
351 pub attributes: u16,
352}
353
354impl From<x86defs::SegmentRegister> for SegmentRegister {
355 fn from(seg: x86defs::SegmentRegister) -> Self {
356 Self {
357 base: seg.base,
358 limit: seg.limit,
359 selector: seg.selector,
360 attributes: seg.attributes.into(),
361 }
362 }
363}
364
365impl From<SegmentRegister> for x86defs::SegmentRegister {
366 fn from(seg: SegmentRegister) -> Self {
367 Self {
368 base: seg.base,
369 limit: seg.limit,
370 selector: seg.selector,
371 attributes: seg.attributes.into(),
372 }
373 }
374}
375
376impl From<hvdef::HvX64SegmentRegister> for SegmentRegister {
377 fn from(seg: hvdef::HvX64SegmentRegister) -> Self {
378 Self {
379 base: seg.base,
380 limit: seg.limit,
381 selector: seg.selector,
382 attributes: seg.attributes,
383 }
384 }
385}
386
387impl From<SegmentRegister> for hvdef::HvX64SegmentRegister {
388 fn from(seg: SegmentRegister) -> Self {
389 Self {
390 base: seg.base,
391 limit: seg.limit,
392 selector: seg.selector,
393 attributes: seg.attributes,
394 }
395 }
396}
397
398#[derive(Debug, Copy, Clone, Protobuf)]
400pub struct DebugState {
401 pub single_step: bool,
403 pub breakpoints: [Option<HardwareBreakpoint>; 4],
405}
406
407#[derive(Debug, Copy, Clone, Protobuf, PartialEq, Eq)]
408pub struct HardwareBreakpoint {
409 pub address: u64,
411 pub ty: BreakpointType,
413 pub size: BreakpointSize,
415}
416
417impl HardwareBreakpoint {
418 pub fn from_dr7(dr7: u64, address: u64, reg: usize) -> Self {
421 let v = dr7 >> (16 + reg * 4);
422 let ty = match v & 3 {
423 0 => BreakpointType::Execute,
424 1 => BreakpointType::Invalid,
425 2 => BreakpointType::Write,
426 3 => BreakpointType::ReadOrWrite,
427 _ => unreachable!(),
428 };
429 let size = match (v >> 2) & 3 {
430 0 => BreakpointSize::Byte,
431 1 => BreakpointSize::Word,
432 2 => BreakpointSize::QWord,
433 3 => BreakpointSize::DWord,
434 _ => unreachable!(),
435 };
436 Self { address, ty, size }
437 }
438
439 pub fn dr7_bits(&self, reg: usize) -> u64 {
441 ((self.ty as u64 | ((self.size as u64) << 2)) << (16 + reg * 4)) | (1 << (1 + reg * 2))
442 }
443}
444
445#[derive(Debug, Copy, Clone, Protobuf, PartialEq, Eq)]
447pub enum BreakpointType {
448 Execute = 0,
450 Invalid = 1,
452 Write = 2,
454 ReadOrWrite = 3,
456}
457
458#[derive(Debug, Copy, Clone, Protobuf, PartialEq, Eq)]
460pub enum BreakpointSize {
461 Byte = 0,
463 Word = 1,
465 DWord = 3,
467 QWord = 2,
469}
470
471#[derive(Debug)]
473pub struct UnsupportedBreakpointSize;
474
475impl TryFrom<usize> for BreakpointSize {
476 type Error = UnsupportedBreakpointSize;
477
478 fn try_from(value: usize) -> Result<Self, Self::Error> {
479 Ok(match value {
480 1 => BreakpointSize::Byte,
481 2 => BreakpointSize::Word,
482 4 => BreakpointSize::DWord,
483 8 => BreakpointSize::QWord,
484 _ => return Err(UnsupportedBreakpointSize),
485 })
486 }
487}
488
489pub fn max_physical_address_size_from_cpuid(mut cpuid: impl FnMut(u32, u32) -> [u32; 4]) -> u8 {
491 const DEFAULT_PHYSICAL_ADDRESS_SIZE: u8 = 32;
492
493 let max_extended = {
494 let result = cpuid(CpuidFunction::ExtendedMaxFunction.0, 0);
495 result[0]
496 };
497
498 if max_extended >= CpuidFunction::ExtendedAddressSpaceSizes.0 {
499 let result = cpuid(CpuidFunction::ExtendedAddressSpaceSizes.0, 0);
500 (result[0] & 0xFF) as u8
501 } else {
502 DEFAULT_PHYSICAL_ADDRESS_SIZE
503 }
504}
505
506#[derive(Debug)]
508pub enum MsrError {
509 Unknown,
512 InvalidAccess,
515}
516
517pub trait MsrErrorExt: Sized {
519 fn or_else_if_unknown(self, f: impl FnOnce() -> Self) -> Self;
521}
522
523impl<T> MsrErrorExt for Result<T, MsrError> {
524 fn or_else_if_unknown(self, f: impl FnOnce() -> Self) -> Self {
525 match self {
526 Err(MsrError::Unknown) => f(),
527 r => r,
528 }
529 }
530}