[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [XTF PATCH 04/16] vvmx: add C wrappers of vmxon/vmread/vmptrld



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.zhang@xxxxxxxxx>
---
 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@xxxxxxxxxxxxx
https://lists.xen.org/xen-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.