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