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