On Fri, 21 Apr 2023 11:36:46 +0000 Janosch Frank <frankja@xxxxxxxxxxxxx> wrote: > The diag308 requires extensive cooperation between the hypervisor and > the Ultravisor so the Ultravisor can make sure all necessary reset > steps have been done. > > Let's check if we get the correct validity errors. > > Signed-off-by: Janosch Frank <frankja@xxxxxxxxxxxxx> > --- > s390x/Makefile | 2 + > s390x/pv-ipl.c | 145 ++++++++++++++++++++++++++++++++++++++++++++ > s390x/unittests.cfg | 4 ++ > 3 files changed, 151 insertions(+) > create mode 100644 s390x/pv-ipl.c > > diff --git a/s390x/Makefile b/s390x/Makefile > index 67be5360..b5b94810 100644 > --- a/s390x/Makefile > +++ b/s390x/Makefile > @@ -43,6 +43,7 @@ tests += $(TEST_DIR)/ex.elf > > pv-tests += $(TEST_DIR)/pv-diags.elf > pv-tests += $(TEST_DIR)/pv-icptcode.elf > +pv-tests += $(TEST_DIR)/pv-ipl.elf > > ifneq ($(HOST_KEY_DOCUMENT),) > ifneq ($(GEN_SE_HEADER),) > @@ -130,6 +131,7 @@ $(TEST_DIR)/pv-icptcode.elf: pv-snippets += $(SNIPPET_DIR)/asm/pv-icpt-112.gbin > $(TEST_DIR)/pv-icptcode.elf: pv-snippets += $(SNIPPET_DIR)/asm/icpt-loop.gbin > $(TEST_DIR)/pv-icptcode.elf: pv-snippets += $(SNIPPET_DIR)/asm/loop.gbin > $(TEST_DIR)/pv-icptcode.elf: pv-snippets += $(SNIPPET_DIR)/asm/pv-icpt-vir-timing.gbin > +$(TEST_DIR)/pv-ipl.elf: pv-snippets += $(SNIPPET_DIR)/asm/pv-diag-308.gbin > > ifneq ($(GEN_SE_HEADER),) > snippets += $(pv-snippets) > diff --git a/s390x/pv-ipl.c b/s390x/pv-ipl.c > new file mode 100644 > index 00000000..aad1275e > --- /dev/null > +++ b/s390x/pv-ipl.c > @@ -0,0 +1,145 @@ > +/* SPDX-License-Identifier: GPL-2.0-only */ > +/* > + * PV diagnose 308 (IPL) tests > + * > + * Copyright (c) 2023 IBM Corp > + * > + * Authors: > + * Janosch Frank <frankja@xxxxxxxxxxxxx> > + */ > +#include <libcflat.h> > +#include <sie.h> > +#include <sclp.h> > +#include <snippet.h> > +#include <pv_icptdata.h> > +#include <asm/facility.h> > +#include <asm/uv.h> > + > +static struct vm vm; > + > +static void test_diag_308(int subcode) > +{ > + extern const char SNIPPET_NAME_START(asm, pv_diag_308)[]; > + extern const char SNIPPET_NAME_END(asm, pv_diag_308)[]; > + extern const char SNIPPET_HDR_START(asm, pv_diag_308)[]; > + extern const char SNIPPET_HDR_END(asm, pv_diag_308)[]; > + int size_hdr = SNIPPET_HDR_LEN(asm, pv_diag_308); > + int size_gbin = SNIPPET_LEN(asm, pv_diag_308); > + uint16_t rc, rrc; > + char prefix[10]; > + int cc; > + > + snprintf(prefix, sizeof(prefix), "subcode %d", subcode); > + > + report_prefix_push(prefix); report_prefix_pushf > + snippet_pv_init(&vm, SNIPPET_NAME_START(asm, pv_diag_308), > + SNIPPET_HDR_START(asm, pv_diag_308), > + size_gbin, size_hdr, SNIPPET_UNPACK_OFF); > + > + /* First exit is a diag 0x500 */ > + sie(&vm); > + assert(pv_icptdata_check_diag(&vm, 0x500)); > + > + /* > + * The snippet asked us for the subcode and we answer with 0 in gr2 not always 0 I guess? > + * SIE will copy gr2 to the guest > + */ > + vm.save_area.guest.grs[2] = subcode; > + > + /* Continue after diag 0x500, next icpt should be the 0x308 */ > + sie(&vm); > + assert(pv_icptdata_check_diag(&vm, 0x308)); > + assert(vm.save_area.guest.grs[2] == subcode); > + > + /* > + * We need to perform several UV calls to emulate the subcode > + * 0/1. Failing to do that should result in a validity. > + * > + * - Mark all cpus as stopped > + * - Unshare all memory > + * - Prepare the reset > + * - Reset the cpus > + * - Load the reset PSW > + */ > + sie_expect_validity(&vm); > + sie(&vm); > + report(uv_validity_check(&vm), "validity, no action"); > + > + /* Mark the CPU as stopped so we can unshare and reset */ > + cc = uv_set_cpu_state(vm.sblk->pv_handle_cpu, PV_CPU_STATE_STP); > + report(!cc, "Set cpu stopped"); > + > + sie_expect_validity(&vm); > + sie(&vm); > + report(uv_validity_check(&vm), "validity, stopped"); > + > + /* Unshare all memory */ > + cc = uv_cmd_nodata(vm.sblk->pv_handle_config, > + UVC_CMD_SET_UNSHARED_ALL, &rc, &rrc); > + report(cc == 0 && rc == 1, "Unshare all"); > + > + sie_expect_validity(&vm); > + sie(&vm); > + report(uv_validity_check(&vm), "validity, stopped, unshared"); > + > + /* Prepare the CPU reset */ > + cc = uv_cmd_nodata(vm.sblk->pv_handle_config, > + UVC_CMD_PREPARE_RESET, &rc, &rrc); > + report(cc == 0 && rc == 1, "Prepare reset call"); > + > + sie_expect_validity(&vm); > + sie(&vm); > + report(uv_validity_check(&vm), "validity, stopped, unshared, prep reset"); > + > + /* > + * Do the reset on the initiating cpu > + * > + * Reset clear for subcode 0 > + * Reset initial for subcode 1 > + */ > + if (subcode == 0) { > + cc = uv_cmd_nodata(vm.sblk->pv_handle_cpu, > + UVC_CMD_CPU_RESET_CLEAR, &rc, &rrc); > + report(cc == 0 && rc == 1, "Clear reset cpu"); > + } else { > + cc = uv_cmd_nodata(vm.sblk->pv_handle_cpu, > + UVC_CMD_CPU_RESET_INITIAL, &rc, &rrc); > + report(cc == 0 && rc == 1, "Initial reset cpu"); > + } > + > + sie_expect_validity(&vm); > + sie(&vm); > + report(uv_validity_check(&vm), "validity, stopped, unshared, prep reset, cpu reset"); > + > + /* Load the PSW from 0x0 */ > + cc = uv_set_cpu_state(vm.sblk->pv_handle_cpu, PV_CPU_STATE_OPR_LOAD); > + report(!cc, "Set cpu load"); > + > + /* > + * Check if we executed the iaddr of the reset PSW, we should > + * see a diagnose 0x9c PV instruction notification. > + */ > + sie(&vm); > + report(pv_icptdata_check_diag(&vm, 0x9c) && > + vm.save_area.guest.grs[0] == 42, > + "continue after load"); > + > + uv_destroy_guest(&vm); > + report_prefix_pop(); > +} > + > +int main(void) > +{ > + report_prefix_push("uv-sie"); > + if (!uv_guest_requirement_checks()) > + goto done; > + > + snippet_setup_guest(&vm, true); > + test_diag_308(0); > + test_diag_308(1); > + sie_guest_destroy(&vm); > + > +done: > + report_prefix_pop(); > + return report_summary(); > +} > diff --git a/s390x/unittests.cfg b/s390x/unittests.cfg > index e2d3478e..e08e5c84 100644 > --- a/s390x/unittests.cfg > +++ b/s390x/unittests.cfg > @@ -223,3 +223,7 @@ file = ex.elf > file = pv-icptcode.elf > smp = 3 > extra_params = -m 2200 > + > +[pv-ipl] > +file = pv-ipl.elf > +extra_params = -m 2200