1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright IBM Corp. 2021, 2022 4 * 5 * Specification exception test. 6 * Tests that specification exceptions occur when expected. 7 * This includes specification exceptions occurring during transactional execution 8 * as these result in another interruption code (the transactional-execution-aborted 9 * bit is set). 10 * 11 * Can be extended by adding triggers to spec_ex_triggers, see comments below. 12 */ 13 #include <stdlib.h> 14 #include <htmintrin.h> 15 #include <libcflat.h> 16 #include <bitops.h> 17 #include <asm/barrier.h> 18 #include <asm/interrupt.h> 19 #include <asm/facility.h> 20 21 /* toggled to signal occurrence of invalid psw fixup */ 22 static bool invalid_psw_expected; 23 static struct psw expected_psw; 24 static struct psw invalid_psw; 25 static struct psw fixup_psw; 26 27 /* 28 * The standard program exception handler cannot deal with invalid old PSWs, 29 * especially not invalid instruction addresses, as in that case one cannot 30 * find the instruction following the faulting one from the old PSW. 31 * The PSW to return to is set by load_psw. 32 */ 33 static void fixup_invalid_psw(struct stack_frame_int *stack) 34 { 35 assert_msg(invalid_psw_expected, 36 "Unexpected invalid PSW during program interrupt fixup: %#lx %#lx", 37 lowcore.pgm_old_psw.mask, lowcore.pgm_old_psw.addr); 38 /* signal occurrence of invalid psw fixup */ 39 invalid_psw_expected = false; 40 invalid_psw = lowcore.pgm_old_psw; 41 lowcore.pgm_old_psw = fixup_psw; 42 } 43 44 /* 45 * Load possibly invalid psw, but setup fixup_psw before, 46 * so that fixup_invalid_psw() can bring us back onto the right track. 47 * Also acts as compiler barrier, -> none required in expect/check_invalid_psw 48 */ 49 static void load_psw(struct psw psw) 50 { 51 uint64_t scratch; 52 53 /* 54 * The fixup psw is the current psw with the instruction address replaced 55 * by the address of the nop following the instruction loading the new psw. 56 */ 57 fixup_psw.mask = extract_psw_mask(); 58 asm volatile ( "larl %[scratch],0f\n" 59 " stg %[scratch],%[fixup_addr]\n" 60 " lpswe %[psw]\n" 61 "0: nop\n" 62 : [scratch] "=&d" (scratch), 63 [fixup_addr] "=&T" (fixup_psw.addr) 64 : [psw] "Q" (psw) 65 : "cc", "memory" 66 ); 67 } 68 69 static void load_short_psw(struct short_psw psw) 70 { 71 uint64_t scratch; 72 73 fixup_psw.mask = extract_psw_mask(); 74 asm volatile ( "larl %[scratch],0f\n" 75 " stg %[scratch],%[fixup_addr]\n" 76 " lpsw %[psw]\n" 77 "0: nop\n" 78 : [scratch] "=&d" (scratch), 79 [fixup_addr] "=&T" (fixup_psw.addr) 80 : [psw] "Q" (psw) 81 : "cc", "memory" 82 ); 83 } 84 85 static void expect_invalid_psw(struct psw psw) 86 { 87 expected_psw = psw; 88 invalid_psw_expected = true; 89 } 90 91 static int check_invalid_psw(void) 92 { 93 /* Since the fixup sets this to false we check for false here. */ 94 if (!invalid_psw_expected) { 95 if (expected_psw.mask == invalid_psw.mask && 96 expected_psw.addr == invalid_psw.addr) 97 return 0; 98 report_fail("Wrong invalid PSW"); 99 } else { 100 report_fail("Expected exception due to invalid PSW"); 101 } 102 return 1; 103 } 104 105 /* For normal PSWs bit 12 has to be 0 to be a valid PSW*/ 106 static int psw_bit_12_is_1(void) 107 { 108 struct psw invalid = { 109 .mask = BIT(63 - 12), 110 .addr = 0x00000000deadbeee 111 }; 112 113 expect_invalid_psw(invalid); 114 load_psw(invalid); 115 return check_invalid_psw(); 116 } 117 118 /* A short PSW needs to have bit 12 set to be valid. */ 119 static int short_psw_bit_12_is_0(void) 120 { 121 struct psw invalid = { 122 .mask = BIT(63 - 12), 123 .addr = 0x00000000deadbeee 124 }; 125 struct short_psw short_invalid = { 126 .mask = 0x0, 127 .addr = 0xdeadbeee 128 }; 129 130 expect_invalid_psw(invalid); 131 load_short_psw(short_invalid); 132 /* 133 * lpsw may optionally check bit 12 before loading the new psw 134 * -> cannot check the expected invalid psw like with lpswe 135 */ 136 return 0; 137 } 138 139 static int bad_alignment(void) 140 { 141 uint32_t words[5] __attribute__((aligned(16))); 142 uint32_t (*bad_aligned)[4] = (uint32_t (*)[4])&words[1]; 143 144 /* LOAD PAIR FROM QUADWORD (LPQ) requires quadword alignment */ 145 asm volatile ("lpq %%r6,%[bad]" 146 : : [bad] "T" (*bad_aligned) 147 : "%r6", "%r7" 148 ); 149 return 0; 150 } 151 152 static int not_even(void) 153 { 154 uint64_t quad[2] __attribute__((aligned(16))) = {0}; 155 156 asm volatile (".insn rxy,0xe3000000008f,%%r7,%[quad]" /* lpq %%r7,%[quad] */ 157 : : [quad] "T" (quad) 158 : "%r7", "%r8" 159 ); 160 return 0; 161 } 162 163 /* 164 * Harness for specification exception testing. 165 * func only triggers exception, reporting is taken care of automatically. 166 * If a trigger is transactable it will also be executed during a transaction. 167 */ 168 struct spec_ex_trigger { 169 const char *name; 170 int (*func)(void); 171 bool transactable; 172 void (*fixup)(struct stack_frame_int *stack); 173 }; 174 175 /* List of all tests to execute */ 176 static const struct spec_ex_trigger spec_ex_triggers[] = { 177 { "psw_bit_12_is_1", &psw_bit_12_is_1, false, &fixup_invalid_psw }, 178 { "short_psw_bit_12_is_0", &short_psw_bit_12_is_0, false, &fixup_invalid_psw }, 179 { "bad_alignment", &bad_alignment, true, NULL }, 180 { "not_even", ¬_even, true, NULL }, 181 { NULL, NULL, false, NULL }, 182 }; 183 184 static void test_spec_ex(const struct spec_ex_trigger *trigger) 185 { 186 int rc; 187 188 expect_pgm_int(); 189 register_pgm_cleanup_func(trigger->fixup); 190 rc = trigger->func(); 191 register_pgm_cleanup_func(NULL); 192 /* test failed, nothing to be done, reporting responsibility of trigger */ 193 if (rc) 194 return; 195 check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); 196 } 197 198 #define TRANSACTION_COMPLETED 4 199 #define TRANSACTION_MAX_RETRIES 5 200 201 /* 202 * NULL must not be passed to __builtin_tbegin via variable, only constant, 203 * forbid diagnose from being NULL at all to keep things simple 204 */ 205 static int __attribute__((nonnull)) 206 with_transaction(int (*trigger)(void), struct __htm_tdb *diagnose) 207 { 208 int cc; 209 210 cc = __builtin_tbegin(diagnose); 211 /* 212 * Everything between tbegin and tend is part of the transaction, 213 * which either completes in its entirety or does not have any effect. 214 * If the transaction fails, execution is reset to this point with another 215 * condition code indicating why the transaction failed. 216 */ 217 if (cc == _HTM_TBEGIN_STARTED) { 218 /* 219 * return code is meaningless: transaction needs to complete 220 * in order to return and completion indicates a test failure 221 */ 222 trigger(); 223 __builtin_tend(); 224 return TRANSACTION_COMPLETED; 225 } else { 226 return cc; 227 } 228 } 229 230 static int retry_transaction(const struct spec_ex_trigger *trigger, unsigned int max_retries, 231 struct __htm_tdb *tdb, uint16_t expected_pgm) 232 { 233 int trans_result, i; 234 uint16_t pgm; 235 236 for (i = 0; i < max_retries; i++) { 237 expect_pgm_int(); 238 trans_result = with_transaction(trigger->func, tdb); 239 if (trans_result == _HTM_TBEGIN_TRANSIENT) { 240 mb(); 241 pgm = lowcore.pgm_int_code; 242 if (pgm == expected_pgm) 243 return 0; 244 else if (pgm == 0) 245 /* 246 * Transaction failed for unknown reason but not because 247 * of an unexpected program exception. Give it another 248 * go so that hopefully it reaches the triggering instruction. 249 */ 250 continue; 251 } 252 return trans_result; 253 } 254 return TRANSACTION_MAX_RETRIES; 255 } 256 257 struct args { 258 uint64_t max_retries; 259 bool diagnose; 260 }; 261 262 static void test_spec_ex_trans(struct args *args, const struct spec_ex_trigger *trigger) 263 { 264 const uint16_t expected_pgm = PGM_INT_CODE_SPECIFICATION | 265 PGM_INT_CODE_TX_ABORTED_EVENT; 266 union { 267 struct __htm_tdb tdb; 268 uint64_t dwords[sizeof(struct __htm_tdb) / sizeof(uint64_t)]; 269 } diag; 270 unsigned int i; 271 int trans_result; 272 273 if (!test_facility(73)) { 274 report_skip("transactional-execution facility not installed"); 275 return; 276 } 277 ctl_set_bit(0, CTL0_TRANSACT_EX_CTL); /* enable transactional-exec */ 278 279 register_pgm_cleanup_func(trigger->fixup); 280 trans_result = retry_transaction(trigger, args->max_retries, &diag.tdb, expected_pgm); 281 register_pgm_cleanup_func(NULL); 282 switch (trans_result) { 283 case 0: 284 report_pass("Program interrupt: expected(%d) == received(%d)", 285 expected_pgm, expected_pgm); 286 break; 287 case _HTM_TBEGIN_INDETERMINATE: 288 case _HTM_TBEGIN_PERSISTENT: 289 report_info("transaction failed with cc %d", trans_result); 290 report_info("transaction abort code: %llu", diag.tdb.abort_code); 291 if (args->diagnose) 292 for (i = 0; i < 32; i++) 293 report_info("diag+%03d: %016lx", i * 8, diag.dwords[i]); 294 break; 295 case _HTM_TBEGIN_TRANSIENT: 296 report_fail("Program interrupt: expected(%d) == received(%d)", 297 expected_pgm, clear_pgm_int()); 298 break; 299 case TRANSACTION_COMPLETED: 300 report_fail("Transaction completed without exception"); 301 break; 302 case TRANSACTION_MAX_RETRIES: 303 report_skip("Transaction retried %lu times with transient failures, giving up", 304 args->max_retries); 305 break; 306 default: 307 report_fail("Invalid transaction result"); 308 break; 309 } 310 311 ctl_clear_bit(0, CTL0_TRANSACT_EX_CTL); 312 } 313 314 static bool parse_unsigned(const char *arg, unsigned int *out) 315 { 316 char *end; 317 long num; 318 319 if (arg[0] == '\0') 320 return false; 321 num = strtol(arg, &end, 10); 322 if (end[0] != '\0' || num < 0) 323 return false; 324 *out = num; 325 return true; 326 } 327 328 static struct args parse_args(int argc, char **argv) 329 { 330 struct args args = { 331 .max_retries = 20, 332 .diagnose = false 333 }; 334 unsigned int i, arg; 335 bool has_arg; 336 const char *flag; 337 338 for (i = 1; i < argc; i++) { 339 if (i + 1 < argc) 340 has_arg = parse_unsigned(argv[i + 1], &arg); 341 else 342 has_arg = false; 343 344 flag = "--max-retries"; 345 if (!strcmp(flag, argv[i])) { 346 if (!has_arg) 347 report_abort("%s needs a positive parameter", flag); 348 args.max_retries = arg; 349 ++i; 350 continue; 351 } 352 if (!strcmp("--diagnose", argv[i])) { 353 args.diagnose = true; 354 continue; 355 } 356 if (!strcmp("--no-diagnose", argv[i])) { 357 args.diagnose = false; 358 continue; 359 } 360 report_abort("Unsupported parameter '%s'", 361 argv[i]); 362 } 363 364 return args; 365 } 366 367 int main(int argc, char **argv) 368 { 369 unsigned int i; 370 371 struct args args = parse_args(argc, argv); 372 373 report_prefix_push("specification exception"); 374 for (i = 0; spec_ex_triggers[i].name; i++) { 375 report_prefix_push(spec_ex_triggers[i].name); 376 test_spec_ex(&spec_ex_triggers[i]); 377 report_prefix_pop(); 378 } 379 report_prefix_pop(); 380 381 report_prefix_push("specification exception during transaction"); 382 for (i = 0; spec_ex_triggers[i].name; i++) { 383 if (spec_ex_triggers[i].transactable) { 384 report_prefix_push(spec_ex_triggers[i].name); 385 test_spec_ex_trans(&args, &spec_ex_triggers[i]); 386 report_prefix_pop(); 387 } 388 } 389 report_prefix_pop(); 390 391 return report_summary(); 392 } 393