xref: /kvm-unit-tests/s390x/spec_ex.c (revision 4c8a99ca02252d4a2bee43f4558fe47ce5ab7ec0)
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", &not_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