xref: /kvm-unit-tests/x86/xsave.c (revision 4c8a99ca02252d4a2bee43f4558fe47ce5ab7ec0)
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_safe(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 XCR_XFEATURE_ENABLED_MASK       0x00000000
46 #define XCR_XFEATURE_ILLEGAL_MASK       0x00000010
47 
48 #define XSTATE_FP       0x1
49 #define XSTATE_SSE      0x2
50 #define XSTATE_YMM      0x4
51 
52 static void test_xsave(void)
53 {
54     unsigned long cr4;
55     uint64_t supported_xcr0;
56     uint64_t test_bits;
57     u64 xcr0;
58 
59     printf("Legal instruction testing:\n");
60 
61     supported_xcr0 = get_supported_xcr0();
62     printf("Supported XCR0 bits: %#lx\n", supported_xcr0);
63 
64     test_bits = XSTATE_FP | XSTATE_SSE;
65     report((supported_xcr0 & test_bits) == test_bits,
66            "Check minimal XSAVE required bits");
67 
68     cr4 = read_cr4();
69     report(write_cr4_safe(cr4 | X86_CR4_OSXSAVE) == 0, "Set CR4 OSXSAVE");
70     report(this_cpu_has(X86_FEATURE_OSXSAVE),
71            "Check CPUID.1.ECX.OSXSAVE - expect 1");
72 
73     printf("\tLegal tests\n");
74     test_bits = XSTATE_FP;
75     report(xsetbv_safe(XCR_XFEATURE_ENABLED_MASK, test_bits) == 0,
76            "\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_FP)");
77 
78     test_bits = XSTATE_FP | XSTATE_SSE;
79     report(xsetbv_safe(XCR_XFEATURE_ENABLED_MASK, test_bits) == 0,
80            "\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_FP | XSTATE_SSE)");
81     report(xgetbv_checking(XCR_XFEATURE_ENABLED_MASK, &xcr0) == 0,
82            "        xgetbv(XCR_XFEATURE_ENABLED_MASK)");
83 
84     printf("\tIllegal tests\n");
85     test_bits = 0;
86     report(xsetbv_safe(XCR_XFEATURE_ENABLED_MASK, test_bits) == GP_VECTOR,
87            "\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, 0) - expect #GP");
88 
89     test_bits = XSTATE_SSE;
90     report(xsetbv_safe(XCR_XFEATURE_ENABLED_MASK, test_bits) == GP_VECTOR,
91            "\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_SSE) - expect #GP");
92 
93     if (supported_xcr0 & XSTATE_YMM) {
94         test_bits = XSTATE_YMM;
95         report(xsetbv_safe(XCR_XFEATURE_ENABLED_MASK, test_bits) == GP_VECTOR,
96                "\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_YMM) - expect #GP");
97 
98         test_bits = XSTATE_FP | XSTATE_YMM;
99         report(xsetbv_safe(XCR_XFEATURE_ENABLED_MASK, test_bits) == GP_VECTOR,
100                "\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_FP | XSTATE_YMM) - expect #GP");
101     }
102 
103     test_bits = XSTATE_SSE;
104     report(xsetbv_safe(XCR_XFEATURE_ILLEGAL_MASK, test_bits) == GP_VECTOR,
105            "\t\txsetbv(XCR_XFEATURE_ILLEGAL_MASK, XSTATE_FP) - expect #GP");
106 
107     test_bits = XSTATE_SSE;
108     report(xsetbv_safe(XCR_XFEATURE_ILLEGAL_MASK, test_bits) == GP_VECTOR,
109            "\t\txgetbv(XCR_XFEATURE_ILLEGAL_MASK, XSTATE_FP) - expect #GP");
110 
111     cr4 &= ~X86_CR4_OSXSAVE;
112     report(write_cr4_safe(cr4) == 0, "Unset CR4 OSXSAVE");
113     report(this_cpu_has(X86_FEATURE_OSXSAVE) == 0,
114            "Check CPUID.1.ECX.OSXSAVE - expect 0");
115 
116     printf("\tIllegal tests:\n");
117     test_bits = XSTATE_FP;
118     report(xsetbv_safe(XCR_XFEATURE_ENABLED_MASK, test_bits) == UD_VECTOR,
119            "\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_FP) - expect #UD");
120 
121     test_bits = XSTATE_FP | XSTATE_SSE;
122     report(xsetbv_safe(XCR_XFEATURE_ENABLED_MASK, test_bits) == UD_VECTOR,
123            "\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_FP | XSTATE_SSE) - expect #UD");
124 
125     printf("\tIllegal tests:\n");
126     report(xgetbv_checking(XCR_XFEATURE_ENABLED_MASK, &xcr0) == UD_VECTOR,
127            "\txgetbv(XCR_XFEATURE_ENABLED_MASK) - expect #UD");
128 }
129 
130 static void test_no_xsave(void)
131 {
132     unsigned long cr4;
133     u64 xcr0;
134 
135     report(this_cpu_has(X86_FEATURE_OSXSAVE) == 0,
136            "Check CPUID.1.ECX.OSXSAVE - expect 0");
137 
138     printf("Illegal instruction testing:\n");
139 
140     cr4 = read_cr4();
141     report(write_cr4_safe(cr4 | X86_CR4_OSXSAVE) == GP_VECTOR,
142            "Set OSXSAVE in CR4 - expect #GP");
143 
144     report(xgetbv_checking(XCR_XFEATURE_ENABLED_MASK, &xcr0) == UD_VECTOR,
145            "Execute xgetbv - expect #UD");
146 
147     report(xsetbv_safe(XCR_XFEATURE_ENABLED_MASK, 0x3) == UD_VECTOR,
148            "Execute xsetbv - expect #UD");
149 }
150 
151 int main(void)
152 {
153     if (this_cpu_has(X86_FEATURE_XSAVE)) {
154         printf("CPU has XSAVE feature\n");
155         test_xsave();
156     } else {
157         printf("CPU don't has XSAVE feature\n");
158         test_no_xsave();
159     }
160     return report_summary();
161 }
162