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