1#![expect(missing_docs)]
8#![no_std]
9#![forbid(unsafe_code)]
10
11pub mod apic;
12pub mod cpuid;
13pub mod msi;
14pub mod serial;
15pub mod snp;
16pub mod tdx;
17pub mod vmx;
18pub mod xsave;
19
20use bitfield_struct::bitfield;
21use open_enum::open_enum;
22use zerocopy::FromBytes;
23use zerocopy::FromZeros;
24use zerocopy::Immutable;
25use zerocopy::IntoBytes;
26use zerocopy::KnownLayout;
27
28pub const X64_CR0_PE: u64 = 0x0000000000000001; pub const X64_CR0_MP: u64 = 0x0000000000000002; pub const X64_CR0_EM: u64 = 0x0000000000000004; pub const X64_CR0_TS: u64 = 0x0000000000000008; pub const X64_CR0_ET: u64 = 0x0000000000000010; pub const X64_CR0_NE: u64 = 0x0000000000000020; pub const X64_CR0_WP: u64 = 0x0000000000010000; pub const X64_CR0_AM: u64 = 0x0000000000040000; pub const X64_CR0_NW: u64 = 0x0000000020000000; pub const X64_CR0_CD: u64 = 0x0000000040000000; pub const X64_CR0_PG: u64 = 0x0000000080000000; pub const X64_CR0_RSVDZ_MASK: u64 = 0x1FFA_FFC0;
42
43pub const X64_CR4_VME: u64 = 0x0000000000000001; pub const X64_CR4_PVI: u64 = 0x0000000000000002; pub const X64_CR4_TSD: u64 = 0x0000000000000004; pub const X64_CR4_DE: u64 = 0x0000000000000008; pub const X64_CR4_PSE: u64 = 0x0000000000000010; pub const X64_CR4_PAE: u64 = 0x0000000000000020; pub const X64_CR4_MCE: u64 = 0x0000000000000040; pub const X64_CR4_PGE: u64 = 0x0000000000000080; pub const X64_CR4_PCE: u64 = 0x0000000000000100; pub const X64_CR4_FXSR: u64 = 0x0000000000000200; pub const X64_CR4_XMMEXCPT: u64 = 0x0000000000000400; pub const X64_CR4_UMIP: u64 = 0x0000000000000800; pub const X64_CR4_LA57: u64 = 0x0000000000001000; pub const X64_CR4_VMXE: u64 = 0x0000000000002000; pub const X64_CR4_RWFSGS: u64 = 0x0000000000010000; pub const X64_CR4_PCIDE: u64 = 0x0000000000020000; pub const X64_CR4_OSXSAVE: u64 = 0x0000000000040000; pub const X64_CR4_SMEP: u64 = 0x0000000000100000; pub const X64_CR4_SMAP: u64 = 0x0000000000200000; pub const X64_CR4_CET: u64 = 0x0000000000800000; pub const X64_EFER_SCE: u64 = 0x0000000000000001; pub const X64_EFER_LME: u64 = 0x0000000000000100; pub const X64_EFER_LMA: u64 = 0x0000000000000400; pub const X64_EFER_NXE: u64 = 0x0000000000000800; pub const X64_EFER_SVME: u64 = 0x0000000000001000; pub const X64_EFER_FFXSR: u64 = 0x0000000000004000; pub const X64_EFER_TCE: u64 = 0x0000000000008000; pub const X86X_MSR_DEFAULT_PAT: u64 = 0x0007040600070406;
73pub const X64_EMPTY_DR7: u64 = 0x0000000000000400;
74
75pub const USER_MODE_DPL: u8 = 3;
76
77pub fn is_canonical_address(v: u64, bits: u32) -> bool {
81 let high = (v as i64) >> (bits - 1);
82 high == 0 || high == -1
83}
84
85pub const X64_DEFAULT_CODE_SEGMENT_ATTRIBUTES: SegmentAttributes = SegmentAttributes::new()
86 .with_granularity(true)
87 .with_long(true)
88 .with_present(true)
89 .with_non_system_segment(true)
90 .with_segment_type(0xb);
91pub const X64_DEFAULT_DATA_SEGMENT_ATTRIBUTES: SegmentAttributes = SegmentAttributes::new()
92 .with_granularity(true)
93 .with_default(true)
94 .with_present(true)
95 .with_non_system_segment(true)
96 .with_segment_type(0x3);
97pub const X64_BUSY_TSS_SEGMENT_ATTRIBUTES: SegmentAttributes = SegmentAttributes::new()
98 .with_present(true)
99 .with_segment_type(0xb);
100
101#[bitfield(u16)]
102#[derive(PartialEq)]
103pub struct SegmentAttributes {
104 #[bits(4)]
105 pub segment_type: u8,
106 pub non_system_segment: bool,
107 #[bits(2)]
108 pub descriptor_privilege_level: u8,
109 pub present: bool,
110 #[bits(4)]
111 _reserved: u8,
112 pub available: bool,
113 pub long: bool,
114 pub default: bool,
115 pub granularity: bool,
116}
117
118impl SegmentAttributes {
119 pub const fn as_bits(&self) -> u16 {
120 self.0
121 }
122}
123
124#[cfg(feature = "arbitrary")]
125impl<'a> arbitrary::Arbitrary<'a> for SegmentAttributes {
126 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
127 let x: u16 = u.arbitrary()?;
128 Ok(x.into())
129 }
130}
131
132#[bitfield(u16)]
134#[derive(PartialEq, Eq)]
135pub struct SegmentSelector {
136 #[bits(2)]
137 pub rpl: u8,
139 pub ti: bool,
141 #[bits(13)]
142 pub index: u16,
144}
145
146impl SegmentSelector {
147 pub const fn as_bits(&self) -> u16 {
148 self.0
149 }
150
151 pub fn from_gdt_index(index: u16, rpl: u8) -> Self {
152 Self::new().with_index(index).with_rpl(rpl).with_ti(false)
153 }
154}
155
156#[derive(Debug, Copy, Clone, PartialEq)]
157pub struct SegmentRegister {
158 pub base: u64,
159 pub limit: u32,
160 pub selector: u16,
161 pub attributes: SegmentAttributes,
162}
163
164#[cfg(feature = "arbitrary")]
165impl<'a> arbitrary::Arbitrary<'a> for SegmentRegister {
166 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
167 Ok(SegmentRegister {
168 base: u.arbitrary()?,
169 limit: u.arbitrary()?,
170 selector: u.arbitrary()?,
171 attributes: u.arbitrary()?,
172 })
173 }
174}
175
176#[bitfield(u64)]
182pub struct MiscEnable {
183 pub fast_string: bool,
184 pub tcc: bool,
185 pub x87_compat: bool,
186 pub tm1: bool,
187 pub split_lock_disable: bool,
188 _reserved5: bool,
189 pub l3cache_disable: bool,
190 pub emon: bool,
191 pub suppress_lock: bool,
192 pub prefetch_disable: bool,
193 pub ferr: bool,
194 pub bts_unavailable: bool,
195 pub pebs_unavailable: bool,
196 pub tm2: bool,
197 _reserved14: bool,
198 _reserved15: bool,
199 pub enhanced_speedstep: bool,
200 _reserved17: bool,
201 pub mwait: bool,
202 pub adj_prefetch_disable: bool,
203 pub enable_speedstep_lock: bool,
204 _reserved21: bool,
205 pub limit_cpuid: bool,
206 pub xtpr_disable: bool,
207 pub l1d_context: bool,
208 #[bits(39)]
209 _reserved: u64,
210}
211
212pub const X86X_MSR_TSC: u32 = 0x10;
213pub const X86X_IA32_MSR_PLATFORM_ID: u32 = 0x17;
214pub const X86X_MSR_APIC_BASE: u32 = 0x1b;
215pub const X86X_MSR_EBL_CR_POWERON: u32 = 0x2a;
216pub const X86X_IA32_MSR_SMI_COUNT: u32 = 0x34;
217pub const X86X_IA32_MSR_FEATURE_CONTROL: u32 = 0x3a;
218pub const X86X_MSR_PPIN_CTL: u32 = 0x4e;
219pub const X86X_MSR_BIOS_UPDT_TRIG: u32 = 0x79;
220pub const X86X_MSR_MC_UPDATE_PATCH_LEVEL: u32 = 0x8b;
221pub const X86X_MSR_PLATFORM_INFO: u32 = 0xce;
222pub const X86X_MSR_UMWAIT_CONTROL: u32 = 0xe1;
223pub const X86X_MSR_MTRR_CAP: u32 = 0xfe;
224pub const X86X_MSR_MISC_FEATURE_ENABLES: u32 = 0x140;
225pub const X86X_MSR_SYSENTER_CS: u32 = 0x174;
226pub const X86X_MSR_SYSENTER_ESP: u32 = 0x175;
227pub const X86X_MSR_SYSENTER_EIP: u32 = 0x176;
228pub const X86X_MSR_MCG_CAP: u32 = 0x179;
229pub const X86X_MSR_MCG_STATUS: u32 = 0x17a;
230
231#[bitfield(u64)]
236#[derive(PartialEq, Eq)]
237pub struct McgCap {
238 pub count: u8,
240 pub ctl_p: bool,
242 pub ext_p: bool,
244 pub cmci_p: bool,
246 pub tes_p: bool,
248 pub seam_nr_p: bool,
250 #[bits(3)]
251 _reserved: u8,
252 pub ext_cnt: u8,
255 pub ser_p: bool,
257 pub emc_p: bool,
260 pub elog_p: bool,
262 pub lmce_p: bool,
264 #[bits(36)]
265 _reserved2: u64,
266}
267
268pub const X86X_IA32_MSR_MISC_ENABLE: u32 = 0x1a0;
269pub const X86X_MSR_MTRR_PHYSBASE0: u32 = 0x200;
270pub const X86X_MSR_MTRR_FIX64K_00000: u32 = 0x0250;
271pub const X86X_MSR_MTRR_FIX16K_80000: u32 = 0x0258;
272pub const X86X_MSR_MTRR_FIX16K_A0000: u32 = 0x0259;
273pub const X86X_MSR_MTRR_FIX4K_C0000: u32 = 0x0268;
274pub const X86X_MSR_MTRR_FIX4K_C8000: u32 = 0x0269;
275pub const X86X_MSR_MTRR_FIX4K_D0000: u32 = 0x026A;
276pub const X86X_MSR_MTRR_FIX4K_D8000: u32 = 0x026B;
277pub const X86X_MSR_MTRR_FIX4K_E0000: u32 = 0x026C;
278pub const X86X_MSR_MTRR_FIX4K_E8000: u32 = 0x026D;
279pub const X86X_MSR_MTRR_FIX4K_F0000: u32 = 0x026E;
280pub const X86X_MSR_MTRR_FIX4K_F8000: u32 = 0x026F;
281pub const X86X_MSR_CR_PAT: u32 = 0x277;
282pub const X86X_MSR_MTRR_DEF_TYPE: u32 = 0x2ff;
283
284pub const X86X_MSR_XSS: u32 = 0xda0;
285
286pub const X86X_IA32_MSR_RAPL_POWER_UNIT: u32 = 0x606;
287pub const X86X_IA32_MSR_PKG_ENERGY_STATUS: u32 = 0x611;
288pub const X86X_IA32_MSR_DRAM_ENERGY_STATUS: u32 = 0x619;
289pub const X86X_IA32_MSR_PP0_ENERGY_STATUS: u32 = 0x639;
290
291pub const X86X_MSR_U_CET: u32 = 0x6a0;
292pub const X86X_MSR_S_CET: u32 = 0x6a2;
293pub const X86X_MSR_PL0_SSP: u32 = 0x6a4;
294pub const X86X_MSR_PL1_SSP: u32 = 0x6a5;
295pub const X86X_MSR_PL2_SSP: u32 = 0x6a6;
296pub const X86X_MSR_PL3_SSP: u32 = 0x6a7;
297pub const X86X_MSR_INTERRUPT_SSP_TABLE_ADDR: u32 = 0x6a8;
298
299pub const X86X_MSR_STAR: u32 = 0xC0000081;
300pub const X86X_MSR_LSTAR: u32 = 0xC0000082;
301pub const X86X_MSR_CSTAR: u32 = 0xC0000083;
302pub const X86X_MSR_SFMASK: u32 = 0xC0000084;
303
304pub const X86X_MSR_EFER: u32 = 0xC0000080;
305pub const X64_MSR_FS_BASE: u32 = 0xC0000100;
306pub const X64_MSR_GS_BASE: u32 = 0xC0000101;
307pub const X64_MSR_KERNEL_GS_BASE: u32 = 0xC0000102;
308
309pub const X86X_MSR_TSC_AUX: u32 = 0xC0000103;
310
311pub const X86X_MSR_SPEC_CTRL: u32 = 0x48;
312pub const X86X_IA32_MSR_XFD: u32 = 0x1C4;
313pub const X86X_IA32_MSR_XFD_ERR: u32 = 0x1C5;
314
315pub const X86X_AMD_MSR_PERF_EVT_SEL0: u32 = 0xC0010000;
316pub const X86X_AMD_MSR_PERF_EVT_SEL1: u32 = 0xC0010001;
317pub const X86X_AMD_MSR_PERF_EVT_SEL2: u32 = 0xC0010002;
318pub const X86X_AMD_MSR_PERF_EVT_SEL3: u32 = 0xC0010003;
319pub const X86X_AMD_MSR_PERF_CTR0: u32 = 0xC0010004;
320pub const X86X_AMD_MSR_PERF_CTR1: u32 = 0xC0010005;
321pub const X86X_AMD_MSR_PERF_CTR2: u32 = 0xC0010006;
322pub const X86X_AMD_MSR_PERF_CTR3: u32 = 0xC0010007;
323pub const X86X_AMD_MSR_SYSCFG: u32 = 0xC0010010;
324pub const X86X_AMD_MSR_HW_CFG: u32 = 0xC0010015;
325pub const X86X_AMD_MSR_NB_CFG: u32 = 0xC001001F;
326pub const X86X_AMD_MSR_VM_CR: u32 = 0xC0010114;
327pub const X86X_AMD_MSR_IGNNE: u32 = 0xC0010115;
328pub const X86X_AMD_MSR_GHCB: u32 = 0xC0010130;
329pub const X86X_AMD_MSR_SEV: u32 = 0xC0010131;
330pub const X86X_AMD_MSR_SECURE_AVIC_CONTROL: u32 = 0xc0010138;
331pub const X86X_AMD_MSR_OSVW_ID_LENGTH: u32 = 0xc0010140;
332pub const X86X_AMD_MSR_OSVW_ID_STATUS: u32 = 0xc0010141;
333pub const X86X_AMD_MSR_LS_CFG: u32 = 0xc0011020;
336pub const X86X_AMD_MSR_DE_CFG: u32 = 0xc0011029;
337pub const X86X_AMD_MSR_BU_CFG2: u32 = 0xc001102a;
339pub const X86X_AMD_MSR_EX_CFG: u32 = 0xc001102c;
343
344pub const DR6_BREAKPOINT_MASK: u64 = 0xf;
345pub const DR6_SINGLE_STEP: u64 = 0x4000;
346
347#[bitfield(u64, default = false)]
348#[derive(PartialEq)]
349pub struct RFlags {
350 pub carry: bool,
352 pub reserved_must_be_1: bool,
353 pub parity: bool,
354 _reserved1: bool,
355 pub adjust: bool,
356 _reserved2: bool,
357 pub zero: bool,
358 pub sign: bool,
359 pub trap: bool,
360 pub interrupt_enable: bool,
361 pub direction: bool,
362 pub overflow: bool,
363 #[bits(2)]
364 pub io_privilege_level: u8,
365 pub nested_task: bool,
366 pub mode: bool,
367
368 pub resume: bool,
370 pub virtual_8086_mode: bool,
371 pub alignment_check: bool,
372 pub virtual_interrupt: bool,
373 pub virtual_interrupt_pending: bool,
374 pub cpuid_allowed: bool,
375 _reserved3: u8,
376 pub aes_key_schedule_loaded: bool,
377 _reserved4: bool,
378
379 _reserved5: u32,
381}
382
383impl RFlags {
384 pub fn at_reset() -> Self {
386 Self::new().with_reserved_must_be_1(true)
387 }
388}
389
390impl core::ops::BitAnd<RFlags> for RFlags {
391 type Output = RFlags;
392
393 fn bitand(self, rhs: RFlags) -> Self::Output {
394 RFlags(self.0 & rhs.0)
395 }
396}
397
398#[cfg(feature = "arbitrary")]
399impl<'a> arbitrary::Arbitrary<'a> for RFlags {
400 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
401 let x: u64 = u.arbitrary()?;
402 Ok(x.into())
403 }
404}
405
406#[repr(C)]
407#[derive(Debug, Clone, Copy, IntoBytes, Immutable, KnownLayout, FromBytes)]
408pub struct IdtEntry64 {
409 pub offset_low: u16,
410 pub selector: u16,
411 pub attributes: IdtAttributes,
412 pub offset_middle: u16,
413 pub offset_high: u32,
414 pub reserved: u32,
415}
416
417#[bitfield(u16)]
418#[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
419pub struct IdtAttributes {
420 #[bits(3)]
421 pub ist: u8,
422 #[bits(5)]
423 _reserved: u8,
424 #[bits(4)]
425 pub gate_type: u8,
426 _reserved2: bool,
427 #[bits(2)]
428 pub dpl: u8,
429 pub present: bool,
430}
431
432#[repr(C)]
433#[derive(Clone, Copy, IntoBytes, Immutable, KnownLayout, FromBytes)]
434pub struct GdtEntry {
435 pub limit_low: u16,
436 pub base_low: u16,
437 pub base_middle: u8,
438 pub attr_low: u8,
439 pub attr_high: u8,
440 pub base_high: u8,
441}
442
443#[repr(C)]
444#[derive(Clone, Copy, IntoBytes, Immutable, KnownLayout, FromBytes)]
445pub struct LargeGdtEntry {
446 pub limit_low: u16,
447 pub base_low: u16,
448 pub base_middle: u8,
449 pub attr_low: u8,
450 pub attr_high: u8,
451 pub base_high: u8,
452 pub base_upper: u32,
453 pub mbz: u32,
454}
455
456impl LargeGdtEntry {
457 pub fn get_gdt_entries(&self) -> [GdtEntry; 2] {
459 let mut entries = [GdtEntry::new_zeroed(); 2];
460 entries.as_mut_bytes().copy_from_slice(self.as_bytes());
461 entries
462 }
463}
464
465#[repr(C, packed)]
466#[derive(Clone, Copy, Immutable, KnownLayout, IntoBytes, FromBytes)]
467pub struct Tss64 {
468 pub _mbz0: u32,
469 pub rsp: [u64; 3],
470 pub ist: [u64; 8],
471 pub _mbz1: u64,
472 pub _mbz2: u16,
473 pub io_map_base: u16,
474}
475
476open_enum! {
477 pub enum Exception: u8 {
478 DIVIDE_ERROR = 0x0,
479 DEBUG = 0x1,
480 BREAKPOINT = 0x3,
481 OVERFLOW = 0x4,
482 BOUND_RANGE_EXCEEDED = 0x5,
483 INVALID_OPCODE = 0x6,
484 DEVICE_NOT_AVAILABLE = 0x7,
485 DOUBLE_FAULT = 0x8,
486 INVALID_TSS = 0x0A,
487 SEGMENT_NOT_PRESENT = 0x0B,
488 STACK_SEGMENT_FAULT = 0x0C,
489 GENERAL_PROTECTION_FAULT = 0x0D,
490 PAGE_FAULT = 0x0E,
491 FLOATING_POINT_EXCEPTION = 0x10,
492 ALIGNMENT_CHECK = 0x11,
493 MACHINE_CHECK = 0x12,
494 SIMD_FLOATING_POINT_EXCEPTION = 0x13,
495 CONTROL_PROTECTION_EXCEPTION = 0x15,
496 SEV_VMM_COMMUNICATION = 0x1D,
497 }
498}
499
500#[bitfield(u32)]
501pub struct PageFaultErrorCode {
502 pub present: bool,
503 pub write: bool,
504 pub user: bool,
505 pub reserved: bool,
506 pub fetch: bool,
507 #[bits(27)]
508 _unused: u32,
509}
510
511pub const X64_PAGE_SIZE: u64 = 0x1000;
512pub const X64_LARGE_PAGE_SIZE: u64 = 0x200000;
513
514#[bitfield(u64)]
515#[derive(PartialEq, Eq, IntoBytes, Immutable, KnownLayout, FromBytes)]
516pub struct Pte {
517 pub present: bool,
518 pub read_write: bool,
519 pub user: bool,
520 pub write_through: bool,
521 pub cache_disable: bool,
522 pub accessed: bool,
523 pub dirty: bool,
524 pub pat: bool,
525 pub global: bool,
526 #[bits(3)]
527 pub available0: u64,
528 #[bits(40)]
529 pub pfn: u64,
530 #[bits(11)]
531 pub available1: u64,
532 pub no_execute: bool,
533}
534
535impl Pte {
536 pub fn address(&self) -> u64 {
537 self.pfn() << 12
538 }
539
540 pub fn with_address(self, address: u64) -> Self {
541 assert!(address & 0xfff == 0);
542 self.with_pfn(address >> 12)
543 }
544
545 pub fn set_address(&mut self, address: u64) -> &mut Self {
546 *self = self.with_address(address);
547 self
548 }
549}
550
551#[bitfield(u64)]
552#[derive(PartialEq, Eq, IntoBytes, Immutable, KnownLayout, FromBytes)]
553pub struct LargePde {
554 pub present: bool,
555 pub read_write: bool,
556 pub user: bool,
557 pub write_through: bool,
558 pub cache_disable: bool,
559 pub accessed: bool,
560 pub dirty: bool,
561 pub large_page: bool,
562 pub global: bool,
563 #[bits(3)]
564 pub available0: u64,
565 pub pat: bool,
566 #[bits(8)]
567 _reserved0: u64,
568 #[bits(31)]
569 pub large_page_base: u64,
570 #[bits(11)]
571 pub available1: u64,
572 pub no_execute: bool,
573}
574
575#[bitfield(u64)]
576#[derive(PartialEq, Eq, IntoBytes, Immutable, KnownLayout, FromBytes)]
577pub struct X86xMcgStatusRegister {
578 pub ripv: bool, pub eipv: bool, pub mcip: bool, #[bits(61)]
582 pub reserved0: u64,
583}
584
585#[repr(C)]
586#[derive(Debug, Copy, Clone, IntoBytes, Immutable, KnownLayout, FromBytes)]
587pub struct ApicRegisterValue {
588 pub value: u32,
589 _reserved: [u32; 3],
590}