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