blob: 54905e06c83543d315887eae8404a68e391dbc89 [file] [log] [blame]
#include "libcflat.h"
#include "desc.h"
#include "processor.h"
char __attribute__((aligned(32))) v32_1[32];
char __attribute__((aligned(32))) v32_2[32];
char __attribute__((aligned(32))) v32_3[32];
static void initialize_avx_buffers(void)
{
int i;
for (i = 0; i < ARRAY_SIZE(v32_1); i++)
v32_1[i] = (char)rdtsc();
memset(v32_2, 0, sizeof(v32_2));
memset(v32_3, 0, sizeof(v32_3));
}
#define __TEST_VMOVDQA(reg1, reg2, FEP) \
do { \
asm volatile(FEP "vmovdqa v32_1(%%rip), %%" #reg1 "\n" \
FEP "vmovdqa %%" #reg1 ", %%" #reg2 "\n" \
FEP "vmovdqa %%" #reg2 ", v32_2(%%rip)\n" \
"vmovdqa %%" #reg2 ", v32_3(%%rip)\n" \
::: "memory", #reg1, #reg2); \
\
report(!memcmp(v32_1, v32_2, sizeof(v32_1)), \
"%s VMOVDQA using " #reg1 " and " #reg2, \
strlen(FEP) ? "Emulated" : "Native"); \
report(!memcmp(v32_1, v32_3, sizeof(v32_1)), \
"%s VMOVDQA using " #reg1 " and " #reg2, \
strlen(FEP) ? "Emulated+Native" : "Native"); \
} while (0)
#define TEST_VMOVDQA(r1, r2) \
do { \
initialize_avx_buffers(); \
\
__TEST_VMOVDQA(ymm##r1, ymm##r2, ""); \
\
if (is_fep_available) \
__TEST_VMOVDQA(ymm##r1, ymm##r2, KVM_FEP); \
} while (0)
static void test_write_xcr0(u64 val)
{
write_xcr0(val);
report(read_xcr0() == val,
"Wanted XCR0 == 0x%lx, got XCR0 == 0x%lx", val, read_xcr0());
}
static __attribute__((target("avx"))) void test_avx_vmovdqa(void)
{
test_write_xcr0(XFEATURE_MASK_FP_SSE | XFEATURE_MASK_YMM);
TEST_VMOVDQA(0, 15);
TEST_VMOVDQA(1, 14);
TEST_VMOVDQA(2, 13);
TEST_VMOVDQA(3, 12);
TEST_VMOVDQA(4, 11);
TEST_VMOVDQA(5, 10);
TEST_VMOVDQA(6, 9);
TEST_VMOVDQA(7, 8);
TEST_VMOVDQA(8, 7);
TEST_VMOVDQA(9, 6);
TEST_VMOVDQA(10, 5);
TEST_VMOVDQA(11, 4);
TEST_VMOVDQA(12, 3);
TEST_VMOVDQA(13, 2);
TEST_VMOVDQA(14, 2);
TEST_VMOVDQA(15, 1);
}
static void test_unsupported_xcrs(void)
{
u64 ign;
int i;
for (i = 1; i < 64; i++) {
/* XGETBV(1) returns "XCR0 & XINUSE" on some CPUs. */
if (i != 1)
report(xgetbv_safe(i, &ign) == GP_VECTOR,
"XGETBV(%u) - expect #GP", i);
report(xsetbv_safe(i, XFEATURE_MASK_FP) == GP_VECTOR,
"XSETBV(%u, FP) - expect #GP", i);
report(xsetbv_safe(i, XFEATURE_MASK_FP_SSE) == GP_VECTOR,
"XSETBV(%u, FP|SSE) - expect #GP", i);
/*
* RCX[63:32] are ignored by XGETBV and XSETBV, i.e. testing
* bits set above 31 will access XCR0.
*/
if (i > 31)
continue;
report(xgetbv_safe(BIT(i), &ign) == GP_VECTOR,
"XGETBV(0x%lx) - expect #GP", BIT(i));
report(xsetbv_safe(BIT(i), XFEATURE_MASK_FP) == GP_VECTOR,
"XSETBV(0x%lx, FP) - expect #GP", BIT(i));
report(xsetbv_safe(BIT(i), XFEATURE_MASK_FP_SSE) == GP_VECTOR,
"XSETBV(0x%lx, FP|SSE) - expect #GP", BIT(i));
}
}
static void test_xsave(void)
{
u64 supported_xcr0;
unsigned long cr4;
printf("Legal instruction testing:\n");
supported_xcr0 = this_cpu_supported_xcr0();
printf("Supported XCR0 bits: %#lx\n", supported_xcr0);
report((supported_xcr0 & XFEATURE_MASK_FP_SSE) == XFEATURE_MASK_FP_SSE,
"FP and SSE should always be supported in XCR0");
cr4 = read_cr4();
write_cr4(cr4 | X86_CR4_OSXSAVE);
report(this_cpu_has(X86_FEATURE_OSXSAVE),
"Check CPUID.1.ECX.OSXSAVE - expect 1");
printf("\tLegal tests\n");
test_write_xcr0(XFEATURE_MASK_FP);
test_write_xcr0(XFEATURE_MASK_FP_SSE);
if (supported_xcr0 & XFEATURE_MASK_YMM)
test_avx_vmovdqa();
printf("\tIllegal tests\n");
report(write_xcr0_safe(0) == GP_VECTOR,
"\t\tWrite XCR0 = 0 - expect #GP");
report(write_xcr0_safe(XFEATURE_MASK_SSE) == GP_VECTOR,
"\t\tWrite XCR0 = SSE - expect #GP");
if (supported_xcr0 & XFEATURE_MASK_YMM) {
report(write_xcr0_safe(XFEATURE_MASK_YMM) == GP_VECTOR,
"\t\tWrite XCR0 = YMM - expect #GP");
report(write_xcr0_safe(XFEATURE_MASK_FP | XFEATURE_MASK_YMM) == GP_VECTOR,
"\t\tWrite XCR0 = (FP | YMM) - expect #GP");
}
test_unsupported_xcrs();
write_cr4(cr4);
report(this_cpu_has(X86_FEATURE_OSXSAVE) == !!(cr4 & X86_CR4_OSXSAVE),
"CPUID.1.ECX.OSXSAVE == CR4.OSXSAVE");
}
static void test_no_xsave(void)
{
unsigned long cr4 = read_cr4();
u64 xcr0;
if (cr4 & X86_CR4_OSXSAVE)
write_cr4(cr4 & ~X86_CR4_OSXSAVE);
report(this_cpu_has(X86_FEATURE_OSXSAVE) == 0,
"Check CPUID.1.ECX.OSXSAVE - expect 0");
report(read_xcr0_safe(&xcr0) == UD_VECTOR,
"Read XCR0 without OSXSAVE enabled - expect #UD");
report(write_xcr0_safe(XFEATURE_MASK_FP_SSE) == UD_VECTOR,
"Write XCR0=(FP|SSE) without XSAVE support - expect #UD");
if (cr4 & X86_CR4_OSXSAVE)
write_cr4(cr4);
}
int main(void)
{
test_no_xsave();
if (this_cpu_has(X86_FEATURE_XSAVE)) {
test_xsave();
} else {
report_skip("XSAVE unsupported, skipping positive tests");
report(write_cr4_safe(read_cr4() | X86_CR4_OSXSAVE) == GP_VECTOR,
"Set CR4.OSXSAVE without XSAVE- expect #GP");
}
return report_summary();
}