These C wrappers record the faults and VMfails in the execution of vmx instructions vmxon, vmread and vmptrld. Further tests can use those records to check if a VMX instruction is implemented correctly by Xen in the nested VMX. Other VMX instructions will be added once their test cases are added.
Signed-off-by: Haozhong Zhang <haozhong.zh...@intel.com> --- include/arch/x86/hvm/vmx/vmcs.h | 179 ++++++++++++++++++++++++++++++++++++++++ tests/vvmx/Makefile | 2 +- tests/vvmx/util.c | 83 +++++++++++++++++++ tests/vvmx/util.h | 78 +++++++++++++++++ tests/vvmx/vmxon.c | 0 5 files changed, 341 insertions(+), 1 deletion(-) create mode 100644 include/arch/x86/hvm/vmx/vmcs.h create mode 100644 tests/vvmx/util.c create mode 100644 tests/vvmx/util.h create mode 100644 tests/vvmx/vmxon.c diff --git a/include/arch/x86/hvm/vmx/vmcs.h b/include/arch/x86/hvm/vmx/vmcs.h new file mode 100644 index 0000000..e1a6ef8 --- /dev/null +++ b/include/arch/x86/hvm/vmx/vmcs.h @@ -0,0 +1,179 @@ +#ifndef XTF_X86_HVM_VMX_VMCS_H +#define XTF_X86_HVM_VMX_VMCS_H + +/* VMCS field encodings. */ +#define VMCS_HIGH(x) ((x) | 1) +enum vmcs_field { + VIRTUAL_PROCESSOR_ID = 0x00000000, + POSTED_INTR_NOTIFICATION_VECTOR = 0x00000002, + EPTP_INDEX = 0x00000004, +#define GUEST_SEG_SELECTOR(sel) (GUEST_ES_SELECTOR + (sel) * 2) /* ES ... GS */ + GUEST_ES_SELECTOR = 0x00000800, + GUEST_CS_SELECTOR = 0x00000802, + GUEST_SS_SELECTOR = 0x00000804, + GUEST_DS_SELECTOR = 0x00000806, + GUEST_FS_SELECTOR = 0x00000808, + GUEST_GS_SELECTOR = 0x0000080a, + GUEST_LDTR_SELECTOR = 0x0000080c, + GUEST_TR_SELECTOR = 0x0000080e, + GUEST_INTR_STATUS = 0x00000810, + GUEST_PML_INDEX = 0x00000812, + HOST_ES_SELECTOR = 0x00000c00, + HOST_CS_SELECTOR = 0x00000c02, + HOST_SS_SELECTOR = 0x00000c04, + HOST_DS_SELECTOR = 0x00000c06, + HOST_FS_SELECTOR = 0x00000c08, + HOST_GS_SELECTOR = 0x00000c0a, + HOST_TR_SELECTOR = 0x00000c0c, + IO_BITMAP_A = 0x00002000, + IO_BITMAP_B = 0x00002002, + MSR_BITMAP = 0x00002004, + VM_EXIT_MSR_STORE_ADDR = 0x00002006, + VM_EXIT_MSR_LOAD_ADDR = 0x00002008, + VM_ENTRY_MSR_LOAD_ADDR = 0x0000200a, + PML_ADDRESS = 0x0000200e, + TSC_OFFSET = 0x00002010, + VIRTUAL_APIC_PAGE_ADDR = 0x00002012, + APIC_ACCESS_ADDR = 0x00002014, + PI_DESC_ADDR = 0x00002016, + VM_FUNCTION_CONTROL = 0x00002018, + EPT_POINTER = 0x0000201a, + EOI_EXIT_BITMAP0 = 0x0000201c, +#define EOI_EXIT_BITMAP(n) (EOI_EXIT_BITMAP0 + (n) * 2) /* n = 0...3 */ + EPTP_LIST_ADDR = 0x00002024, + VMREAD_BITMAP = 0x00002026, + VMWRITE_BITMAP = 0x00002028, + VIRT_EXCEPTION_INFO = 0x0000202a, + XSS_EXIT_BITMAP = 0x0000202c, + TSC_MULTIPLIER = 0x00002032, + GUEST_PHYSICAL_ADDRESS = 0x00002400, + VMCS_LINK_POINTER = 0x00002800, + GUEST_IA32_DEBUGCTL = 0x00002802, + GUEST_PAT = 0x00002804, + GUEST_EFER = 0x00002806, + GUEST_PERF_GLOBAL_CTRL = 0x00002808, + GUEST_PDPTE0 = 0x0000280a, +#define GUEST_PDPTE(n) (GUEST_PDPTE0 + (n) * 2) /* n = 0...3 */ + GUEST_BNDCFGS = 0x00002812, + HOST_PAT = 0x00002c00, + HOST_EFER = 0x00002c02, + HOST_PERF_GLOBAL_CTRL = 0x00002c04, + PIN_BASED_VM_EXEC_CONTROL = 0x00004000, + CPU_BASED_VM_EXEC_CONTROL = 0x00004002, + EXCEPTION_BITMAP = 0x00004004, + PAGE_FAULT_ERROR_CODE_MASK = 0x00004006, + PAGE_FAULT_ERROR_CODE_MATCH = 0x00004008, + CR3_TARGET_COUNT = 0x0000400a, + VM_EXIT_CONTROLS = 0x0000400c, + VM_EXIT_MSR_STORE_COUNT = 0x0000400e, + VM_EXIT_MSR_LOAD_COUNT = 0x00004010, + VM_ENTRY_CONTROLS = 0x00004012, + VM_ENTRY_MSR_LOAD_COUNT = 0x00004014, + VM_ENTRY_INTR_INFO = 0x00004016, + VM_ENTRY_EXCEPTION_ERROR_CODE = 0x00004018, + VM_ENTRY_INSTRUCTION_LEN = 0x0000401a, + TPR_THRESHOLD = 0x0000401c, + SECONDARY_VM_EXEC_CONTROL = 0x0000401e, + PLE_GAP = 0x00004020, + PLE_WINDOW = 0x00004022, + VM_INSTRUCTION_ERROR = 0x00004400, + VM_EXIT_REASON = 0x00004402, + VM_EXIT_INTR_INFO = 0x00004404, + VM_EXIT_INTR_ERROR_CODE = 0x00004406, + IDT_VECTORING_INFO = 0x00004408, + IDT_VECTORING_ERROR_CODE = 0x0000440a, + VM_EXIT_INSTRUCTION_LEN = 0x0000440c, + VMX_INSTRUCTION_INFO = 0x0000440e, +#define GUEST_SEG_LIMIT(sel) (GUEST_ES_LIMIT + (sel) * 2) /* ES ... GS */ + GUEST_ES_LIMIT = 0x00004800, + GUEST_CS_LIMIT = 0x00004802, + GUEST_SS_LIMIT = 0x00004804, + GUEST_DS_LIMIT = 0x00004806, + GUEST_FS_LIMIT = 0x00004808, + GUEST_GS_LIMIT = 0x0000480a, + GUEST_LDTR_LIMIT = 0x0000480c, + GUEST_TR_LIMIT = 0x0000480e, + GUEST_GDTR_LIMIT = 0x00004810, + GUEST_IDTR_LIMIT = 0x00004812, +#define GUEST_SEG_AR_BYTES(sel) (GUEST_ES_AR_BYTES + (sel) * 2) /* ES ... GS */ + GUEST_ES_AR_BYTES = 0x00004814, + GUEST_CS_AR_BYTES = 0x00004816, + GUEST_SS_AR_BYTES = 0x00004818, + GUEST_DS_AR_BYTES = 0x0000481a, + GUEST_FS_AR_BYTES = 0x0000481c, + GUEST_GS_AR_BYTES = 0x0000481e, + GUEST_LDTR_AR_BYTES = 0x00004820, + GUEST_TR_AR_BYTES = 0x00004822, + GUEST_INTERRUPTIBILITY_INFO = 0x00004824, + GUEST_ACTIVITY_STATE = 0x00004826, + GUEST_SMBASE = 0x00004828, + GUEST_SYSENTER_CS = 0x0000482a, + GUEST_PREEMPTION_TIMER = 0x0000482e, + HOST_SYSENTER_CS = 0x00004c00, + CR0_GUEST_HOST_MASK = 0x00006000, + CR4_GUEST_HOST_MASK = 0x00006002, + CR0_READ_SHADOW = 0x00006004, + CR4_READ_SHADOW = 0x00006006, + CR3_TARGET_VALUE0 = 0x00006008, +#define CR3_TARGET_VALUE(n) (CR3_TARGET_VALUE0 + (n) * 2) /* n < CR3_TARGET_COUNT */ + EXIT_QUALIFICATION = 0x00006400, + GUEST_LINEAR_ADDRESS = 0x0000640a, + GUEST_CR0 = 0x00006800, + GUEST_CR3 = 0x00006802, + GUEST_CR4 = 0x00006804, +#define GUEST_SEG_BASE(sel) (GUEST_ES_BASE + (sel) * 2) /* ES ... GS */ + GUEST_ES_BASE = 0x00006806, + GUEST_CS_BASE = 0x00006808, + GUEST_SS_BASE = 0x0000680a, + GUEST_DS_BASE = 0x0000680c, + GUEST_FS_BASE = 0x0000680e, + GUEST_GS_BASE = 0x00006810, + GUEST_LDTR_BASE = 0x00006812, + GUEST_TR_BASE = 0x00006814, + GUEST_GDTR_BASE = 0x00006816, + GUEST_IDTR_BASE = 0x00006818, + GUEST_DR7 = 0x0000681a, + GUEST_RSP = 0x0000681c, + GUEST_RIP = 0x0000681e, + GUEST_RFLAGS = 0x00006820, + GUEST_PENDING_DBG_EXCEPTIONS = 0x00006822, + GUEST_SYSENTER_ESP = 0x00006824, + GUEST_SYSENTER_EIP = 0x00006826, + HOST_CR0 = 0x00006c00, + HOST_CR3 = 0x00006c02, + HOST_CR4 = 0x00006c04, + HOST_FS_BASE = 0x00006c06, + HOST_GS_BASE = 0x00006c08, + HOST_TR_BASE = 0x00006c0a, + HOST_GDTR_BASE = 0x00006c0c, + HOST_IDTR_BASE = 0x00006c0e, + HOST_SYSENTER_ESP = 0x00006c10, + HOST_SYSENTER_EIP = 0x00006c12, + HOST_RSP = 0x00006c14, + HOST_RIP = 0x00006c16, +}; + +/* VM Instruction error numbers */ +enum vmx_insn_errno +{ + VMX_INSN_VMCLEAR_INVALID_PHYADDR = 2, + VMX_INSN_VMLAUNCH_NONCLEAR_VMCS = 4, + VMX_INSN_VMRESUME_NONLAUNCHED_VMCS = 5, + VMX_INSN_INVALID_CONTROL_STATE = 7, + VMX_INSN_INVALID_HOST_STATE = 8, + VMX_INSN_VMPTRLD_INVALID_PHYADDR = 9, + VMX_INSN_UNSUPPORTED_VMCS_COMPONENT = 12, + VMX_INSN_VMXON_IN_VMX_ROOT = 15, +}; + +#endif /* XTF_X86_HVM_VMX_VMCS_H */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/tests/vvmx/Makefile b/tests/vvmx/Makefile index 54769fa..24d3720 100644 --- a/tests/vvmx/Makefile +++ b/tests/vvmx/Makefile @@ -6,6 +6,6 @@ TEST-ENVS := hvm64 TEST-EXTRA-CFG := extra.cfg.in -obj-perenv += main.o cpuid.o msr.o +obj-perenv += main.o cpuid.o msr.o util.o include $(ROOT)/build/gen.mk diff --git a/tests/vvmx/util.c b/tests/vvmx/util.c new file mode 100644 index 0000000..8cd35c5 --- /dev/null +++ b/tests/vvmx/util.c @@ -0,0 +1,83 @@ +#include <xtf.h> +#include <arch/x86/hvm/vmx/vmcs.h> +#include "util.h" + +#define VMPTRLD_OPCODE ".byte 0x0f,0xc7\n" /* reg/opcode: /6 */ +#define VMREAD_OPCODE ".byte 0x0f,0x78\n" +#define VMXON_OPCODE ".byte 0xf3,0x0f,0xc7\n" + +#define MODRM_EAX_06 ".byte 0x30\n" /* [EAX], with reg/opcode: /6 */ +#define MODRM_EAX_ECX ".byte 0xc1\n" /* EAX, ECX */ + +uint8_t vmxon(uint64_t paddr, exinfo_t *fault_info) +{ + exinfo_t fault = 0; + uint8_t valid = 0, invalid = 0; + + asm volatile("1: "VMXON_OPCODE MODRM_EAX_06 "\n\t" + " setc %0; setz %1 \n\t" + "2: \n\t" + _ASM_EXTABLE_HANDLER(1b, 2b, ex_record_fault_edi) + : "=q" (invalid), "=q" (valid), "+D" (fault) + : "a" (&paddr) + : "memory", "cc"); + + if ( fault && fault_info ) + *fault_info = fault; + + return (fault ? VMXERR_FAULT : 0) | + (valid ? VMXERR_VMFAIL_VALID : 0) | + (invalid ? VMXERR_VMFAIL_INVALID : 0); +} + +uint8_t vmread(enum vmcs_field field, uint64_t *val, exinfo_t *fault_info) +{ + exinfo_t fault = 0; + uint8_t valid = 0, invalid = 0; + + asm volatile("1: "VMREAD_OPCODE MODRM_EAX_ECX "\n\t" + " setc %0; setz %1 \n\t" + "2: \n\t" + _ASM_EXTABLE_HANDLER(1b, 2b, ex_record_fault_edi) + : "=q" (invalid), "=q" (valid), "+D" (fault), "=c" (*val) + : "a" (field) + : "memory", "cc"); + + if ( fault && fault_info ) + *fault_info = fault; + + return (fault ? VMXERR_FAULT : 0) | + (valid ? VMXERR_VMFAIL_VALID : 0) | + (invalid ? VMXERR_VMFAIL_INVALID : 0); +} + +uint8_t vmptrld(uint64_t paddr, exinfo_t *fault_info) +{ + exinfo_t fault = 0; + uint8_t valid = 0, invalid = 0; + + asm volatile("1: "VMPTRLD_OPCODE MODRM_EAX_06 "\n\t" + " setc %0; setz %1 \n\t" + "2: \n\t" + _ASM_EXTABLE_HANDLER(1b, 2b, ex_record_fault_edi) + : "=q" (invalid), "=q" (valid), "+D" (fault) + : "a" (&paddr) + : "memory", "cc"); + + if ( fault && fault_info ) + *fault_info = fault; + + return (fault ? VMXERR_FAULT : 0) | + (valid ? VMXERR_VMFAIL_VALID : 0) | + (invalid ? VMXERR_VMFAIL_INVALID : 0); +} + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/tests/vvmx/util.h b/tests/vvmx/util.h new file mode 100644 index 0000000..57d3398 --- /dev/null +++ b/tests/vvmx/util.h @@ -0,0 +1,78 @@ +#ifndef XTF_TESTS_VVMX_UTIL_H +#define XTF_TESTS_VVMX_UTIL_H + +#include <arch/x86/exinfo.h> +#include <arch/x86/hvm/vmx/vmcs.h> + +/** + * Flags for errors during the execution of a VMX instruction. + * + * NB. Besides VMXERR_NOERR, other flags are not mutually exclusive, + * because we should not assume Xen implements the nested VMX + * instructions correctly. + */ +#define VMXERR_NOERR 0 +#define VMXERR_VMFAIL_VALID (1 << 0) +#define VMXERR_VMFAIL_INVALID (1 << 1) +#define VMXERR_FAULT (1 << 2) + +/** + * vmxon + * + * Parameters: + * @paddr: the physical address of the VMXON region + * @fault: return the information of fault encountered in the execution + * + * Return: + * VMXERR_ flags. + * + * If VMXERR_FAULT is present and @fault is not NULL, the fault + * information will be returned via @fault. + */ +uint8_t vmxon(uint64_t paddr, exinfo_t *fault); + +/** + * vmread + * + * Parameters: + * @field: the encoding of the VMCS field to read + * @value: return the value of the VMCS field if no error is encountered + * @fault: return the information of fault encountered in the execution + * + * Return: + * VMXERR_ flags. + * + * If VMXERR_FAULT is present and @fault is not NULL, the fault + * information will be returned via @fault. + * + * If VMXERR_NOERR is returned and @value is not NULL, the value of + * VMCS field @field will be returned via @value. + */ +uint8_t vmread(enum vmcs_field field, uint64_t *value, exinfo_t *fault); + +/** + * vmptrld + * + * Parameters: + * @paddr: the physical address of VMCS + * @fault: return the information of fault encountered in the execution + * + * Return: + * VMXERR_ flags. + * + * If VMXERR_FAULT is present and @fault is not NULL, the fault + * information will be returned via @fault. + */ +uint8_t vmptrld(uint64_t paddr, exinfo_t *fault); + +#endif /* XTF_TESTS_VVMX_UTIL_H */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/tests/vvmx/vmxon.c b/tests/vvmx/vmxon.c new file mode 100644 index 0000000..e69de29 -- 2.10.1 _______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org https://lists.xen.org/xen-devel