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