xref: /DragonOS/kernel/src/arch/x86_64/kvm/vmx/vmcs.rs (revision 86ee1395de7c614865236ee15071c3603b794e44)
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_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 {
446     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 
515 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 |=
523         (access_type as u32) | (index) << 1 | (vmcs_type as u32) << 10 | (vmcs_width as u32) << 13;
524     return encoding;
525 }
526 
527 const fn encode_vmcs_field_full(vmcs_type: VmcsType, vmcs_width: VmcsWidth, index: u32) -> u32 {
528     encode_vmcs_field(VmcsAccessType::FULL, vmcs_type, vmcs_width, index)
529 }
530 
531 // fn decode_vmcs_field(field: u32) -> (VmcsAccessType, VmcsType, VmcsWidth, u16){
532 //     (FromPrimitive::from_u32(field & 1).unwrap() ,
533 //         FromPrimitive::from_u32((field>>10) & 0x3).unwrap(),
534 //         FromPrimitive::from_u32((field>>13) & 0x3).unwrap(),
535 //         ((field>>1) & 0x1ff) as u16
536 //     )
537 // }
538