blob: 5fa135b81c8689b5aa35457ac5cb55fc150c84c5 [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright IBM Corp. 2021
*
* Specification exception interception test.
* Checks that specification exception interceptions occur as expected when
* specification exception interpretation is off/on.
*/
#include <libcflat.h>
#include <stdlib.h>
#include <sclp.h>
#include <asm/page.h>
#include <asm/arch_def.h>
#include <alloc_page.h>
#include <sie.h>
#include <snippet.h>
#include <hardware.h>
static struct vm vm;
extern const char SNIPPET_NAME_START(c, spec_ex)[];
extern const char SNIPPET_NAME_END(c, spec_ex)[];
static bool strict;
static void setup_guest(void)
{
char *guest;
int binary_size = SNIPPET_LEN(c, spec_ex);
setup_vm();
guest = alloc_pages(8);
memcpy(guest, SNIPPET_NAME_START(c, spec_ex), binary_size);
sie_guest_create(&vm, (uint64_t) guest, HPAGE_SIZE);
}
static void reset_guest(void)
{
vm.sblk->gpsw = snippet_psw;
vm.sblk->icptcode = 0;
}
static void test_spec_ex_sie(void)
{
const char *msg;
setup_guest();
report_prefix_push("SIE spec ex interpretation");
report_prefix_push("off");
reset_guest();
sie(&vm);
/* interpretation off -> initial exception must cause interception */
report(vm.sblk->icptcode == ICPT_PROGI
&& vm.sblk->iprcc == PGM_INT_CODE_SPECIFICATION
&& vm.sblk->gpsw.addr != 0xdeadbeee,
"Received specification exception intercept for initial exception");
report_prefix_pop();
report_prefix_push("on");
vm.sblk->ecb |= ECB_SPECI;
reset_guest();
sie(&vm);
/* interpretation on -> configuration dependent if initial exception causes
* interception, but invalid new program PSW must
*/
report(vm.sblk->icptcode == ICPT_PROGI
&& vm.sblk->iprcc == PGM_INT_CODE_SPECIFICATION,
"Received specification exception intercept");
msg = "Interpreted initial exception, intercepted invalid program new PSW exception";
if (strict)
report(vm.sblk->gpsw.addr == 0xdeadbeee, "%s", msg);
else if (vm.sblk->gpsw.addr == 0xdeadbeee)
report_info("%s", msg);
else
report_info("Did not interpret initial exception");
report_prefix_pop();
report_prefix_pop();
}
static bool parse_strict(int argc, char **argv)
{
uint16_t machine_id;
char *list;
bool ret;
if (argc < 1)
return false;
if (strcmp("--strict", argv[0]))
return false;
machine_id = get_machine_id();
if (argc < 2) {
printf("No argument to --strict, ignoring\n");
return false;
}
list = argv[1];
if (list[0] == '!') {
ret = true;
list++;
} else {
ret = false;
}
while (true) {
long input = 0;
if (strlen(list) == 0)
return ret;
input = strtol(list, &list, 16);
if (*list == ',')
list++;
else if (*list != '\0')
break;
if (input == machine_id)
return !ret;
}
printf("Invalid --strict argument \"%s\", ignoring\n", list);
return ret;
}
int main(int argc, char **argv)
{
strict = parse_strict(argc - 1, argv + 1);
if (!sclp_facilities.has_sief2) {
report_skip("SIEF2 facility unavailable");
goto out;
}
test_spec_ex_sie();
out:
return report_summary();
}