Skip to main content

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 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    /// VMX basic exit reason
19    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/// VMX exit reason
57#[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, // 32 on X86, 64 on X64.
86}
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    /// 0 - Memory, 1 - Register
365    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);