1 /* SPDX-License-Identifier: GPL-2.0-only */ 2 /* 3 * PV diagnose 308 (IPL) tests 4 * 5 * Copyright (c) 2023 IBM Corp 6 * 7 * Authors: 8 * Janosch Frank <frankja@linux.ibm.com> 9 */ 10 #include <libcflat.h> 11 #include <sie.h> 12 #include <sclp.h> 13 #include <snippet.h> 14 #include <pv_icptdata.h> 15 #include <asm/facility.h> 16 #include <asm/uv.h> 17 18 static struct vm vm; 19 20 static void test_diag_308(int subcode) 21 { 22 extern const char SNIPPET_NAME_START(asm, pv_diag_308)[]; 23 extern const char SNIPPET_NAME_END(asm, pv_diag_308)[]; 24 extern const char SNIPPET_HDR_START(asm, pv_diag_308)[]; 25 extern const char SNIPPET_HDR_END(asm, pv_diag_308)[]; 26 int size_hdr = SNIPPET_HDR_LEN(asm, pv_diag_308); 27 int size_gbin = SNIPPET_LEN(asm, pv_diag_308); 28 uint16_t rc, rrc; 29 int cc; 30 31 report_prefix_pushf("subcode %d", subcode); 32 snippet_pv_init(&vm, SNIPPET_NAME_START(asm, pv_diag_308), 33 SNIPPET_HDR_START(asm, pv_diag_308), 34 size_gbin, size_hdr, SNIPPET_UNPACK_OFF); 35 36 /* First exit is a diag 0x500 */ 37 sie(&vm); 38 assert(pv_icptdata_check_diag(&vm, 0x500)); 39 40 /* 41 * The snippet asked us for the subcode and we answer by 42 * putting the value in gr2. 43 * SIE will copy gr2 to the guest 44 */ 45 vm.save_area.guest.grs[2] = subcode; 46 47 /* Continue after diag 0x500, next icpt should be the 0x308 */ 48 sie(&vm); 49 assert(pv_icptdata_check_diag(&vm, 0x308)); 50 assert(vm.save_area.guest.grs[2] == subcode); 51 52 /* 53 * We need to perform several UV calls to emulate the subcode 54 * 0/1. Failing to do that should result in a validity. 55 * 56 * - Mark all cpus as stopped 57 * - Unshare all memory 58 * - Prepare the reset 59 * - Reset the cpus 60 * - Load the reset PSW 61 */ 62 sie_expect_validity(&vm); 63 sie(&vm); 64 report(uv_validity_check(&vm), "validity, no action"); 65 66 /* Mark the CPU as stopped so we can unshare and reset */ 67 cc = uv_set_cpu_state(vm.sblk->pv_handle_cpu, PV_CPU_STATE_STP); 68 report(!cc, "Set cpu stopped"); 69 70 sie_expect_validity(&vm); 71 sie(&vm); 72 report(uv_validity_check(&vm), "validity, stopped"); 73 74 /* Unshare all memory */ 75 cc = uv_cmd_nodata(vm.sblk->pv_handle_config, 76 UVC_CMD_SET_UNSHARED_ALL, &rc, &rrc); 77 report(cc == 0 && rc == 1, "Unshare all"); 78 79 sie_expect_validity(&vm); 80 sie(&vm); 81 report(uv_validity_check(&vm), "validity, stopped, unshared"); 82 83 /* Prepare the CPU reset */ 84 cc = uv_cmd_nodata(vm.sblk->pv_handle_config, 85 UVC_CMD_PREPARE_RESET, &rc, &rrc); 86 report(cc == 0 && rc == 1, "Prepare reset call"); 87 88 sie_expect_validity(&vm); 89 sie(&vm); 90 report(uv_validity_check(&vm), "validity, stopped, unshared, prep reset"); 91 92 /* 93 * Do the reset on the initiating cpu 94 * 95 * Reset clear for subcode 0 96 * Reset initial for subcode 1 97 */ 98 if (subcode == 0) { 99 cc = uv_cmd_nodata(vm.sblk->pv_handle_cpu, 100 UVC_CMD_CPU_RESET_CLEAR, &rc, &rrc); 101 report(cc == 0 && rc == 1, "Clear reset cpu"); 102 } else { 103 cc = uv_cmd_nodata(vm.sblk->pv_handle_cpu, 104 UVC_CMD_CPU_RESET_INITIAL, &rc, &rrc); 105 report(cc == 0 && rc == 1, "Initial reset cpu"); 106 } 107 108 sie_expect_validity(&vm); 109 sie(&vm); 110 report(uv_validity_check(&vm), "validity, stopped, unshared, prep reset, cpu reset"); 111 112 /* Load the PSW from 0x0 */ 113 cc = uv_set_cpu_state(vm.sblk->pv_handle_cpu, PV_CPU_STATE_OPR_LOAD); 114 report(!cc, "Set cpu load"); 115 116 /* 117 * Check if we executed the iaddr of the reset PSW, we should 118 * see a diagnose 0x9c PV instruction notification. 119 */ 120 sie(&vm); 121 report(pv_icptdata_check_diag(&vm, 0x9c) && 122 vm.save_area.guest.grs[0] == 42, 123 "continue after load"); 124 125 uv_destroy_guest(&vm); 126 report_prefix_pop(); 127 } 128 129 int main(void) 130 { 131 report_prefix_push("uv-sie"); 132 if (!uv_host_requirement_checks()) 133 goto done; 134 135 snippet_setup_guest(&vm, true); 136 test_diag_308(0); 137 test_diag_308(1); 138 sie_guest_destroy(&vm); 139 140 done: 141 report_prefix_pop(); 142 return report_summary(); 143 } 144