Only test legal action so far, we can extend it later.

Signed-off-by: Sheng Yang <[email protected]>
---
 kvm/test/config-x86-common.mak |    5 +-
 kvm/test/x86/xsave.c           |  173 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 177 insertions(+), 1 deletions(-)
 create mode 100644 kvm/test/x86/xsave.c

diff --git a/kvm/test/config-x86-common.mak b/kvm/test/config-x86-common.mak
index 9084e2d..2110e4e 100644
--- a/kvm/test/config-x86-common.mak
+++ b/kvm/test/config-x86-common.mak
@@ -24,7 +24,8 @@ FLATLIBS = lib/libcflat.a $(libgcc)
 
 tests-common = $(TEST_DIR)/vmexit.flat $(TEST_DIR)/tsc.flat \
                $(TEST_DIR)/smptest.flat  $(TEST_DIR)/port80.flat \
-               $(TEST_DIR)/realmode.flat $(TEST_DIR)/msr.flat
+               $(TEST_DIR)/realmode.flat $(TEST_DIR)/msr.flat \
+               $(TEST_DIR)/xsave.flat
 
 test_cases: $(tests-common) $(tests)
 
@@ -58,6 +59,8 @@ $(TEST_DIR)/realmode.o: bits = 32
 
 $(TEST_DIR)/msr.flat: $(cstart.o) $(TEST_DIR)/msr.o
 
