All of lore.kernel.org
 help / color / mirror / Atom feed
From: Sheng Yang <sheng@linux.intel.com>
To: Avi Kivity <avi@redhat.com>
Cc: Marcelo Tosatti <mtosatti@redhat.com>,
	kvm@vger.kernel.org, Sheng Yang <sheng@linux.intel.com>
Subject: [PATCH v4] test: Add XSAVE unit test
Date: Sun, 13 Jun 2010 16:32:17 +0800	[thread overview]
Message-ID: <1276417937-6191-1-git-send-email-sheng@linux.intel.com> (raw)
In-Reply-To: <4C14940D.1050900@redhat.com>

Based on IDT test framework.

Signed-off-by: Sheng Yang <sheng@linux.intel.com>
---
 kvm/test/config-x86-common.mak |    2 +
 kvm/test/config-x86_64.mak     |    3 +-
 kvm/test/x86/xsave.c           |  262 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 266 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 800b635..0e1ccce 100644
--- a/kvm/test/config-x86-common.mak
+++ b/kvm/test/config-x86-common.mak
@@ -61,6 +61,8 @@ $(TEST_DIR)/msr.flat: $(cstart.o) $(TEST_DIR)/msr.o
 
 $(TEST_DIR)/idt_test.flat: $(cstart.o) $(TEST_DIR)/idt.o $(TEST_DIR)/idt_test.o
 
+$(TEST_DIR)/xsave.flat: $(cstart.o) $(TEST_DIR)/idt.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/config-x86_64.mak b/kvm/test/config-x86_64.mak
index f9cd121..2da2906 100644
--- a/kvm/test/config-x86_64.mak
+++ b/kvm/test/config-x86_64.mak
@@ -5,6 +5,7 @@ ldarch = elf64-x86-64
 CFLAGS += -D__x86_64__
 
 tests = $(TEST_DIR)/access.flat $(TEST_DIR)/apic.flat \
-	  $(TEST_DIR)/emulator.flat $(TEST_DIR)/idt_test.flat
+	  $(TEST_DIR)/emulator.flat $(TEST_DIR)/idt_test.flat \
+	  $(TEST_DIR)/xsave.flat
 
 include config-x86-common.mak
