1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

//! Intel VMX specific definitions.

// TODO: move VMX defs somewhere?

use bitfield_struct::bitfield;
use open_enum::open_enum;
use zerocopy::AsBytes;
use zerocopy::FromBytes;
use zerocopy::FromZeroes;

open_enum! {
    /// VMX exit reason
    pub enum VmxExit: u32 {
        EXCEPTION = 0x0,
        HW_INTERRUPT = 0x1,
        TRIPLE_FAULT = 0x2,
        SMI_INTR = 0x6,
        INTERRUPT_WINDOW = 7,
        NMI_WINDOW = 8,
        PAUSE_INSTRUCTION = 0x28,
        CPUID = 0xA,
        HLT_INSTRUCTION = 0xC,
        VMCALL_INSTRUCTION = 0x12,
        WBINVD_INSTRUCTION = 0x36,
        CR_ACCESS = 0x1C,
        IO_INSTRUCTION = 0x1E,
        MSR_READ = 0x1F,
        MSR_WRITE = 0x20,
        TPR_BELOW_THRESHOLD = 0x2B,
        EPT_VIOLATION = 0x30,
        XSETBV = 0x37,
        TDCALL = 0x4D,
    }
}

impl VmxExit {
    pub(crate) const fn from_bits(value: u64) -> Self {
        Self(value as u32)
    }

    pub(crate) const fn into_bits(self) -> u64 {
        self.0 as u64
    }
}

pub const VMX_ENTRY_CONTROL_LONG_MODE_GUEST: u32 = 0x00000200;
pub const VMX_FEATURE_CONTROL_LOCKED: u64 = 0x0000000000000001;

#[repr(u32)]
#[derive(Debug, PartialEq, Eq)]
pub enum FieldWidth {
    Width16 = 0,
    Width32 = 2,
    Width64 = 1,
    WidthNatural = 3, // 32 on X86, 64 on X64.
}

impl FieldWidth {
    const fn from_bits(value: u32) -> Self {
        match value {
            0 => FieldWidth::Width16,
            2 => FieldWidth::Width32,
            1 => FieldWidth::Width64,
            3 => FieldWidth::WidthNatural,
            _ => panic!("Invalid field width"),
        }
    }

    const fn into_bits(self) -> u32 {
        self as u32
    }
}

#[bitfield(u32)]
pub struct VmcsField {
    #[bits(1)]
    pub access_high: u32,
    #[bits(9)]
    pub index: u32,
    #[bits(2)]
    pub typ: u32,
    #[bits(1)]
    pub reserved: u32,
    #[bits(2)]
    pub field_width: FieldWidth,
    #[bits(17)]
    pub reserved2: u32,
}

impl VmcsField {
    pub const VMX_VMCS_ENTRY_CONTROLS: Self = Self(0x00004012);

    pub const VMX_VMCS_GUEST_CR0: Self = Self(0x00006800);
    pub const VMX_VMCS_GUEST_CR3: Self = Self(0x00006802);
    pub const VMX_VMCS_GUEST_CR4: Self = Self(0x00006804);
    pub const VMX_VMCS_GUEST_DR7: Self = Self(0x0000681A);

    pub const VMX_VMCS_GUEST_ES_SELECTOR: Self = Self(0x00000800);
    pub const VMX_VMCS_GUEST_ES_BASE: Self = Self(0x00006806);
    pub const VMX_VMCS_GUEST_ES_LIMIT: Self = Self(0x00004800);
    pub const VMX_VMCS_GUEST_ES_AR: Self = Self(0x00004814);

    pub const VMX_VMCS_GUEST_CS_SELECTOR: Self = Self(0x00000802);
    pub const VMX_VMCS_GUEST_CS_BASE: Self = Self(0x00006808);
    pub const VMX_VMCS_GUEST_CS_LIMIT: Self = Self(0x00004802);
    pub const VMX_VMCS_GUEST_CS_AR: Self = Self(0x00004816);

    pub const VMX_VMCS_GUEST_SS_SELECTOR: Self = Self(0x00000804);
    pub const VMX_VMCS_GUEST_SS_BASE: Self = Self(0x0000680A);
    pub const VMX_VMCS_GUEST_SS_LIMIT: Self = Self(0x00004804);
    pub const VMX_VMCS_GUEST_SS_AR: Self = Self(0x00004818);

