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