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