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