Only test legal action so far, we can extend it later. Signed-off-by: Sheng Yang <sheng@xxxxxxxxxxxxxxx> --- 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 majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html