1 /* Basic PCID & INVPCID functionality test */ 2 3 #include "libcflat.h" 4 #include "processor.h" 5 #include "desc.h" 6 7 static void test_pcid_enabled(void) 8 { 9 int passed = 0; 10 ulong cr0 = read_cr0(), cr3 = read_cr3(), cr4 = read_cr4(); 11 12 /* try setting CR4.PCIDE, no exception expected */ 13 if (write_cr4_safe(cr4 | X86_CR4_PCIDE) != 0) 14 goto report; 15 16 /* try clearing CR0.PG when CR4.PCIDE=1, #GP expected */ 17 if (write_cr0_safe(cr0 & ~X86_CR0_PG) != GP_VECTOR) 18 goto report; 19 20 write_cr4(cr4); 21 22 /* try setting CR4.PCIDE when CR3[11:0] != 0 , #GP expected */ 23 write_cr3(cr3 | 0x001); 24 if (write_cr4_safe(cr4 | X86_CR4_PCIDE) != GP_VECTOR) 25 goto report; 26 write_cr3(cr3); 27 28 passed = 1; 29 30 report: 31 report(passed, "Test on PCID when enabled"); 32 } 33 34 static void test_pcid_disabled(void) 35 { 36 int passed = 0; 37 ulong cr4 = read_cr4(); 38 39 /* try setting CR4.PCIDE, #GP expected */ 40 if (write_cr4_safe(cr4 | X86_CR4_PCIDE) != GP_VECTOR) 41 goto report; 42 43 passed = 1; 44 45 report: 46 report(passed, "Test on PCID when disabled"); 47 } 48 49 static void test_invpcid_enabled(int pcid_enabled) 50 { 51 int passed = 0, i; 52 ulong cr4 = read_cr4(); 53 struct invpcid_desc desc; 54 55 memset(&desc, 0, sizeof(desc)); 56 57 /* try executing invpcid when CR4.PCIDE=0, desc.pcid=0 and type=0..3 58 * no exception expected 59 */ 60 for (i = 0; i < 4; i++) { 61 if (invpcid_safe(i, &desc) != 0) 62 goto report; 63 } 64 65 /* try executing invpcid when CR4.PCIDE=0, desc.pcid=1 and type=0..1 66 * #GP expected 67 */ 68 desc.pcid = 1; 69 for (i = 0; i < 2; i++) { 70 if (invpcid_safe(i, &desc) != GP_VECTOR) 71 goto report; 72 } 73 74 /* Skip tests that require the PCIDE=1 if PCID isn't supported. */ 75 if (!pcid_enabled) 76 goto success; 77 78 if (write_cr4_safe(cr4 | X86_CR4_PCIDE) != 0) 79 goto report; 80 81 /* try executing invpcid when CR4.PCIDE=1 82 * no exception expected 83 */ 84 desc.pcid = 10; 85 if (invpcid_safe(2, &desc) != 0) 86 goto report; 87 88 success: 89 passed = 1; 90 91 report: 92 report(passed, "Test on INVPCID when enabled"); 93 } 94 95 static void test_invpcid_disabled(void) 96 { 97 int passed = 0; 98 struct invpcid_desc desc; 99 100 /* try executing invpcid, #UD expected */ 101 if (invpcid_safe(2, &desc) != UD_VECTOR) 102 goto report; 103 104 passed = 1; 105 106 report: 107 report(passed, "Test on INVPCID when disabled"); 108 } 109 110 int main(int ac, char **av) 111 { 112 int pcid_enabled = 0, invpcid_enabled = 0; 113 114 if (this_cpu_has(X86_FEATURE_PCID)) 115 pcid_enabled = 1; 116 if (this_cpu_has(X86_FEATURE_INVPCID)) 117 invpcid_enabled = 1; 118 119 if (pcid_enabled) 120 test_pcid_enabled(); 121 else 122 test_pcid_disabled(); 123 124 if (invpcid_enabled) 125 test_invpcid_enabled(pcid_enabled); 126 else 127 test_invpcid_disabled(); 128 129 return report_summary(); 130 } 131