xref: /kvm-unit-tests/s390x/uv-guest.c (revision 533bbdb33d17fe64aa9b19eed7671b43e18aeb31)
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>
19*533bbdb3SJanosch 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 	uvcb.header.len = sizeof(uvcb);
732ea7afb6SJanosch Frank 	cc = uv_call(0, (u64)&uvcb);
742ea7afb6SJanosch Frank 	report(cc == 0 && uvcb.header.rc == UVC_RC_EXECUTED, "successful query");
752ea7afb6SJanosch Frank 
762ea7afb6SJanosch Frank 	/*
772ea7afb6SJanosch Frank 	 * These bits have been introduced with the very first
782ea7afb6SJanosch Frank 	 * Ultravisor version and are expected to always be available
792ea7afb6SJanosch Frank 	 * because they are basic building blocks.
802ea7afb6SJanosch Frank 	 */
812989246eSJanosch Frank 	report(test_bit_inv(BIT_UVC_CMD_QUI, &uvcb.inst_calls_list[0]),
822ea7afb6SJanosch Frank 	       "query indicated");
832989246eSJanosch Frank 	report(test_bit_inv(BIT_UVC_CMD_SET_SHARED_ACCESS, &uvcb.inst_calls_list[0]),
842ea7afb6SJanosch Frank 	       "share indicated");
852989246eSJanosch Frank 	report(test_bit_inv(BIT_UVC_CMD_REMOVE_SHARED_ACCESS, &uvcb.inst_calls_list[0]),
862ea7afb6SJanosch Frank 	       "unshare indicated");
872ea7afb6SJanosch Frank 	report_prefix_pop();
882ea7afb6SJanosch Frank }
892ea7afb6SJanosch Frank 
902ea7afb6SJanosch Frank static void test_sharing(void)
912ea7afb6SJanosch Frank {
922ea7afb6SJanosch Frank 	struct uv_cb_share uvcb = {
932ea7afb6SJanosch Frank 		.header.cmd = UVC_CMD_SET_SHARED_ACCESS,
942ea7afb6SJanosch Frank 		.header.len = sizeof(uvcb) - 8,
952ea7afb6SJanosch Frank 		.paddr = page,
962ea7afb6SJanosch Frank 	};
972ea7afb6SJanosch Frank 	int cc;
982ea7afb6SJanosch Frank 
992ea7afb6SJanosch Frank 	report_prefix_push("share");
1002ea7afb6SJanosch Frank 	cc = uv_call(0, (u64)&uvcb);
1012ea7afb6SJanosch Frank 	report(cc == 1 && uvcb.header.rc == UVC_RC_INV_LEN, "length");
1022ea7afb6SJanosch Frank 	uvcb.header.len = sizeof(uvcb);
1032ea7afb6SJanosch Frank 	cc = uv_call(0, (u64)&uvcb);
1042ea7afb6SJanosch Frank 	report(cc == 0 && uvcb.header.rc == UVC_RC_EXECUTED, "share");
105e161cc86SJanosch Frank 	uvcb.paddr = get_ram_size() + PAGE_SIZE;
106e161cc86SJanosch Frank 	cc = uv_call(0, (u64)&uvcb);
107e161cc86SJanosch Frank 	report(cc == 1 && uvcb.header.rc == 0x101, "invalid memory");
108e161cc86SJanosch Frank 	uvcb.paddr = page;
1092ea7afb6SJanosch Frank 	report_prefix_pop();
1102ea7afb6SJanosch Frank 
1112ea7afb6SJanosch Frank 	report_prefix_push("unshare");
1122ea7afb6SJanosch Frank 	uvcb.header.cmd = UVC_CMD_REMOVE_SHARED_ACCESS;
1132ea7afb6SJanosch Frank 	uvcb.header.len -= 8;
1142ea7afb6SJanosch Frank 	cc = uv_call(0, (u64)&uvcb);
1152ea7afb6SJanosch Frank 	report(cc == 1 && uvcb.header.rc == UVC_RC_INV_LEN, "length");
1162ea7afb6SJanosch Frank 	uvcb.header.len = sizeof(uvcb);
1172ea7afb6SJanosch Frank 	cc = uv_call(0, (u64)&uvcb);
1182ea7afb6SJanosch Frank 	report(cc == 0 && uvcb.header.rc == UVC_RC_EXECUTED, "unshare");
1192ea7afb6SJanosch Frank 	report_prefix_pop();
1202ea7afb6SJanosch Frank 
1212ea7afb6SJanosch Frank 	report_prefix_pop();
1222ea7afb6SJanosch Frank }
1232ea7afb6SJanosch Frank 
1242ea7afb6SJanosch Frank static void test_invalid(void)
1252ea7afb6SJanosch Frank {
1262ea7afb6SJanosch Frank 	struct uv_cb_header uvcb = {
1272ea7afb6SJanosch Frank 		.len = 16,
1282ea7afb6SJanosch Frank 		.cmd = 0x4242,
1292ea7afb6SJanosch Frank 	};
1302ea7afb6SJanosch Frank 	int cc;
1312ea7afb6SJanosch Frank 
1322ea7afb6SJanosch Frank 	cc = uv_call(0, (u64)&uvcb);
1332ea7afb6SJanosch Frank 	report(cc == 1 && uvcb.rc == UVC_RC_INV_CMD, "invalid command");
1342ea7afb6SJanosch Frank }
1352ea7afb6SJanosch Frank 
1362ea7afb6SJanosch Frank int main(void)
1372ea7afb6SJanosch Frank {
1382ea7afb6SJanosch Frank 	bool has_uvc = test_facility(158);
1392ea7afb6SJanosch Frank 
1402ea7afb6SJanosch Frank 	report_prefix_push("uvc");
1412ea7afb6SJanosch Frank 	if (!has_uvc) {
1422ea7afb6SJanosch Frank 		report_skip("Ultravisor call facility is not available");
1432ea7afb6SJanosch Frank 		goto done;
1442ea7afb6SJanosch Frank 	}
1452ea7afb6SJanosch Frank 
146*533bbdb3SJanosch Frank 	if (!uv_os_is_guest()) {
147*533bbdb3SJanosch Frank 		report_skip("Not a protected guest");
148*533bbdb3SJanosch Frank 		goto done;
149*533bbdb3SJanosch Frank 	}
150*533bbdb3SJanosch Frank 
1512ea7afb6SJanosch Frank 	page = (unsigned long)alloc_page();
1522ea7afb6SJanosch Frank 	test_priv();
1532ea7afb6SJanosch Frank 	test_invalid();
1542ea7afb6SJanosch Frank 	test_query();
1552ea7afb6SJanosch Frank 	test_sharing();
1562ea7afb6SJanosch Frank 	free_page((void *)page);
1572ea7afb6SJanosch Frank done:
1582ea7afb6SJanosch Frank 	report_prefix_pop();
1592ea7afb6SJanosch Frank 	return report_summary();
1602ea7afb6SJanosch Frank }
161