#ifndef _VISOR_VMX_H_ #define _VISOR_VMX_H_ #include /* begin VMX field definitions */ #define GUEST_ES_SELECTOR 0x0800 #define GUEST_CS_SELECTOR 0x0802 #define GUEST_SS_SELECTOR 0x0804 #define GUEST_DS_SELECTOR 0x0806 #define GUEST_FS_SELECTOR 0x0808 #define GUEST_GS_SELECTOR 0x080A #define HOST_ES_SELECTOR 0x0C00 #define HOST_CS_SELECTOR 0x0C02 #define HOST_SS_SELECTOR 0x0C04 #define HOST_DS_SELECTOR 0x0C06 #define HOST_FS_SELECTOR 0x0C08 #define HOST_GS_SELECTOR 0x0C0A #define HOST_TR_SELECTOR 0x0C0C #define VMCS_LINK_POINTER 0x2800 #define GUEST_IA32_DEBUGCTL 0x2802 #define GUEST_IA32_PAT 0x2804 #define GUEST_IA32_EFER 0x2806 #define HOST_IA32_PAT 0x2C00 #define HOST_IA32_EFER 0x2C02 #define PIN_BASED_VM_EXEC_CONTROL 0x4000 #define CPU_BASED_VM_EXEC_CONTROL 0x4002 #define EXCEPTION_BITMAP 0x4004 #define CR3_TARGET_COUNT 0x400A #define VM_EXIT_CONTROLS 0x400C #define VM_EXIT_MSR_STORE_COUNT 0x400E #define VM_ENTRY_CONTROLS 0x4012 #define VM_ENTRY_MSR_LOAD_COUNT 0x4014 #define VM_ENTRY_INTR_INFO_FIELD 0x4016 #define CPU_BASED_VM_EXEC_CONTROL2 0x401E #define VMCS_INSTRUCTION_ERROR 0x4400 #define GUEST_ES_LIMIT 0x4800 #define GUEST_ES_ACCESS 0x4814 #define GUEST_SYSENTER_CS 0x482A #define HOST_SYSENTER_CS 0x4C00 #define GUEST_CR0 0x6800 #define GUEST_CR3 0x6802 #define GUEST_CR4 0x6804 #define GUEST_ES_BASE 0x6806 #define GUEST_FS_BASE 0x680E #define GUEST_GS_BASE 0x6810 #define GUEST_GDTR_BASE 0x6816 #define GUEST_IDTR_BASE 0x6818 #define GUEST_DR7 0x681A #define GUEST_RSP 0x681C #define GUEST_RIP 0x681E #define GUEST_RFLAGS 0x6820 #define GUEST_SYSENTER_ESP 0x6824 #define GUEST_SYSENTER_EIP 0x6826 #define HOST_CR0 0x6C00 #define HOST_CR3 0x6C02 #define HOST_CR4 0x6C04 #define HOST_FS_BASE 0x6C06 #define HOST_GS_BASE 0x6C08 #define HOST_TR_BASE 0x6C0A #define HOST_GDTR_BASE 0x6C0C #define HOST_IDTR_BASE 0x6C0E #define HOST_SYSENTER_ESP 0x6C10 #define HOST_SYSENTER_EIP 0x6C12 #define HOST_RSP 0x6C14 #define HOST_RIP 0x6C16 /* end VMX field definitions */ struct VMXON { uint32_t revisionID; uint32_t abortIndicator; char vmcsData[]; }; struct VMCS { uint32_t revisionID; /* Guest-state area */ /* Host-state area */ /* VM-execution control fields */ /* VM-exit control fields */ /* VM-entry control fields */ /* VM-exit information fields */ }; static inline uint64_t vmxon(void *region) { uint64_t regionpa = (uint64_t)region; uint64_t flags; __asm__ volatile ( "vmxon %1\n\t" "pushf \n\t" "pop %0\n\t" : "=r"(flags) : "m"(regionpa)); return flags; } static inline void vmxoff(void) { __asm__ volatile ("vmxoff\n\t" ::); } static inline uint64_t vmptrld(void *region) { uint64_t regionpa = (uint64_t)region; uint64_t flags; __asm__ volatile ( "vmptrld %1\n\t" "pushf \n\t" "pop %0\n\t" : "=r"(flags) : "m"(regionpa)); return flags; } static inline void vmptrst(void *arg) { __asm__ volatile ("vmptrst\n\t" ::); } static inline uint64_t vmclear(void *region) { uint64_t regionpa = (uint64_t)region; uint64_t flags; __asm__ volatile ( "vmclear %1\n\t" "pushf \n\t" "pop %0\n\t" : "=r"(flags) : "m"(regionpa)); return flags; } static inline uint64_t vmlaunch(void) { uint64_t flags; __asm__ volatile ( "vmlaunch \n\t" "pushf \n\t" "pop %0\n\t" : "=r"(flags)); return flags; } static inline void vmresume(void) { __asm__ volatile ("vmresume\n\t" ::); } static inline uint64_t vmread(uint64_t field) { uint64_t value; __asm__ volatile ("vmread %0, %1\n\t" : "=rm"(value) : "r"(field)); return value; } static inline uint64_t vmwrite(uint64_t field, uint64_t value) { uint64_t flags; __asm__ volatile ( "vmwrite %1, %2\n\t" "pushf \n\t" "pop %0 \n\t" : "=r"(flags) : "rm"(value), "r"(field)); return flags; } static inline void vmcall() { __asm__ volatile ("vmcall\n\t" ::); } static inline const char * vmx_describe_error(uint32_t error) { switch (error) { default: return "Unknown VMX Error"; case 0: return NULL; case 1: return "VMCALL executed in VMX root operation"; case 2: return "VMCLEAR with invalid physical address"; case 3: return "VMCLEAR with VMXON pointer"; case 4: return "VMLAUNCH with non-clear VMCS"; case 5: return "VMRESUME with non-launched VMCS"; case 6: return "VMRESUME after VMXOFF (VMXOFF and VMXON between VMLAUNCH and VMRESUME)"; case 7: return "VM entry with invalid control field(s)"; case 8: return "VM entry with invalid host-state field(s)"; case 9: return "VMPTRLD with invalid physical address"; case 10: return "VMPTRLD with VMXON pointer"; case 11: return "VMPTRLD with incorrect VMCS revision identifier"; case 12: return "VMREAD/VMWRITE from/to unsupported VMCS component"; case 13: return "VMWRITE to read-only VMCS component"; case 15: return "VMXON executed in VMX root operation"; case 16: return "VM entry with invalid executive-VMCS pointer"; case 17: return "VM entry with non-launched executive VMCS"; case 18: return "VM entry with executive-VMCS pointer not VMXON pointer (when attempting to deactivate the dual-monitor treatment of SMIs and SMM)"; case 19: return "VMCALL with non-clear VMCS (when attempting to activate the dual-monitor treatment of SMIs and SMM)"; case 20: return "VMCALL with invalid VM-exit control fields"; case 22: return "VMCALL with incorrect MSEG revision identifier (when attempting to activate the dual-monitor treatment of SMIs and SMM)"; case 23: return "VMXOFF under dual-monitor treatment of SMIs and SMM"; case 24: return "VMCALL with invalid SMM-monitor features (when attempting to activate the dual-monitor treatment of SMIs and SMM)"; case 25: return "VM entry with invalid VM-execution control fields in executive VMCS (when attempting to return from SMM)"; case 26: return "VM entry with events blocked by MOV SS"; case 28: return "Invalid operand to INVEPT/INVVPID"; } } static inline const char * vmcs_describe_error(void) { uint32_t error = vmread(VMCS_INSTRUCTION_ERROR) & 0xffffffff; return vmx_describe_error(error); } #endif