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 */
fixup_invalid_psw(struct stack_frame_int * stack)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 */
load_psw(struct psw psw)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
load_short_psw(struct short_psw psw)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
expect_invalid_psw(struct psw psw)85 static void expect_invalid_psw(struct psw psw)
86 {
87 expected_psw = psw;
88 invalid_psw_expected = true;
89 }
90
clear_invalid_psw(void)91 static void clear_invalid_psw(void)
92 {
93 expected_psw = PSW(0, 0);
94 invalid_psw_expected = false;
95 }
96
check_invalid_psw(void)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*/
psw_bit_12_is_1(void)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
psw_odd_address(void)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: lgr %[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. */
short_psw_bit_12_is_0(void)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
odd_ex_target(void)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
bad_alignment_lqp(void)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
bad_alignment_lrl(void)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
not_even(void)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
test_spec_ex(const struct spec_ex_trigger * trigger)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))
with_transaction(int (* trigger)(void),struct __htm_tdb * diagnose)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
retry_transaction(const struct spec_ex_trigger * trigger,unsigned int max_retries,struct __htm_tdb * tdb,uint16_t expected_pgm)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
test_spec_ex_trans(struct args * args,const struct spec_ex_trigger * trigger)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
parse_unsigned(const char * arg,unsigned int * out)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
parse_args(int argc,char ** argv)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
main(int argc,char ** argv)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