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