x86defs/
vmx.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Intel VMX specific definitions.
5
6// TODO: move VMX defs somewhere?
7
8use bitfield_struct::bitfield;
9use open_enum::open_enum;
10use zerocopy::FromBytes;
11use zerocopy::Immutable;
12use zerocopy::IntoBytes;
13use zerocopy::KnownLayout;
14
15open_enum! {
16    /// VMX basic exit reason
17    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/// VMX exit reason
54#[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, // 32 on X86, 64 on X64.
83}
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    /// 0 - Memory, 1 - Register
362    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}