xref: /kvm-unit-tests/s390x/uv-guest.c (revision c315f52b88b967cfb4cd58f3b4e1987378c47f3b)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 /*
3  * Guest Ultravisor Call tests
4  *
5  * Copyright IBM Corp. 2020, 2022
6  *
7  * Authors:
8  *  Janosch Frank <frankja@linux.ibm.com>
9  */
10 
11 #include <libcflat.h>
12 #include <alloc_page.h>
13 #include <asm/page.h>
14 #include <asm/asm-offsets.h>
15 #include <asm/interrupt.h>
16 #include <asm/facility.h>
17 #include <asm/uv.h>
18 #include <sclp.h>
19 #include <uv.h>
20 
21 static unsigned long page;
22 
test_priv(void)23 static void test_priv(void)
24 {
25 	struct uv_cb_header uvcb = {};
26 
27 	report_prefix_push("privileged");
28 
29 	report_prefix_push("query");
30 	uvcb.cmd = UVC_CMD_QUI;
31 	uvcb.len = sizeof(struct uv_cb_qui);
32 	expect_pgm_int();
33 	enter_pstate();
34 	uv_call_once(0, (u64)&uvcb);
35 	check_pgm_int_code(PGM_INT_CODE_PRIVILEGED_OPERATION);
36 	report_prefix_pop();
37 
38 	report_prefix_push("share");
39 	uvcb.cmd = UVC_CMD_SET_SHARED_ACCESS;
40 	uvcb.len = sizeof(struct uv_cb_share);
41 	expect_pgm_int();
42 	enter_pstate();
43 	uv_call_once(0, (u64)&uvcb);
44 	check_pgm_int_code(PGM_INT_CODE_PRIVILEGED_OPERATION);
45 	report_prefix_pop();
46 
47 	report_prefix_push("unshare");
48 	uvcb.cmd = UVC_CMD_REMOVE_SHARED_ACCESS;
49 	uvcb.len = sizeof(struct uv_cb_share);
50 	expect_pgm_int();
51 	enter_pstate();
52 	uv_call_once(0, (u64)&uvcb);
53 	check_pgm_int_code(PGM_INT_CODE_PRIVILEGED_OPERATION);
54 	report_prefix_pop();
55 
56 	report_prefix_push("attest");
57 	uvcb.cmd = UVC_CMD_ATTESTATION;
58 	uvcb.len = sizeof(struct uv_cb_attest);
59 	expect_pgm_int();
60 	enter_pstate();
61 	uv_call_once(0, (uint64_t)&uvcb);
62 	check_pgm_int_code(PGM_INT_CODE_PRIVILEGED_OPERATION);
63 	report_prefix_pop();
64 
65 	report_prefix_pop();
66 }
67 
test_query(void)68 static void test_query(void)
69 {
70 	struct uv_cb_qui uvcb = {
71 		.header.cmd = UVC_CMD_QUI,
72 		/* A dword below the minimum length */
73 		.header.len = 0xa0,
74 	};
75 	int cc;
76 
77 	report_prefix_push("query");
78 	cc = uv_call(0, (u64)&uvcb);
79 	report(cc == 1 && uvcb.header.rc == UVC_RC_INV_LEN, "length");
80 
81 	/*
82 	 * BIT_UVC_CMD_QUI, BIT_UVC_CMD_SET_SHARED_ACCESS and
83 	 * BIT_UVC_CMD_REMOVE_SHARED_ACCESS are always present as they
84 	 * have been introduced with the first Ultravisor version.
85 	 * However, we only need to check for QUI as
86 	 * SET/REMOVE SHARED are used to fence this test to be only
87 	 * executed by protected guests.
88 	 */
89 	report(uv_query_test_call(BIT_UVC_CMD_QUI), "query indicated");
90 	report_prefix_pop();
91 }
92 
test_sharing(void)93 static void test_sharing(void)
94 {
95 	struct uv_cb_share uvcb = {
96 		.header.cmd = UVC_CMD_SET_SHARED_ACCESS,
97 		.header.len = sizeof(uvcb) - 8,
98 		.paddr = page,
99 	};
100 	int cc;
101 
102 	report_prefix_push("share");
103 	cc = uv_call(0, (u64)&uvcb);
104 	report(cc == 1 && uvcb.header.rc == UVC_RC_INV_LEN, "length");
105 	uvcb.header.len = sizeof(uvcb);
106 	cc = uv_call(0, (u64)&uvcb);
107 	report(cc == 0 && uvcb.header.rc == UVC_RC_EXECUTED, "share");
108 	uvcb.paddr = get_ram_size() + PAGE_SIZE;
109 	cc = uv_call(0, (u64)&uvcb);
110 	report(cc == 1 && uvcb.header.rc == 0x101, "invalid memory");
111 	uvcb.paddr = page;
112 	report_prefix_pop();
113 
114 	report_prefix_push("unshare");
115 	uvcb.header.cmd = UVC_CMD_REMOVE_SHARED_ACCESS;
116 	uvcb.header.len -= 8;
117 	cc = uv_call(0, (u64)&uvcb);
118 	report(cc == 1 && uvcb.header.rc == UVC_RC_INV_LEN, "length");
119 	uvcb.header.len = sizeof(uvcb);
120 	cc = uv_call(0, (u64)&uvcb);
121 	report(cc == 0 && uvcb.header.rc == UVC_RC_EXECUTED, "unshare");
122 	report_prefix_pop();
123 }
124 
125 static struct {
126 	const char *name;
127 	uint16_t cmd;
128 	uint16_t len;
129 	int call_bit;
130 } invalid_cmds[] = {
131 	{ "bogus", 0x4242, sizeof(struct uv_cb_header), -1 },
132 	{ "init", UVC_CMD_INIT_UV, sizeof(struct uv_cb_init), BIT_UVC_CMD_INIT_UV },
133 	{ "create conf", UVC_CMD_CREATE_SEC_CONF, sizeof(struct uv_cb_cgc), BIT_UVC_CMD_CREATE_SEC_CONF },
134 	{ "destroy conf", UVC_CMD_DESTROY_SEC_CONF, sizeof(struct uv_cb_nodata), BIT_UVC_CMD_DESTROY_SEC_CONF },
135 	{ "create cpu", UVC_CMD_CREATE_SEC_CPU, sizeof(struct uv_cb_csc), BIT_UVC_CMD_CREATE_SEC_CPU },
136 	{ "destroy cpu", UVC_CMD_DESTROY_SEC_CPU, sizeof(struct uv_cb_nodata), BIT_UVC_CMD_DESTROY_SEC_CPU },
137 	{ "conv to", UVC_CMD_CONV_TO_SEC_STOR, sizeof(struct uv_cb_cts), BIT_UVC_CMD_CONV_TO_SEC_STOR },
138 	{ "conv from", UVC_CMD_CONV_FROM_SEC_STOR, sizeof(struct uv_cb_cfs), BIT_UVC_CMD_CONV_FROM_SEC_STOR },
139 	{ "set sec conf", UVC_CMD_SET_SEC_CONF_PARAMS, sizeof(struct uv_cb_ssc), BIT_UVC_CMD_SET_SEC_PARMS },
140 	{ "unpack", UVC_CMD_UNPACK_IMG, sizeof(struct uv_cb_unp), BIT_UVC_CMD_UNPACK_IMG },
141 	{ "verify", UVC_CMD_VERIFY_IMG, sizeof(struct uv_cb_nodata), BIT_UVC_CMD_VERIFY_IMG },
142 	{ "cpu reset", UVC_CMD_CPU_RESET, sizeof(struct uv_cb_nodata), BIT_UVC_CMD_CPU_RESET },
143 	{ "cpu initial reset", UVC_CMD_CPU_RESET_INITIAL, sizeof(struct uv_cb_nodata), BIT_UVC_CMD_CPU_RESET_INITIAL },
144 	{ "prepare clear reset", UVC_CMD_PREPARE_RESET, sizeof(struct uv_cb_nodata), BIT_UVC_CMD_PREPARE_RESET },
145 	{ "cpu clear reset", UVC_CMD_CPU_RESET_CLEAR, sizeof(struct uv_cb_nodata), BIT_UVC_CMD_CPU_PERFORM_CLEAR_RESET },
146 	{ "cpu set state", UVC_CMD_CPU_SET_STATE, sizeof(struct uv_cb_cpu_set_state), BIT_UVC_CMD_CPU_SET_STATE },
147 	{ "pin shared", UVC_CMD_PIN_PAGE_SHARED, sizeof(struct uv_cb_cfs), BIT_UVC_CMD_PIN_PAGE_SHARED },
148 	{ "unpin shared", UVC_CMD_UNPIN_PAGE_SHARED, sizeof(struct uv_cb_cts), BIT_UVC_CMD_UNPIN_PAGE_SHARED },
149 	{ NULL, 0, 0 },
150 };
151 
test_invalid(void)152 static void test_invalid(void)
153 {
154 	struct uv_cb_header *hdr = (void *)page;
155 	int cc, i;
156 
157 	report_prefix_push("invalid");
158 	for (i = 0; invalid_cmds[i].name; i++) {
159 		hdr->cmd = invalid_cmds[i].cmd;
160 		hdr->len = invalid_cmds[i].len;
161 		cc = uv_call(0, (u64)hdr);
162 		report(cc == 1 && hdr->rc == UVC_RC_INV_CMD &&
163 		       (invalid_cmds[i].call_bit == -1 || !uv_query_test_call(invalid_cmds[i].call_bit)),
164 		       "%s", invalid_cmds[i].name);
165 	}
166 	report_prefix_pop();
167 }
168 
test_share_bits(void)169 static void test_share_bits(void)
170 {
171 	bool unshare = uv_query_test_call(BIT_UVC_CMD_REMOVE_SHARED_ACCESS);
172 	bool share = uv_query_test_call(BIT_UVC_CMD_SET_SHARED_ACCESS);
173 
174 	report_prefix_push("query");
175 	report(!(share ^ unshare), "share bits are identical");
176 	report_prefix_pop();
177 }
178 
main(void)179 int main(void)
180 {
181 	bool has_uvc = test_facility(158);
182 
183 	report_prefix_push("uvc");
184 	if (!has_uvc) {
185 		report_skip("Ultravisor call facility is not available");
186 		goto done;
187 	}
188 
189 	/*
190 	 * Needs to be done before the guest-fence,
191 	 * as the fence tests if both shared bits are present
192 	 */
193 	test_share_bits();
194 
195 	if (!uv_os_is_guest()) {
196 		report_skip("Not a protected guest");
197 		goto done;
198 	}
199 
200 	page = (unsigned long)alloc_page();
201 	test_priv();
202 	test_invalid();
203 	test_query();
204 	test_sharing();
205 	free_page((void *)page);
206 done:
207 	report_prefix_pop();
208 	return report_summary();
209 }
210