diff --git a/kvm/test/x86/xsave.c b/kvm/test/x86/xsave.c
new file mode 100644
index 0000000..d5cd2d8
--- /dev/null
+++ b/kvm/test/x86/xsave.c
@@ -0,0 +1,262 @@
+#include "libcflat.h"
+#include "idt.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);
+}
+
+int xgetbv_checking(u32 index, u64 *result)
+{
+    u32 eax, edx;
+
+    asm volatile(ASM_TRY("1f")
+            ".byte 0x0f,0x01,0xd0\n\t" /* xgetbv */
+            "1:"
+            : "=a" (eax), "=d" (edx)
+            : "c" (index));
+    *result = eax + ((u64)edx << 32);
+    return exception_vector();
+}
+
+int xsetbv_checking(u32 index, u64 value)
+{
+    u32 eax = value;
+    u32 edx = value >> 32;
+
+    asm volatile(ASM_TRY("1f")
+            ".byte 0x0f,0x01,0xd1\n\t" /* xsetbv */
+            "1:"
+            : : "a" (eax), "d" (edx), "c" (index));
+    return exception_vector();
+}
+
+unsigned long read_cr4(void)
+{
+    unsigned long val;
+    asm volatile("mov %%cr4,%0" : "=r" (val));
+    return val;
+}
+
+int write_cr4_checking(unsigned long val)
+{
+    asm volatile(ASM_TRY("1f")
+            "mov %0,%%cr4\n\t"
+            "1:": : "r" (val));
+    return exception_vector();
+}
+
+#define CPUID_1_ECX_XSAVE	    (1 << 26)
+#define CPUID_1_ECX_OSXSAVE	    (1 << 27)
+int check_cpuid_1_ecx(unsigned int bit)
+{
+    unsigned int eax, ebx, ecx, edx;
+    cpuid(1, &eax, &ebx, &ecx, &edx);
+    if (ecx & bit)
+        return 1;
+    return 0;
+}
+
+uint64_t get_supported_xcr0(void)
+{
+    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 XCR_XFEATURE_ILLEGAL_MASK       0x00000010
+
+#define XSTATE_FP       0x1
+#define XSTATE_SSE      0x2
+#define XSTATE_YMM      0x4
+
+static int total_tests, fail_tests;
+
+void pass_if(int condition)
+{
+    total_tests ++;
+    if (condition)
+        printf("Pass!\n");
+    else {
+        printf("Fail!\n");
+        fail_tests ++;
+    }
+}
+
+void test_xsave(void)
+{
+    unsigned long cr4;
+    uint64_t supported_xcr0;
+    uint64_t test_bits;
+    u64 xcr0;
+    int r;
+
+    printf("Legal instruction testing:\n");
+    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;
+    pass_if((supported_xcr0 & test_bits) == test_bits);
+
+    printf("Set CR4 OSXSAVE: ");
+    cr4 = read_cr4();
+    r = write_cr4_checking(cr4 | X86_CR4_OSXSAVE);
+    pass_if(r == 0);
+
+    printf("Check CPUID.1.ECX.OSXSAVE - expect 1: ");
+    pass_if(check_cpuid_1_ecx(CPUID_1_ECX_OSXSAVE));
+
+    printf("    Legal tests\n");
+    printf("        xsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_FP): ");
+    test_bits = XSTATE_FP;
+    r = xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits);
+    pass_if(r == 0);
+    printf("        xsetbv(XCR_XFEATURE_ENABLED_MASK, "
+            "XSTATE_FP | XSTATE_SSE): ");
+    test_bits = XSTATE_FP | XSTATE_SSE;
+    r = xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits);
+    pass_if(r == 0);
+    printf("        xgetbv(XCR_XFEATURE_ENABLED_MASK): ");
+    r = xgetbv_checking(XCR_XFEATURE_ENABLED_MASK, &xcr0);
+    pass_if(r == 0);
+    printf("    Illegal tests\n");
+    printf("        xsetbv(XCR_XFEATURE_ENABLED_MASK, 0) - expect #GP: ");
+    test_bits = 0;
+    r = xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits);
+    pass_if(r == GP_VECTOR);
+    printf("        xsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_SSE) "
+            "- expect #GP: ");
+    test_bits = XSTATE_SSE;
+    r = xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits);
+    pass_if(r == GP_VECTOR);
+    if (supported_xcr0 & XSTATE_YMM) {
+        printf("        xsetbv(XCR_XFEATURE_ENABLED_MASK, "
+                "XSTATE_YMM) - expect #GP: ");
+        test_bits = XSTATE_YMM;
+        r = xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits);
+        pass_if(r == GP_VECTOR);
+        printf("        xsetbv(XCR_XFEATURE_ENABLED_MASK, "
+                "XSTATE_FP | XSTATE_YMM) - expect #GP: ");
+        test_bits = XSTATE_FP | XSTATE_YMM;
+        r = xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits);
+        pass_if(r == GP_VECTOR);
+    }
+    printf("        xsetbv(XCR_XFEATURE_ILLEGAL_MASK, XSTATE_FP) "
+            "- expect #GP: ");
+    test_bits = XSTATE_SSE;
+    r = xsetbv_checking(XCR_XFEATURE_ILLEGAL_MASK, test_bits);
+    pass_if(r == GP_VECTOR);
+    printf("        xgetbv(XCR_XFEATURE_ILLEGAL_MASK, XSTATE_FP) "
+            "- expect #GP: ");
+    test_bits = XSTATE_SSE;
+    r = xsetbv_checking(XCR_XFEATURE_ILLEGAL_MASK, test_bits);
+    pass_if(r == GP_VECTOR);
+
+    printf("Unset CR4 OSXSAVE: ");
+    cr4 &= ~X86_CR4_OSXSAVE;
+    r = write_cr4_checking(cr4);
+    pass_if(r == 0);
+    printf("Check CPUID.1.ECX.OSXSAVE - expect 0: ");
+    pass_if(check_cpuid_1_ecx(CPUID_1_ECX_OSXSAVE) == 0);
+    printf("    Illegal tests:\n");
+    printf("        xsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_FP) - expect #UD: ");
+    test_bits = XSTATE_FP;
+    r = xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits);
+    pass_if(r == UD_VECTOR);
+    printf("        xsetbv(XCR_XFEATURE_ENABLED_MASK, "
+            "XSTATE_FP | XSTATE_SSE) - expect #UD: ");
+    test_bits = XSTATE_FP | XSTATE_SSE;
+    r = xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits);
+    pass_if(r == UD_VECTOR);
+    printf("    Illegal tests:\n");
+    printf("	xgetbv(XCR_XFEATURE_ENABLED_MASK) - expect #UD: ");
+    r = xgetbv_checking(XCR_XFEATURE_ENABLED_MASK, &xcr0);
+    pass_if(r == UD_VECTOR);
+}
+
+void test_no_xsave(void)
+{
+    unsigned long cr4;
+    u64 xcr0;
+    int r;
+
+    printf("Check CPUID.1.ECX.OSXSAVE - expect 0: ");
+    pass_if(check_cpuid_1_ecx(CPUID_1_ECX_OSXSAVE) == 0);
+
+    printf("Illegal instruction testing:\n");
+
+    printf("Set OSXSAVE in CR4 - expect #GP: ");
+    cr4 = read_cr4();
+    r = write_cr4_checking(cr4 | X86_CR4_OSXSAVE);
+    pass_if(r == GP_VECTOR);
+
+    printf("Execute xgetbv - expect #UD: ");
+    r = xgetbv_checking(XCR_XFEATURE_ENABLED_MASK, &xcr0);
+    pass_if(r == UD_VECTOR);
+
+    printf("Execute xsetbv - expect #UD: ");
+    r = xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, 0x3);
+    pass_if(r == UD_VECTOR);
+}
+
+int main(void)
+{
+    setup_idt();
+    if (check_cpuid_1_ecx(CPUID_1_ECX_XSAVE)) {
+        printf("CPU has XSAVE feature\n");
+        test_xsave();
+    } else {
+        printf("CPU don't has XSAVE feature\n");
+        test_no_xsave();
+    }
+    printf("Total test: %d\n", total_tests);
+    if (fail_tests == 0)
+        printf("ALL PASS!\n");
+    else {
+        printf("Fail %d tests.\n", fail_tests);
+        return 0;
+    }
+    return 1;
+}
-- 
1.7.0.1


  reply	other threads:[~2010-06-13  8:31 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-06-11  7:45 [PATCH v3] test: Add XSAVE unit test Sheng Yang
2010-06-13  8:17 ` Avi Kivity
2010-06-13  8:32   ` Sheng Yang [this message]
2010-06-13  8:43     ` [PATCH v4] " Avi Kivity
2010-06-13  8:47       ` Sheng Yang
2010-06-13  8:49       ` Sheng Yang
2010-06-14 20:43         ` Marcelo Tosatti

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1276417937-6191-1-git-send-email-sheng@linux.intel.com \
    --to=sheng@linux.intel.com \
    --cc=avi@redhat.com \
    --cc=kvm@vger.kernel.org \
    --cc=mtosatti@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.