1 #ifndef __VMX_H 2 #define __VMX_H 3 4 #include "libcflat.h" 5 #include "processor.h" 6 7 struct vmcs { 8 u32 revision_id; /* vmcs revision identifier */ 9 u32 abort; /* VMX-abort indicator */ 10 /* VMCS data */ 11 char data[0]; 12 }; 13 14 struct regs { 15 u64 rax; 16 u64 rcx; 17 u64 rdx; 18 u64 rbx; 19 u64 cr2; 20 u64 rbp; 21 u64 rsi; 22 u64 rdi; 23 u64 r8; 24 u64 r9; 25 u64 r10; 26 u64 r11; 27 u64 r12; 28 u64 r13; 29 u64 r14; 30 u64 r15; 31 u64 rflags; 32 }; 33 34 struct vmx_test { 35 const char *name; 36 int (*init)(struct vmcs *vmcs); 37 void (*guest_main)(); 38 int (*exit_handler)(); 39 void (*syscall_handler)(u64 syscall_no); 40 struct regs guest_regs; 41 struct vmcs *vmcs; 42 int exits; 43 }; 44 45 union vmx_basic { 46 u64 val; 47 struct { 48 u32 revision; 49 u32 size:13, 50 reserved1: 3, 51 width:1, 52 dual:1, 53 type:4, 54 insouts:1, 55 ctrl:1, 56 reserved2:8; 57 }; 58 }; 59 60 union vmx_ctrl_msr { 61 u64 val; 62 struct { 63 u32 set, clr; 64 }; 65 }; 66 67 union vmx_ept_vpid { 68 u64 val; 69 struct { 70 u32:16, 71 super:2, 72 : 2, 73 invept:1, 74 : 11; 75 u32 invvpid:1; 76 }; 77 }; 78 79 enum Encoding { 80 /* 16-Bit Control Fields */ 81 VPID = 0x0000ul, 82 /* Posted-interrupt notification vector */ 83 PINV = 0x0002ul, 84 /* EPTP index */ 85 EPTP_IDX = 0x0004ul, 86 87 /* 16-Bit Guest State Fields */ 88 GUEST_SEL_ES = 0x0800ul, 89 GUEST_SEL_CS = 0x0802ul, 90 GUEST_SEL_SS = 0x0804ul, 91 GUEST_SEL_DS = 0x0806ul, 92 GUEST_SEL_FS = 0x0808ul, 93 GUEST_SEL_GS = 0x080aul, 94 GUEST_SEL_LDTR = 0x080cul, 95 GUEST_SEL_TR = 0x080eul, 96 GUEST_INT_STATUS = 0x0810ul, 97 98 /* 16-Bit Host State Fields */ 99 HOST_SEL_ES = 0x0c00ul, 100 HOST_SEL_CS = 0x0c02ul, 101 HOST_SEL_SS = 0x0c04ul, 102 HOST_SEL_DS = 0x0c06ul, 103 HOST_SEL_FS = 0x0c08ul, 104 HOST_SEL_GS = 0x0c0aul, 105 HOST_SEL_TR = 0x0c0cul, 106 107 /* 64-Bit Control Fields */ 108 IO_BITMAP_A = 0x2000ul, 109 IO_BITMAP_B = 0x2002ul, 110 MSR_BITMAP = 0x2004ul, 111 EXIT_MSR_ST_ADDR = 0x2006ul, 112 EXIT_MSR_LD_ADDR = 0x2008ul, 113 ENTER_MSR_LD_ADDR = 0x200aul, 114 VMCS_EXEC_PTR = 0x200cul, 115 TSC_OFFSET = 0x2010ul, 116 TSC_OFFSET_HI = 0x2011ul, 117 APIC_VIRT_ADDR = 0x2012ul, 118 APIC_ACCS_ADDR = 0x2014ul, 119 EPTP = 0x201aul, 120 EPTP_HI = 0x201bul, 121 122 /* 64-Bit Readonly Data Field */ 123 INFO_PHYS_ADDR = 0x2400ul, 124 125 /* 64-Bit Guest State */ 126 VMCS_LINK_PTR = 0x2800ul, 127 VMCS_LINK_PTR_HI = 0x2801ul, 128 GUEST_DEBUGCTL = 0x2802ul, 129 GUEST_DEBUGCTL_HI = 0x2803ul, 130 GUEST_EFER = 0x2806ul, 131 GUEST_PAT = 0x2804ul, 132 GUEST_PERF_GLOBAL_CTRL = 0x2808ul, 133 GUEST_PDPTE = 0x280aul, 134 135 /* 64-Bit Host State */ 136 HOST_PAT = 0x2c00ul, 137 HOST_EFER = 0x2c02ul, 138 HOST_PERF_GLOBAL_CTRL = 0x2c04ul, 139 140 /* 32-Bit Control Fields */ 141 PIN_CONTROLS = 0x4000ul, 142 CPU_EXEC_CTRL0 = 0x4002ul, 143 EXC_BITMAP = 0x4004ul, 144 PF_ERROR_MASK = 0x4006ul, 145 PF_ERROR_MATCH = 0x4008ul, 146 CR3_TARGET_COUNT = 0x400aul, 147 EXI_CONTROLS = 0x400cul, 148 EXI_MSR_ST_CNT = 0x400eul, 149 EXI_MSR_LD_CNT = 0x4010ul, 150 ENT_CONTROLS = 0x4012ul, 151 ENT_MSR_LD_CNT = 0x4014ul, 152 ENT_INTR_INFO = 0x4016ul, 153 ENT_INTR_ERROR = 0x4018ul, 154 ENT_INST_LEN = 0x401aul, 155 TPR_THRESHOLD = 0x401cul, 156 CPU_EXEC_CTRL1 = 0x401eul, 157 158 /* 32-Bit R/O Data Fields */ 159 VMX_INST_ERROR = 0x4400ul, 160 EXI_REASON = 0x4402ul, 161 EXI_INTR_INFO = 0x4404ul, 162 EXI_INTR_ERROR = 0x4406ul, 163 IDT_VECT_INFO = 0x4408ul, 164 IDT_VECT_ERROR = 0x440aul, 165 EXI_INST_LEN = 0x440cul, 166 EXI_INST_INFO = 0x440eul, 167 168 /* 32-Bit Guest State Fields */ 169 GUEST_LIMIT_ES = 0x4800ul, 170 GUEST_LIMIT_CS = 0x4802ul, 171 GUEST_LIMIT_SS = 0x4804ul, 172 GUEST_LIMIT_DS = 0x4806ul, 173 GUEST_LIMIT_FS = 0x4808ul, 174 GUEST_LIMIT_GS = 0x480aul, 175 GUEST_LIMIT_LDTR = 0x480cul, 176 GUEST_LIMIT_TR = 0x480eul, 177 GUEST_LIMIT_GDTR = 0x4810ul, 178 GUEST_LIMIT_IDTR = 0x4812ul, 179 GUEST_AR_ES = 0x4814ul, 180 GUEST_AR_CS = 0x4816ul, 181 GUEST_AR_SS = 0x4818ul, 182 GUEST_AR_DS = 0x481aul, 183 GUEST_AR_FS = 0x481cul, 184 GUEST_AR_GS = 0x481eul, 185 GUEST_AR_LDTR = 0x4820ul, 186 GUEST_AR_TR = 0x4822ul, 187 GUEST_INTR_STATE = 0x4824ul, 188 GUEST_ACTV_STATE = 0x4826ul, 189 GUEST_SMBASE = 0x4828ul, 190 GUEST_SYSENTER_CS = 0x482aul, 191 PREEMPT_TIMER_VALUE = 0x482eul, 192 193 /* 32-Bit Host State Fields */ 194 HOST_SYSENTER_CS = 0x4c00ul, 195 196 /* Natural-Width Control Fields */ 197 CR0_MASK = 0x6000ul, 198 CR4_MASK = 0x6002ul, 199 CR0_READ_SHADOW = 0x6004ul, 200 CR4_READ_SHADOW = 0x6006ul, 201 CR3_TARGET_0 = 0x6008ul, 202 CR3_TARGET_1 = 0x600aul, 203 CR3_TARGET_2 = 0x600cul, 204 CR3_TARGET_3 = 0x600eul, 205 206 /* Natural-Width R/O Data Fields */ 207 EXI_QUALIFICATION = 0x6400ul, 208 IO_RCX = 0x6402ul, 209 IO_RSI = 0x6404ul, 210 IO_RDI = 0x6406ul, 211 IO_RIP = 0x6408ul, 212 GUEST_LINEAR_ADDRESS = 0x640aul, 213 214 /* Natural-Width Guest State Fields */ 215 GUEST_CR0 = 0x6800ul, 216 GUEST_CR3 = 0x6802ul, 217 GUEST_CR4 = 0x6804ul, 218 GUEST_BASE_ES = 0x6806ul, 219 GUEST_BASE_CS = 0x6808ul, 220 GUEST_BASE_SS = 0x680aul, 221 GUEST_BASE_DS = 0x680cul, 222 GUEST_BASE_FS = 0x680eul, 223 GUEST_BASE_GS = 0x6810ul, 224 GUEST_BASE_LDTR = 0x6812ul, 225 GUEST_BASE_TR = 0x6814ul, 226 GUEST_BASE_GDTR = 0x6816ul, 227 GUEST_BASE_IDTR = 0x6818ul, 228 GUEST_DR7 = 0x681aul, 229 GUEST_RSP = 0x681cul, 230 GUEST_RIP = 0x681eul, 231 GUEST_RFLAGS = 0x6820ul, 232 GUEST_PENDING_DEBUG = 0x6822ul, 233 GUEST_SYSENTER_ESP = 0x6824ul, 234 GUEST_SYSENTER_EIP = 0x6826ul, 235 236 /* Natural-Width Host State Fields */ 237 HOST_CR0 = 0x6c00ul, 238 HOST_CR3 = 0x6c02ul, 239 HOST_CR4 = 0x6c04ul, 240 HOST_BASE_FS = 0x6c06ul, 241 HOST_BASE_GS = 0x6c08ul, 242 HOST_BASE_TR = 0x6c0aul, 243 HOST_BASE_GDTR = 0x6c0cul, 244 HOST_BASE_IDTR = 0x6c0eul, 245 HOST_SYSENTER_ESP = 0x6c10ul, 246 HOST_SYSENTER_EIP = 0x6c12ul, 247 HOST_RSP = 0x6c14ul, 248 HOST_RIP = 0x6c16ul 249 }; 250 251 enum Reason { 252 VMX_EXC_NMI = 0, 253 VMX_EXTINT = 1, 254 VMX_TRIPLE_FAULT = 2, 255 VMX_INIT = 3, 256 VMX_SIPI = 4, 257 VMX_SMI_IO = 5, 258 VMX_SMI_OTHER = 6, 259 VMX_INTR_WINDOW = 7, 260 VMX_NMI_WINDOW = 8, 261 VMX_TASK_SWITCH = 9, 262 VMX_CPUID = 10, 263 VMX_GETSEC = 11, 264 VMX_HLT = 12, 265 VMX_INVD = 13, 266 VMX_INVLPG = 14, 267 VMX_RDPMC = 15, 268 VMX_RDTSC = 16, 269 VMX_RSM = 17, 270 VMX_VMCALL = 18, 271 VMX_VMCLEAR = 19, 272 VMX_VMLAUNCH = 20, 273 VMX_VMPTRLD = 21, 274 VMX_VMPTRST = 22, 275 VMX_VMREAD = 23, 276 VMX_VMRESUME = 24, 277 VMX_VMWRITE = 25, 278 VMX_VMXOFF = 26, 279 VMX_VMXON = 27, 280 VMX_CR = 28, 281 VMX_DR = 29, 282 VMX_IO = 30, 283 VMX_RDMSR = 31, 284 VMX_WRMSR = 32, 285 VMX_FAIL_STATE = 33, 286 VMX_FAIL_MSR = 34, 287 VMX_MWAIT = 36, 288 VMX_MTF = 37, 289 VMX_MONITOR = 39, 290 VMX_PAUSE = 40, 291 VMX_FAIL_MCHECK = 41, 292 VMX_TPR_THRESHOLD = 43, 293 VMX_APIC_ACCESS = 44, 294 VMX_GDTR_IDTR = 46, 295 VMX_LDTR_TR = 47, 296 VMX_EPT_VIOLATION = 48, 297 VMX_EPT_MISCONFIG = 49, 298 VMX_INVEPT = 50, 299 VMX_PREEMPT = 52, 300 VMX_INVVPID = 53, 301 VMX_WBINVD = 54, 302 VMX_XSETBV = 55 303 }; 304 305 #define X86_EFLAGS_CF 0x00000001 /* Carry Flag */ 306 #define X86_EFLAGS_ZF 0x00000040 /* Zero Flag */ 307 308 enum Ctrl_exi { 309 EXI_SAVE_DBGCTLS = 1UL << 2, 310 EXI_HOST_64 = 1UL << 9, 311 EXI_LOAD_PERF = 1UL << 12, 312 EXI_INTA = 1UL << 15, 313 EXI_SAVE_PAT = 1UL << 18, 314 EXI_LOAD_PAT = 1UL << 19, 315 EXI_SAVE_EFER = 1UL << 20, 316 EXI_LOAD_EFER = 1UL << 21, 317 EXI_SAVE_PREEMPT = 1UL << 22, 318 }; 319 320 enum Ctrl_ent { 321 ENT_LOAD_DBGCTLS = 1UL << 2, 322 ENT_GUEST_64 = 1UL << 9, 323 ENT_LOAD_PAT = 1UL << 14, 324 ENT_LOAD_EFER = 1UL << 15, 325 }; 326 327 enum Ctrl_pin { 328 PIN_EXTINT = 1ul << 0, 329 PIN_NMI = 1ul << 3, 330 PIN_VIRT_NMI = 1ul << 5, 331 PIN_PREEMPT = 1ul << 6, 332 }; 333 334 enum Ctrl0 { 335 CPU_INTR_WINDOW = 1ul << 2, 336 CPU_HLT = 1ul << 7, 337 CPU_INVLPG = 1ul << 9, 338 CPU_MWAIT = 1ul << 10, 339 CPU_RDPMC = 1ul << 11, 340 CPU_RDTSC = 1ul << 12, 341 CPU_CR3_LOAD = 1ul << 15, 342 CPU_CR3_STORE = 1ul << 16, 343 CPU_CR8_LOAD = 1ul << 19, 344 CPU_CR8_STORE = 1ul << 20, 345 CPU_TPR_SHADOW = 1ul << 21, 346 CPU_NMI_WINDOW = 1ul << 22, 347 CPU_IO = 1ul << 24, 348 CPU_IO_BITMAP = 1ul << 25, 349 CPU_MSR_BITMAP = 1ul << 28, 350 CPU_MONITOR = 1ul << 29, 351 CPU_PAUSE = 1ul << 30, 352 CPU_SECONDARY = 1ul << 31, 353 }; 354 355 enum Ctrl1 { 356 CPU_EPT = 1ul << 1, 357 CPU_VPID = 1ul << 5, 358 CPU_URG = 1ul << 7, 359 CPU_WBINVD = 1ul << 6, 360 CPU_RDRAND = 1ul << 11, 361 }; 362 363 #define SAVE_GPR \ 364 "xchg %rax, regs\n\t" \ 365 "xchg %rbx, regs+0x8\n\t" \ 366 "xchg %rcx, regs+0x10\n\t" \ 367 "xchg %rdx, regs+0x18\n\t" \ 368 "xchg %rbp, regs+0x28\n\t" \ 369 "xchg %rsi, regs+0x30\n\t" \ 370 "xchg %rdi, regs+0x38\n\t" \ 371 "xchg %r8, regs+0x40\n\t" \ 372 "xchg %r9, regs+0x48\n\t" \ 373 "xchg %r10, regs+0x50\n\t" \ 374 "xchg %r11, regs+0x58\n\t" \ 375 "xchg %r12, regs+0x60\n\t" \ 376 "xchg %r13, regs+0x68\n\t" \ 377 "xchg %r14, regs+0x70\n\t" \ 378 "xchg %r15, regs+0x78\n\t" 379 380 #define LOAD_GPR SAVE_GPR 381 382 #define SAVE_GPR_C \ 383 "xchg %%rax, regs\n\t" \ 384 "xchg %%rbx, regs+0x8\n\t" \ 385 "xchg %%rcx, regs+0x10\n\t" \ 386 "xchg %%rdx, regs+0x18\n\t" \ 387 "xchg %%rbp, regs+0x28\n\t" \ 388 "xchg %%rsi, regs+0x30\n\t" \ 389 "xchg %%rdi, regs+0x38\n\t" \ 390 "xchg %%r8, regs+0x40\n\t" \ 391 "xchg %%r9, regs+0x48\n\t" \ 392 "xchg %%r10, regs+0x50\n\t" \ 393 "xchg %%r11, regs+0x58\n\t" \ 394 "xchg %%r12, regs+0x60\n\t" \ 395 "xchg %%r13, regs+0x68\n\t" \ 396 "xchg %%r14, regs+0x70\n\t" \ 397 "xchg %%r15, regs+0x78\n\t" 398 399 #define LOAD_GPR_C SAVE_GPR_C 400 401 #define SAVE_RFLAGS \ 402 "pushf\n\t" \ 403 "pop host_rflags\n\t" 404 405 #define LOAD_RFLAGS \ 406 "push host_rflags\n\t" \ 407 "popf\n\t" 408 409 #define VMX_IO_SIZE_MASK 0x7 410 #define _VMX_IO_BYTE 0 411 #define _VMX_IO_WORD 1 412 #define _VMX_IO_LONG 3 413 #define VMX_IO_DIRECTION_MASK (1ul << 3) 414 #define VMX_IO_IN (1ul << 3) 415 #define VMX_IO_OUT 0 416 #define VMX_IO_STRING (1ul << 4) 417 #define VMX_IO_REP (1ul << 5) 418 #define VMX_IO_OPRAND_IMM (1ul << 6) 419 #define VMX_IO_PORT_MASK 0xFFFF0000 420 #define VMX_IO_PORT_SHIFT 16 421 422 #define VMX_TEST_START 0 423 #define VMX_TEST_VMEXIT 1 424 #define VMX_TEST_EXIT 2 425 #define VMX_TEST_RESUME 3 426 #define VMX_TEST_LAUNCH_ERR 4 427 #define VMX_TEST_RESUME_ERR 5 428 429 #define HYPERCALL_BIT (1ul << 12) 430 #define HYPERCALL_MASK 0xFFF 431 #define HYPERCALL_VMEXIT 0x1 432 433 #define EPTP_PG_WALK_LEN_SHIFT 3ul 434 #define EPTP_AD_FLAG (1ul << 6) 435 436 #define EPT_MEM_TYPE_UC 0ul 437 #define EPT_MEM_TYPE_WC 1ul 438 #define EPT_MEM_TYPE_WT 4ul 439 #define EPT_MEM_TYPE_WP 5ul 440 #define EPT_MEM_TYPE_WB 6ul 441 442 #define EPT_RA 1ul 443 #define EPT_WA 2ul 444 #define EPT_EA 4ul 445 #define EPT_PRESENT (EPT_RA | EPT_WA | EPT_EA) 446 #define EPT_ACCESS_FLAG (1ul << 8) 447 #define EPT_DIRTY_FLAG (1ul << 9) 448 #define EPT_LARGE_PAGE (1ul << 7) 449 #define EPT_MEM_TYPE_SHIFT 3ul 450 #define EPT_IGNORE_PAT (1ul << 6) 451 #define EPT_SUPPRESS_VE (1ull << 63) 452 453 #define EPT_CAP_WT 1ull 454 #define EPT_CAP_PWL4 (1ull << 6) 455 #define EPT_CAP_UC (1ull << 8) 456 #define EPT_CAP_WB (1ull << 14) 457 #define EPT_CAP_2M_PAGE (1ull << 16) 458 #define EPT_CAP_1G_PAGE (1ull << 17) 459 #define EPT_CAP_INVEPT (1ull << 20) 460 #define EPT_CAP_INVEPT_SINGLE (1ull << 25) 461 #define EPT_CAP_INVEPT_ALL (1ull << 26) 462 #define EPT_CAP_AD_FLAG (1ull << 21) 463 464 #define PAGE_SIZE_2M (512 * PAGE_SIZE) 465 #define PAGE_SIZE_1G (512 * PAGE_SIZE_2M) 466 #define EPT_PAGE_LEVEL 4 467 #define EPT_PGDIR_WIDTH 9 468 #define EPT_PGDIR_MASK 511 469 #define PAGE_MASK (~(PAGE_SIZE-1)) 470 #define PAGE_MASK_2M (~(PAGE_SIZE_2M-1)) 471 472 #define EPT_VLT_RD 1 473 #define EPT_VLT_WR (1 << 1) 474 #define EPT_VLT_FETCH (1 << 2) 475 #define EPT_VLT_PERM_RD (1 << 3) 476 #define EPT_VLT_PERM_WR (1 << 4) 477 #define EPT_VLT_PERM_EX (1 << 5) 478 #define EPT_VLT_LADDR_VLD (1 << 7) 479 #define EPT_VLT_PADDR (1 << 8) 480 481 #define MAGIC_VAL_1 0x12345678ul 482 #define MAGIC_VAL_2 0x87654321ul 483 #define MAGIC_VAL_3 0xfffffffful 484 485 #define INVEPT_SINGLE 1 486 #define INVEPT_GLOBAL 2 487 488 #define ACTV_ACTIVE 0 489 #define ACTV_HLT 1 490 491 extern struct regs regs; 492 493 extern union vmx_basic basic; 494 extern union vmx_ctrl_msr ctrl_pin_rev; 495 extern union vmx_ctrl_msr ctrl_cpu_rev[2]; 496 extern union vmx_ctrl_msr ctrl_exit_rev; 497 extern union vmx_ctrl_msr ctrl_enter_rev; 498 extern union vmx_ept_vpid ept_vpid; 499 500 void vmx_set_test_stage(u32 s); 501 u32 vmx_get_test_stage(void); 502 void vmx_inc_test_stage(void); 503 504 static inline int vmcs_clear(struct vmcs *vmcs) 505 { 506 bool ret; 507 u64 rflags = read_rflags() | X86_EFLAGS_CF | X86_EFLAGS_ZF; 508 509 asm volatile ("push %1; popf; vmclear %2; setbe %0" 510 : "=q" (ret) : "q" (rflags), "m" (vmcs) : "cc"); 511 return ret; 512 } 513 514 static inline u64 vmcs_read(enum Encoding enc) 515 { 516 u64 val; 517 asm volatile ("vmread %1, %0" : "=rm" (val) : "r" ((u64)enc) : "cc"); 518 return val; 519 } 520 521 static inline int vmcs_write(enum Encoding enc, u64 val) 522 { 523 bool ret; 524 asm volatile ("vmwrite %1, %2; setbe %0" 525 : "=q"(ret) : "rm" (val), "r" ((u64)enc) : "cc"); 526 return ret; 527 } 528 529 static inline int vmcs_save(struct vmcs **vmcs) 530 { 531 bool ret; 532 u64 rflags = read_rflags() | X86_EFLAGS_CF | X86_EFLAGS_ZF; 533 534 asm volatile ("push %1; popf; vmptrst %2; setbe %0" 535 : "=q" (ret) : "q" (rflags), "m" (*vmcs) : "cc"); 536 return ret; 537 } 538 539 static inline void invept(unsigned long type, u64 eptp) 540 { 541 struct { 542 u64 eptp, gpa; 543 } operand = {eptp, 0}; 544 asm volatile("invept %0, %1\n" ::"m"(operand),"r"(type)); 545 } 546 547 void print_vmexit_info(); 548 void ept_sync(int type, u64 eptp); 549 void install_ept_entry(unsigned long *pml4, int pte_level, 550 unsigned long guest_addr, unsigned long pte, 551 unsigned long *pt_page); 552 void install_1g_ept(unsigned long *pml4, unsigned long phys, 553 unsigned long guest_addr, u64 perm); 554 void install_2m_ept(unsigned long *pml4, unsigned long phys, 555 unsigned long guest_addr, u64 perm); 556 void install_ept(unsigned long *pml4, unsigned long phys, 557 unsigned long guest_addr, u64 perm); 558 void setup_ept_range(unsigned long *pml4, unsigned long start, 559 unsigned long len, int map_1g, int map_2m, u64 perm); 560 unsigned long get_ept_pte(unsigned long *pml4, 561 unsigned long guest_addr, int level); 562 int set_ept_pte(unsigned long *pml4, unsigned long guest_addr, 563 int level, u64 pte_val); 564 565 #endif 566 567