    pub const VMX_VMCS_GUEST_DS_SELECTOR: Self = Self(0x00000806);
    pub const VMX_VMCS_GUEST_DS_BASE: Self = Self(0x0000680C);
    pub const VMX_VMCS_GUEST_DS_LIMIT: Self = Self(0x00004806);
    pub const VMX_VMCS_GUEST_DS_AR: Self = Self(0x0000481A);

    pub const VMX_VMCS_GUEST_FS_SELECTOR: Self = Self(0x00000808);
    pub const VMX_VMCS_GUEST_FS_BASE: Self = Self(0x0000680E);
    pub const VMX_VMCS_GUEST_FS_LIMIT: Self = Self(0x00004808);
    pub const VMX_VMCS_GUEST_FS_AR: Self = Self(0x0000481C);

    pub const VMX_VMCS_GUEST_GS_SELECTOR: Self = Self(0x0000080A);
    pub const VMX_VMCS_GUEST_GS_BASE: Self = Self(0x00006810);
    pub const VMX_VMCS_GUEST_GS_LIMIT: Self = Self(0x0000480A);
    pub const VMX_VMCS_GUEST_GS_AR: Self = Self(0x0000481E);

    pub const VMX_VMCS_GUEST_LDTR_SELECTOR: Self = Self(0x0000080C);
    pub const VMX_VMCS_GUEST_LDTR_BASE: Self = Self(0x00006812);
    pub const VMX_VMCS_GUEST_LDTR_LIMIT: Self = Self(0x0000480C);
    pub const VMX_VMCS_GUEST_LDTR_AR: Self = Self(0x00004820);

    pub const VMX_VMCS_GUEST_TR_SELECTOR: Self = Self(0x0000080E);
    pub const VMX_VMCS_GUEST_TR_BASE: Self = Self(0x00006814);
    pub const VMX_VMCS_GUEST_TR_LIMIT: Self = Self(0x0000480E);
    pub const VMX_VMCS_GUEST_TR_AR: Self = Self(0x00004822);

    pub const VMX_VMCS_GUEST_GDTR_BASE: Self = Self(0x00006816);
    pub const VMX_VMCS_GUEST_GDTR_LIMIT: Self = Self(0x00004810);

    pub const VMX_VMCS_GUEST_IDTR_BASE: Self = Self(0x00006818);
    pub const VMX_VMCS_GUEST_IDTR_LIMIT: Self = Self(0x00004812);

    pub const VMX_VMCS_GUEST_PAT: Self = Self(0x00002804);
    pub const VMX_VMCS_GUEST_EFER: Self = Self(0x00002806);

    pub const VMX_VMCS_EOI_EXIT_0: Self = Self(0x0000201C);
    pub const VMX_VMCS_EOI_EXIT_1: Self = Self(0x0000201E);
    pub const VMX_VMCS_EOI_EXIT_2: Self = Self(0x00002020);
    pub const VMX_VMCS_EOI_EXIT_3: Self = Self(0x00002022);

    pub const VMX_VMCS_PROCESSOR_CONTROLS: Self = Self(0x00004002);
    pub const VMX_VMCS_EXCEPTION_BITMAP: Self = Self(0x00004004);
    pub const VMX_VMCS_ENTRY_INTERRUPT_INFO: Self = Self(0x00004016);
    pub const VMX_VMCS_ENTRY_EXCEPTION_ERROR_CODE: Self = Self(0x00004018);
    pub const VMX_VMCS_ENTRY_INSTRUCTION_LENGTH: Self = Self(0x0000401A);
    pub const VMX_VMCS_TPR_THRESHOLD: Self = Self(0x0000401C);
    pub const VMX_VMCS_SECONDARY_PROCESSOR_CONTROLS: Self = Self(0x0000401E);

    pub const VMX_VMCS_CR0_GUEST_HOST_MASK: Self = Self(0x00006000);
    pub const VMX_VMCS_CR4_GUEST_HOST_MASK: Self = Self(0x00006002);
    pub const VMX_VMCS_CR0_READ_SHADOW: Self = Self(0x00006004);
    pub const VMX_VMCS_CR4_READ_SHADOW: Self = Self(0x00006006);

