1 use bitflags::bitflags;
2 use num_derive::FromPrimitive;
3
4 pub const PAGE_SIZE: usize = 0x1000;
5
6 #[repr(C, align(4096))]
7 #[derive(Clone, Debug)]
8 pub struct VMCSRegion {
9 pub revision_id: u32,
10 pub abort_indicator: u32,
11 data: [u8; PAGE_SIZE - 8],
12 }
13
14 // (Intel Manual: 25.11.2 VMREAD, VMWRITE, and Encodings of VMCS Fields)
15 #[derive(FromPrimitive)]
16 enum VmcsAccessType {
17 FULL = 0,
18 HIGH = 1,
19 }
20
21 #[derive(FromPrimitive)]
22 enum VmcsType {
23 CONTROL = 0,
24 VMEXIT = 1,
25 GUEST = 2,
26 HOST = 3,
27 }
28
29 #[derive(FromPrimitive)]
30 enum VmcsWidth {
31 BIT16 = 0,
32 BIT64 = 1,
33 BIT32 = 2,
34 NATURAL = 3,
35 }
36
37 #[derive(FromPrimitive)]
38 #[allow(non_camel_case_types)]
39 // (Intel Manual: APPENDIX B FIELD ENCODING IN VMCS)
40 pub enum VmcsFields {
41 // [CONTROL] fields
42 // 16-bit control fields
43 CTRL_VIRT_PROC_ID = encode_vmcs_field_full(VmcsType::CONTROL, VmcsWidth::BIT16, 0) as isize,
44 CTRL_POSTED_INTR_N_VECTOR =
45 encode_vmcs_field_full(VmcsType::CONTROL, VmcsWidth::BIT16, 1) as isize,
46 CTRL_EPTP_INDEX = encode_vmcs_field_full(VmcsType::CONTROL, VmcsWidth::BIT16, 2) as isize,
47 // 64-bit control fields
48 CTRL_IO_BITMAP_A_ADDR = encode_vmcs_field_full(VmcsType::CONTROL, VmcsWidth::BIT64, 0) as isize,
49 CTRL_IO_BITMAP_B_ADDR = encode_vmcs_field_full(VmcsType::CONTROL, VmcsWidth::BIT64, 1) as isize,
50 CTRL_MSR_BITMAP_ADDR = encode_vmcs_field_full(VmcsType::CONTROL, VmcsWidth::BIT64, 2) as isize, // control whether RDMSR or WRMSR cause VM exit
51 CTRL_VMEXIT_MSR_STORE_ADDR =
52 encode_vmcs_field_full(VmcsType::CONTROL, VmcsWidth::BIT64, 3) as isize,
53 CTRL_VMEXIT_MSR_LOAD_ADDR =
54 encode_vmcs_field_full(VmcsType::CONTROL, VmcsWidth::BIT64, 4) as isize,
55 CTRL_VMENTRY_MSR_LOAD_ADDR =
56 encode_vmcs_field_full(VmcsType::CONTROL, VmcsWidth::BIT64, 5) as isize,
57 CTRL_EXECUTIVE_VMCS_PTR =
58 encode_vmcs_field_full(VmcsType::CONTROL, VmcsWidth::BIT64, 6) as isize,
59 CTRL_PML_ADDR = encode_vmcs_field_full(VmcsType::CONTROL, VmcsWidth::BIT64, 7) as isize,
60 CTRL_TSC_ADDR = encode_vmcs_field_full(VmcsType::CONTROL, VmcsWidth::BIT64, 8) as isize,
61 CTRL_VIRT_APIC_ADDR = encode_vmcs_field_full(VmcsType::CONTROL, VmcsWidth::BIT64, 9) as isize,
62 CTRL_APIC_ACCESS_ADDR =
63 encode_vmcs_field_full(VmcsType::CONTROL, VmcsWidth::BIT64, 10) as isize,
64 CTRL_POSTED_INTR_DESC_ADDR =
65 encode_vmcs_field_full(VmcsType::CONTROL, VmcsWidth::BIT64, 11) as isize,
66 CTRL_VMFUNC_CTRL = encode_vmcs_field_full(VmcsType::CONTROL, VmcsWidth::BIT64, 12) as isize,
67 CTRL_EPTP_PTR = encode_vmcs_field_full(VmcsType::CONTROL, VmcsWidth::BIT64, 13) as isize,
68 CTRL_EOI_EXIT_BITMAP_0 =
69 encode_vmcs_field_full(VmcsType::CONTROL, VmcsWidth::BIT64, 14) as isize,
70 CTRL_EOI_EXIT_BITMAP_1 =
71 encode_vmcs_field_full(VmcsType::CONTROL, VmcsWidth::BIT64, 15) as isize,
72 CTRL_EOI_EXIT_BITMAP_2 =
73 encode_vmcs_field_full(VmcsType::CONTROL, VmcsWidth::BIT64, 16) as isize,
74 CTRL_EOI_EXIT_BITMAP_3 =
75 encode_vmcs_field_full(VmcsType::CONTROL, VmcsWidth::BIT64, 17) as isize,
76 CTRL_EPT_LIST_ADDR = encode_vmcs_field_full(VmcsType::CONTROL, VmcsWidth::BIT64, 18) as isize,
77 CTRL_VMREAD_BITMAP_ADDR =
78 encode_vmcs_field_full(VmcsType::CONTROL, VmcsWidth::BIT64, 19) as isize,
79 CTRL_VMWRITE_BITMAP_ADDR =
80 encode_vmcs_field_full(VmcsType::CONTROL, VmcsWidth::BIT64, 20) as isize,
81 CTRL_VIRT_EXECPT_INFO_ADDR =
82 encode_vmcs_field_full(VmcsType::CONTROL, VmcsWidth::BIT64, 21) as isize,
83 CTRL_XSS_EXITING_BITMAP =
84 encode_vmcs_field_full(VmcsType::CONTROL, VmcsWidth::BIT64, 22) as isize,
85 CTRL_ENCLS_EXITING_BITMAP =
86 encode_vmcs_field_full(VmcsType::CONTROL, VmcsWidth::BIT64, 23) as isize,
87 CTRL_TSC_MULTIPLIER = encode_vmcs_field_full(VmcsType::CONTROL, VmcsWidth::BIT64, 25) as isize,
88 // 32-bit control fields
89 CTRL_PIN_BASED_VM_EXEC_CTRLS =
90 encode_vmcs_field_full(VmcsType::CONTROL, VmcsWidth::BIT32, 0) as isize, // control async event handling (i.e. interrupts)
91 CTRL_PRIMARY_PROCESSOR_VM_EXEC_CTRLS =
92 encode_vmcs_field_full(VmcsType::CONTROL, VmcsWidth::BIT32, 1) as isize, // control sync event handling (i.e. instruction exits)
93 CTRL_EXPECTION_BITMAP = encode_vmcs_field_full(VmcsType::CONTROL, VmcsWidth::BIT32, 2) as isize, // bitmap to control exceptions that cause a VM exit
94 CTRL_PAGE_FAULT_ERR_CODE_MASK =
95 encode_vmcs_field_full(VmcsType::CONTROL, VmcsWidth::BIT32, 3) as isize,
96 CTRL_PAGE_FAULT_ERR_CODE_MATCH =
97 encode_vmcs_field_full(VmcsType::CONTROL, VmcsWidth::BIT32, 4) as isize,
98 CTRL_CR3_TARGET_COUNT = encode_vmcs_field_full(VmcsType::CONTROL, VmcsWidth::BIT32, 5) as isize,
99 CTRL_PRIMARY_VM_EXIT_CTRLS =
100 encode_vmcs_field_full(VmcsType::CONTROL, VmcsWidth::BIT32, 6) as isize,
101 CTRL_VM_EXIT_MSR_STORE_COUNT =
102 encode_vmcs_field_full(VmcsType::CONTROL, VmcsWidth::BIT32, 7) as isize,
103 CTRL_VM_EXIT_MSR_LOAD_COUNT =
104 encode_vmcs_field_full(VmcsType::CONTROL, VmcsWidth::BIT32, 8) as isize,
105 CTRL_VM_ENTRY_CTRLS = encode_vmcs_field_full(VmcsType::CONTROL, VmcsWidth::BIT32, 9) as isize,
106 CTRL_VM_ENTRY_MSR_LOAD_COUNT =
107 encode_vmcs_field_full(VmcsType::CONTROL, VmcsWidth::BIT32, 10) as isize,
108 CTRL_VM_ENTRY_INTR_INFO_FIELD =
109 encode_vmcs_field_full(VmcsType::CONTROL, VmcsWidth::BIT32, 11) as isize,
110 CTRL_VM_ENTRY_EXCEPTION_ERR_CODE =
111 encode_vmcs_field_full(VmcsType::CONTROL, VmcsWidth::BIT32, 12) as isize,
112 CTRL_VM_ENTRY_INSTR_LEN =
113 encode_vmcs_field_full(VmcsType::CONTROL, VmcsWidth::BIT32, 13) as isize,
114 CTRL_TPR_THRESHOLD = encode_vmcs_field_full(VmcsType::CONTROL, VmcsWidth::BIT32, 14) as isize,
115 CTRL_SECONDARY_PROCESSOR_VM_EXEC_CTRLS =
116 encode_vmcs_field_full(VmcsType::CONTROL, VmcsWidth::BIT32, 15) as isize,
117 CTRL_PLE_GAP = encode_vmcs_field_full(VmcsType::CONTROL, VmcsWidth::BIT32, 16) as isize,
118 CTRL_PLE_WINDOW = encode_vmcs_field_full(VmcsType::CONTROL, VmcsWidth::BIT32, 17) as isize,
119 // natural control fields
120 CTRL_CR0_GUEST_HOST_MASK =
121 encode_vmcs_field_full(VmcsType::CONTROL, VmcsWidth::NATURAL, 0) as isize, // control executions of insts that access cr0
122 CTRL_CR4_GUEST_HOST_MASK =
123 encode_vmcs_field_full(VmcsType::CONTROL, VmcsWidth::NATURAL, 1) as isize,
124 CTRL_CR0_READ_SHADOW =
125 encode_vmcs_field_full(VmcsType::CONTROL, VmcsWidth::NATURAL, 2) as isize, // control executions of insts that access cr0
126 CTRL_CR4_READ_SHADOW =
127 encode_vmcs_field_full(VmcsType::CONTROL, VmcsWidth::NATURAL, 3) as isize,
128 CTRL_CR3_TARGET_VALUE_0 =
129 encode_vmcs_field_full(VmcsType::CONTROL, VmcsWidth::NATURAL, 4) as isize,
130 CTRL_CR3_TARGET_VALUE_1 =
131 encode_vmcs_field_full(VmcsType::CONTROL, VmcsWidth::NATURAL, 5) as isize,
132 CTRL_CR3_TARGET_VALUE_2 =
133 encode_vmcs_field_full(VmcsType::CONTROL, VmcsWidth::NATURAL, 6) as isize,
134 CTRL_CR3_TARGET_VALUE_3 =
135 encode_vmcs_field_full(VmcsType::CONTROL, VmcsWidth::NATURAL, 7) as isize,
136
137 // [VMEXIT] fields read-only
138 // No 16-bit vmexit fields
139 // 64-bit vmexit fields
140 VMEXIT_GUEST_PHY_ADDR = encode_vmcs_field_full(VmcsType::VMEXIT, VmcsWidth::BIT64, 0) as isize,
141 // 32-bit vmexit fields
142 VMEXIT_INSTR_ERR = encode_vmcs_field_full(VmcsType::VMEXIT, VmcsWidth::BIT32, 0) as isize,
143 VMEXIT_EXIT_REASON = encode_vmcs_field_full(VmcsType::VMEXIT, VmcsWidth::BIT32, 1) as isize,
144 VMEXIT_INT_INFO = encode_vmcs_field_full(VmcsType::VMEXIT, VmcsWidth::BIT32, 2) as isize,
145 VMEXIT_INT_ERR_CODE = encode_vmcs_field_full(VmcsType::VMEXIT, VmcsWidth::BIT32, 3) as isize,
146 VMEXIT_IDT_VECTOR_INFO = encode_vmcs_field_full(VmcsType::VMEXIT, VmcsWidth::BIT32, 4) as isize,
147 VMEXIT_IDT_VECTOR_ERR_CODE =
148 encode_vmcs_field_full(VmcsType::VMEXIT, VmcsWidth::BIT32, 5) as isize,
149 VMEXIT_INSTR_LEN = encode_vmcs_field_full(VmcsType::VMEXIT, VmcsWidth::BIT32, 6) as isize,
150 VMEXIT_INSTR_INFO = encode_vmcs_field_full(VmcsType::VMEXIT, VmcsWidth::BIT32, 7) as isize,
151 // natural vmexit fields
152 VMEXIT_QUALIFICATION = encode_vmcs_field_full(VmcsType::VMEXIT, VmcsWidth::NATURAL, 0) as isize,
153 VMEXIT_IO_RCX = encode_vmcs_field_full(VmcsType::VMEXIT, VmcsWidth::NATURAL, 1) as isize,
154 VMEXIT_IO_RSX = encode_vmcs_field_full(VmcsType::VMEXIT, VmcsWidth::NATURAL, 2) as isize,
155 VMEXIT_IO_RDI = encode_vmcs_field_full(VmcsType::VMEXIT, VmcsWidth::NATURAL, 3) as isize,
156 VMEXIT_IO_RIP = encode_vmcs_field_full(VmcsType::VMEXIT, VmcsWidth::NATURAL, 4) as isize,
157 VMEXIT_GUEST_LINEAR_ADDR =
158 encode_vmcs_field_full(VmcsType::VMEXIT, VmcsWidth::NATURAL, 5) as isize,
159
160 // [GUEST] fields
161 // 16-bit guest fields
162 GUEST_ES_SELECTOR = encode_vmcs_field_full(VmcsType::GUEST, VmcsWidth::BIT16, 0) as isize,
163 GUEST_CS_SELECTOR = encode_vmcs_field_full(VmcsType::GUEST, VmcsWidth::BIT16, 1) as isize,
164 GUEST_SS_SELECTOR = encode_vmcs_field_full(VmcsType::GUEST, VmcsWidth::BIT16, 2) as isize,
165 GUEST_DS_SELECTOR = encode_vmcs_field_full(VmcsType::GUEST, VmcsWidth::BIT16, 3) as isize,
166 GUEST_FS_SELECTOR = encode_vmcs_field_full(VmcsType::GUEST, VmcsWidth::BIT16, 4) as isize,
167 GUEST_GS_SELECTOR = encode_vmcs_field_full(VmcsType::GUEST, VmcsWidth::BIT16, 5) as isize,
168 GUEST_LDTR_SELECTOR = encode_vmcs_field_full(VmcsType::GUEST, VmcsWidth::BIT16, 6) as isize,
169 GUEST_TR_SELECTOR = encode_vmcs_field_full(VmcsType::GUEST, VmcsWidth::BIT16, 7) as isize,
170 GUEST_INTR_STATUS = encode_vmcs_field_full(VmcsType::GUEST, VmcsWidth::BIT16, 8) as isize,
171 GUEST_PML_INDEX = encode_vmcs_field_full(VmcsType::GUEST, VmcsWidth::BIT16, 9) as isize,
172 // 64-bit guest fields
173 GUEST_VMCS_LINK_PTR = encode_vmcs_field_full(VmcsType::GUEST, VmcsWidth::BIT64, 0) as isize,
174 GUEST_DEBUGCTL = encode_vmcs_field_full(VmcsType::GUEST, VmcsWidth::BIT64, 1) as isize,
175 GUEST_PAT = encode_vmcs_field_full(VmcsType::GUEST, VmcsWidth::BIT64, 2) as isize,
176 GUEST_EFER = encode_vmcs_field_full(VmcsType::GUEST, VmcsWidth::BIT64, 3) as isize,
177 GUEST_PERF_GLOBAL_CTRL = encode_vmcs_field_full(VmcsType::GUEST, VmcsWidth::BIT64, 4) as isize,
178 GUEST_PDPTE0 = encode_vmcs_field_full(VmcsType::GUEST, VmcsWidth::BIT64, 5) as isize,
179 GUEST_PDPTE1 = encode_vmcs_field_full(VmcsType::GUEST, VmcsWidth::BIT64, 6) as isize,
180 GUEST_PDPTE2 = encode_vmcs_field_full(VmcsType::GUEST, VmcsWidth::BIT64, 7) as isize,
181 GUEST_PDPTE3 = encode_vmcs_field_full(VmcsType::GUEST, VmcsWidth::BIT64, 8) as isize,
182 // 32-bit guest fields
183 GUEST_ES_LIMIT = encode_vmcs_field_full(VmcsType::GUEST, VmcsWidth::BIT32, 0) as isize,
184 GUEST_CS_LIMIT = encode_vmcs_field_full(VmcsType::GUEST, VmcsWidth::BIT32, 1) as isize,
185 GUEST_SS_LIMIT = encode_vmcs_field_full(VmcsType::GUEST, VmcsWidth::BIT32, 2) as isize,
186 GUEST_DS_LIMIT = encode_vmcs_field_full(VmcsType::GUEST, VmcsWidth::BIT32, 3) as isize,
187 GUEST_FS_LIMIT = encode_vmcs_field_full(VmcsType::GUEST, VmcsWidth::BIT32, 4) as isize,
188 GUEST_GS_LIMIT = encode_vmcs_field_full(VmcsType::GUEST, VmcsWidth::BIT32, 5) as isize,
189 GUEST_LDTR_LIMIT = encode_vmcs_field_full(VmcsType::GUEST, VmcsWidth::BIT32, 6) as isize,
190 GUEST_TR_LIMIT = encode_vmcs_field_full(VmcsType::GUEST, VmcsWidth::BIT32, 7) as isize,
191 GUEST_GDTR_LIMIT = encode_vmcs_field_full(VmcsType::GUEST, VmcsWidth::BIT32, 8) as isize,
192 GUEST_IDTR_LIMIT = encode_vmcs_field_full(VmcsType::GUEST, VmcsWidth::BIT32, 9) as isize,
193 GUEST_ES_ACCESS_RIGHTS = encode_vmcs_field_full(VmcsType::GUEST, VmcsWidth::BIT32, 10) as isize,
194 GUEST_CS_ACCESS_RIGHTS = encode_vmcs_field_full(VmcsType::GUEST, VmcsWidth::BIT32, 11) as isize,
195 GUEST_SS_ACCESS_RIGHTS = encode_vmcs_field_full(VmcsType::GUEST, VmcsWidth::BIT32, 12) as isize,
196 GUEST_DS_ACCESS_RIGHTS = encode_vmcs_field_full(VmcsType::GUEST, VmcsWidth::BIT32, 13) as isize,
197 GUEST_FS_ACCESS_RIGHTS = encode_vmcs_field_full(VmcsType::GUEST, VmcsWidth::BIT32, 14) as isize,
198 GUEST_GS_ACCESS_RIGHTS = encode_vmcs_field_full(VmcsType::GUEST, VmcsWidth::BIT32, 15) as isize,
199 GUEST_LDTR_ACCESS_RIGHTS =
200 encode_vmcs_field_full(VmcsType::GUEST, VmcsWidth::BIT32, 16) as isize,
201 GUEST_TR_ACCESS_RIGHTS = encode_vmcs_field_full(VmcsType::GUEST, VmcsWidth::BIT32, 17) as isize,
202 GUEST_INTERRUPTIBILITY_STATE =
203 encode_vmcs_field_full(VmcsType::GUEST, VmcsWidth::BIT32, 18) as isize,
204 GUEST_ACTIVITY_STATE = encode_vmcs_field_full(VmcsType::GUEST, VmcsWidth::BIT32, 19) as isize,
205 GUEST_SMBASE = encode_vmcs_field_full(VmcsType::GUEST, VmcsWidth::BIT32, 20) as isize,
206 GUEST_SYSENTER_CS = encode_vmcs_field_full(VmcsType::GUEST, VmcsWidth::BIT32, 21) as isize,
207 GUEST_VMX_PREEMPT_TIMER_VALUE = 0x482E as isize,
208 // natural guest fields
209 GUEST_CR0 = encode_vmcs_field_full(VmcsType::GUEST, VmcsWidth::NATURAL, 0) as isize,
210 GUEST_CR3 = encode_vmcs_field_full(VmcsType::GUEST, VmcsWidth::NATURAL, 1) as isize,
211 GUEST_CR4 = encode_vmcs_field_full(VmcsType::GUEST, VmcsWidth::NATURAL, 2) as isize,
212 GUEST_ES_BASE = encode_vmcs_field_full(VmcsType::GUEST, VmcsWidth::NATURAL, 3) as isize,
213 GUEST_CS_BASE = encode_vmcs_field_full(VmcsType::GUEST, VmcsWidth::NATURAL, 4) as isize,
214 GUEST_SS_BASE = encode_vmcs_field_full(VmcsType::GUEST, VmcsWidth::NATURAL, 5) as isize,
215 GUEST_DS_BASE = encode_vmcs_field_full(VmcsType::GUEST, VmcsWidth::NATURAL, 6) as isize,
216 GUEST_FS_BASE = encode_vmcs_field_full(VmcsType::GUEST, VmcsWidth::NATURAL, 7) as isize,
217 GUEST_GS_BASE = encode_vmcs_field_full(VmcsType::GUEST, VmcsWidth::NATURAL, 8) as isize,
218 GUEST_LDTR_BASE = encode_vmcs_field_full(VmcsType::GUEST, VmcsWidth::NATURAL, 9) as isize,
219 GUEST_TR_BASE = encode_vmcs_field_full(VmcsType::GUEST, VmcsWidth::NATURAL, 10) as isize,
220 GUEST_GDTR_BASE = encode_vmcs_field_full(VmcsType::GUEST, VmcsWidth::NATURAL, 11) as isize,
221 GUEST_IDTR_BASE = encode_vmcs_field_full(VmcsType::GUEST, VmcsWidth::NATURAL, 12) as isize,
222 GUEST_DR7 = encode_vmcs_field_full(VmcsType::GUEST, VmcsWidth::NATURAL, 13) as isize,
223 GUEST_RSP = encode_vmcs_field_full(VmcsType::GUEST, VmcsWidth::NATURAL, 14) as isize,
224 GUEST_RIP = encode_vmcs_field_full(VmcsType::GUEST, VmcsWidth::NATURAL, 15) as isize,
225 GUEST_RFLAGS = encode_vmcs_field_full(VmcsType::GUEST, VmcsWidth::NATURAL, 16) as isize,
226 GUEST_PENDING_DBG_EXCEPTIONS =
227 encode_vmcs_field_full(VmcsType::GUEST, VmcsWidth::NATURAL, 17) as isize,
228 GUEST_SYSENTER_ESP = encode_vmcs_field_full(VmcsType::GUEST, VmcsWidth::NATURAL, 18) as isize,
229 GUEST_SYSENTER_EIP = encode_vmcs_field_full(VmcsType::GUEST, VmcsWidth::NATURAL, 19) as isize,
230
231 // [HOST] fields
232 // host 16 bit fields
233 HOST_ES_SELECTOR = encode_vmcs_field_full(VmcsType::HOST, VmcsWidth::BIT16, 0) as isize,
234 HOST_CS_SELECTOR = encode_vmcs_field_full(VmcsType::HOST, VmcsWidth::BIT16, 1) as isize,
235 HOST_SS_SELECTOR = encode_vmcs_field_full(VmcsType::HOST, VmcsWidth::BIT16, 2) as isize,
236 HOST_DS_SELECTOR = encode_vmcs_field_full(VmcsType::HOST, VmcsWidth::BIT16, 3) as isize,
237 HOST_FS_SELECTOR = encode_vmcs_field_full(VmcsType::HOST, VmcsWidth::BIT16, 4) as isize,
238 HOST_GS_SELECTOR = encode_vmcs_field_full(VmcsType::HOST, VmcsWidth::BIT16, 5) as isize,
239 HOST_TR_SELECTOR = encode_vmcs_field_full(VmcsType::HOST, VmcsWidth::BIT16, 6) as isize,
240 // host 64 bit fields
241 HOST_PAT = encode_vmcs_field_full(VmcsType::HOST, VmcsWidth::BIT64, 0) as isize,
242 HOST_EFER = encode_vmcs_field_full(VmcsType::HOST, VmcsWidth::BIT64, 1) as isize,
243 HOST_PERF_GLOBAL_CTRL = encode_vmcs_field_full(VmcsType::HOST, VmcsWidth::BIT64, 2) as isize,
244 // host 32 bit fields
245 HOST_SYSENTER_CS = encode_vmcs_field_full(VmcsType::HOST, VmcsWidth::BIT32, 0) as isize,
246 // host natural fields
247 HOST_CR0 = encode_vmcs_field_full(VmcsType::HOST, VmcsWidth::NATURAL, 0) as isize,
248 HOST_CR3 = encode_vmcs_field_full(VmcsType::HOST, VmcsWidth::NATURAL, 1) as isize,
249 HOST_CR4 = encode_vmcs_field_full(VmcsType::HOST, VmcsWidth::NATURAL, 2) as isize,
250 HOST_FS_BASE = encode_vmcs_field_full(VmcsType::HOST, VmcsWidth::NATURAL, 3) as isize,
251 HOST_GS_BASE = encode_vmcs_field_full(VmcsType::HOST, VmcsWidth::NATURAL, 4) as isize,
252 HOST_TR_BASE = encode_vmcs_field_full(VmcsType::HOST, VmcsWidth::NATURAL, 5) as isize,
253 HOST_GDTR_BASE = encode_vmcs_field_full(VmcsType::HOST, VmcsWidth::NATURAL, 6) as isize,
254 HOST_IDTR_BASE = encode_vmcs_field_full(VmcsType::HOST, VmcsWidth::NATURAL, 7) as isize,
255 HOST_SYSENTER_ESP = encode_vmcs_field_full(VmcsType::HOST, VmcsWidth::NATURAL, 8) as isize,
256 HOST_SYSENTER_EIP = encode_vmcs_field_full(VmcsType::HOST, VmcsWidth::NATURAL, 9) as isize,
257 HOST_RSP = encode_vmcs_field_full(VmcsType::HOST, VmcsWidth::NATURAL, 10) as isize,
258 HOST_RIP = encode_vmcs_field_full(VmcsType::HOST, VmcsWidth::NATURAL, 11) as isize,
259 }
260
261 // (Intel Manual: 25.6 VM-EXECUTION CONTROL FIELDS)
262 bitflags! {
263 // (Intel Manual: 25.6.1 Pin-Based VM-Execution Controls)
264 #[allow(non_camel_case_types)]
265 pub struct VmxPinBasedExecuteCtrl: u32 {
266 const EXTERNAL_INTERRUPT_EXITING = 1 << 0; // external interrupts cause VM exits
267 const NMI_EXITING = 1 << 3; // non-maskable interrupts (NMIs) cause VM exits.
268 const VIRTUAL_NMIS = 1 << 5; // NMIs are never blocked and the “blocking by NMI” bit (bit 3) in the interruptibility-state field indicates “virtual-NMI blocking”
269 const VMX_PREEMPTION_TIMER = 1 << 6; // the VMX-preemption timer counts down in VMX non-root operation
270 const PROCESS_POSTED_INTERRUPTS = 1 << 7; // he processor treats interrupts with the posted-interrupt notification vector
271 }
272
273 // (Intel Manual: 25.6.2 Processor-Based VM-Execution Controls)
274 #[allow(non_camel_case_types)]
275 pub struct VmxPrimaryProcessBasedExecuteCtrl: u32{
276 const INTERRUPT_WINDOW_EXITING = 1 << 2; // VM exits on interrupt window RFLAGS.IF = 1
277 const USE_TSC_OFFSETTING = 1 << 3; // TSC offsetting is enabled
278 const HLT_EXITING = 1 << 7;
279 const INVLPG_EXITING = 1 << 9;
280 const MWAIT_EXITING = 1 << 10;
281 const RDPMC_EXITING = 1 << 11;
282 const RDTSC_EXITING = 1 << 12;
283 const CR3_LOAD_EXITING = 1 << 15;
284 const CR3_STR_EXITING = 1 << 16;
285 const CR8_LOAD_EXITING = 1 << 19;
286 const CR8_STR_EXITING = 1 << 20;
287 const USE_TPR_SHADOW = 1 << 21;
288 const NMI_WINDOW_EXITING = 1 << 22;
289 const MOV_DR_EXITING = 1 << 23;
290 const UNCOND_IO_EXITING = 1 << 24;
291 const USE_IO_BITMAPS = 1 << 25;
292 const MONITOR_TRAP_FLAG = 1 << 27;
293 const USE_MSR_BITMAPS = 1 << 28;
294 const MONITOR_EXITING = 1 << 29;
295 const PAUSE_EXITING = 1 << 30;
296 const ACTIVATE_SECONDARY_CONTROLS = 1 << 31;
297 }
298
299 // (Intel Manual: 25.6.2 Processor-Based VM-Execution Controls)
300 pub struct VmxSecondaryProcessBasedExecuteCtrl: u32{
301 const VIRT_APIC_ACCESS = 1 << 0;
302 const ENABLE_EPT = 1 << 1;
303 const DESCRIPTOR_TABLE_EXITING = 1 << 2;
304 const ENABLE_RDTSCP = 1 << 3;
305 const VIRT_X2APIC_MODE = 1 << 4;
306 const ENABLE_VPID = 1 << 5;
307 const WBINVD_EXITING = 1 << 6;
308 const UNRESTRICTED_GUEST = 1 << 7;
309 const APCI_REGISTER_VIRT = 1 << 8;
310 const VIRT_INTR_DELIVERY = 1 << 9;
311 const PAUSE_LOOP_EXITING = 1 << 10;
312 const RDRAND_EXITING = 1 << 11;
313 const ENABLE_INVPCID = 1 << 12;
314 const ENABLE_VM_FUNCTIONS = 1 << 13;
315 const VMCS_SHADOWING = 1 << 14;
316 const ENABLE_ENCLS_EXITING = 1 << 15;
317 const RDSEED_EXITING = 1 << 16;
318 const ENABLE_PML = 1 << 17;
319 const EPT_VIOLATION_VE = 1 << 18;
320 const CONCEAL_VMX_FROM_PT = 1 << 19;
321 const ENABLE_XSAVES_XRSTORS = 1 << 20;
322 const PASID_TRANSLATION = 1 << 21;
323 const MODE_BASED_EPT_EXEC = 1 << 22;
324 const SUB_PAGE_WRITE_PERM = 1 << 23;
325 const PT_USE_GUEST_PYH_ADDR = 1 << 24;
326 const USE_TSC_SCALING = 1 << 25;
327 const ENABLE_USER_WAIT_PAUSE = 1 << 26;
328 const ENABLE_PCONFIG = 1 << 27;
329 const ENABLE_ENCLV_EXITING = 1 << 28;
330 const VMM_BUS_LOCK_DETECTION = 1 << 30;
331 const INST_TIMEOUT = 1 << 31;
332 }
333
334 // (Intel Manual: 25.7.1 VM-Exit Controls)
335 #[allow(non_camel_case_types)]
336 pub struct VmxPrimaryExitCtrl: u32 {
337 const SAVE_DBG_CTRLS = 1 << 2;
338 const HOST_ADDR_SPACE_SIZE = 1 << 9; // determines if a virtual processor will be in 64-bit mode after a VM exit
339 const LOAD_IA32_PERF_GLOBAL_CTRL = 1 << 12;
340 const ACK_INTERRUPT_ON_EXIT = 1 << 15;
341 const SAVE_IA32_PAT = 1 << 18;
342 const LOAD_IA32_PAT = 1 << 19;
343 const SAVE_IA32_EFER = 1 << 20;
344 const LOAD_IA32_EFER = 1 << 21;
345 const SAVE_VMX_PREEMPT_TIMER_VALUE = 1 << 22;
346 const CLEAR_IA32_BNDCFGS = 1 << 23;
347 const CONCEAL_VMX_FROM_PT = 1 << 24;
348 const CLEAR_IA32_RTIT_CTL = 1 << 25;
349 const CLEAR_IA32_LBR_CTL = 1 << 26;
350 const CLEAR_UINV = 1 << 27;
351 const LOAD_CET_STATE = 1 << 28;
352 const LOAD_PKRS = 1 << 29;
353 const SAVE_IA32_PERF_GLOBAL_CTL = 1 << 30;
354 const ACTIVATE_SECONDARY_CONTROLS = 1 << 31;
355 }
356
357 // (Intel Manual: 25.8.1 VM-Entry Controls)
358 #[allow(non_camel_case_types)]
359 pub struct VmxEntryCtrl: u32 {
360 const LOAD_DBG_CTRLS = 1 << 2;
361 const IA32E_MODE_GUEST = 1 << 9;
362 const ENTRY_TO_SMM = 1 << 10;
363 const DEACTIVATE_DUAL_MONITOR = 1 << 11;
364 const LOAD_IA32_PERF_GLOBAL_CTRL = 1 << 13;
365 const LOAD_IA32_PAT = 1 << 14;
366 const LOAD_IA32_EFER = 1 << 15;
367 const LOAD_IA32_BNDCFGS = 1 << 16;
368 const CONCEAL_VMX_FROM_PT = 1 << 17;
369 const LOAD_IA32_RTIT_CTL = 1 << 18;
370 const LOAD_UINV = 1 << 19;
371 const LOAD_CET_STATE = 1 << 20;
372 const LOAD_PKRS = 1 << 21;
373 const LOAD_IA32_PERF_GLOBAL_CTL = 1 << 22;
374 }
375
376 }
377
378 #[derive(FromPrimitive)]
379 #[allow(non_camel_case_types)]
380 pub enum VmxExitReason {
381 EXCEPTION_OR_NMI = 0,
382 EXTERNAL_INTERRUPT = 1,
383 TRIPLE_FAULT = 2,
384 INIT_SIGNAL = 3,
385 SIPI = 4,
386 IO_SMI = 5,
387 OTHER_SMI = 6,
388 INTERRUPT_WINDOW = 7,
389 NMI_WINDOW = 8,
390 TASK_SWITCH = 9,
391 CPUID = 10,
392 GETSEC = 11,
393 HLT = 12,
394 INVD = 13,
395 INVLPG = 14,
396 RDPMC = 15,
397 RDTSC = 16,
398 RSM = 17,
399 VMCALL = 18,
400 VMCLEAR = 19,
401 VMLAUNCH = 20,
402 VMPTRLD = 21,
403 VMPTRST = 22,
404 VMREAD = 23,
405 VMRESUME = 24,
406 VMWRITE = 25,
407 VMXOFF = 26,
408 VMXON = 27,
409 CR_ACCESS = 28,
410 DR_ACCESS = 29,
411 IO_INSTRUCTION = 30,
412 RDMSR = 31,
413 WRMSR = 32,
414 VM_ENTRY_FAILURE_INVALID_GUEST_STATE = 33,
415 VM_ENTRY_FAILURE_MSR_LOADING = 34,
416 MWAIT = 36,
417 MONITOR_TRAP_FLAG = 37,
418 MONITOR = 39,
419 PAUSE = 40,
420 VM_ENTRY_FAILURE_MACHINE_CHECK_EVENT = 41,
421 TPR_BELOW_THRESHOLD = 43,
422 APIC_ACCESS = 44,
423 VIRTUALIZED_EOI = 45,
424 ACCESS_GDTR_OR_IDTR = 46,
425 ACCESS_LDTR_OR_TR = 47,
426 EPT_VIOLATION = 48,
427 EPT_MISCONFIG = 49,
428 INVEPT = 50,
429 RDTSCP = 51,
430 VMX_PREEMPTION_TIMER_EXPIRED = 52,
431 INVVPID = 53,
432 WBINVD = 54,
433 XSETBV = 55,
434 APIC_WRITE = 56,
435 RDRAND = 57,
436 INVPCID = 58,
437 VMFUNC = 59,
438 ENCLS = 60,
439 RDSEED = 61,
440 PML_FULL = 62,
441 XSAVES = 63,
442 XRSTORS = 64,
443 }
444
445 impl From<i32> for VmxExitReason {
from(num: i32) -> Self446 fn from(num: i32) -> Self {
447 match num {
448 0 => VmxExitReason::EXCEPTION_OR_NMI,
449 1 => VmxExitReason::EXTERNAL_INTERRUPT,
450 2 => VmxExitReason::TRIPLE_FAULT,
451 3 => VmxExitReason::INIT_SIGNAL,
452 4 => VmxExitReason::SIPI,
453 5 => VmxExitReason::IO_SMI,
454 6 => VmxExitReason::OTHER_SMI,
455 7 => VmxExitReason::INTERRUPT_WINDOW,
456 8 => VmxExitReason::NMI_WINDOW,
457 9 => VmxExitReason::TASK_SWITCH,
458 10 => VmxExitReason::CPUID,
459 11 => VmxExitReason::GETSEC,
460 12 => VmxExitReason::HLT,
461 13 => VmxExitReason::INVD,
462 14 => VmxExitReason::INVLPG,
463 15 => VmxExitReason::RDPMC,
464 16 => VmxExitReason::RDTSC,
465 17 => VmxExitReason::RSM,
466 18 => VmxExitReason::VMCALL,
467 19 => VmxExitReason::VMCLEAR,
468 20 => VmxExitReason::VMLAUNCH,
469 21 => VmxExitReason::VMPTRLD,
470 22 => VmxExitReason::VMPTRST,
471 23 => VmxExitReason::VMREAD,
472 24 => VmxExitReason::VMRESUME,
473 25 => VmxExitReason::VMWRITE,
474 26 => VmxExitReason::VMXOFF,
475 27 => VmxExitReason::VMXON,
476 28 => VmxExitReason::CR_ACCESS,
477 29 => VmxExitReason::DR_ACCESS,
478 30 => VmxExitReason::IO_INSTRUCTION,
479 31 => VmxExitReason::RDMSR,
480 32 => VmxExitReason::WRMSR,
481 33 => VmxExitReason::VM_ENTRY_FAILURE_INVALID_GUEST_STATE,
482 34 => VmxExitReason::VM_ENTRY_FAILURE_MSR_LOADING,
483 36 => VmxExitReason::MWAIT,
484 37 => VmxExitReason::MONITOR_TRAP_FLAG,
485 39 => VmxExitReason::MONITOR,
486 40 => VmxExitReason::PAUSE,
487 41 => VmxExitReason::VM_ENTRY_FAILURE_MACHINE_CHECK_EVENT,
488 43 => VmxExitReason::TPR_BELOW_THRESHOLD,
489 44 => VmxExitReason::APIC_ACCESS,
490 45 => VmxExitReason::VIRTUALIZED_EOI,
491 46 => VmxExitReason::ACCESS_GDTR_OR_IDTR,
492 47 => VmxExitReason::ACCESS_LDTR_OR_TR,
493 48 => VmxExitReason::EPT_VIOLATION,
494 49 => VmxExitReason::EPT_MISCONFIG,
495 50 => VmxExitReason::INVEPT,
496 51 => VmxExitReason::RDTSCP,
497 52 => VmxExitReason::VMX_PREEMPTION_TIMER_EXPIRED,
498 53 => VmxExitReason::INVVPID,
499 54 => VmxExitReason::WBINVD,
500 55 => VmxExitReason::XSETBV,
501 56 => VmxExitReason::APIC_WRITE,
502 57 => VmxExitReason::RDRAND,
503 58 => VmxExitReason::INVPCID,
504 59 => VmxExitReason::VMFUNC,
505 60 => VmxExitReason::ENCLS,
506 61 => VmxExitReason::RDSEED,
507 62 => VmxExitReason::PML_FULL,
508 63 => VmxExitReason::XSAVES,
509 64 => VmxExitReason::XRSTORS,
510 _ => panic!("Invalid VmxExitReason number: {}", num),
511 }
512 }
513 }
514
encode_vmcs_field( access_type: VmcsAccessType, vmcs_type: VmcsType, vmcs_width: VmcsWidth, index: u32, ) -> u32515 const fn encode_vmcs_field(
516 access_type: VmcsAccessType,
517 vmcs_type: VmcsType,
518 vmcs_width: VmcsWidth,
519 index: u32,
520 ) -> u32 {
521 let mut encoding: u32 = 0;
522 encoding |= (access_type as u32)
523 | (index as u32) << 1
524 | (vmcs_type as u32) << 10
525 | (vmcs_width as u32) << 13;
526 return encoding;
527 }
528
encode_vmcs_field_full(vmcs_type: VmcsType, vmcs_width: VmcsWidth, index: u32) -> u32529 const fn encode_vmcs_field_full(vmcs_type: VmcsType, vmcs_width: VmcsWidth, index: u32) -> u32 {
530 encode_vmcs_field(VmcsAccessType::FULL, vmcs_type, vmcs_width, index)
531 }
532
533 // fn decode_vmcs_field(field: u32) -> (VmcsAccessType, VmcsType, VmcsWidth, u16){
534 // (FromPrimitive::from_u32(field & 1).unwrap() ,
535 // FromPrimitive::from_u32((field>>10) & 0x3).unwrap(),
536 // FromPrimitive::from_u32((field>>13) & 0x3).unwrap(),
537 // ((field>>1) & 0x1ff) as u16
538 // )
539 // }
540