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