    pub const VMX_VMCS_GUEST_INTERRUPTIBILITY: Self = Self(0x00004824);

    pub const VMX_VMCS_GUEST_SYSENTER_CS_MSR: Self = Self(0x0000482A);
    pub const VMX_VMCS_GUEST_SYSENTER_ESP_MSR: Self = Self(0x00006824);
    pub const VMX_VMCS_GUEST_SYSENTER_EIP_MSR: Self = Self(0x00006826);
}

#[bitfield(u32)]
pub struct VmxSegmentAttributes {
    #[bits(4)]
    pub typ: u32,
    #[bits(1)]
    pub user: u32,
    #[bits(2)]
    pub dpl: u32,
    pub present: bool,
    #[bits(4)]
    pub reserved1: u32,
    pub available: bool,
    #[bits(1)]
    pub long_mode: u32,
    #[bits(1)]
    pub default_size: u32,
    #[bits(1)]
    pub granularity: u32,
    pub null: bool,
    #[bits(15)]
    pub reserved: u32,
}

pub const IO_SIZE_8_BIT: u8 = 0;
pub const IO_SIZE_16_BIT: u8 = 1;
pub const IO_SIZE_32_BIT: u8 = 3;

#[bitfield(u32)]
pub struct ExitQualificationIo {
    #[bits(2)]
    pub access_size: u8,
    #[bits(1)]
    pub reserved1: u8,
    pub is_in: bool,
    pub is_string: bool,
    pub rep_prefix: bool,
    pub immediate_operand: bool,
    #[bits(9)]
    pub reserved2: u32,
    pub port: u16,
}

#[bitfield(u64)]
pub struct VmxEptExitQualification {
    #[bits(3)]
    pub access_mask: u8,
    #[bits(4)]
    pub ept_access_mask: u8,
    pub gva_valid: bool,
    pub caused_by_gpa_access: bool,
    pub gva_user: bool,
    pub gva_read_write: bool,
    pub gva_no_execute: bool,
    pub nmi_unmasking_due_to_iret: bool,
    pub shadow_stack: bool,
    pub ept_supervisor_shadow_stack: bool,
    #[bits(49)]
    pub reserved: u64,
}

#[bitfield(u64)]
pub struct CrAccessQualification {
    #[bits(4)]
    pub cr: u8,
    #[bits(2)]
    pub access_type: u8,
    pub lmsw_is_memory: bool,
    #[bits(1)]
    _reserved1: u8,
    #[bits(4)]
    pub gp_register: u8,
    #[bits(4)]
    _reserved2: u8,
    pub lmsw_source_data: u16,
    _reserved3: u32,
}

pub const CR_ACCESS_TYPE_MOV_TO_CR: u8 = 0;
pub const CR_ACCESS_TYPE_MOV_FROM_CR: u8 = 1;
pub const CR_ACCESS_TYPE_CLTS: u8 = 2;
pub const CR_ACCESS_TYPE_LMSW: u8 = 3;

#[bitfield(u32)]
pub struct InterruptionInformation {
    #[bits(8)]
    pub vector: u8,
    #[bits(3)]
    pub interruption_type: u8,
    pub deliver_error_code: bool,
    #[bits(19)]
    pub reserved: u32,
    pub valid: bool,
}

pub const INTERRUPT_TYPE_EXTERNAL: u8 = 0;
pub const INTERRUPT_TYPE_NMI: u8 = 2;
pub const INTERRUPT_TYPE_HARDWARE_EXCEPTION: u8 = 3;
pub const INTERRUPT_TYPE_SOFTWARE_INTERRUPT: u8 = 4;
pub const INTERRUPT_TYPE_PRIVILEGED_SOFTWARE_INTERRUPT: u8 = 5;
pub const INTERRUPT_TYPE_SOFTWARE_EXCEPTION: u8 = 6;

#[bitfield(u32)]
pub struct Interruptibility {
    pub blocked_by_sti: bool,
    pub blocked_by_movss: bool,
    pub blocked_by_smi: bool,
    pub blocked_by_nmi: bool,
    #[bits(28)]
    _reserved: u32,
}

