1use bitfield_struct::bitfield;
9use open_enum::open_enum;
10use zerocopy::FromBytes;
11use zerocopy::Immutable;
12use zerocopy::IntoBytes;
13use zerocopy::KnownLayout;
14
15open_enum! {
16 pub enum VmxExitBasic: u16 {
18 EXCEPTION = 0x0,
19 HW_INTERRUPT = 0x1,
20 TRIPLE_FAULT = 0x2,
21 SMI_INTR = 0x6,
22 INTERRUPT_WINDOW = 0x7,
23 NMI_WINDOW = 0x8,
24 PAUSE_INSTRUCTION = 0x28,
25 CPUID = 0xA,
26 HLT_INSTRUCTION = 0xC,
27 VMCALL_INSTRUCTION = 0x12,
28 CR_ACCESS = 0x1C,
29 IO_INSTRUCTION = 0x1E,
30 MSR_READ = 0x1F,
31 MSR_WRITE = 0x20,
32 BAD_GUEST_STATE = 0x21,
33 TPR_BELOW_THRESHOLD = 0x2B,
34 GDTR_OR_IDTR = 0x2E,
35 LDTR_OR_TR = 0x2F,
36 EPT_VIOLATION = 0x30,
37 WBINVD_INSTRUCTION = 0x36,
38 XSETBV = 0x37,
39 TDCALL = 0x4D,
40 }
41}
42
43impl VmxExitBasic {
44 pub(crate) const fn from_bits(value: u64) -> Self {
45 Self(value as u16)
46 }
47
48 pub(crate) const fn into_bits(self) -> u64 {
49 self.0 as u64
50 }
51}
52
53#[bitfield(u32)]
55#[derive(PartialEq, Eq)]
56pub struct VmxExit {
57 #[bits(16)]
58 pub basic_reason: VmxExitBasic,
59 #[bits(10)]
60 rsvd_0: u64,
61 #[bits(1)]
62 pub bus_lock_preempted: bool,
63 #[bits(1)]
64 pub enclave_interruption: bool,
65 #[bits(1)]
66 pub pending_mtf: bool,
67 #[bits(2)]
68 rsvd_1: u8,
69 #[bits(1)]
70 pub vm_enter_failed: bool,
71}
72
73pub const VMX_ENTRY_CONTROL_LONG_MODE_GUEST: u32 = 0x00000200;
74pub const VMX_FEATURE_CONTROL_LOCKED: u64 = 0x0000000000000001;
75
76#[repr(u32)]
77#[derive(Debug, PartialEq, Eq)]
78pub enum FieldWidth {
79 Width16 = 0,
80 Width32 = 2,
81 Width64 = 1,
82 WidthNatural = 3, }
84
85impl FieldWidth {
86 const fn from_bits(value: u32) -> Self {
87 match value {
88 0 => FieldWidth::Width16,
89 2 => FieldWidth::Width32,
90 1 => FieldWidth::Width64,
91 3 => FieldWidth::WidthNatural,
92 _ => panic!("Invalid field width"),
93 }
94 }
95
96 const fn into_bits(self) -> u32 {
97 self as u32
98 }
99}
100
101#[bitfield(u32)]
102pub struct VmcsField {
103 #[bits(1)]
104 pub access_high: u32,
105 #[bits(9)]
106 pub index: u32,
107 #[bits(2)]
108 pub typ: u32,
109 #[bits(1)]
110 pub reserved: u32,
111 #[bits(2)]
112 pub field_width: FieldWidth,
113 #[bits(17)]
114 pub reserved2: u32,
115}
116
117impl VmcsField {
118 pub const VMX_VMCS_ENTRY_CONTROLS: Self = Self(0x00004012);
119
120 pub const VMX_VMCS_GUEST_CR0: Self = Self(0x00006800);
121 pub const VMX_VMCS_GUEST_CR3: Self = Self(0x00006802);
122 pub const VMX_VMCS_GUEST_CR4: Self = Self(0x00006804);
123 pub const VMX_VMCS_GUEST_DR7: Self = Self(0x0000681A);
124
125 pub const VMX_VMCS_GUEST_ES_SELECTOR: Self = Self(0x00000800);
126 pub const VMX_VMCS_GUEST_ES_BASE: Self = Self(0x00006806);
127 pub const VMX_VMCS_GUEST_ES_LIMIT: Self = Self(0x00004800);
128 pub const VMX_VMCS_GUEST_ES_AR: Self = Self(0x00004814);
129
130 pub const VMX_VMCS_GUEST_CS_SELECTOR: Self = Self(0x00000802);
131 pub const VMX_VMCS_GUEST_CS_BASE: Self = Self(0x00006808);
132 pub const VMX_VMCS_GUEST_CS_LIMIT: Self = Self(0x00004802);
133 pub const VMX_VMCS_GUEST_CS_AR: Self = Self(0x00004816);
134
135 pub const VMX_VMCS_GUEST_SS_SELECTOR: Self = Self(0x00000804);
136 pub const VMX_VMCS_GUEST_SS_BASE: Self = Self(0x0000680A);
137 pub const VMX_VMCS_GUEST_SS_LIMIT: Self = Self(0x00004804);
138 pub const VMX_VMCS_GUEST_SS_AR: Self = Self(0x00004818);
139
140 pub const VMX_VMCS_GUEST_DS_SELECTOR: Self = Self(0x00000806);
141 pub const VMX_VMCS_GUEST_DS_BASE: Self = Self(0x0000680C);
142 pub const VMX_VMCS_GUEST_DS_LIMIT: Self = Self(0x00004806);
143 pub const VMX_VMCS_GUEST_DS_AR: Self = Self(0x0000481A);
144
145 pub const VMX_VMCS_GUEST_FS_SELECTOR: Self = Self(0x00000808);
146 pub const VMX_VMCS_GUEST_FS_BASE: Self = Self(0x0000680E);
147 pub const VMX_VMCS_GUEST_FS_LIMIT: Self = Self(0x00004808);
148 pub const VMX_VMCS_GUEST_FS_AR: Self = Self(0x0000481C);
149
150 pub const VMX_VMCS_GUEST_GS_SELECTOR: Self = Self(0x0000080A);
151 pub const VMX_VMCS_GUEST_GS_BASE: Self = Self(0x00006810);
152 pub const VMX_VMCS_GUEST_GS_LIMIT: Self = Self(0x0000480A);
153 pub const VMX_VMCS_GUEST_GS_AR: Self = Self(0x0000481E);
154
155 pub const VMX_VMCS_GUEST_LDTR_SELECTOR: Self = Self(0x0000080C);
156 pub const VMX_VMCS_GUEST_LDTR_BASE: Self = Self(0x00006812);
157 pub const VMX_VMCS_GUEST_LDTR_LIMIT: Self = Self(0x0000480C);
158 pub const VMX_VMCS_GUEST_LDTR_AR: Self = Self(0x00004820);
159
160 pub const VMX_VMCS_GUEST_TR_SELECTOR: Self = Self(0x0000080E);
161 pub const VMX_VMCS_GUEST_TR_BASE: Self = Self(0x00006814);
162 pub const VMX_VMCS_GUEST_TR_LIMIT: Self = Self(0x0000480E);
163 pub const VMX_VMCS_GUEST_TR_AR: Self = Self(0x00004822);
164
165 pub const VMX_VMCS_GUEST_GDTR_BASE: Self = Self(0x00006816);
166 pub const VMX_VMCS_GUEST_GDTR_LIMIT: Self = Self(0x00004810);
167
168 pub const VMX_VMCS_GUEST_IDTR_BASE: Self = Self(0x00006818);
169 pub const VMX_VMCS_GUEST_IDTR_LIMIT: Self = Self(0x00004812);
170
171 pub const VMX_VMCS_GUEST_PAT: Self = Self(0x00002804);
172 pub const VMX_VMCS_GUEST_EFER: Self = Self(0x00002806);
173
174 pub const VMX_VMCS_VIRTUAL_APIC_PAGE: Self = Self(0x00002012);
175
176 pub const VMX_VMCS_EOI_EXIT_0: Self = Self(0x0000201C);
177 pub const VMX_VMCS_EOI_EXIT_1: Self = Self(0x0000201E);
178 pub const VMX_VMCS_EOI_EXIT_2: Self = Self(0x00002020);
179 pub const VMX_VMCS_EOI_EXIT_3: Self = Self(0x00002022);
180
181 pub const VMX_VMCS_PROCESSOR_CONTROLS: Self = Self(0x00004002);
182 pub const VMX_VMCS_EXCEPTION_BITMAP: Self = Self(0x00004004);
183 pub const VMX_VMCS_ENTRY_INTERRUPT_INFO: Self = Self(0x00004016);
184 pub const VMX_VMCS_ENTRY_EXCEPTION_ERROR_CODE: Self = Self(0x00004018);
185 pub const VMX_VMCS_ENTRY_INSTRUCTION_LENGTH: Self = Self(0x0000401A);
186 pub const VMX_VMCS_TPR_THRESHOLD: Self = Self(0x0000401C);
187 pub const VMX_VMCS_SECONDARY_PROCESSOR_CONTROLS: Self = Self(0x0000401E);
188
189 pub const VMX_VMCS_CR0_GUEST_HOST_MASK: Self = Self(0x00006000);
190 pub const VMX_VMCS_CR4_GUEST_HOST_MASK: Self = Self(0x00006002);
191 pub const VMX_VMCS_CR0_READ_SHADOW: Self = Self(0x00006004);
192 pub const VMX_VMCS_CR4_READ_SHADOW: Self = Self(0x00006006);
193
194 pub const VMX_VMCS_GUEST_INTERRUPTIBILITY: Self = Self(0x00004824);
195
196 pub const VMX_VMCS_GUEST_SYSENTER_CS_MSR: Self = Self(0x0000482A);
197 pub const VMX_VMCS_GUEST_SYSENTER_ESP_MSR: Self = Self(0x00006824);
198 pub const VMX_VMCS_GUEST_SYSENTER_EIP_MSR: Self = Self(0x00006826);
199}
200
201#[bitfield(u32)]
202pub struct VmxSegmentAttributes {
203 #[bits(4)]
204 pub typ: u32,
205 #[bits(1)]
206 pub user: u32,
207 #[bits(2)]
208 pub dpl: u32,
209 pub present: bool,
210 #[bits(4)]
211 pub reserved1: u32,
212 pub available: bool,
213 #[bits(1)]
214 pub long_mode: u32,
215 #[bits(1)]
216 pub default_size: u32,
217 #[bits(1)]
218 pub granularity: u32,
219 pub null: bool,
220 #[bits(15)]
221 pub reserved: u32,
222}
223
224pub const IO_SIZE_8_BIT: u8 = 0;
225pub const IO_SIZE_16_BIT: u8 = 1;
226pub const IO_SIZE_32_BIT: u8 = 3;
227
228#[bitfield(u32)]
229pub struct ExitQualificationIo {
230 #[bits(2)]
231 pub access_size: u8,
232 #[bits(1)]
233 pub reserved1: u8,
234 pub is_in: bool,
235 pub is_string: bool,
236 pub rep_prefix: bool,
237 pub immediate_operand: bool,
238 #[bits(9)]
239 pub reserved2: u32,
240 pub port: u16,
241}
242
243#[bitfield(u64)]
244pub struct VmxEptExitQualification {
245 #[bits(3)]
246 pub access_mask: u8,
247 #[bits(4)]
248 pub ept_access_mask: u8,
249 pub gva_valid: bool,
250 pub caused_by_gpa_access: bool,
251 pub gva_user: bool,
252 pub gva_read_write: bool,
253 pub gva_no_execute: bool,
254 pub nmi_unmasking_due_to_iret: bool,
255 pub shadow_stack: bool,
256 pub ept_supervisor_shadow_stack: bool,
257 #[bits(49)]
258 pub reserved: u64,
259}
260
261#[bitfield(u64)]
262pub struct CrAccessQualification {
263 #[bits(4)]
264 pub cr: u8,
265 #[bits(2)]
266 pub access_type: u8,
267 pub lmsw_is_memory: bool,
268 #[bits(1)]
269 _reserved1: u8,
270 #[bits(4)]
271 pub gp_register: u8,
272 #[bits(4)]
273 _reserved2: u8,
274 pub lmsw_source_data: u16,
275 _reserved3: u32,
276}
277
278pub const CR_ACCESS_TYPE_MOV_TO_CR: u8 = 0;
279pub const CR_ACCESS_TYPE_MOV_FROM_CR: u8 = 1;
280pub const CR_ACCESS_TYPE_CLTS: u8 = 2;
281pub const CR_ACCESS_TYPE_LMSW: u8 = 3;
282
283#[bitfield(u32)]
284pub struct InterruptionInformation {
285 #[bits(8)]
286 pub vector: u8,
287 #[bits(3)]
288 pub interruption_type: u8,
289 pub deliver_error_code: bool,
290 #[bits(19)]
291 pub reserved: u32,
292 pub valid: bool,
293}
294
295#[bitfield(u32)]
296pub struct GdtrOrIdtrInstructionInfo {
297 #[bits(2)]
298 pub scaling: u8,
299 #[bits(5)]
300 _reserved1: u8,
301 #[bits(3)]
302 pub address_size: u8,
303 _reserved2: bool,
304 pub operand_size: bool,
305 #[bits(3)]
306 _reserved3: u8,
307 #[bits(3)]
308 pub segment_register: u8,
309 #[bits(4)]
310 pub index_register: u8,
311 pub index_register_invalid: bool,
312 #[bits(4)]
313 pub base_register: u8,
314 pub base_register_invalid: bool,
315 #[bits(2)]
316 pub instruction: GdtrOrIdtrInstruction,
317 #[bits(2)]
318 _reserved4: u8,
319}
320
321#[derive(Copy, Clone, Debug, PartialEq)]
322pub enum GdtrOrIdtrInstruction {
323 Sgdt = 0,
324 Sidt = 1,
325 Lgdt = 2,
326 Lidt = 3,
327}
328
329impl GdtrOrIdtrInstruction {
330 const fn from_bits(value: u8) -> Self {
331 match value {
332 0 => GdtrOrIdtrInstruction::Sgdt,
333 1 => GdtrOrIdtrInstruction::Sidt,
334 2 => GdtrOrIdtrInstruction::Lgdt,
335 3 => GdtrOrIdtrInstruction::Lidt,
336 _ => unreachable!(),
337 }
338 }
339
340 const fn into_bits(self) -> u8 {
341 self as u8
342 }
343
344 pub const fn is_load(self) -> bool {
345 match self {
346 GdtrOrIdtrInstruction::Lgdt | GdtrOrIdtrInstruction::Lidt => true,
347 GdtrOrIdtrInstruction::Sgdt | GdtrOrIdtrInstruction::Sidt => false,
348 }
349 }
350}
351
352#[bitfield(u32)]
353pub struct LdtrOrTrInstructionInfo {
354 #[bits(2)]
355 pub scaling: u8,
356 _reserved1: bool,
357 #[bits(4)]
358 pub register_1: u8,
359 #[bits(3)]
360 pub address_size: u8,
361 pub memory_or_register: bool,
363 #[bits(4)]
364 _reserved2: u8,
365 #[bits(3)]
366 pub segment_register: u8,
367 #[bits(4)]
368 pub index_register: u8,
369 pub index_register_invalid: bool,
370 #[bits(4)]
371 pub base_register: u8,
372 pub base_register_invalid: bool,
373 #[bits(2)]
374 pub instruction: LdtrOrTrInstruction,
375 #[bits(2)]
376 _reserved4: u8,
377}
378
379#[derive(Copy, Clone, Debug, PartialEq)]
380pub enum LdtrOrTrInstruction {
381 Sldt = 0,
382 Str = 1,
383 Lldt = 2,
384 Ltr = 3,
385}
386
387impl LdtrOrTrInstruction {
388 const fn from_bits(value: u8) -> Self {
389 match value {
390 0 => LdtrOrTrInstruction::Sldt,
391 1 => LdtrOrTrInstruction::Str,
392 2 => LdtrOrTrInstruction::Lldt,
393 3 => LdtrOrTrInstruction::Ltr,
394 _ => unreachable!(),
395 }
396 }
397
398 const fn into_bits(self) -> u8 {
399 self as u8
400 }
401
402 pub const fn is_load(self) -> bool {
403 match self {
404 LdtrOrTrInstruction::Lldt | LdtrOrTrInstruction::Ltr => true,
405 LdtrOrTrInstruction::Sldt | LdtrOrTrInstruction::Str => false,
406 }
407 }
408}
409
410pub const INTERRUPT_TYPE_EXTERNAL: u8 = 0;
411pub const INTERRUPT_TYPE_NMI: u8 = 2;
412pub const INTERRUPT_TYPE_HARDWARE_EXCEPTION: u8 = 3;
413pub const INTERRUPT_TYPE_SOFTWARE_INTERRUPT: u8 = 4;
414pub const INTERRUPT_TYPE_PRIVILEGED_SOFTWARE_INTERRUPT: u8 = 5;
415pub const INTERRUPT_TYPE_SOFTWARE_EXCEPTION: u8 = 6;
416
417#[bitfield(u32)]
418pub struct Interruptibility {
419 pub blocked_by_sti: bool,
420 pub blocked_by_movss: bool,
421 pub blocked_by_smi: bool,
422 pub blocked_by_nmi: bool,
423 #[bits(28)]
424 _reserved: u32,
425}
426
427#[bitfield(u32)]
428#[derive(PartialEq, Eq)]
429pub struct ProcessorControls {
430 #[bits(2)]
431 _reserved: u32,
432 pub interrupt_window_exiting: bool,
433 pub use_tsc_offsetting: bool,
434 #[bits(3)]
435 _reserved2: u32,
436 pub hlt_exiting: bool,
437 _reserved3: bool,
438 pub invlpg_exiting: bool,
439 pub mwait_exiting: bool,
440 pub rdpmc_exiting: bool,
441 pub rdtsc_exiting: bool,
442 #[bits(2)]
443 _reserved4: u32,
444 pub cr3_load_exiting: bool,
445 pub cr3_store_exiting: bool,
446 pub activate_tertiary_controls: bool,
447 _reserved5: bool,
448 pub cr8_load_exiting: bool,
449 pub cr8_store_exiting: bool,
450 pub use_tpr_shadow: bool,
451 pub nmi_window_exiting: bool,
452 pub mov_dr_exiting: bool,
453 pub unconditional_io_exiting: bool,
454 pub use_io_bitmaps: bool,
455 _reserved6: bool,
456 pub monitor_trap_flag: bool,
457 pub use_msr_bitmaps: bool,
458 pub monitor_exiting: bool,
459 pub pause_exiting: bool,
460 pub activate_secondary_controls: bool,
461}
462
463#[bitfield(u32)]
464pub struct SecondaryProcessorControls {
465 pub virtualize_apic_accesses: bool,
466 pub enable_ept: bool,
467 pub descriptor_table_exiting: bool,
468 pub enable_rdtscp: bool,
469 pub virtualize_x2apic_mode: bool,
470 pub enable_vpid: bool,
471 pub wbinvd_exiting: bool,
472 pub unrestricted_guest: bool,
473 pub apic_register_virtualization: bool,
474 pub virtual_interrupt_delivery: bool,
475 pub pause_loop_exiting: bool,
476 pub rdrand_exiting: bool,
477 pub enable_invpcid: bool,
478 pub enable_vmfunc: bool,
479 pub vmcs_shadowing: bool,
480 pub enable_encls_exiting: bool,
481 pub rdseed_exiting: bool,
482 pub enable_pml: bool,
483 pub ept_violation_ve: bool,
484 pub conceal_vmx_from_pt: bool,
485 pub enable_xsaves_xrstors: bool,
486 pub pasid_translation: bool,
487 pub mode_based_execute_control: bool,
488 pub sub_page_write_permissions: bool,
489 pub pt_uses_guest_physical_addresses: bool,
490 pub use_tsc_scaling: bool,
491 pub enable_user_wait_and_pause: bool,
492 pub enable_pconfig: bool,
493 pub enable_enclv_exiting: bool,
494 _reserved: bool,
495 pub vmm_bus_lock_detection: bool,
496 pub instruction_timeout: bool,
497}
498
499#[repr(C)]
500#[derive(Debug, Copy, Clone, IntoBytes, Immutable, KnownLayout, FromBytes)]
501pub struct ApicRegister {
502 pub value: u32,
503 _reserved: [u32; 3],
504}
505
506#[repr(C)]
507#[derive(Debug, Clone, IntoBytes, Immutable, KnownLayout, FromBytes)]
508pub struct ApicPage {
509 pub reserved_0: [ApicRegister; 2],
510 pub id: ApicRegister,
511 pub version: ApicRegister,
512 pub reserved_4: [ApicRegister; 4],
513 pub tpr: ApicRegister,
514 pub apr: ApicRegister,
515 pub ppr: ApicRegister,
516 pub eoi: ApicRegister,
517 pub rrd: ApicRegister,
518 pub ldr: ApicRegister,
519 pub dfr: ApicRegister,
520 pub svr: ApicRegister,
521 pub isr: [ApicRegister; 8],
522 pub tmr: [ApicRegister; 8],
523 pub irr: [ApicRegister; 8],
524 pub esr: ApicRegister,
525 pub reserved_29: [ApicRegister; 6],
526 pub lvt_cmci: ApicRegister,
527 pub icr: [ApicRegister; 2],
528 pub lvt_timer: ApicRegister,
529 pub lvt_thermal: ApicRegister,
530 pub lvt_pmc: ApicRegister,
531 pub lvt_lint0: ApicRegister,
532 pub lvt_lint1: ApicRegister,
533 pub lvt_error: ApicRegister,
534 pub timer_icr: ApicRegister,
535 pub timer_ccr: ApicRegister,
536 pub reserved_3a: [ApicRegister; 4],
537 pub timer_dcr: ApicRegister,
538 pub reserved_3f: ApicRegister,
539 pub reserved_40: [ApicRegister; 0xc0],
540}