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>
10d05bf604SJanis 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>
17d05bf604SJanis Schoetterl-Glausch #include <hardware.h>
1849934b5aSJanis Schoetterl-Glausch
1949934b5aSJanis Schoetterl-Glausch static struct vm vm;
20d05bf604SJanis Schoetterl-Glausch static bool strict;
2149934b5aSJanis Schoetterl-Glausch
setup_guest(void)2249934b5aSJanis Schoetterl-Glausch static void setup_guest(void)
2349934b5aSJanis Schoetterl-Glausch {
24*be76de4dSNico Boehr extern const char SNIPPET_NAME_START(c, spec_ex)[];
25*be76de4dSNico Boehr extern const char SNIPPET_NAME_END(c, spec_ex)[];
2649934b5aSJanis Schoetterl-Glausch
2749934b5aSJanis Schoetterl-Glausch setup_vm();
28*be76de4dSNico Boehr
29*be76de4dSNico Boehr snippet_setup_guest(&vm, false);
30*be76de4dSNico Boehr snippet_init(&vm, SNIPPET_NAME_START(c, spec_ex),
31*be76de4dSNico Boehr SNIPPET_LEN(c, spec_ex), SNIPPET_UNPACK_OFF);
3249934b5aSJanis Schoetterl-Glausch }
3349934b5aSJanis Schoetterl-Glausch
reset_guest(void)3449934b5aSJanis Schoetterl-Glausch static void reset_guest(void)
3549934b5aSJanis Schoetterl-Glausch {
3649934b5aSJanis Schoetterl-Glausch vm.sblk->gpsw = snippet_psw;
3749934b5aSJanis Schoetterl-Glausch vm.sblk->icptcode = 0;
3849934b5aSJanis Schoetterl-Glausch }
3949934b5aSJanis Schoetterl-Glausch
test_spec_ex_sie(void)4049934b5aSJanis Schoetterl-Glausch static void test_spec_ex_sie(void)
4149934b5aSJanis Schoetterl-Glausch {
42d05bf604SJanis Schoetterl-Glausch const char *msg;
43d05bf604SJanis Schoetterl-Glausch
4449934b5aSJanis Schoetterl-Glausch setup_guest();
4549934b5aSJanis Schoetterl-Glausch
4649934b5aSJanis Schoetterl-Glausch report_prefix_push("SIE spec ex interpretation");
4749934b5aSJanis Schoetterl-Glausch report_prefix_push("off");
4849934b5aSJanis Schoetterl-Glausch reset_guest();
4949934b5aSJanis Schoetterl-Glausch sie(&vm);
5049934b5aSJanis Schoetterl-Glausch /* interpretation off -> initial exception must cause interception */
5149934b5aSJanis Schoetterl-Glausch report(vm.sblk->icptcode == ICPT_PROGI
5249934b5aSJanis Schoetterl-Glausch && vm.sblk->iprcc == PGM_INT_CODE_SPECIFICATION
5349934b5aSJanis Schoetterl-Glausch && vm.sblk->gpsw.addr != 0xdeadbeee,
5449934b5aSJanis Schoetterl-Glausch "Received specification exception intercept for initial exception");
5549934b5aSJanis Schoetterl-Glausch report_prefix_pop();
5649934b5aSJanis Schoetterl-Glausch
5749934b5aSJanis Schoetterl-Glausch report_prefix_push("on");
5849934b5aSJanis Schoetterl-Glausch vm.sblk->ecb |= ECB_SPECI;
5949934b5aSJanis Schoetterl-Glausch reset_guest();
6049934b5aSJanis Schoetterl-Glausch sie(&vm);
6149934b5aSJanis Schoetterl-Glausch /* interpretation on -> configuration dependent if initial exception causes
6249934b5aSJanis Schoetterl-Glausch * interception, but invalid new program PSW must
6349934b5aSJanis Schoetterl-Glausch */
6449934b5aSJanis Schoetterl-Glausch report(vm.sblk->icptcode == ICPT_PROGI
6549934b5aSJanis Schoetterl-Glausch && vm.sblk->iprcc == PGM_INT_CODE_SPECIFICATION,
6649934b5aSJanis Schoetterl-Glausch "Received specification exception intercept");
67d05bf604SJanis Schoetterl-Glausch msg = "Interpreted initial exception, intercepted invalid program new PSW exception";
68d05bf604SJanis Schoetterl-Glausch if (strict)
69d05bf604SJanis Schoetterl-Glausch report(vm.sblk->gpsw.addr == 0xdeadbeee, "%s", msg);
70d05bf604SJanis Schoetterl-Glausch else if (vm.sblk->gpsw.addr == 0xdeadbeee)
71d05bf604SJanis Schoetterl-Glausch report_info("%s", msg);
7249934b5aSJanis Schoetterl-Glausch else
7349934b5aSJanis Schoetterl-Glausch report_info("Did not interpret initial exception");
7449934b5aSJanis Schoetterl-Glausch report_prefix_pop();
7549934b5aSJanis Schoetterl-Glausch report_prefix_pop();
7649934b5aSJanis Schoetterl-Glausch }
7749934b5aSJanis Schoetterl-Glausch
parse_strict(int argc,char ** argv)78d05bf604SJanis Schoetterl-Glausch static bool parse_strict(int argc, char **argv)
79d05bf604SJanis Schoetterl-Glausch {
80d05bf604SJanis Schoetterl-Glausch uint16_t machine_id;
81d05bf604SJanis Schoetterl-Glausch char *list;
82d05bf604SJanis Schoetterl-Glausch bool ret;
83d05bf604SJanis Schoetterl-Glausch
84d05bf604SJanis Schoetterl-Glausch if (argc < 1)
85d05bf604SJanis Schoetterl-Glausch return false;
86d05bf604SJanis Schoetterl-Glausch if (strcmp("--strict", argv[0]))
87d05bf604SJanis Schoetterl-Glausch return false;
88d05bf604SJanis Schoetterl-Glausch
89d05bf604SJanis Schoetterl-Glausch machine_id = get_machine_id();
90d05bf604SJanis Schoetterl-Glausch if (argc < 2) {
91d05bf604SJanis Schoetterl-Glausch printf("No argument to --strict, ignoring\n");
92d05bf604SJanis Schoetterl-Glausch return false;
93d05bf604SJanis Schoetterl-Glausch }
94d05bf604SJanis Schoetterl-Glausch list = argv[1];
95d05bf604SJanis Schoetterl-Glausch if (list[0] == '!') {
96d05bf604SJanis Schoetterl-Glausch ret = true;
97d05bf604SJanis Schoetterl-Glausch list++;
98d05bf604SJanis Schoetterl-Glausch } else {
99d05bf604SJanis Schoetterl-Glausch ret = false;
100d05bf604SJanis Schoetterl-Glausch }
101d05bf604SJanis Schoetterl-Glausch while (true) {
102d05bf604SJanis Schoetterl-Glausch long input = 0;
103d05bf604SJanis Schoetterl-Glausch
104d05bf604SJanis Schoetterl-Glausch if (strlen(list) == 0)
105d05bf604SJanis Schoetterl-Glausch return ret;
106d05bf604SJanis Schoetterl-Glausch input = strtol(list, &list, 16);
107d05bf604SJanis Schoetterl-Glausch if (*list == ',')
108d05bf604SJanis Schoetterl-Glausch list++;
109d05bf604SJanis Schoetterl-Glausch else if (*list != '\0')
110d05bf604SJanis Schoetterl-Glausch break;
111d05bf604SJanis Schoetterl-Glausch if (input == machine_id)
112d05bf604SJanis Schoetterl-Glausch return !ret;
113d05bf604SJanis Schoetterl-Glausch }
114d05bf604SJanis Schoetterl-Glausch printf("Invalid --strict argument \"%s\", ignoring\n", list);
115d05bf604SJanis Schoetterl-Glausch return ret;
116d05bf604SJanis Schoetterl-Glausch }
117d05bf604SJanis Schoetterl-Glausch
main(int argc,char ** argv)11849934b5aSJanis Schoetterl-Glausch int main(int argc, char **argv)
11949934b5aSJanis Schoetterl-Glausch {
120d05bf604SJanis Schoetterl-Glausch strict = parse_strict(argc - 1, argv + 1);
12149934b5aSJanis Schoetterl-Glausch if (!sclp_facilities.has_sief2) {
12249934b5aSJanis Schoetterl-Glausch report_skip("SIEF2 facility unavailable");
12349934b5aSJanis Schoetterl-Glausch goto out;
12449934b5aSJanis Schoetterl-Glausch }
12549934b5aSJanis Schoetterl-Glausch
12649934b5aSJanis Schoetterl-Glausch test_spec_ex_sie();
12749934b5aSJanis Schoetterl-Glausch out:
12849934b5aSJanis Schoetterl-Glausch return report_summary();
12949934b5aSJanis Schoetterl-Glausch }
130