#[bitfield(u32)]
#[derive(PartialEq, Eq)]
pub struct ProcessorControls {
    #[bits(2)]
    _reserved: u32,
    pub interrupt_window_exiting: bool,
    pub use_tsc_offsetting: bool,
    #[bits(3)]
    _reserved2: u32,
    pub hlt_exiting: bool,
    _reserved3: bool,
    pub invlpg_exiting: bool,
    pub mwait_exiting: bool,
    pub rdpmc_exiting: bool,
    pub rdtsc_exiting: bool,
    #[bits(2)]
    _reserved4: u32,
    pub cr3_load_exiting: bool,
    pub cr3_store_exiting: bool,
    pub activate_tertiary_controls: bool,
    _reserved5: bool,
    pub cr8_load_exiting: bool,
    pub cr8_store_exiting: bool,
    pub use_tpr_shadow: bool,
    pub nmi_window_exiting: bool,
    pub mov_dr_exiting: bool,
    pub unconditional_io_exiting: bool,
    pub use_io_bitmaps: bool,
    _reserved6: bool,
    pub monitor_trap_flag: bool,
    pub use_msr_bitmaps: bool,
    pub monitor_exiting: bool,
    pub pause_exiting: bool,
    pub activate_secondary_controls: bool,
}

#[bitfield(u32)]
pub struct SecondaryProcessorControls {
    pub virtualize_apic_accesses: bool,
    pub enable_ept: bool,
    pub descriptor_table_exiting: bool,
    pub enable_rdtscp: bool,
    pub virtualize_x2apic_mode: bool,
    pub enable_vpid: bool,
    pub wbinvd_exiting: bool,
    pub unrestricted_guest: bool,
    pub apic_register_virtualization: bool,
    pub virtual_interrupt_delivery: bool,
    pub pause_loop_exiting: bool,
    pub rdrand_exiting: bool,
    pub enable_invpcid: bool,
    pub enable_vmfunc: bool,
    pub vmcs_shadowing: bool,
    pub enable_encls_exiting: bool,
    pub rdseed_exiting: bool,
    pub enable_pml: bool,
    pub ept_violation_ve: bool,
    pub conceal_vmx_from_pt: bool,
    pub enable_xsaves_xrstors: bool,
    pub pasid_translation: bool,
    pub mode_based_execute_control: bool,
    pub sub_page_write_permissions: bool,
    pub pt_uses_guest_physical_addresses: bool,
    pub use_tsc_scaling: bool,
    pub enable_user_wait_and_pause: bool,
    pub enable_pconfig: bool,
    pub enable_enclv_exiting: bool,
    _reserved: bool,
    pub vmm_bus_lock_detection: bool,
    pub instruction_timeout: bool,
}

#[repr(C)]
#[derive(Debug, Copy, Clone, AsBytes, FromBytes, FromZeroes)]
pub struct ApicRegister {
    pub value: u32,
    _reserved: [u32; 3],
}

#[repr(C)]
#[derive(Debug, Clone, AsBytes, FromBytes, FromZeroes)]
pub struct ApicPage {
    pub reserved_0: [ApicRegister; 2],
    pub id: ApicRegister,
    pub version: ApicRegister,
    pub reserved_4: [ApicRegister; 4],
    pub tpr: ApicRegister,
    pub apr: ApicRegister,
    pub ppr: ApicRegister,
    pub eoi: ApicRegister,
    pub rrd: ApicRegister,
    pub ldr: ApicRegister,
    pub dfr: ApicRegister,
    pub svr: ApicRegister,
    pub isr: [ApicRegister; 8],
    pub tmr: [ApicRegister; 8],
    pub irr: [ApicRegister; 8],
    pub esr: ApicRegister,
    pub reserved_29: [ApicRegister; 6],
    pub lvt_cmci: ApicRegister,
    pub icr: [ApicRegister; 2],
    pub lvt_timer: ApicRegister,
    pub lvt_thermal: ApicRegister,
    pub lvt_pmc: ApicRegister,
    pub lvt_lint0: ApicRegister,
    pub lvt_lint1: ApicRegister,
    pub lvt_error: ApicRegister,
    pub timer_icr: ApicRegister,
    pub timer_ccr: ApicRegister,
    pub reserved_3a: [ApicRegister; 4],
    pub timer_dcr: ApicRegister,
    pub reserved_3f: ApicRegister,
    pub reserved_40: [ApicRegister; 0xc0],
}