/* SPDX-License-Identifier: GPL-2.0-only */ /* * PV diagnose 308 (IPL) tests * * Copyright (c) 2023 IBM Corp * * Authors: * Janosch Frank */ #include #include #include #include #include #include #include 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; int cc; report_prefix_pushf("subcode %d", subcode); 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(sie_is_diag_icpt(&vm, 0x500)); /* * The snippet asked us for the subcode and we answer by * putting the value in gr2. * 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(sie_is_diag_icpt(&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(sie_is_diag_icpt(&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_host_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(); }