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 <sie-icpt.h>
15 #include <asm/facility.h>
16 #include <asm/uv.h>
17
18 static struct vm vm;
19
test_diag_308(int subcode)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(sie_is_diag_icpt(&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(sie_is_diag_icpt(&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(sie_is_diag_icpt(&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
main(void)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