xref: /kvm-unit-tests/s390x/uv-guest.c (revision 1b642bff27c26cef26a150d2ac3be0380457f1e4)
1fa624cc2SJanosch Frank /* SPDX-License-Identifier: GPL-2.0-only */
22ea7afb6SJanosch Frank /*
32ea7afb6SJanosch Frank  * Guest Ultravisor Call tests
42ea7afb6SJanosch Frank  *
52ea7afb6SJanosch Frank  * Copyright (c) 2020 IBM Corp
62ea7afb6SJanosch Frank  *
72ea7afb6SJanosch Frank  * Authors:
82ea7afb6SJanosch Frank  *  Janosch Frank <frankja@linux.ibm.com>
92ea7afb6SJanosch Frank  */
102ea7afb6SJanosch Frank 
112ea7afb6SJanosch Frank #include <libcflat.h>
122ea7afb6SJanosch Frank #include <alloc_page.h>
132ea7afb6SJanosch Frank #include <asm/page.h>
142ea7afb6SJanosch Frank #include <asm/asm-offsets.h>
152ea7afb6SJanosch Frank #include <asm/interrupt.h>
162ea7afb6SJanosch Frank #include <asm/facility.h>
172ea7afb6SJanosch Frank #include <asm/uv.h>
18e161cc86SJanosch Frank #include <sclp.h>
19533bbdb3SJanosch Frank #include <uv.h>
202ea7afb6SJanosch Frank 
212ea7afb6SJanosch Frank static unsigned long page;
222ea7afb6SJanosch Frank 
232ea7afb6SJanosch Frank static void test_priv(void)
242ea7afb6SJanosch Frank {
252ea7afb6SJanosch Frank 	struct uv_cb_header uvcb = {};
262ea7afb6SJanosch Frank 
272ea7afb6SJanosch Frank 	report_prefix_push("privileged");
282ea7afb6SJanosch Frank 
292ea7afb6SJanosch Frank 	report_prefix_push("query");
302ea7afb6SJanosch Frank 	uvcb.cmd = UVC_CMD_QUI;
312ea7afb6SJanosch Frank 	uvcb.len = sizeof(struct uv_cb_qui);
322ea7afb6SJanosch Frank 	expect_pgm_int();
332ea7afb6SJanosch Frank 	enter_pstate();
3488fb0e5dSJanosch Frank 	uv_call_once(0, (u64)&uvcb);
352ea7afb6SJanosch Frank 	check_pgm_int_code(PGM_INT_CODE_PRIVILEGED_OPERATION);
362ea7afb6SJanosch Frank 	report_prefix_pop();
372ea7afb6SJanosch Frank 
382ea7afb6SJanosch Frank 	report_prefix_push("share");
392ea7afb6SJanosch Frank 	uvcb.cmd = UVC_CMD_SET_SHARED_ACCESS;
402ea7afb6SJanosch Frank 	uvcb.len = sizeof(struct uv_cb_share);
412ea7afb6SJanosch Frank 	expect_pgm_int();
422ea7afb6SJanosch Frank 	enter_pstate();
4388fb0e5dSJanosch Frank 	uv_call_once(0, (u64)&uvcb);
442ea7afb6SJanosch Frank 	check_pgm_int_code(PGM_INT_CODE_PRIVILEGED_OPERATION);
452ea7afb6SJanosch Frank 	report_prefix_pop();
462ea7afb6SJanosch Frank 
472ea7afb6SJanosch Frank 	report_prefix_push("unshare");
482ea7afb6SJanosch Frank 	uvcb.cmd = UVC_CMD_REMOVE_SHARED_ACCESS;
492ea7afb6SJanosch Frank 	uvcb.len = sizeof(struct uv_cb_share);
502ea7afb6SJanosch Frank 	expect_pgm_int();
512ea7afb6SJanosch Frank 	enter_pstate();
5288fb0e5dSJanosch Frank 	uv_call_once(0, (u64)&uvcb);
532ea7afb6SJanosch Frank 	check_pgm_int_code(PGM_INT_CODE_PRIVILEGED_OPERATION);
542ea7afb6SJanosch Frank 	report_prefix_pop();
552ea7afb6SJanosch Frank 
562ea7afb6SJanosch Frank 	report_prefix_pop();
572ea7afb6SJanosch Frank }
582ea7afb6SJanosch Frank 
592ea7afb6SJanosch Frank static void test_query(void)
602ea7afb6SJanosch Frank {
612ea7afb6SJanosch Frank 	struct uv_cb_qui uvcb = {
622ea7afb6SJanosch Frank 		.header.cmd = UVC_CMD_QUI,
6383d815a2SJanosch Frank 		/* A dword below the minimum length */
6483d815a2SJanosch Frank 		.header.len = 0xa0,
652ea7afb6SJanosch Frank 	};
662ea7afb6SJanosch Frank 	int cc;
672ea7afb6SJanosch Frank 
682ea7afb6SJanosch Frank 	report_prefix_push("query");
692ea7afb6SJanosch Frank 	cc = uv_call(0, (u64)&uvcb);
702ea7afb6SJanosch Frank 	report(cc == 1 && uvcb.header.rc == UVC_RC_INV_LEN, "length");
712ea7afb6SJanosch Frank 
722ea7afb6SJanosch Frank 	/*
73*1b642bffSSteffen Eiden 	 * BIT_UVC_CMD_QUI, BIT_UVC_CMD_SET_SHARED_ACCESS and
74*1b642bffSSteffen Eiden 	 * BIT_UVC_CMD_REMOVE_SHARED_ACCESS are always present as they
75*1b642bffSSteffen Eiden 	 * have been introduced with the first Ultravisor version.
76*1b642bffSSteffen Eiden 	 * However, we only need to check for QUI as
77*1b642bffSSteffen Eiden 	 * SET/REMOVE SHARED are used to fence this test to be only
78*1b642bffSSteffen Eiden 	 * executed by protected guests.
792ea7afb6SJanosch Frank 	 */
80*1b642bffSSteffen Eiden 	report(uv_query_test_call(BIT_UVC_CMD_QUI), "query indicated");
812ea7afb6SJanosch Frank 	report_prefix_pop();
822ea7afb6SJanosch Frank }
832ea7afb6SJanosch Frank 
842ea7afb6SJanosch Frank static void test_sharing(void)
852ea7afb6SJanosch Frank {
862ea7afb6SJanosch Frank 	struct uv_cb_share uvcb = {
872ea7afb6SJanosch Frank 		.header.cmd = UVC_CMD_SET_SHARED_ACCESS,
882ea7afb6SJanosch Frank 		.header.len = sizeof(uvcb) - 8,
892ea7afb6SJanosch Frank 		.paddr = page,
902ea7afb6SJanosch Frank 	};
912ea7afb6SJanosch Frank 	int cc;
922ea7afb6SJanosch Frank 
932ea7afb6SJanosch Frank 	report_prefix_push("share");
942ea7afb6SJanosch Frank 	cc = uv_call(0, (u64)&uvcb);
952ea7afb6SJanosch Frank 	report(cc == 1 && uvcb.header.rc == UVC_RC_INV_LEN, "length");
962ea7afb6SJanosch Frank 	uvcb.header.len = sizeof(uvcb);
972ea7afb6SJanosch Frank 	cc = uv_call(0, (u64)&uvcb);
982ea7afb6SJanosch Frank 	report(cc == 0 && uvcb.header.rc == UVC_RC_EXECUTED, "share");
99e161cc86SJanosch Frank 	uvcb.paddr = get_ram_size() + PAGE_SIZE;
100e161cc86SJanosch Frank 	cc = uv_call(0, (u64)&uvcb);
101e161cc86SJanosch Frank 	report(cc == 1 && uvcb.header.rc == 0x101, "invalid memory");
102e161cc86SJanosch Frank 	uvcb.paddr = page;
1032ea7afb6SJanosch Frank 	report_prefix_pop();
1042ea7afb6SJanosch Frank 
1052ea7afb6SJanosch Frank 	report_prefix_push("unshare");
1062ea7afb6SJanosch Frank 	uvcb.header.cmd = UVC_CMD_REMOVE_SHARED_ACCESS;
1072ea7afb6SJanosch Frank 	uvcb.header.len -= 8;
1082ea7afb6SJanosch Frank 	cc = uv_call(0, (u64)&uvcb);
1092ea7afb6SJanosch Frank 	report(cc == 1 && uvcb.header.rc == UVC_RC_INV_LEN, "length");
1102ea7afb6SJanosch Frank 	uvcb.header.len = sizeof(uvcb);
1112ea7afb6SJanosch Frank 	cc = uv_call(0, (u64)&uvcb);
1122ea7afb6SJanosch Frank 	report(cc == 0 && uvcb.header.rc == UVC_RC_EXECUTED, "unshare");
1132ea7afb6SJanosch Frank 	report_prefix_pop();
1142ea7afb6SJanosch Frank 
1152ea7afb6SJanosch Frank 	report_prefix_pop();
1162ea7afb6SJanosch Frank }
1172ea7afb6SJanosch Frank 
1183c645a43SJanosch Frank static struct {
1193c645a43SJanosch Frank 	const char *name;
1203c645a43SJanosch Frank 	uint16_t cmd;
1213c645a43SJanosch Frank 	uint16_t len;
1223c645a43SJanosch Frank 	int call_bit;
1233c645a43SJanosch Frank } invalid_cmds[] = {
1243c645a43SJanosch Frank 	{ "bogus", 0x4242, sizeof(struct uv_cb_header), -1 },
1253c645a43SJanosch Frank 	{ "init", UVC_CMD_INIT_UV, sizeof(struct uv_cb_init), BIT_UVC_CMD_INIT_UV },
1263c645a43SJanosch Frank 	{ "create conf", UVC_CMD_CREATE_SEC_CONF, sizeof(struct uv_cb_cgc), BIT_UVC_CMD_CREATE_SEC_CONF },
1273c645a43SJanosch Frank 	{ "destroy conf", UVC_CMD_DESTROY_SEC_CONF, sizeof(struct uv_cb_nodata), BIT_UVC_CMD_DESTROY_SEC_CONF },
1283c645a43SJanosch Frank 	{ "create cpu", UVC_CMD_CREATE_SEC_CPU, sizeof(struct uv_cb_csc), BIT_UVC_CMD_CREATE_SEC_CPU },
1293c645a43SJanosch Frank 	{ "destroy cpu", UVC_CMD_DESTROY_SEC_CPU, sizeof(struct uv_cb_nodata), BIT_UVC_CMD_DESTROY_SEC_CPU },
1303c645a43SJanosch Frank 	{ "conv to", UVC_CMD_CONV_TO_SEC_STOR, sizeof(struct uv_cb_cts), BIT_UVC_CMD_CONV_TO_SEC_STOR },
1313c645a43SJanosch Frank 	{ "conv from", UVC_CMD_CONV_FROM_SEC_STOR, sizeof(struct uv_cb_cfs), BIT_UVC_CMD_CONV_FROM_SEC_STOR },
1323c645a43SJanosch Frank 	{ "set sec conf", UVC_CMD_SET_SEC_CONF_PARAMS, sizeof(struct uv_cb_ssc), BIT_UVC_CMD_SET_SEC_PARMS },
1333c645a43SJanosch Frank 	{ "unpack", UVC_CMD_UNPACK_IMG, sizeof(struct uv_cb_unp), BIT_UVC_CMD_UNPACK_IMG },
1343c645a43SJanosch Frank 	{ "verify", UVC_CMD_VERIFY_IMG, sizeof(struct uv_cb_nodata), BIT_UVC_CMD_VERIFY_IMG },
1353c645a43SJanosch Frank 	{ "cpu reset", UVC_CMD_CPU_RESET, sizeof(struct uv_cb_nodata), BIT_UVC_CMD_CPU_RESET },
1363c645a43SJanosch Frank 	{ "cpu initial reset", UVC_CMD_CPU_RESET_INITIAL, sizeof(struct uv_cb_nodata), BIT_UVC_CMD_CPU_RESET_INITIAL },
1375630c446SJanosch Frank 	{ "prepare clear reset", UVC_CMD_PREPARE_RESET, sizeof(struct uv_cb_nodata), BIT_UVC_CMD_PREPARE_RESET },
1383c645a43SJanosch Frank 	{ "cpu clear reset", UVC_CMD_CPU_RESET_CLEAR, sizeof(struct uv_cb_nodata), BIT_UVC_CMD_CPU_PERFORM_CLEAR_RESET },
1393c645a43SJanosch Frank 	{ "cpu set state", UVC_CMD_CPU_SET_STATE, sizeof(struct uv_cb_cpu_set_state), BIT_UVC_CMD_CPU_SET_STATE },
1403c645a43SJanosch Frank 	{ "pin shared", UVC_CMD_PIN_PAGE_SHARED, sizeof(struct uv_cb_cfs), BIT_UVC_CMD_PIN_PAGE_SHARED },
1413c645a43SJanosch Frank 	{ "unpin shared", UVC_CMD_UNPIN_PAGE_SHARED, sizeof(struct uv_cb_cts), BIT_UVC_CMD_UNPIN_PAGE_SHARED },
1423c645a43SJanosch Frank 	{ NULL, 0, 0 },
1433c645a43SJanosch Frank };
1443c645a43SJanosch Frank 
1452ea7afb6SJanosch Frank static void test_invalid(void)
1462ea7afb6SJanosch Frank {
1473c645a43SJanosch Frank 	struct uv_cb_header *hdr = (void *)page;
1483c645a43SJanosch Frank 	int cc, i;
1492ea7afb6SJanosch Frank 
1503c645a43SJanosch Frank 	report_prefix_push("invalid");
1513c645a43SJanosch Frank 	for (i = 0; invalid_cmds[i].name; i++) {
1523c645a43SJanosch Frank 		hdr->cmd = invalid_cmds[i].cmd;
1533c645a43SJanosch Frank 		hdr->len = invalid_cmds[i].len;
1543c645a43SJanosch Frank 		cc = uv_call(0, (u64)hdr);
1553c645a43SJanosch Frank 		report(cc == 1 && hdr->rc == UVC_RC_INV_CMD &&
1563c645a43SJanosch Frank 		       (invalid_cmds[i].call_bit == -1 || !uv_query_test_call(invalid_cmds[i].call_bit)),
1573c645a43SJanosch Frank 		       "%s", invalid_cmds[i].name);
1583c645a43SJanosch Frank 	}
1593c645a43SJanosch Frank 	report_prefix_pop();
1602ea7afb6SJanosch Frank }
1612ea7afb6SJanosch Frank 
1622ea7afb6SJanosch Frank int main(void)
1632ea7afb6SJanosch Frank {
1642ea7afb6SJanosch Frank 	bool has_uvc = test_facility(158);
1652ea7afb6SJanosch Frank 
1662ea7afb6SJanosch Frank 	report_prefix_push("uvc");
1672ea7afb6SJanosch Frank 	if (!has_uvc) {
1682ea7afb6SJanosch Frank 		report_skip("Ultravisor call facility is not available");
1692ea7afb6SJanosch Frank 		goto done;
1702ea7afb6SJanosch Frank 	}
1712ea7afb6SJanosch Frank 
172533bbdb3SJanosch Frank 	if (!uv_os_is_guest()) {
173533bbdb3SJanosch Frank 		report_skip("Not a protected guest");
174533bbdb3SJanosch Frank 		goto done;
175533bbdb3SJanosch Frank 	}
176533bbdb3SJanosch Frank 
1772ea7afb6SJanosch Frank 	page = (unsigned long)alloc_page();
1782ea7afb6SJanosch Frank 	test_priv();
1792ea7afb6SJanosch Frank 	test_invalid();
1802ea7afb6SJanosch Frank 	test_query();
1812ea7afb6SJanosch Frank 	test_sharing();
1822ea7afb6SJanosch Frank 	free_page((void *)page);
1832ea7afb6SJanosch Frank done:
1842ea7afb6SJanosch Frank 	report_prefix_pop();
1852ea7afb6SJanosch Frank 	return report_summary();
1862ea7afb6SJanosch Frank }
187