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