1 /* SPDX-License-Identifier: GPL-2.0-only */ 2 /* 3 * Interception tests - for s390x CPU instruction that cause a VM exit 4 * 5 * Copyright (c) 2017 Red Hat Inc 6 * 7 * Authors: 8 * Thomas Huth <thuth@redhat.com> 9 */ 10 #include <libcflat.h> 11 #include <sclp.h> 12 #include <asm/asm-offsets.h> 13 #include <asm/interrupt.h> 14 #include <asm/page.h> 15 #include <asm/facility.h> 16 #include <asm/time.h> 17 18 static uint8_t pagebuf[PAGE_SIZE * 2] __attribute__((aligned(PAGE_SIZE * 2))); 19 20 static unsigned long nr_iterations; 21 static unsigned long time_to_run; 22 23 /* Test the STORE PREFIX instruction */ 24 static void test_stpx(void) 25 { 26 uint32_t old_prefix = -1U, tst_prefix = -1U; 27 uint32_t new_prefix = (uint32_t)(intptr_t)pagebuf; 28 29 /* Can we successfully change the prefix? */ 30 old_prefix = get_prefix(); 31 set_prefix(new_prefix); 32 tst_prefix = get_prefix(); 33 set_prefix(old_prefix); 34 report(old_prefix == 0 && tst_prefix == new_prefix, "store prefix"); 35 36 expect_pgm_int(); 37 low_prot_enable(); 38 asm volatile(" stpx 0(%0) " : : "r"(8)); 39 low_prot_disable(); 40 check_pgm_int_code(PGM_INT_CODE_PROTECTION); 41 42 expect_pgm_int(); 43 asm volatile(" stpx 0(%0) " : : "r"(1)); 44 check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); 45 46 expect_pgm_int(); 47 asm volatile(" stpx 0(%0) " : : "r"(-8L)); 48 check_pgm_int_code(PGM_INT_CODE_ADDRESSING); 49 } 50 51 /* Test the SET PREFIX instruction */ 52 static void test_spx(void) 53 { 54 uint32_t new_prefix = (uint32_t)(intptr_t)pagebuf; 55 uint32_t old_prefix; 56 57 memset(pagebuf, 0, PAGE_SIZE * 2); 58 59 /* 60 * Temporarily change the prefix page to our buffer, and store 61 * some facility bits there ... at least some of them should be 62 * set in our buffer afterwards. 63 */ 64 old_prefix = get_prefix(); 65 set_prefix(new_prefix); 66 stfl(); 67 set_prefix(old_prefix); 68 report(pagebuf[GEN_LC_STFL] != 0, "stfl to new prefix"); 69 70 expect_pgm_int(); 71 asm volatile(" spx 0(%0) " : : "r"(1)); 72 check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); 73 74 expect_pgm_int(); 75 asm volatile(" spx 0(%0) " : : "r"(-8L)); 76 check_pgm_int_code(PGM_INT_CODE_ADDRESSING); 77 } 78 79 /* Test the STORE CPU ADDRESS instruction */ 80 static void test_stap(void) 81 { 82 uint16_t cpuid = 0xffff; 83 84 asm volatile ("stap %0\n" : "+Q"(cpuid)); 85 report(cpuid != 0xffff, "get cpu address"); 86 87 expect_pgm_int(); 88 low_prot_enable(); 89 asm volatile ("stap 0(%0)\n" : : "r"(8)); 90 low_prot_disable(); 91 check_pgm_int_code(PGM_INT_CODE_PROTECTION); 92 93 expect_pgm_int(); 94 asm volatile ("stap 0(%0)\n" : : "r"(1)); 95 check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); 96 97 expect_pgm_int(); 98 asm volatile ("stap 0(%0)\n" : : "r"(-8L)); 99 check_pgm_int_code(PGM_INT_CODE_ADDRESSING); 100 } 101 102 /* Test the STORE CPU ID instruction */ 103 static void test_stidp(void) 104 { 105 struct cpuid id = {}; 106 107 asm volatile ("stidp %0\n" : "+Q"(id)); 108 report(id.type, "type set"); 109 report(!id.version || id.version == 0xff, "version valid"); 110 report(!id.reserved, "reserved bits not set"); 111 112 expect_pgm_int(); 113 low_prot_enable(); 114 asm volatile ("stidp 0(%0)\n" : : "r"(8)); 115 low_prot_disable(); 116 check_pgm_int_code(PGM_INT_CODE_PROTECTION); 117 118 expect_pgm_int(); 119 asm volatile ("stidp 0(%0)\n" : : "r"(1)); 120 check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); 121 122 expect_pgm_int(); 123 asm volatile ("stidp 0(%0)\n" : : "r"(-8L)); 124 check_pgm_int_code(PGM_INT_CODE_ADDRESSING); 125 } 126 127 /* Test the TEST BLOCK instruction */ 128 static void test_testblock(void) 129 { 130 int cc; 131 132 memset(pagebuf, 0xaa, PAGE_SIZE); 133 134 asm volatile ( 135 " lghi %%r0,0\n" 136 " .insn rre,0xb22c0000,0,%1\n" 137 " ipm %0\n" 138 " srl %0,28\n" 139 : "=d" (cc) 140 : "a"(pagebuf + 0x123) 141 : "memory", "0", "cc"); 142 report(cc == 0 && pagebuf[0] == 0 && pagebuf[PAGE_SIZE - 1] == 0, 143 "page cleared"); 144 145 expect_pgm_int(); 146 low_prot_enable(); 147 asm volatile (" .insn rre,0xb22c0000,0,%0\n" : : "r"(4096)); 148 low_prot_disable(); 149 check_pgm_int_code(PGM_INT_CODE_PROTECTION); 150 151 expect_pgm_int(); 152 asm volatile (" .insn rre,0xb22c0000,0,%0\n" : : "r"(-4096L)); 153 check_pgm_int_code(PGM_INT_CODE_ADDRESSING); 154 } 155 156 static void test_diag318(void) 157 { 158 expect_pgm_int(); 159 enter_pstate(); 160 asm volatile("diag %0,0,0x318\n" : : "d" (0x42)); 161 check_pgm_int_code(PGM_INT_CODE_PRIVILEGED_OPERATION); 162 163 if (!sclp_facilities.has_diag318) 164 expect_pgm_int(); 165 166 asm volatile("diag %0,0,0x318\n" : : "d" (0x42)); 167 168 if (!sclp_facilities.has_diag318) 169 check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); 170 171 } 172 173 struct { 174 const char *name; 175 void (*func)(void); 176 bool run_it; 177 } tests[] = { 178 { "stpx", test_stpx, false }, 179 { "spx", test_spx, false }, 180 { "stap", test_stap, false }, 181 { "stidp", test_stidp, false }, 182 { "testblock", test_testblock, false }, 183 { "diag318", test_diag318, false }, 184 { NULL, NULL, false } 185 }; 186 187 static void parse_intercept_test_args(int argc, char **argv) 188 { 189 int i, ti; 190 bool run_all = true; 191 192 for (i = 1; i < argc; i++) { 193 if (!strcmp("-i", argv[i])) { 194 i++; 195 if (i >= argc) 196 report_abort("-i needs a parameter"); 197 nr_iterations = atol(argv[i]); 198 } else if (!strcmp("-t", argv[i])) { 199 i++; 200 if (i >= argc) 201 report_abort("-t needs a parameter"); 202 time_to_run = atol(argv[i]); 203 } else for (ti = 0; tests[ti].name != NULL; ti++) { 204 if (!strcmp(tests[ti].name, argv[i])) { 205 run_all = false; 206 tests[ti].run_it = true; 207 break; 208 } else if (tests[ti + 1].name == NULL) { 209 report_abort("Unsupported parameter '%s'", 210 argv[i]); 211 } 212 } 213 } 214 215 if (run_all) { 216 for (ti = 0; tests[ti].name != NULL; ti++) 217 tests[ti].run_it = true; 218 } 219 } 220 221 int main(int argc, char **argv) 222 { 223 uint64_t startclk; 224 int ti; 225 226 parse_intercept_test_args(argc, argv); 227 228 if (nr_iterations == 0 && time_to_run == 0) 229 nr_iterations = 1; 230 231 report_prefix_push("intercept"); 232 233 startclk = get_clock_ms(); 234 for (;;) { 235 for (ti = 0; tests[ti].name != NULL; ti++) { 236 report_prefix_push(tests[ti].name); 237 if (tests[ti].run_it) 238 tests[ti].func(); 239 report_prefix_pop(); 240 } 241 if (nr_iterations) { 242 nr_iterations -= 1; 243 if (nr_iterations == 0) 244 break; 245 } 246 if (time_to_run) { 247 if (get_clock_ms() - startclk > time_to_run) 248 break; 249 } 250 } 251 252 report_prefix_pop(); 253 254 return report_summary(); 255 } 256