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