blob: cd2cdceefca263e03379da7d9e00ec4b7bd4a241 [file] [log] [blame]
#include "libcflat.h"
#include "desc.h"
#include "processor.h"
#ifdef __x86_64__
#define uint64_t unsigned long
#else
#define uint64_t unsigned long long
#endif
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();
}
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)
{
return (cpuid(1).c & bit) != 0;
}
uint64_t get_supported_xcr0(void)
{
struct cpuid r;
r = cpuid_indexed(0xd, 0);
printf("eax %x, ebx %x, ecx %x, edx %x\n",
r.a, r.b, r.c, r.d);
return r.a + ((u64)r.d << 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 1;
}
return 0;
}