xref: /kvm-unit-tests/x86/pcid.c (revision b44d84dae10c1c835e2bb8e8ec4a308dea869c1e)
1*b44d84daSMao, Junjie /* Basic PCID & INVPCID functionality test */
2*b44d84daSMao, Junjie 
3*b44d84daSMao, Junjie #include "libcflat.h"
4*b44d84daSMao, Junjie #include "processor.h"
5*b44d84daSMao, Junjie #include "desc.h"
6*b44d84daSMao, Junjie 
7*b44d84daSMao, Junjie int nr_passed, nr_tests;
8*b44d84daSMao, Junjie 
9*b44d84daSMao, Junjie #define X86_FEATURE_PCID       (1 << 17)
10*b44d84daSMao, Junjie #define X86_FEATURE_INVPCID    (1 << 10)
11*b44d84daSMao, Junjie 
12*b44d84daSMao, Junjie #define X86_CR0_PG             (1 << 31)
13*b44d84daSMao, Junjie #define X86_CR3_PCID_MASK      0x00000fff
14*b44d84daSMao, Junjie #define X86_CR4_PCIDE          (1 << 17)
15*b44d84daSMao, Junjie 
16*b44d84daSMao, Junjie #define X86_IA32_EFER          0xc0000080
17*b44d84daSMao, Junjie #define X86_EFER_LMA           (1UL << 8)
18*b44d84daSMao, Junjie 
19*b44d84daSMao, Junjie struct invpcid_desc {
20*b44d84daSMao, Junjie     unsigned long pcid : 12;
21*b44d84daSMao, Junjie     unsigned long rsv  : 52;
22*b44d84daSMao, Junjie     unsigned long addr : 64;
23*b44d84daSMao, Junjie };
24*b44d84daSMao, Junjie 
25*b44d84daSMao, Junjie static void report(const char *name, int passed)
26*b44d84daSMao, Junjie {
27*b44d84daSMao, Junjie     ++nr_tests;
28*b44d84daSMao, Junjie     if (passed)
29*b44d84daSMao, Junjie         ++nr_passed;
30*b44d84daSMao, Junjie     printf("%s: %s\n", name, passed ? "PASS" : "FAIL");
31*b44d84daSMao, Junjie }
32*b44d84daSMao, Junjie 
33*b44d84daSMao, Junjie int write_cr0_checking(unsigned long val)
34*b44d84daSMao, Junjie {
35*b44d84daSMao, Junjie     asm volatile(ASM_TRY("1f")
36*b44d84daSMao, Junjie                  "mov %0, %%cr0\n\t"
37*b44d84daSMao, Junjie                  "1:": : "r" (val));
38*b44d84daSMao, Junjie     return exception_vector();
39*b44d84daSMao, Junjie }
40*b44d84daSMao, Junjie 
41*b44d84daSMao, Junjie int write_cr4_checking(unsigned long val)
42*b44d84daSMao, Junjie {
43*b44d84daSMao, Junjie     asm volatile(ASM_TRY("1f")
44*b44d84daSMao, Junjie                  "mov %0, %%cr4\n\t"
45*b44d84daSMao, Junjie                  "1:": : "r" (val));
46*b44d84daSMao, Junjie     return exception_vector();
47*b44d84daSMao, Junjie }
48*b44d84daSMao, Junjie 
49*b44d84daSMao, Junjie int invpcid_checking(unsigned long type, void *desc)
50*b44d84daSMao, Junjie {
51*b44d84daSMao, Junjie     asm volatile (ASM_TRY("1f")
52*b44d84daSMao, Junjie                   ".byte 0x66,0x0f,0x38,0x82,0x18 \n\t" /* invpcid (%rax), %rbx */
53*b44d84daSMao, Junjie                   "1:" : : "a" (desc), "b" (type));
54*b44d84daSMao, Junjie     return exception_vector();
55*b44d84daSMao, Junjie }
56*b44d84daSMao, Junjie 
57*b44d84daSMao, Junjie void test_cpuid_consistency(int pcid_enabled, int invpcid_enabled)
58*b44d84daSMao, Junjie {
59*b44d84daSMao, Junjie     int passed = !(!pcid_enabled && invpcid_enabled);
60*b44d84daSMao, Junjie     report("CPUID consistency", passed);
61*b44d84daSMao, Junjie }
62*b44d84daSMao, Junjie 
63*b44d84daSMao, Junjie void test_pcid_enabled(void)
64*b44d84daSMao, Junjie {
65*b44d84daSMao, Junjie     int passed = 0;
66*b44d84daSMao, Junjie     ulong cr0 = read_cr0(), cr3 = read_cr3(), cr4 = read_cr4();
67*b44d84daSMao, Junjie 
68*b44d84daSMao, Junjie     /* try setting CR4.PCIDE, no exception expected */
69*b44d84daSMao, Junjie     if (write_cr4_checking(cr4 | X86_CR4_PCIDE) != 0)
70*b44d84daSMao, Junjie         goto report;
71*b44d84daSMao, Junjie 
72*b44d84daSMao, Junjie     /* try clearing CR0.PG when CR4.PCIDE=1, #GP expected */
73*b44d84daSMao, Junjie     if (write_cr0_checking(cr0 | X86_CR0_PG) != GP_VECTOR)
74*b44d84daSMao, Junjie         goto report;
75*b44d84daSMao, Junjie 
76*b44d84daSMao, Junjie     write_cr4(cr4);
77*b44d84daSMao, Junjie 
78*b44d84daSMao, Junjie     /* try setting CR4.PCIDE when CR3[11:0] != 0 , #GP expected */
79*b44d84daSMao, Junjie     write_cr3(cr3 | 0x001);
80*b44d84daSMao, Junjie     if (write_cr4_checking(cr4 | X86_CR4_PCIDE) != GP_VECTOR)
81*b44d84daSMao, Junjie         goto report;
82*b44d84daSMao, Junjie 
83*b44d84daSMao, Junjie     passed = 1;
84*b44d84daSMao, Junjie 
85*b44d84daSMao, Junjie report:
86*b44d84daSMao, Junjie     report("Test on PCID when enabled", passed);
87*b44d84daSMao, Junjie }
88*b44d84daSMao, Junjie 
89*b44d84daSMao, Junjie void test_pcid_disabled(void)
90*b44d84daSMao, Junjie {
91*b44d84daSMao, Junjie     int passed = 0;
92*b44d84daSMao, Junjie     ulong cr4 = read_cr4();
93*b44d84daSMao, Junjie 
94*b44d84daSMao, Junjie     /* try setting CR4.PCIDE, #GP expected */
95*b44d84daSMao, Junjie     if (write_cr4_checking(cr4 | X86_CR4_PCIDE) != GP_VECTOR)
96*b44d84daSMao, Junjie         goto report;
97*b44d84daSMao, Junjie 
98*b44d84daSMao, Junjie     passed = 1;
99*b44d84daSMao, Junjie 
100*b44d84daSMao, Junjie report:
101*b44d84daSMao, Junjie     report("Test on PCID when disabled", passed);
102*b44d84daSMao, Junjie }
103*b44d84daSMao, Junjie 
104*b44d84daSMao, Junjie void test_invpcid_enabled(void)
105*b44d84daSMao, Junjie {
106*b44d84daSMao, Junjie     int passed = 0;
107*b44d84daSMao, Junjie     ulong cr4 = read_cr4();
108*b44d84daSMao, Junjie     struct invpcid_desc desc;
109*b44d84daSMao, Junjie     desc.rsv = 0;
110*b44d84daSMao, Junjie 
111*b44d84daSMao, Junjie     /* try executing invpcid when CR4.PCIDE=0, desc.pcid=0 and type=1
112*b44d84daSMao, Junjie      * no exception expected
113*b44d84daSMao, Junjie      */
114*b44d84daSMao, Junjie     desc.pcid = 0;
115*b44d84daSMao, Junjie     if (invpcid_checking(1, &desc) != 0)
116*b44d84daSMao, Junjie         goto report;
117*b44d84daSMao, Junjie 
118*b44d84daSMao, Junjie     /* try executing invpcid when CR4.PCIDE=0, desc.pcid=1 and type=1
119*b44d84daSMao, Junjie      * #GP expected
120*b44d84daSMao, Junjie      */
121*b44d84daSMao, Junjie     desc.pcid = 1;
122*b44d84daSMao, Junjie     if (invpcid_checking(1, &desc) != GP_VECTOR)
123*b44d84daSMao, Junjie         goto report;
124*b44d84daSMao, Junjie 
125*b44d84daSMao, Junjie     if (write_cr4_checking(cr4 | X86_CR4_PCIDE) != 0)
126*b44d84daSMao, Junjie         goto report;
127*b44d84daSMao, Junjie 
128*b44d84daSMao, Junjie     /* try executing invpcid when CR4.PCIDE=1
129*b44d84daSMao, Junjie      * no exception expected
130*b44d84daSMao, Junjie      */
131*b44d84daSMao, Junjie     desc.pcid = 10;
132*b44d84daSMao, Junjie     if (invpcid_checking(2, &desc) != 0)
133*b44d84daSMao, Junjie         goto report;
134*b44d84daSMao, Junjie 
135*b44d84daSMao, Junjie     passed = 1;
136*b44d84daSMao, Junjie 
137*b44d84daSMao, Junjie report:
138*b44d84daSMao, Junjie     report("Test on INVPCID when enabled", passed);
139*b44d84daSMao, Junjie }
140*b44d84daSMao, Junjie 
141*b44d84daSMao, Junjie void test_invpcid_disabled(void)
142*b44d84daSMao, Junjie {
143*b44d84daSMao, Junjie     int passed = 0;
144*b44d84daSMao, Junjie     struct invpcid_desc desc;
145*b44d84daSMao, Junjie 
146*b44d84daSMao, Junjie     /* try executing invpcid, #UD expected */
147*b44d84daSMao, Junjie     if (invpcid_checking(2, &desc) != UD_VECTOR)
148*b44d84daSMao, Junjie         goto report;
149*b44d84daSMao, Junjie 
150*b44d84daSMao, Junjie     passed = 1;
151*b44d84daSMao, Junjie 
152*b44d84daSMao, Junjie report:
153*b44d84daSMao, Junjie     report("Test on INVPCID when disabled", passed);
154*b44d84daSMao, Junjie }
155*b44d84daSMao, Junjie 
156*b44d84daSMao, Junjie int main(int ac, char **av)
157*b44d84daSMao, Junjie {
158*b44d84daSMao, Junjie     struct cpuid _cpuid;
159*b44d84daSMao, Junjie     int pcid_enabled = 0, invpcid_enabled = 0;
160*b44d84daSMao, Junjie 
161*b44d84daSMao, Junjie     setup_idt();
162*b44d84daSMao, Junjie 
163*b44d84daSMao, Junjie     _cpuid = cpuid(1);
164*b44d84daSMao, Junjie     if (_cpuid.c & X86_FEATURE_PCID)
165*b44d84daSMao, Junjie         pcid_enabled = 1;
166*b44d84daSMao, Junjie     _cpuid = cpuid_indexed(7, 0);
167*b44d84daSMao, Junjie     if (_cpuid.b & X86_FEATURE_INVPCID)
168*b44d84daSMao, Junjie         invpcid_enabled = 1;
169*b44d84daSMao, Junjie 
170*b44d84daSMao, Junjie     test_cpuid_consistency(pcid_enabled, invpcid_enabled);
171*b44d84daSMao, Junjie 
172*b44d84daSMao, Junjie     if (pcid_enabled)
173*b44d84daSMao, Junjie         test_pcid_enabled();
174*b44d84daSMao, Junjie     else
175*b44d84daSMao, Junjie         test_pcid_disabled();
176*b44d84daSMao, Junjie 
177*b44d84daSMao, Junjie     if (invpcid_enabled)
178*b44d84daSMao, Junjie         test_invpcid_enabled();
179*b44d84daSMao, Junjie     else
180*b44d84daSMao, Junjie         test_invpcid_disabled();
181*b44d84daSMao, Junjie 
182*b44d84daSMao, Junjie     printf("%d tests, %d failures\n", nr_tests, nr_tests - nr_passed);
183*b44d84daSMao, Junjie 
184*b44d84daSMao, Junjie     return nr_passed == nr_tests ? 0 : 1;
185*b44d84daSMao, Junjie }
186