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