xref: /kvm-unit-tests/s390x/pv-ipl.c (revision 1f08a91a41402b0e032ecce8ed1b5952cbfca0ea)
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