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