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 void clear_invalid_psw(void) 92 { 93 expected_psw = PSW(0, 0); 94 invalid_psw_expected = false; 95 } 96 97 static int check_invalid_psw(void) 98 { 99 /* Since the fixup sets this to false we check for false here. */ 100 if (!invalid_psw_expected) { 101 /* 102 * Early exception recognition: pgm_int_id == 0. 103 * Late exception recognition: psw address has been 104 * incremented by pgm_int_id (unpredictable value) 105 */ 106 if (expected_psw.mask == invalid_psw.mask && 107 expected_psw.addr == invalid_psw.addr - lowcore.pgm_int_id) 108 return 0; 109 report_fail("Wrong invalid PSW"); 110 } else { 111 report_fail("Expected exception due to invalid PSW"); 112 } 113 return 1; 114 } 115 116 /* For normal PSWs bit 12 has to be 0 to be a valid PSW*/ 117 static int psw_bit_12_is_1(void) 118 { 119 struct psw invalid = PSW(BIT(63 - 12), 0x00000000deadbeee); 120 121 expect_invalid_psw(invalid); 122 load_psw(invalid); 123 return check_invalid_psw(); 124 } 125 126 extern char misaligned_code_pre[]; 127 asm ( ".balign 2\n" 128 "misaligned_code_pre:\n" 129 " . = . + 1\n" 130 " larl %r0,0\n" 131 " br %r1\n" 132 ); 133 134 static int psw_odd_address(void) 135 { 136 struct psw odd = PSW_WITH_CUR_MASK(((uint64_t)&misaligned_code_pre) + 1); 137 uint64_t executed_addr; 138 139 expect_invalid_psw(odd); 140 fixup_psw.mask = extract_psw_mask(); 141 asm volatile ( "xgr %%r0,%%r0\n" 142 " larl %%r1,0f\n" 143 " stg %%r1,%[fixup_addr]\n" 144 " lpswe %[odd_psw]\n" 145 "0: lr %[executed_addr],%%r0\n" 146 : [fixup_addr] "=&T" (fixup_psw.addr), 147 [executed_addr] "=d" (executed_addr) 148 : [odd_psw] "Q" (odd) 149 : "cc", "%r0", "%r1", "memory" /* Compiler barrier like in load_psw */ 150 ); 151 152 if (!executed_addr) { 153 return check_invalid_psw(); 154 } else { 155 assert(executed_addr == odd.addr); 156 clear_invalid_psw(); 157 report_fail("did not execute unaligned instructions"); 158 return 1; 159 } 160 } 161 162 /* A short PSW needs to have bit 12 set to be valid. */ 163 static int short_psw_bit_12_is_0(void) 164 { 165 struct psw invalid = PSW(BIT(63 - 12), 0x00000000deadbeee); 166 struct short_psw short_invalid = { 167 .mask = 0x0, 168 .addr = 0xdeadbeee 169 }; 170 171 expect_invalid_psw(invalid); 172 load_short_psw(short_invalid); 173 /* 174 * lpsw may optionally check bit 12 before loading the new psw 175 * -> cannot check the expected invalid psw like with lpswe 176 */ 177 return 0; 178 } 179 180 static int odd_ex_target(void) 181 { 182 uint64_t pre_target_addr; 183 int to = 0, from = 0x0dd; 184 185 asm volatile ( ".pushsection .text.ex_odd\n" 186 " .balign 2\n" 187 "pre_odd_ex_target%=:\n" 188 " . = . + 1\n" 189 " lr %[to],%[from]\n" 190 " .popsection\n" 191 192 " larl %[pre_target_addr],pre_odd_ex_target%=\n" 193 " ex 0,1(%[pre_target_addr])\n" 194 : [pre_target_addr] "=&a" (pre_target_addr), 195 [to] "+d" (to) 196 : [from] "d" (from) 197 ); 198 199 assert((pre_target_addr + 1) & 1); 200 report(to != from, "did not perform ex with odd target"); 201 return 0; 202 } 203 204 static int bad_alignment_lqp(void) 205 { 206 uint32_t words[5] __attribute__((aligned(16))); 207 uint32_t (*bad_aligned)[4] = (uint32_t (*)[4])&words[1]; 208 209 /* LOAD PAIR FROM QUADWORD (LPQ) requires quadword alignment */ 210 asm volatile ("lpq %%r6,%[bad]" 211 : : [bad] "T" (*bad_aligned) 212 : "%r6", "%r7" 213 ); 214 return 0; 215 } 216 217 static int bad_alignment_lrl(void) 218 { 219 uint64_t r; 220 221 asm volatile ( ".pushsection .rodata\n" 222 " .balign 4\n" 223 " . = . + 2\n" 224 "0: .fill 4\n" 225 " .popsection\n" 226 227 " lrl %0,0b\n" 228 : "=d" (r) 229 ); 230 return 0; 231 } 232 233 static int not_even(void) 234 { 235 uint64_t quad[2] __attribute__((aligned(16))) = {0}; 236 237 asm volatile (".insn rxy,0xe3000000008f,%%r7,%[quad]" /* lpq %%r7,%[quad] */ 238 : : [quad] "T" (quad) 239 : "%r7", "%r8" 240 ); 241 return 0; 242 } 243 244 /* 245 * Harness for specification exception testing. 246 * func only triggers exception, reporting is taken care of automatically. 247 * If a trigger is transactable it will also be executed during a transaction. 248 */ 249 struct spec_ex_trigger { 250 const char *name; 251 int (*func)(void); 252 bool transactable; 253 void (*fixup)(struct stack_frame_int *stack); 254 }; 255 256 /* List of all tests to execute */ 257 static const struct spec_ex_trigger spec_ex_triggers[] = { 258 { "psw_bit_12_is_1", &psw_bit_12_is_1, false, &fixup_invalid_psw }, 259 { "short_psw_bit_12_is_0", &short_psw_bit_12_is_0, false, &fixup_invalid_psw }, 260 { "psw_odd_address", &psw_odd_address, false, &fixup_invalid_psw }, 261 { "odd_ex_target", &odd_ex_target, true, NULL }, 262 { "bad_alignment_lqp", &bad_alignment_lqp, true, NULL }, 263 { "bad_alignment_lrl", &bad_alignment_lrl, true, NULL }, 264 { "not_even", ¬_even, true, NULL }, 265 { NULL, NULL, false, NULL }, 266 }; 267 268 static void test_spec_ex(const struct spec_ex_trigger *trigger) 269 { 270 int rc; 271 272 expect_pgm_int(); 273 register_pgm_cleanup_func(trigger->fixup); 274 rc = trigger->func(); 275 register_pgm_cleanup_func(NULL); 276 /* test failed, nothing to be done, reporting responsibility of trigger */ 277 if (rc) 278 return; 279 check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); 280 } 281 282 #define TRANSACTION_COMPLETED 4 283 #define TRANSACTION_MAX_RETRIES 5 284 285 /* 286 * NULL must not be passed to __builtin_tbegin via variable, only constant, 287 * forbid diagnose from being NULL at all to keep things simple 288 */ 289 static int __attribute__((nonnull)) 290 with_transaction(int (*trigger)(void), struct __htm_tdb *diagnose) 291 { 292 int cc; 293 294 cc = __builtin_tbegin(diagnose); 295 /* 296 * Everything between tbegin and tend is part of the transaction, 297 * which either completes in its entirety or does not have any effect. 298 * If the transaction fails, execution is reset to this point with another 299 * condition code indicating why the transaction failed. 300 */ 301 if (cc == _HTM_TBEGIN_STARTED) { 302 /* 303 * return code is meaningless: transaction needs to complete 304 * in order to return and completion indicates a test failure 305 */ 306 trigger(); 307 __builtin_tend(); 308 return TRANSACTION_COMPLETED; 309 } else { 310 return cc; 311 } 312 } 313 314 static int retry_transaction(const struct spec_ex_trigger *trigger, unsigned int max_retries, 315 struct __htm_tdb *tdb, uint16_t expected_pgm) 316 { 317 int trans_result, i; 318 uint16_t pgm; 319 320 for (i = 0; i < max_retries; i++) { 321 expect_pgm_int(); 322 trans_result = with_transaction(trigger->func, tdb); 323 if (trans_result == _HTM_TBEGIN_TRANSIENT) { 324 mb(); 325 pgm = lowcore.pgm_int_code; 326 if (pgm == expected_pgm) 327 return 0; 328 else if (pgm == 0) 329 /* 330 * Transaction failed for unknown reason but not because 331 * of an unexpected program exception. Give it another 332 * go so that hopefully it reaches the triggering instruction. 333 */ 334 continue; 335 } 336 return trans_result; 337 } 338 return TRANSACTION_MAX_RETRIES; 339 } 340 341 struct args { 342 uint64_t max_retries; 343 bool diagnose; 344 }; 345 346 static void test_spec_ex_trans(struct args *args, const struct spec_ex_trigger *trigger) 347 { 348 const uint16_t expected_pgm = PGM_INT_CODE_SPECIFICATION | 349 PGM_INT_CODE_TX_ABORTED_EVENT; 350 union { 351 struct __htm_tdb tdb; 352 uint64_t dwords[sizeof(struct __htm_tdb) / sizeof(uint64_t)]; 353 } diag; 354 unsigned int i; 355 int trans_result; 356 357 if (!test_facility(73)) { 358 report_skip("transactional-execution facility not installed"); 359 return; 360 } 361 ctl_set_bit(0, CTL0_TRANSACT_EX_CTL); /* enable transactional-exec */ 362 363 register_pgm_cleanup_func(trigger->fixup); 364 trans_result = retry_transaction(trigger, args->max_retries, &diag.tdb, expected_pgm); 365 register_pgm_cleanup_func(NULL); 366 switch (trans_result) { 367 case 0: 368 report_pass("Program interrupt: expected(%d) == received(%d)", 369 expected_pgm, expected_pgm); 370 break; 371 case _HTM_TBEGIN_INDETERMINATE: 372 case _HTM_TBEGIN_PERSISTENT: 373 report_info("transaction failed with cc %d", trans_result); 374 report_info("transaction abort code: %llu", diag.tdb.abort_code); 375 if (args->diagnose) 376 for (i = 0; i < 32; i++) 377 report_info("diag+%03d: %016lx", i * 8, diag.dwords[i]); 378 break; 379 case _HTM_TBEGIN_TRANSIENT: 380 report_fail("Program interrupt: expected(%d) == received(%d)", 381 expected_pgm, clear_pgm_int()); 382 break; 383 case TRANSACTION_COMPLETED: 384 report_fail("Transaction completed without exception"); 385 break; 386 case TRANSACTION_MAX_RETRIES: 387 report_skip("Transaction retried %lu times with transient failures, giving up", 388 args->max_retries); 389 break; 390 default: 391 report_fail("Invalid transaction result"); 392 break; 393 } 394 395 ctl_clear_bit(0, CTL0_TRANSACT_EX_CTL); 396 } 397 398 static bool parse_unsigned(const char *arg, unsigned int *out) 399 { 400 char *end; 401 long num; 402 403 if (arg[0] == '\0') 404 return false; 405 num = strtol(arg, &end, 10); 406 if (end[0] != '\0' || num < 0) 407 return false; 408 *out = num; 409 return true; 410 } 411 412 static struct args parse_args(int argc, char **argv) 413 { 414 struct args args = { 415 .max_retries = 20, 416 .diagnose = false 417 }; 418 unsigned int i, arg; 419 bool has_arg; 420 const char *flag; 421 422 for (i = 1; i < argc; i++) { 423 if (i + 1 < argc) 424 has_arg = parse_unsigned(argv[i + 1], &arg); 425 else 426 has_arg = false; 427 428 flag = "--max-retries"; 429 if (!strcmp(flag, argv[i])) { 430 if (!has_arg) 431 report_abort("%s needs a positive parameter", flag); 432 args.max_retries = arg; 433 ++i; 434 continue; 435 } 436 if (!strcmp("--diagnose", argv[i])) { 437 args.diagnose = true; 438 continue; 439 } 440 if (!strcmp("--no-diagnose", argv[i])) { 441 args.diagnose = false; 442 continue; 443 } 444 report_abort("Unsupported parameter '%s'", 445 argv[i]); 446 } 447 448 return args; 449 } 450 451 int main(int argc, char **argv) 452 { 453 unsigned int i; 454 455 struct args args = parse_args(argc, argv); 456 457 report_prefix_push("specification exception"); 458 for (i = 0; spec_ex_triggers[i].name; i++) { 459 report_prefix_push(spec_ex_triggers[i].name); 460 test_spec_ex(&spec_ex_triggers[i]); 461 report_prefix_pop(); 462 } 463 report_prefix_pop(); 464 465 report_prefix_push("specification exception during transaction"); 466 for (i = 0; spec_ex_triggers[i].name; i++) { 467 if (spec_ex_triggers[i].transactable) { 468 report_prefix_push(spec_ex_triggers[i].name); 469 test_spec_ex_trans(&args, &spec_ex_triggers[i]); 470 report_prefix_pop(); 471 } 472 } 473 report_prefix_pop(); 474 475 return report_summary(); 476 } 477