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