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