+$(TEST_DIR)/xsave.flat: $(cstart.o) $(TEST_DIR)/xsave.o
+
 arch_clean:
        $(RM) $(TEST_DIR)/*.o $(TEST_DIR)/*.flat \
        $(TEST_DIR)/.*.d $(TEST_DIR)/lib/.*.d $(TEST_DIR)/lib/*.o
diff --git a/kvm/test/x86/xsave.c b/kvm/test/x86/xsave.c
new file mode 100644
index 0000000..2d6ea07
--- /dev/null
+++ b/kvm/test/x86/xsave.c
@@ -0,0 +1,173 @@
+#include "libcflat.h"
+
+#ifdef __x86_64__
+#define uint64_t unsigned long
+#else
+#define uint64_t unsigned long long
+#endif
+
+static inline void __cpuid(unsigned int *eax, unsigned int *ebx,
+                               unsigned int *ecx, unsigned int *edx)
+{
+       /* ecx is often an input as well as an output. */
+       asm volatile("cpuid"
+           : "=a" (*eax),
+             "=b" (*ebx),
+             "=c" (*ecx),
+             "=d" (*edx)
+           : "0" (*eax), "2" (*ecx));
+}
+
+/*
+ * Generic CPUID function
+ * clear %ecx since some cpus (Cyrix MII) do not set or clear %ecx
+ * resulting in stale register contents being returned.
+ */
+void cpuid(unsigned int op,
+                unsigned int *eax, unsigned int *ebx,
+                unsigned int *ecx, unsigned int *edx)
+{
+       *eax = op;
+       *ecx = 0;
+       __cpuid(eax, ebx, ecx, edx);
+}
+
+/* Some CPUID calls want 'count' to be placed in ecx */
+void cpuid_count(unsigned int op, int count,
+                      unsigned int *eax, unsigned int *ebx,
+                      unsigned int *ecx, unsigned int *edx)
+{
+       *eax = op;
+       *ecx = count;
+       __cpuid(eax, ebx, ecx, edx);
+}
+
+u64 xgetbv(u32 index)
+{
+       u32 eax, edx;
+
+       asm volatile(".byte 0x0f,0x01,0xd0" /* xgetbv */
+                    : "=a" (eax), "=d" (edx)
+                    : "c" (index));
+       return eax + ((u64)edx << 32);
+}
+
+void xsetbv(u32 index, u64 value)
+{
+       u32 eax = value;
+       u32 edx = value >> 32;
+
+       asm volatile(".byte 0x0f,0x01,0xd1" /* xsetbv */
+                    : : "a" (eax), "d" (edx), "c" (index));
+}
+
+unsigned long read_cr4(void)
+{
+       unsigned long val;
+       asm volatile("mov %%cr4,%0" : "=r" (val));
+       return val;
+}
+
+void write_cr4(unsigned long val)
+{
+       asm volatile("mov %0,%%cr4": : "r" (val));
+}
+
+#define CPUID_1_ECX_XSAVE          (1 << 26)
+int check_xsave()
+{
+       unsigned int eax, ebx, ecx, edx;
+       cpuid(1, &eax, &ebx, &ecx, &edx);
+       if (ecx & CPUID_1_ECX_XSAVE)
+               return 1;
+       return 0;
+}
+
+uint64_t get_supported_xcr0()
+{
+       unsigned int eax, ebx, ecx, edx;
+       cpuid_count(0xd, 0, &eax, &ebx, &ecx, &edx);
+       printf("eax %x, ebx %x, ecx %x, edx %x\n",
+               eax, ebx, ecx, edx);
+       return eax + ((u64)edx << 32);
+}
+
+#define X86_CR4_OSXSAVE                        0x00040000
+#define XCR_XFEATURE_ENABLED_MASK       0x00000000
+
+#define XSTATE_FP       0x1
+#define XSTATE_SSE      0x2
+#define XSTATE_YMM      0x4
+
+static unsigned int fault_mask;
+
+void pass_if(int condition)
+{
+       if (condition)
+               printf("Pass!\n");
+       else
+               printf("Fail!\n");
+}
+
+void pass_if_no_fault(void)
+{
+       pass_if(!fault_mask);
+       fault_mask = 0;
+}
+
+void pass_if_fault(unsigned int fault_bit)
+{
+       pass_if(fault_mask & fault_bit);
+       fault_mask = 0;
+}
+
+#define UD_VECTOR_MASK     (1 << 6)
+#define GP_VECTOR_MASK     (1 << 13)
+
+void test_xsave()
+{
+       unsigned int cr4;
+       uint64_t supported_xcr0;
+       uint64_t test_bits;
+
+       supported_xcr0 = get_supported_xcr0();
+       printf("Supported XCR0 bits: 0x%x\n", supported_xcr0);
+
+       printf("Check minimal XSAVE required bits: ");
+       test_bits = XSTATE_FP | XSTATE_SSE | XSTATE_YMM;
+       pass_if((supported_xcr0 & test_bits) == test_bits);
+
+       printf("Check CR4 OSXSAVE: ");
+       cr4 = read_cr4();
+       write_cr4(cr4 | X86_CR4_OSXSAVE);
+       pass_if_no_fault();
+
+       printf("Check XSETBV for XCR0 bits\n");
+       printf("    Legal tests\n");
+       printf("    XSTATE_FP: ");
+       test_bits = XSTATE_FP;
+       xsetbv(XCR_XFEATURE_ENABLED_MASK, test_bits);
+       pass_if_no_fault();
+       printf("    XSTATE_FP | XSTATE_SSE: ");
+       test_bits = XSTATE_FP | XSTATE_SSE;
+       xsetbv(XCR_XFEATURE_ENABLED_MASK, test_bits);
+       pass_if_no_fault();
+       printf("    XSTATE_FP | XSTATE_SSE | XSTATE_YMM: ");
+       test_bits = XSTATE_FP | XSTATE_SSE | XSTATE_YMM;
+       xsetbv(XCR_XFEATURE_ENABLED_MASK, test_bits);
+       pass_if_no_fault();
+}
+
+int main()
+{
+       int cpuid_has_xsave;
+
+       cpuid_has_xsave = check_xsave();
+       if (cpuid_has_xsave) {
+               printf("CPU has XSAVE feature\n");
+               test_xsave();
+       } else
+               printf("CPU don't has XSAVE feature\n");
+       return 0;
+}
+
-- 
1.7.0.1

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to