xref: /kvm-unit-tests/x86/pcid.c (revision 386ed5c2f9e98a2605817748c44c0cefa60dc88e)
1 /* Basic PCID & INVPCID functionality test */
2 
3 #include "libcflat.h"
4 #include "processor.h"
5 #include "desc.h"
6 
7 struct invpcid_desc {
8     u64 pcid : 12;
9     u64 rsv  : 52;
10     u64 addr : 64;
11 };
12 
13 static void test_pcid_enabled(void)
14 {
15     int passed = 0;
16     ulong cr0 = read_cr0(), cr3 = read_cr3(), cr4 = read_cr4();
17 
18     /* try setting CR4.PCIDE, no exception expected */
19     if (write_cr4_safe(cr4 | X86_CR4_PCIDE) != 0)
20         goto report;
21 
22     /* try clearing CR0.PG when CR4.PCIDE=1, #GP expected */
23     if (write_cr0_safe(cr0 & ~X86_CR0_PG) != GP_VECTOR)
24         goto report;
25 
26     write_cr4(cr4);
27 
28     /* try setting CR4.PCIDE when CR3[11:0] != 0 , #GP expected */
29     write_cr3(cr3 | 0x001);
30     if (write_cr4_safe(cr4 | X86_CR4_PCIDE) != GP_VECTOR)
31         goto report;
32     write_cr3(cr3);
33 
34     passed = 1;
35 
36 report:
37     report(passed, "Test on PCID when enabled");
38 }
39 
40 static void test_pcid_disabled(void)
41 {
42     int passed = 0;
43     ulong cr4 = read_cr4();
44 
45     /* try setting CR4.PCIDE, #GP expected */
46     if (write_cr4_safe(cr4 | X86_CR4_PCIDE) != GP_VECTOR)
47         goto report;
48 
49     passed = 1;
50 
51 report:
52     report(passed, "Test on PCID when disabled");
53 }
54 
55 static void test_invpcid_enabled(int pcid_enabled)
56 {
57     int passed = 0, i;
58     ulong cr4 = read_cr4();
59     struct invpcid_desc desc;
60 
61     memset(&desc, 0, sizeof(desc));
62 
63     /* try executing invpcid when CR4.PCIDE=0, desc.pcid=0 and type=0..3
64      * no exception expected
65      */
66     for (i = 0; i < 4; i++) {
67         if (invpcid_safe(i, &desc) != 0)
68             goto report;
69     }
70 
71     /* try executing invpcid when CR4.PCIDE=0, desc.pcid=1 and type=0..1
72      * #GP expected
73      */
74     desc.pcid = 1;
75     for (i = 0; i < 2; i++) {
76         if (invpcid_safe(i, &desc) != GP_VECTOR)
77             goto report;
78     }
79 
80     /* Skip tests that require the PCIDE=1 if PCID isn't supported. */
81     if (!pcid_enabled)
82         goto success;
83 
84     if (write_cr4_safe(cr4 | X86_CR4_PCIDE) != 0)
85         goto report;
86 
87     /* try executing invpcid when CR4.PCIDE=1
88      * no exception expected
89      */
90     desc.pcid = 10;
91     if (invpcid_safe(2, &desc) != 0)
92         goto report;
93 
94 success:
95     passed = 1;
96 
97 report:
98     report(passed, "Test on INVPCID when enabled");
99 }
100 
101 static void test_invpcid_disabled(void)
102 {
103     int passed = 0;
104     struct invpcid_desc desc;
105 
106     /* try executing invpcid, #UD expected */
107     if (invpcid_safe(2, &desc) != UD_VECTOR)
108         goto report;
109 
110     passed = 1;
111 
112 report:
113     report(passed, "Test on INVPCID when disabled");
114 }
115 
116 int main(int ac, char **av)
117 {
118     int pcid_enabled = 0, invpcid_enabled = 0;
119 
120     if (this_cpu_has(X86_FEATURE_PCID))
121         pcid_enabled = 1;
122     if (this_cpu_has(X86_FEATURE_INVPCID))
123         invpcid_enabled = 1;
124 
125     if (pcid_enabled)
126         test_pcid_enabled();
127     else
128         test_pcid_disabled();
129 
130     if (invpcid_enabled)
131         test_invpcid_enabled(pcid_enabled);
132     else
133         test_invpcid_disabled();
134 
135     return report_summary();
136 }
137