xref: /kvm-unit-tests/x86/xsave.c (revision 2c96b77ec9d3b1fcec7525174e23a6240ee05949)
1 #include "libcflat.h"
2 #include "desc.h"
3 #include "processor.h"
4 
5 #ifdef __x86_64__
6 #define uint64_t unsigned long
7 #else
8 #define uint64_t unsigned long long
9 #endif
10 
11 static int xgetbv_checking(u32 index, u64 *result)
12 {
13     u32 eax, edx;
14 
15     asm volatile(ASM_TRY("1f")
16             ".byte 0x0f,0x01,0xd0\n\t" /* xgetbv */
17             "1:"
18             : "=a" (eax), "=d" (edx)
19             : "c" (index));
20     *result = eax + ((u64)edx << 32);
21     return exception_vector();
22 }
23 
24 static int xsetbv_checking(u32 index, u64 value)
25 {
26     u32 eax = value;
27     u32 edx = value >> 32;
28 
29     asm volatile(ASM_TRY("1f")
30             ".byte 0x0f,0x01,0xd1\n\t" /* xsetbv */
31             "1:"
32             : : "a" (eax), "d" (edx), "c" (index));
33     return exception_vector();
34 }
35 
36 static uint64_t get_supported_xcr0(void)
37 {
38     struct cpuid r;
39     r = cpuid_indexed(0xd, 0);
40     printf("eax %x, ebx %x, ecx %x, edx %x\n",
41             r.a, r.b, r.c, r.d);
42     return r.a + ((u64)r.d << 32);
43 }
44 
45 #define X86_CR4_OSXSAVE			0x00040000
46 #define XCR_XFEATURE_ENABLED_MASK       0x00000000
47 #define XCR_XFEATURE_ILLEGAL_MASK       0x00000010
48 
49 #define XSTATE_FP       0x1
50 #define XSTATE_SSE      0x2
51 #define XSTATE_YMM      0x4
52 
53 static void test_xsave(void)
54 {
55     unsigned long cr4;
56     uint64_t supported_xcr0;
57     uint64_t test_bits;
58     u64 xcr0;
59 
60     printf("Legal instruction testing:\n");
61 
62     supported_xcr0 = get_supported_xcr0();
63     printf("Supported XCR0 bits: %#lx\n", supported_xcr0);
64 
65     test_bits = XSTATE_FP | XSTATE_SSE;
66     report((supported_xcr0 & test_bits) == test_bits,
67            "Check minimal XSAVE required bits");
68 
69     cr4 = read_cr4();
70     report(write_cr4_checking(cr4 | X86_CR4_OSXSAVE) == 0, "Set CR4 OSXSAVE");
71     report(this_cpu_has(X86_FEATURE_OSXSAVE),
72            "Check CPUID.1.ECX.OSXSAVE - expect 1");
73 
74     printf("\tLegal tests\n");
75     test_bits = XSTATE_FP;
76     report(xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits) == 0,
77            "\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_FP)");
78 
79     test_bits = XSTATE_FP | XSTATE_SSE;
80     report(xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits) == 0,
81            "\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_FP | XSTATE_SSE)");
82     report(xgetbv_checking(XCR_XFEATURE_ENABLED_MASK, &xcr0) == 0,
83            "        xgetbv(XCR_XFEATURE_ENABLED_MASK)");
84 
85     printf("\tIllegal tests\n");
86     test_bits = 0;
87     report(xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits) == GP_VECTOR,
88            "\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, 0) - expect #GP");
89 
90     test_bits = XSTATE_SSE;
91     report(xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits) == GP_VECTOR,
92            "\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_SSE) - expect #GP");
93 
94     if (supported_xcr0 & XSTATE_YMM) {
95         test_bits = XSTATE_YMM;
96         report(xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits) == GP_VECTOR,
97                "\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_YMM) - expect #GP");
98 
99         test_bits = XSTATE_FP | XSTATE_YMM;
100         report(xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits) == GP_VECTOR,
101                "\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_FP | XSTATE_YMM) - expect #GP");
102     }
103 
104     test_bits = XSTATE_SSE;
105     report(xsetbv_checking(XCR_XFEATURE_ILLEGAL_MASK, test_bits) == GP_VECTOR,
106            "\t\txsetbv(XCR_XFEATURE_ILLEGAL_MASK, XSTATE_FP) - expect #GP");
107 
108     test_bits = XSTATE_SSE;
109     report(xsetbv_checking(XCR_XFEATURE_ILLEGAL_MASK, test_bits) == GP_VECTOR,
110            "\t\txgetbv(XCR_XFEATURE_ILLEGAL_MASK, XSTATE_FP) - expect #GP");
111 
112     cr4 &= ~X86_CR4_OSXSAVE;
113     report(write_cr4_checking(cr4) == 0, "Unset CR4 OSXSAVE");
114     report(this_cpu_has(X86_FEATURE_OSXSAVE) == 0,
115            "Check CPUID.1.ECX.OSXSAVE - expect 0");
116 
117     printf("\tIllegal tests:\n");
118     test_bits = XSTATE_FP;
119     report(xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits) == UD_VECTOR,
120            "\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_FP) - expect #UD");
121 
122     test_bits = XSTATE_FP | XSTATE_SSE;
123     report(xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits) == UD_VECTOR,
124            "\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_FP | XSTATE_SSE) - expect #UD");
125 
126     printf("\tIllegal tests:\n");
127     report(xgetbv_checking(XCR_XFEATURE_ENABLED_MASK, &xcr0) == UD_VECTOR,
128            "\txgetbv(XCR_XFEATURE_ENABLED_MASK) - expect #UD");
129 }
130 
131 static void test_no_xsave(void)
132 {
133     unsigned long cr4;
134     u64 xcr0;
135 
136     report(this_cpu_has(X86_FEATURE_OSXSAVE) == 0,
137            "Check CPUID.1.ECX.OSXSAVE - expect 0");
138 
139     printf("Illegal instruction testing:\n");
140 
141     cr4 = read_cr4();
142     report(write_cr4_checking(cr4 | X86_CR4_OSXSAVE) == GP_VECTOR,
143            "Set OSXSAVE in CR4 - expect #GP");
144 
145     report(xgetbv_checking(XCR_XFEATURE_ENABLED_MASK, &xcr0) == UD_VECTOR,
146            "Execute xgetbv - expect #UD");
147 
148     report(xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, 0x3) == UD_VECTOR,
149            "Execute xsetbv - expect #UD");
150 }
151 
152 int main(void)
153 {
154     if (this_cpu_has(X86_FEATURE_XSAVE)) {
155         printf("CPU has XSAVE feature\n");
156         test_xsave();
157     } else {
158         printf("CPU don't has XSAVE feature\n");
159         test_no_xsave();
160     }
161     return report_summary();
162 }
163