xref: /kvm-unit-tests/s390x/spec_ex-sie.c (revision d05bf604dc82bb0b77ea90bbfdd05556b0c229ed)
149934b5aSJanis Schoetterl-Glausch // SPDX-License-Identifier: GPL-2.0-only
249934b5aSJanis Schoetterl-Glausch /*
349934b5aSJanis Schoetterl-Glausch  * Copyright IBM Corp. 2021
449934b5aSJanis Schoetterl-Glausch  *
549934b5aSJanis Schoetterl-Glausch  * Specification exception interception test.
649934b5aSJanis Schoetterl-Glausch  * Checks that specification exception interceptions occur as expected when
749934b5aSJanis Schoetterl-Glausch  * specification exception interpretation is off/on.
849934b5aSJanis Schoetterl-Glausch  */
949934b5aSJanis Schoetterl-Glausch #include <libcflat.h>
10*d05bf604SJanis Schoetterl-Glausch #include <stdlib.h>
1149934b5aSJanis Schoetterl-Glausch #include <sclp.h>
1249934b5aSJanis Schoetterl-Glausch #include <asm/page.h>
1349934b5aSJanis Schoetterl-Glausch #include <asm/arch_def.h>
1449934b5aSJanis Schoetterl-Glausch #include <alloc_page.h>
1549934b5aSJanis Schoetterl-Glausch #include <sie.h>
1649934b5aSJanis Schoetterl-Glausch #include <snippet.h>
17*d05bf604SJanis Schoetterl-Glausch #include <hardware.h>
1849934b5aSJanis Schoetterl-Glausch 
1949934b5aSJanis Schoetterl-Glausch static struct vm vm;
2049934b5aSJanis Schoetterl-Glausch extern const char SNIPPET_NAME_START(c, spec_ex)[];
2149934b5aSJanis Schoetterl-Glausch extern const char SNIPPET_NAME_END(c, spec_ex)[];
22*d05bf604SJanis Schoetterl-Glausch static bool strict;
2349934b5aSJanis Schoetterl-Glausch 
2449934b5aSJanis Schoetterl-Glausch static void setup_guest(void)
2549934b5aSJanis Schoetterl-Glausch {
2649934b5aSJanis Schoetterl-Glausch 	char *guest;
2749934b5aSJanis Schoetterl-Glausch 	int binary_size = SNIPPET_LEN(c, spec_ex);
2849934b5aSJanis Schoetterl-Glausch 
2949934b5aSJanis Schoetterl-Glausch 	setup_vm();
3049934b5aSJanis Schoetterl-Glausch 	guest = alloc_pages(8);
3149934b5aSJanis Schoetterl-Glausch 	memcpy(guest, SNIPPET_NAME_START(c, spec_ex), binary_size);
3249934b5aSJanis Schoetterl-Glausch 	sie_guest_create(&vm, (uint64_t) guest, HPAGE_SIZE);
3349934b5aSJanis Schoetterl-Glausch }
3449934b5aSJanis Schoetterl-Glausch 
3549934b5aSJanis Schoetterl-Glausch static void reset_guest(void)
3649934b5aSJanis Schoetterl-Glausch {
3749934b5aSJanis Schoetterl-Glausch 	vm.sblk->gpsw = snippet_psw;
3849934b5aSJanis Schoetterl-Glausch 	vm.sblk->icptcode = 0;
3949934b5aSJanis Schoetterl-Glausch }
4049934b5aSJanis Schoetterl-Glausch 
4149934b5aSJanis Schoetterl-Glausch static void test_spec_ex_sie(void)
4249934b5aSJanis Schoetterl-Glausch {
43*d05bf604SJanis Schoetterl-Glausch 	const char *msg;
44*d05bf604SJanis Schoetterl-Glausch 
4549934b5aSJanis Schoetterl-Glausch 	setup_guest();
4649934b5aSJanis Schoetterl-Glausch 
4749934b5aSJanis Schoetterl-Glausch 	report_prefix_push("SIE spec ex interpretation");
4849934b5aSJanis Schoetterl-Glausch 	report_prefix_push("off");
4949934b5aSJanis Schoetterl-Glausch 	reset_guest();
5049934b5aSJanis Schoetterl-Glausch 	sie(&vm);
5149934b5aSJanis Schoetterl-Glausch 	/* interpretation off -> initial exception must cause interception */
5249934b5aSJanis Schoetterl-Glausch 	report(vm.sblk->icptcode == ICPT_PROGI
5349934b5aSJanis Schoetterl-Glausch 	       && vm.sblk->iprcc == PGM_INT_CODE_SPECIFICATION
5449934b5aSJanis Schoetterl-Glausch 	       && vm.sblk->gpsw.addr != 0xdeadbeee,
5549934b5aSJanis Schoetterl-Glausch 	       "Received specification exception intercept for initial exception");
5649934b5aSJanis Schoetterl-Glausch 	report_prefix_pop();
5749934b5aSJanis Schoetterl-Glausch 
5849934b5aSJanis Schoetterl-Glausch 	report_prefix_push("on");
5949934b5aSJanis Schoetterl-Glausch 	vm.sblk->ecb |= ECB_SPECI;
6049934b5aSJanis Schoetterl-Glausch 	reset_guest();
6149934b5aSJanis Schoetterl-Glausch 	sie(&vm);
6249934b5aSJanis Schoetterl-Glausch 	/* interpretation on -> configuration dependent if initial exception causes
6349934b5aSJanis Schoetterl-Glausch 	 * interception, but invalid new program PSW must
6449934b5aSJanis Schoetterl-Glausch 	 */
6549934b5aSJanis Schoetterl-Glausch 	report(vm.sblk->icptcode == ICPT_PROGI
6649934b5aSJanis Schoetterl-Glausch 	       && vm.sblk->iprcc == PGM_INT_CODE_SPECIFICATION,
6749934b5aSJanis Schoetterl-Glausch 	       "Received specification exception intercept");
68*d05bf604SJanis Schoetterl-Glausch 	msg = "Interpreted initial exception, intercepted invalid program new PSW exception";
69*d05bf604SJanis Schoetterl-Glausch 	if (strict)
70*d05bf604SJanis Schoetterl-Glausch 		report(vm.sblk->gpsw.addr == 0xdeadbeee, "%s", msg);
71*d05bf604SJanis Schoetterl-Glausch 	else if (vm.sblk->gpsw.addr == 0xdeadbeee)
72*d05bf604SJanis Schoetterl-Glausch 		report_info("%s", msg);
7349934b5aSJanis Schoetterl-Glausch 	else
7449934b5aSJanis Schoetterl-Glausch 		report_info("Did not interpret initial exception");
7549934b5aSJanis Schoetterl-Glausch 	report_prefix_pop();
7649934b5aSJanis Schoetterl-Glausch 	report_prefix_pop();
7749934b5aSJanis Schoetterl-Glausch }
7849934b5aSJanis Schoetterl-Glausch 
79*d05bf604SJanis Schoetterl-Glausch static bool parse_strict(int argc, char **argv)
80*d05bf604SJanis Schoetterl-Glausch {
81*d05bf604SJanis Schoetterl-Glausch 	uint16_t machine_id;
82*d05bf604SJanis Schoetterl-Glausch 	char *list;
83*d05bf604SJanis Schoetterl-Glausch 	bool ret;
84*d05bf604SJanis Schoetterl-Glausch 
85*d05bf604SJanis Schoetterl-Glausch 	if (argc < 1)
86*d05bf604SJanis Schoetterl-Glausch 		return false;
87*d05bf604SJanis Schoetterl-Glausch 	if (strcmp("--strict", argv[0]))
88*d05bf604SJanis Schoetterl-Glausch 		return false;
89*d05bf604SJanis Schoetterl-Glausch 
90*d05bf604SJanis Schoetterl-Glausch 	machine_id = get_machine_id();
91*d05bf604SJanis Schoetterl-Glausch 	if (argc < 2) {
92*d05bf604SJanis Schoetterl-Glausch 		printf("No argument to --strict, ignoring\n");
93*d05bf604SJanis Schoetterl-Glausch 		return false;
94*d05bf604SJanis Schoetterl-Glausch 	}
95*d05bf604SJanis Schoetterl-Glausch 	list = argv[1];
96*d05bf604SJanis Schoetterl-Glausch 	if (list[0] == '!') {
97*d05bf604SJanis Schoetterl-Glausch 		ret = true;
98*d05bf604SJanis Schoetterl-Glausch 		list++;
99*d05bf604SJanis Schoetterl-Glausch 	} else {
100*d05bf604SJanis Schoetterl-Glausch 		ret = false;
101*d05bf604SJanis Schoetterl-Glausch 	}
102*d05bf604SJanis Schoetterl-Glausch 	while (true) {
103*d05bf604SJanis Schoetterl-Glausch 		long input = 0;
104*d05bf604SJanis Schoetterl-Glausch 
105*d05bf604SJanis Schoetterl-Glausch 		if (strlen(list) == 0)
106*d05bf604SJanis Schoetterl-Glausch 			return ret;
107*d05bf604SJanis Schoetterl-Glausch 		input = strtol(list, &list, 16);
108*d05bf604SJanis Schoetterl-Glausch 		if (*list == ',')
109*d05bf604SJanis Schoetterl-Glausch 			list++;
110*d05bf604SJanis Schoetterl-Glausch 		else if (*list != '\0')
111*d05bf604SJanis Schoetterl-Glausch 			break;
112*d05bf604SJanis Schoetterl-Glausch 		if (input == machine_id)
113*d05bf604SJanis Schoetterl-Glausch 			return !ret;
114*d05bf604SJanis Schoetterl-Glausch 	}
115*d05bf604SJanis Schoetterl-Glausch 	printf("Invalid --strict argument \"%s\", ignoring\n", list);
116*d05bf604SJanis Schoetterl-Glausch 	return ret;
117*d05bf604SJanis Schoetterl-Glausch }
118*d05bf604SJanis Schoetterl-Glausch 
11949934b5aSJanis Schoetterl-Glausch int main(int argc, char **argv)
12049934b5aSJanis Schoetterl-Glausch {
121*d05bf604SJanis Schoetterl-Glausch 	strict = parse_strict(argc - 1, argv + 1);
12249934b5aSJanis Schoetterl-Glausch 	if (!sclp_facilities.has_sief2) {
12349934b5aSJanis Schoetterl-Glausch 		report_skip("SIEF2 facility unavailable");
12449934b5aSJanis Schoetterl-Glausch 		goto out;
12549934b5aSJanis Schoetterl-Glausch 	}
12649934b5aSJanis Schoetterl-Glausch 
12749934b5aSJanis Schoetterl-Glausch 	test_spec_ex_sie();
12849934b5aSJanis Schoetterl-Glausch out:
12949934b5aSJanis Schoetterl-Glausch 	return report_summary();
13049934b5aSJanis Schoetterl-Glausch }
131