xref: /kvm-unit-tests/s390x/uv-host.c (revision 0a5b31d2539d67b2e46b037012bb83f09b585c9e)
128ccfb1eSJanosch Frank /* SPDX-License-Identifier: GPL-2.0-only */
228ccfb1eSJanosch Frank /*
328ccfb1eSJanosch Frank  * Guest Ultravisor Call tests
428ccfb1eSJanosch Frank  *
528ccfb1eSJanosch Frank  * Copyright (c) 2021 IBM Corp
628ccfb1eSJanosch Frank  *
728ccfb1eSJanosch Frank  * Authors:
828ccfb1eSJanosch Frank  *  Janosch Frank <frankja@linux.ibm.com>
928ccfb1eSJanosch Frank  */
1028ccfb1eSJanosch Frank 
1128ccfb1eSJanosch Frank #include <libcflat.h>
1228ccfb1eSJanosch Frank #include <alloc.h>
1328ccfb1eSJanosch Frank #include <vmalloc.h>
1428ccfb1eSJanosch Frank #include <sclp.h>
1528ccfb1eSJanosch Frank #include <smp.h>
1628ccfb1eSJanosch Frank #include <uv.h>
1728ccfb1eSJanosch Frank #include <asm/page.h>
1828ccfb1eSJanosch Frank #include <asm/sigp.h>
1928ccfb1eSJanosch Frank #include <asm/pgtable.h>
2028ccfb1eSJanosch Frank #include <asm/asm-offsets.h>
2128ccfb1eSJanosch Frank #include <asm/interrupt.h>
2228ccfb1eSJanosch Frank #include <asm/facility.h>
2328ccfb1eSJanosch Frank #include <asm/uv.h>
2428ccfb1eSJanosch Frank #include <asm-generic/barrier.h>
2528ccfb1eSJanosch Frank 
2628ccfb1eSJanosch Frank static struct uv_cb_qui uvcb_qui;
2728ccfb1eSJanosch Frank static struct uv_cb_init uvcb_init;
2828ccfb1eSJanosch Frank static struct uv_cb_cgc uvcb_cgc;
2928ccfb1eSJanosch Frank static struct uv_cb_csc uvcb_csc;
3028ccfb1eSJanosch Frank 
3128ccfb1eSJanosch Frank extern int diag308_load_reset(u64 code);
3228ccfb1eSJanosch Frank 
3328ccfb1eSJanosch Frank struct cmd_list{
3428ccfb1eSJanosch Frank 	const char *name;
3528ccfb1eSJanosch Frank 	uint16_t cmd;
3628ccfb1eSJanosch Frank 	uint16_t len;
3728ccfb1eSJanosch Frank 	int call_bit;
3828ccfb1eSJanosch Frank };
3928ccfb1eSJanosch Frank 
4028ccfb1eSJanosch Frank static void cpu_loop(void)
4128ccfb1eSJanosch Frank {
4228ccfb1eSJanosch Frank 	for (;;) {}
4328ccfb1eSJanosch Frank }
4428ccfb1eSJanosch Frank 
4528ccfb1eSJanosch Frank static struct cmd_list cmds[] = {
4628ccfb1eSJanosch Frank 	{ "init", UVC_CMD_INIT_UV, sizeof(struct uv_cb_init), BIT_UVC_CMD_INIT_UV },
4728ccfb1eSJanosch Frank 	{ "create conf", UVC_CMD_CREATE_SEC_CONF, sizeof(struct uv_cb_cgc), BIT_UVC_CMD_CREATE_SEC_CONF },
4828ccfb1eSJanosch Frank 	{ "destroy conf", UVC_CMD_DESTROY_SEC_CONF, sizeof(struct uv_cb_nodata), BIT_UVC_CMD_DESTROY_SEC_CONF },
4928ccfb1eSJanosch Frank 	{ "create cpu", UVC_CMD_CREATE_SEC_CPU, sizeof(struct uv_cb_csc), BIT_UVC_CMD_CREATE_SEC_CPU },
5028ccfb1eSJanosch Frank 	{ "destroy cpu", UVC_CMD_DESTROY_SEC_CPU, sizeof(struct uv_cb_nodata), BIT_UVC_CMD_DESTROY_SEC_CPU },
5128ccfb1eSJanosch Frank 	{ "conv to", UVC_CMD_CONV_TO_SEC_STOR, sizeof(struct uv_cb_cts), BIT_UVC_CMD_CONV_TO_SEC_STOR },
5228ccfb1eSJanosch Frank 	{ "conv from", UVC_CMD_CONV_FROM_SEC_STOR, sizeof(struct uv_cb_cfs), BIT_UVC_CMD_CONV_FROM_SEC_STOR },
5328ccfb1eSJanosch Frank 	{ "set sec conf", UVC_CMD_SET_SEC_CONF_PARAMS, sizeof(struct uv_cb_ssc), BIT_UVC_CMD_SET_SEC_PARMS },
5428ccfb1eSJanosch Frank 	{ "unpack", UVC_CMD_UNPACK_IMG, sizeof(struct uv_cb_unp), BIT_UVC_CMD_UNPACK_IMG },
5528ccfb1eSJanosch Frank 	{ "verify", UVC_CMD_VERIFY_IMG, sizeof(struct uv_cb_nodata), BIT_UVC_CMD_VERIFY_IMG },
5628ccfb1eSJanosch Frank 	{ "cpu reset", UVC_CMD_CPU_RESET, sizeof(struct uv_cb_nodata), BIT_UVC_CMD_CPU_RESET },
5728ccfb1eSJanosch Frank 	{ "cpu initial reset", UVC_CMD_CPU_RESET_INITIAL, sizeof(struct uv_cb_nodata), BIT_UVC_CMD_CPU_RESET_INITIAL },
5828ccfb1eSJanosch Frank 	{ "conf clear reset", UVC_CMD_PERF_CONF_CLEAR_RESET, sizeof(struct uv_cb_nodata), BIT_UVC_CMD_PREPARE_CLEAR_RESET },
5928ccfb1eSJanosch Frank 	{ "cpu clear reset", UVC_CMD_CPU_RESET_CLEAR, sizeof(struct uv_cb_nodata), BIT_UVC_CMD_CPU_PERFORM_CLEAR_RESET },
6028ccfb1eSJanosch Frank 	{ "cpu set state", UVC_CMD_CPU_SET_STATE, sizeof(struct uv_cb_cpu_set_state), BIT_UVC_CMD_CPU_SET_STATE },
6128ccfb1eSJanosch Frank 	{ "pin shared", UVC_CMD_PIN_PAGE_SHARED, sizeof(struct uv_cb_cfs), BIT_UVC_CMD_PIN_PAGE_SHARED },
6228ccfb1eSJanosch Frank 	{ "unpin shared", UVC_CMD_UNPIN_PAGE_SHARED, sizeof(struct uv_cb_cts), BIT_UVC_CMD_UNPIN_PAGE_SHARED },
6328ccfb1eSJanosch Frank 	{ NULL, 0, 0 },
6428ccfb1eSJanosch Frank };
6528ccfb1eSJanosch Frank 
6628ccfb1eSJanosch Frank static void test_priv(void)
6728ccfb1eSJanosch Frank {
6828ccfb1eSJanosch Frank 	struct uv_cb_header uvcb = {};
6928ccfb1eSJanosch Frank 	uint16_t pgm;
7028ccfb1eSJanosch Frank 	int i;
7128ccfb1eSJanosch Frank 
7228ccfb1eSJanosch Frank 	report_prefix_push("privileged");
7328ccfb1eSJanosch Frank 	for (i = 0; cmds[i].name; i++) {
7428ccfb1eSJanosch Frank 		expect_pgm_int();
7528ccfb1eSJanosch Frank 		uvcb.cmd = cmds[i].cmd;
7628ccfb1eSJanosch Frank 		uvcb.len = cmds[i].len;
7728ccfb1eSJanosch Frank 		enter_pstate();
7828ccfb1eSJanosch Frank 		uv_call(0, (uint64_t)&uvcb);
7928ccfb1eSJanosch Frank 		pgm = clear_pgm_int();
8028ccfb1eSJanosch Frank 		report(pgm == PGM_INT_CODE_PRIVILEGED_OPERATION, "%s", cmds[i].name);
8128ccfb1eSJanosch Frank 	}
8228ccfb1eSJanosch Frank 	report_prefix_pop();
8328ccfb1eSJanosch Frank }
8428ccfb1eSJanosch Frank 
8528ccfb1eSJanosch Frank static void test_config_destroy(void)
8628ccfb1eSJanosch Frank {
8728ccfb1eSJanosch Frank 	int rc;
8828ccfb1eSJanosch Frank 	struct uv_cb_nodata uvcb = {
8928ccfb1eSJanosch Frank 		.header.cmd = UVC_CMD_DESTROY_SEC_CONF,
9028ccfb1eSJanosch Frank 		.header.len = sizeof(uvcb),
9128ccfb1eSJanosch Frank 		.handle = uvcb_cgc.guest_handle,
9228ccfb1eSJanosch Frank 	};
9328ccfb1eSJanosch Frank 
9428ccfb1eSJanosch Frank 	report_prefix_push("dsc");
9528ccfb1eSJanosch Frank 	uvcb.header.len -= 8;
9628ccfb1eSJanosch Frank 	rc = uv_call(0, (uint64_t)&uvcb);
9728ccfb1eSJanosch Frank 	report(rc == 1 && uvcb.header.rc == UVC_RC_INV_LEN,
9828ccfb1eSJanosch Frank 	       "hdr invalid length");
9928ccfb1eSJanosch Frank 	uvcb.header.len += 8;
10028ccfb1eSJanosch Frank 
10128ccfb1eSJanosch Frank 	uvcb.handle += 1;
10228ccfb1eSJanosch Frank 	rc = uv_call(0, (uint64_t)&uvcb);
10328ccfb1eSJanosch Frank 	report(rc == 1 && uvcb.header.rc == UVC_RC_INV_GHANDLE, "invalid handle");
10428ccfb1eSJanosch Frank 	uvcb.handle -= 1;
10528ccfb1eSJanosch Frank 
10628ccfb1eSJanosch Frank 	rc = uv_call(0, (uint64_t)&uvcb);
10728ccfb1eSJanosch Frank 	report(rc == 0 && uvcb.header.rc == UVC_RC_EXECUTED, "success");
10828ccfb1eSJanosch Frank 	report_prefix_pop();
10928ccfb1eSJanosch Frank }
11028ccfb1eSJanosch Frank 
11128ccfb1eSJanosch Frank static void test_cpu_destroy(void)
11228ccfb1eSJanosch Frank {
11328ccfb1eSJanosch Frank 	int rc;
11428ccfb1eSJanosch Frank 	struct uv_cb_nodata uvcb = {
11528ccfb1eSJanosch Frank 		.header.len = sizeof(uvcb),
11628ccfb1eSJanosch Frank 		.header.cmd = UVC_CMD_DESTROY_SEC_CPU,
11728ccfb1eSJanosch Frank 		.handle = uvcb_csc.cpu_handle,
11828ccfb1eSJanosch Frank 	};
11928ccfb1eSJanosch Frank 
12028ccfb1eSJanosch Frank 	report_prefix_push("dcpu");
12128ccfb1eSJanosch Frank 
12228ccfb1eSJanosch Frank 	uvcb.header.len -= 8;
12328ccfb1eSJanosch Frank 	rc = uv_call(0, (uint64_t)&uvcb);
12428ccfb1eSJanosch Frank 	report(rc == 1 && uvcb.header.rc == UVC_RC_INV_LEN,
12528ccfb1eSJanosch Frank 	       "hdr invalid length");
12628ccfb1eSJanosch Frank 	uvcb.header.len += 8;
12728ccfb1eSJanosch Frank 
12828ccfb1eSJanosch Frank 	uvcb.handle += 1;
12928ccfb1eSJanosch Frank 	rc = uv_call(0, (uint64_t)&uvcb);
13028ccfb1eSJanosch Frank 	report(rc == 1 && uvcb.header.rc == UVC_RC_INV_CHANDLE, "invalid handle");
13128ccfb1eSJanosch Frank 	uvcb.handle -= 1;
13228ccfb1eSJanosch Frank 
13328ccfb1eSJanosch Frank 	rc = uv_call(0, (uint64_t)&uvcb);
13428ccfb1eSJanosch Frank 	report(rc == 0 && uvcb.header.rc == UVC_RC_EXECUTED, "success");
13528ccfb1eSJanosch Frank 
13628ccfb1eSJanosch Frank 	report_prefix_pop();
13728ccfb1eSJanosch Frank }
13828ccfb1eSJanosch Frank 
13928ccfb1eSJanosch Frank static void test_cpu_create(void)
14028ccfb1eSJanosch Frank {
14128ccfb1eSJanosch Frank 	int rc;
14228ccfb1eSJanosch Frank 	unsigned long tmp;
14328ccfb1eSJanosch Frank 
14428ccfb1eSJanosch Frank 	report_prefix_push("csc");
14528ccfb1eSJanosch Frank 	uvcb_csc.header.len = sizeof(uvcb_csc);
14628ccfb1eSJanosch Frank 	uvcb_csc.header.cmd = UVC_CMD_CREATE_SEC_CPU;
14728ccfb1eSJanosch Frank 	uvcb_csc.guest_handle = uvcb_cgc.guest_handle;
14828ccfb1eSJanosch Frank 	uvcb_csc.stor_origin = (unsigned long)memalign(PAGE_SIZE, uvcb_qui.cpu_stor_len);
14928ccfb1eSJanosch Frank 	uvcb_csc.state_origin = (unsigned long)memalign(PAGE_SIZE, PAGE_SIZE);
15028ccfb1eSJanosch Frank 
15128ccfb1eSJanosch Frank 	uvcb_csc.header.len -= 8;
15228ccfb1eSJanosch Frank 	rc = uv_call(0, (uint64_t)&uvcb_csc);
15328ccfb1eSJanosch Frank 	report(uvcb_csc.header.rc == UVC_RC_INV_LEN && rc == 1 &&
15428ccfb1eSJanosch Frank 	       !uvcb_csc.cpu_handle, "hdr invalid length");
15528ccfb1eSJanosch Frank 	uvcb_csc.header.len += 8;
15628ccfb1eSJanosch Frank 
15728ccfb1eSJanosch Frank 	uvcb_csc.guest_handle += 1;
15828ccfb1eSJanosch Frank 	rc = uv_call(0, (uint64_t)&uvcb_csc);
15928ccfb1eSJanosch Frank 	report(uvcb_csc.header.rc == UVC_RC_INV_GHANDLE && rc == 1,
16028ccfb1eSJanosch Frank 	       "invalid guest handle");
16128ccfb1eSJanosch Frank 	uvcb_csc.guest_handle -= 1;
16228ccfb1eSJanosch Frank 
16328ccfb1eSJanosch Frank 	uvcb_csc.num = uvcb_qui.max_guest_cpus + 1;
16428ccfb1eSJanosch Frank 	rc = uv_call(0, (uint64_t)&uvcb_csc);
16528ccfb1eSJanosch Frank 	report(uvcb_csc.header.rc == 0x103 && rc == 1,
16628ccfb1eSJanosch Frank 	       "invalid cpu #");
16728ccfb1eSJanosch Frank 	uvcb_csc.num = 0;
16828ccfb1eSJanosch Frank 
16928ccfb1eSJanosch Frank 	tmp = uvcb_csc.stor_origin;
17028ccfb1eSJanosch Frank 	uvcb_csc.stor_origin = get_max_ram_size() + PAGE_SIZE;
17128ccfb1eSJanosch Frank 	rc = uv_call(0, (uint64_t)&uvcb_csc);
17228ccfb1eSJanosch Frank 	report(uvcb_csc.header.rc == 0x105 && rc == 1,
17328ccfb1eSJanosch Frank 	       "cpu stor inaccessible");
17428ccfb1eSJanosch Frank 	uvcb_csc.stor_origin = tmp;
17528ccfb1eSJanosch Frank 
17628ccfb1eSJanosch Frank 	tmp = uvcb_csc.stor_origin;
17728ccfb1eSJanosch Frank 	uvcb_csc.stor_origin = 0;
17828ccfb1eSJanosch Frank 	rc = uv_call(0, (uint64_t)&uvcb_csc);
17928ccfb1eSJanosch Frank 	report(uvcb_csc.header.rc == 0x106 && rc == 1,
18028ccfb1eSJanosch Frank 	       "cpu stor in lowcore");
18128ccfb1eSJanosch Frank 	uvcb_csc.stor_origin = tmp;
18228ccfb1eSJanosch Frank 
18328ccfb1eSJanosch Frank 	tmp = uvcb_csc.state_origin;
18428ccfb1eSJanosch Frank 	uvcb_csc.state_origin = get_max_ram_size() + PAGE_SIZE;
18528ccfb1eSJanosch Frank 	rc = uv_call(0, (uint64_t)&uvcb_csc);
18628ccfb1eSJanosch Frank 	report(uvcb_csc.header.rc == 0x107 && rc == 1,
18728ccfb1eSJanosch Frank 	       "SIE SD inaccessible");
18828ccfb1eSJanosch Frank 	uvcb_csc.state_origin = tmp;
18928ccfb1eSJanosch Frank 
19028ccfb1eSJanosch Frank 	rc = uv_call(0, (uint64_t)&uvcb_csc);
19128ccfb1eSJanosch Frank 	report(rc == 0 && uvcb_csc.header.rc == UVC_RC_EXECUTED &&
19228ccfb1eSJanosch Frank 	       uvcb_csc.cpu_handle, "success");
19328ccfb1eSJanosch Frank 
19428ccfb1eSJanosch Frank 	tmp = uvcb_csc.stor_origin;
19528ccfb1eSJanosch Frank 	uvcb_csc.stor_origin = (unsigned long)memalign(PAGE_SIZE, uvcb_qui.cpu_stor_len);
19628ccfb1eSJanosch Frank 	rc = uv_call(0, (uint64_t)&uvcb_csc);
19728ccfb1eSJanosch Frank 	report(rc == 1 && uvcb_csc.header.rc == 0x104, "already defined");
19828ccfb1eSJanosch Frank 	uvcb_csc.stor_origin = tmp;
19928ccfb1eSJanosch Frank 	report_prefix_pop();
20028ccfb1eSJanosch Frank }
20128ccfb1eSJanosch Frank 
20228ccfb1eSJanosch Frank static void test_config_create(void)
20328ccfb1eSJanosch Frank {
20428ccfb1eSJanosch Frank 	int rc;
20528ccfb1eSJanosch Frank 	unsigned long vsize, tmp;
20628ccfb1eSJanosch Frank 	static struct uv_cb_cgc uvcb;
20728ccfb1eSJanosch Frank 
20828ccfb1eSJanosch Frank 	uvcb_cgc.header.cmd = UVC_CMD_CREATE_SEC_CONF;
20928ccfb1eSJanosch Frank 	uvcb_cgc.header.len = sizeof(uvcb_cgc);
21028ccfb1eSJanosch Frank 	report_prefix_push("cgc");
21128ccfb1eSJanosch Frank 
21228ccfb1eSJanosch Frank 	uvcb_cgc.guest_stor_origin = 0;
21328ccfb1eSJanosch Frank 	uvcb_cgc.guest_stor_len = 42 * (1UL << 20);
21428ccfb1eSJanosch Frank 	vsize = uvcb_qui.conf_base_virt_stor_len +
21528ccfb1eSJanosch Frank 		((uvcb_cgc.guest_stor_len / (1UL << 20)) * uvcb_qui.conf_virt_var_stor_len);
21628ccfb1eSJanosch Frank 
21728ccfb1eSJanosch Frank 	uvcb_cgc.conf_base_stor_origin = (uint64_t)memalign(PAGE_SIZE * 4, uvcb_qui.conf_base_phys_stor_len);
21828ccfb1eSJanosch Frank 	uvcb_cgc.conf_var_stor_origin = (uint64_t)memalign(PAGE_SIZE, vsize);
21928ccfb1eSJanosch Frank 	uvcb_cgc.guest_asce = (uint64_t)memalign(PAGE_SIZE, 4 * PAGE_SIZE) | ASCE_DT_SEGMENT | REGION_TABLE_LENGTH | ASCE_P;
22028ccfb1eSJanosch Frank 	uvcb_cgc.guest_sca = (uint64_t)memalign(PAGE_SIZE * 4, PAGE_SIZE * 4);
22128ccfb1eSJanosch Frank 
22228ccfb1eSJanosch Frank 	uvcb_cgc.header.len -= 8;
22328ccfb1eSJanosch Frank 	rc = uv_call(0, (uint64_t)&uvcb_cgc);
22428ccfb1eSJanosch Frank 	report(uvcb_cgc.header.rc == UVC_RC_INV_LEN && rc == 1 &&
22528ccfb1eSJanosch Frank 	       !uvcb_cgc.guest_handle, "hdr invalid length");
22628ccfb1eSJanosch Frank 	uvcb_cgc.header.len += 8;
22728ccfb1eSJanosch Frank 
22828ccfb1eSJanosch Frank 	uvcb_cgc.guest_stor_origin = uvcb_qui.max_guest_stor_addr + (1UL << 20) * 2 + 1;
22928ccfb1eSJanosch Frank 	rc = uv_call(0, (uint64_t)&uvcb_cgc);
23028ccfb1eSJanosch Frank 	report(uvcb_cgc.header.rc == 0x101 && rc == 1,
23128ccfb1eSJanosch Frank 	       "MSO > max guest addr");
23228ccfb1eSJanosch Frank 	uvcb_cgc.guest_stor_origin = 0;
23328ccfb1eSJanosch Frank 
23428ccfb1eSJanosch Frank 	uvcb_cgc.guest_stor_origin = uvcb_qui.max_guest_stor_addr - (1UL << 20);
23528ccfb1eSJanosch Frank 	rc = uv_call(0, (uint64_t)&uvcb_cgc);
23628ccfb1eSJanosch Frank 	report(uvcb_cgc.header.rc == 0x102 && rc == 1,
23728ccfb1eSJanosch Frank 	       "MSO + MSL > max guest addr");
23828ccfb1eSJanosch Frank 	uvcb_cgc.guest_stor_origin = 0;
23928ccfb1eSJanosch Frank 
24028ccfb1eSJanosch Frank 	uvcb_cgc.guest_asce &= ~ASCE_P;
24128ccfb1eSJanosch Frank 	rc = uv_call(0, (uint64_t)&uvcb_cgc);
24228ccfb1eSJanosch Frank 	report(uvcb_cgc.header.rc == 0x105 && rc == 1,
24328ccfb1eSJanosch Frank 	       "ASCE private bit missing");
24428ccfb1eSJanosch Frank 	uvcb_cgc.guest_asce |= ASCE_P;
24528ccfb1eSJanosch Frank 
24628ccfb1eSJanosch Frank 	uvcb_cgc.guest_asce |= 0x20;
24728ccfb1eSJanosch Frank 	rc = uv_call(0, (uint64_t)&uvcb_cgc);
24828ccfb1eSJanosch Frank 	report(uvcb_cgc.header.rc == 0x105 && rc == 1,
24928ccfb1eSJanosch Frank 	       "ASCE bit 58 set");
25028ccfb1eSJanosch Frank 	uvcb_cgc.guest_asce &= ~0x20;
25128ccfb1eSJanosch Frank 
25228ccfb1eSJanosch Frank 	tmp = uvcb_cgc.conf_base_stor_origin;
25328ccfb1eSJanosch Frank 	uvcb_cgc.conf_base_stor_origin = get_max_ram_size() + 8;
25428ccfb1eSJanosch Frank 	rc = uv_call(0, (uint64_t)&uvcb_cgc);
25528ccfb1eSJanosch Frank 	report(uvcb_cgc.header.rc == 0x108 && rc == 1,
25628ccfb1eSJanosch Frank 	       "base storage origin > available memory");
25728ccfb1eSJanosch Frank 	uvcb_cgc.conf_base_stor_origin = tmp;
25828ccfb1eSJanosch Frank 
25928ccfb1eSJanosch Frank 	tmp = uvcb_cgc.conf_base_stor_origin;
26028ccfb1eSJanosch Frank 	uvcb_cgc.conf_base_stor_origin = 0x1000;
26128ccfb1eSJanosch Frank 	rc = uv_call(0, (uint64_t)&uvcb_cgc);
26228ccfb1eSJanosch Frank 	report(uvcb_cgc.header.rc == 0x109 && rc == 1,
26328ccfb1eSJanosch Frank 	       "base storage origin contains lowcore");
26428ccfb1eSJanosch Frank 	uvcb_cgc.conf_base_stor_origin = tmp;
26528ccfb1eSJanosch Frank 
26628ccfb1eSJanosch Frank 	if (smp_query_num_cpus() == 1) {
26728ccfb1eSJanosch Frank 		sigp_retry(1, SIGP_SET_PREFIX,
26828ccfb1eSJanosch Frank 			   uvcb_cgc.conf_var_stor_origin + PAGE_SIZE, NULL);
26928ccfb1eSJanosch Frank 		rc = uv_call(0, (uint64_t)&uvcb_cgc);
27028ccfb1eSJanosch Frank 		report(uvcb_cgc.header.rc == 0x10e && rc == 1 &&
27128ccfb1eSJanosch Frank 		       !uvcb_cgc.guest_handle, "variable storage area contains lowcore");
27228ccfb1eSJanosch Frank 		sigp_retry(1, SIGP_SET_PREFIX, 0x0, NULL);
27328ccfb1eSJanosch Frank 	}
27428ccfb1eSJanosch Frank 
27528ccfb1eSJanosch Frank 	tmp = uvcb_cgc.guest_sca;
27628ccfb1eSJanosch Frank 	uvcb_cgc.guest_sca = 0;
27728ccfb1eSJanosch Frank 	rc = uv_call(0, (uint64_t)&uvcb_cgc);
27828ccfb1eSJanosch Frank 	report(uvcb_cgc.header.rc == 0x10c && rc == 1,
27928ccfb1eSJanosch Frank 	       "sca == 0");
28028ccfb1eSJanosch Frank 	uvcb_cgc.guest_sca = tmp;
28128ccfb1eSJanosch Frank 
28228ccfb1eSJanosch Frank 	tmp = uvcb_cgc.guest_sca;
28328ccfb1eSJanosch Frank 	uvcb_cgc.guest_sca = get_max_ram_size() + + PAGE_SIZE * 4;
28428ccfb1eSJanosch Frank 	rc = uv_call(0, (uint64_t)&uvcb_cgc);
28528ccfb1eSJanosch Frank 	report(uvcb_cgc.header.rc == 0x10d && rc == 1,
28628ccfb1eSJanosch Frank 	       "sca inaccessible");
28728ccfb1eSJanosch Frank 	uvcb_cgc.guest_sca = tmp;
28828ccfb1eSJanosch Frank 
28928ccfb1eSJanosch Frank 	rc = uv_call(0, (uint64_t)&uvcb_cgc);
29028ccfb1eSJanosch Frank 	report(rc == 0 && uvcb_cgc.header.rc == UVC_RC_EXECUTED, "successful");
29128ccfb1eSJanosch Frank 
29228ccfb1eSJanosch Frank 	uvcb_cgc.header.rc = 0;
29328ccfb1eSJanosch Frank 	uvcb_cgc.header.rrc = 0;
29428ccfb1eSJanosch Frank 	tmp = uvcb_cgc.guest_handle;
29528ccfb1eSJanosch Frank 	uvcb_cgc.guest_handle = 0;
29628ccfb1eSJanosch Frank 	rc = uv_call(0, (uint64_t)&uvcb_cgc);
29728ccfb1eSJanosch Frank 	report(uvcb_cgc.header.rc >= 0x100 && rc == 1, "reuse uvcb");
29828ccfb1eSJanosch Frank 	uvcb_cgc.guest_handle = tmp;
29928ccfb1eSJanosch Frank 
30028ccfb1eSJanosch Frank 	/* Copy over most data from uvcb_cgc, so we have the ASCE that was used. */
30128ccfb1eSJanosch Frank 	memcpy(&uvcb, &uvcb_cgc, sizeof(uvcb));
30228ccfb1eSJanosch Frank 
30328ccfb1eSJanosch Frank 	/* Reset the header and handle */
30428ccfb1eSJanosch Frank 	uvcb.header.rc = 0;
30528ccfb1eSJanosch Frank 	uvcb.header.rrc = 0;
30628ccfb1eSJanosch Frank 	uvcb.guest_handle = 0;
30728ccfb1eSJanosch Frank 
30828ccfb1eSJanosch Frank 	/* Use new storage areas. */
30928ccfb1eSJanosch Frank 	uvcb.conf_base_stor_origin = (uint64_t)memalign(PAGE_SIZE * 4, uvcb_qui.conf_base_phys_stor_len);
31028ccfb1eSJanosch Frank 	uvcb.conf_var_stor_origin = (uint64_t)memalign(PAGE_SIZE, vsize);
31128ccfb1eSJanosch Frank 
31228ccfb1eSJanosch Frank 	rc = uv_call(0, (uint64_t)&uvcb);
31328ccfb1eSJanosch Frank 	report(uvcb.header.rc >= 0x104 && rc == 1 && !uvcb.guest_handle,
31428ccfb1eSJanosch Frank 	       "reuse ASCE");
31528ccfb1eSJanosch Frank 	free((void *)uvcb.conf_base_stor_origin);
31628ccfb1eSJanosch Frank 	free((void *)uvcb.conf_var_stor_origin);
31728ccfb1eSJanosch Frank 
31828ccfb1eSJanosch Frank 	/* Missing: 106, 10a, a0b */
31928ccfb1eSJanosch Frank 	report_prefix_pop();
32028ccfb1eSJanosch Frank }
32128ccfb1eSJanosch Frank 
32228ccfb1eSJanosch Frank static void test_init(void)
32328ccfb1eSJanosch Frank {
32428ccfb1eSJanosch Frank 	int rc;
32528ccfb1eSJanosch Frank 	uint64_t mem;
32628ccfb1eSJanosch Frank 	struct psw psw;
32728ccfb1eSJanosch Frank 
32828ccfb1eSJanosch Frank 	/* Donated storage needs to be over 2GB */
32928ccfb1eSJanosch Frank 	mem = (uint64_t)memalign(1UL << 31, uvcb_qui.uv_base_stor_len);
33028ccfb1eSJanosch Frank 
33128ccfb1eSJanosch Frank 	uvcb_init.header.len = sizeof(uvcb_init);
33228ccfb1eSJanosch Frank 	uvcb_init.header.cmd = UVC_CMD_INIT_UV;
33328ccfb1eSJanosch Frank 	uvcb_init.stor_origin = mem;
33428ccfb1eSJanosch Frank 	uvcb_init.stor_len = uvcb_qui.uv_base_stor_len;
33528ccfb1eSJanosch Frank 
33628ccfb1eSJanosch Frank 	report_prefix_push("init");
33728ccfb1eSJanosch Frank 	uvcb_init.header.len -= 8;
33828ccfb1eSJanosch Frank 	rc = uv_call(0, (uint64_t)&uvcb_init);
33928ccfb1eSJanosch Frank 	report(rc == 1 && uvcb_init.header.rc == UVC_RC_INV_LEN,
34028ccfb1eSJanosch Frank 	       "hdr invalid length");
34128ccfb1eSJanosch Frank 	uvcb_init.header.len += 8;
34228ccfb1eSJanosch Frank 
34328ccfb1eSJanosch Frank 	uvcb_init.stor_len -= 8;
34428ccfb1eSJanosch Frank 	rc = uv_call(0, (uint64_t)&uvcb_init);
34528ccfb1eSJanosch Frank 	report(rc == 1 && uvcb_init.header.rc == 0x103,
34628ccfb1eSJanosch Frank 	       "storage invalid length");
34728ccfb1eSJanosch Frank 	uvcb_init.stor_len += 8;
34828ccfb1eSJanosch Frank 
34928ccfb1eSJanosch Frank 	uvcb_init.stor_origin =  get_max_ram_size() + 8;
35028ccfb1eSJanosch Frank 	rc = uv_call(0, (uint64_t)&uvcb_init);
35128ccfb1eSJanosch Frank 	report(rc == 1 && uvcb_init.header.rc == 0x104,
35228ccfb1eSJanosch Frank 	       "storage origin invalid");
35328ccfb1eSJanosch Frank 	uvcb_init.stor_origin = mem;
35428ccfb1eSJanosch Frank 
35528ccfb1eSJanosch Frank 	uvcb_init.stor_origin = get_max_ram_size() - 8;
35628ccfb1eSJanosch Frank 	rc = uv_call(0, (uint64_t)&uvcb_init);
35728ccfb1eSJanosch Frank 	report(rc == 1 && uvcb_init.header.rc == 0x105,
35828ccfb1eSJanosch Frank 	       "storage + length invalid");
35928ccfb1eSJanosch Frank 	uvcb_init.stor_origin = mem;
36028ccfb1eSJanosch Frank 
36128ccfb1eSJanosch Frank 	uvcb_init.stor_origin = 1UL << 30;
36228ccfb1eSJanosch Frank 	rc = uv_call(0, (uint64_t)&uvcb_init);
36328ccfb1eSJanosch Frank 	report(rc == 1 && uvcb_init.header.rc == 0x108,
36428ccfb1eSJanosch Frank 	       "storage below 2GB");
36528ccfb1eSJanosch Frank 	uvcb_init.stor_origin = mem;
36628ccfb1eSJanosch Frank 
36728ccfb1eSJanosch Frank 	psw.mask = extract_psw_mask();
36828ccfb1eSJanosch Frank 	psw.addr = (unsigned long)cpu_loop;
36928ccfb1eSJanosch Frank 	smp_cpu_setup(1, psw);
37028ccfb1eSJanosch Frank 	rc = uv_call(0, (uint64_t)&uvcb_init);
37128ccfb1eSJanosch Frank 	report(rc == 1 && uvcb_init.header.rc == 0x102,
37228ccfb1eSJanosch Frank 	       "too many running cpus");
37328ccfb1eSJanosch Frank 	smp_cpu_stop(1);
37428ccfb1eSJanosch Frank 
37528ccfb1eSJanosch Frank 	rc = uv_call(0, (uint64_t)&uvcb_init);
37628ccfb1eSJanosch Frank 	report(rc == 0 && uvcb_init.header.rc == UVC_RC_EXECUTED, "successful");
37728ccfb1eSJanosch Frank 
37828ccfb1eSJanosch Frank 	mem = (uint64_t)memalign(1UL << 31, uvcb_qui.uv_base_stor_len);
37928ccfb1eSJanosch Frank 	rc = uv_call(0, (uint64_t)&uvcb_init);
38028ccfb1eSJanosch Frank 	report(rc == 1 && uvcb_init.header.rc == 0x101, "double init");
38128ccfb1eSJanosch Frank 	free((void *)mem);
38228ccfb1eSJanosch Frank 
38328ccfb1eSJanosch Frank 	report_prefix_pop();
38428ccfb1eSJanosch Frank }
38528ccfb1eSJanosch Frank 
38628ccfb1eSJanosch Frank static void test_query(void)
38728ccfb1eSJanosch Frank {
38828ccfb1eSJanosch Frank 	int i = 0;
38928ccfb1eSJanosch Frank 
39028ccfb1eSJanosch Frank 	uvcb_qui.header.cmd = UVC_CMD_QUI;
39128ccfb1eSJanosch Frank 	uvcb_qui.header.len = sizeof(uvcb_qui);
39228ccfb1eSJanosch Frank 
39328ccfb1eSJanosch Frank 	report_prefix_push("query");
39428ccfb1eSJanosch Frank 	uvcb_qui.header.len = 0xa0;
39528ccfb1eSJanosch Frank 	uv_call(0, (uint64_t)&uvcb_qui);
39628ccfb1eSJanosch Frank 	report(uvcb_qui.header.rc == UVC_RC_INV_LEN, "length");
39728ccfb1eSJanosch Frank 
39828ccfb1eSJanosch Frank 	uvcb_qui.header.len = 0xa8;
39928ccfb1eSJanosch Frank 	uv_call(0, (uint64_t)&uvcb_qui);
40028ccfb1eSJanosch Frank 	report(uvcb_qui.header.rc == 0x100, "insf length");
40128ccfb1eSJanosch Frank 
40228ccfb1eSJanosch Frank 	uvcb_qui.header.len = sizeof(uvcb_qui);
40328ccfb1eSJanosch Frank 	uv_call(0, (uint64_t)&uvcb_qui);
40428ccfb1eSJanosch Frank 	report(uvcb_qui.header.rc == UVC_RC_EXECUTED, "successful query");
40528ccfb1eSJanosch Frank 
40628ccfb1eSJanosch Frank 	for (i = 0; cmds[i].name; i++)
40728ccfb1eSJanosch Frank 		report(uv_query_test_call(cmds[i].call_bit), "%s", cmds[i].name);
40828ccfb1eSJanosch Frank 
40928ccfb1eSJanosch Frank 	report_prefix_pop();
41028ccfb1eSJanosch Frank }
41128ccfb1eSJanosch Frank 
41228ccfb1eSJanosch Frank static struct cmd_list invalid_cmds[] = {
41328ccfb1eSJanosch Frank 	{ "bogus", 0x4242, sizeof(struct uv_cb_header), -1},
41428ccfb1eSJanosch Frank 	{ "share", UVC_CMD_SET_SHARED_ACCESS, sizeof(struct uv_cb_share), BIT_UVC_CMD_SET_SHARED_ACCESS },
41528ccfb1eSJanosch Frank 	{ "unshare", UVC_CMD_REMOVE_SHARED_ACCESS, sizeof(struct uv_cb_share), BIT_UVC_CMD_REMOVE_SHARED_ACCESS },
41628ccfb1eSJanosch Frank 	{ NULL, 0, 0 },
41728ccfb1eSJanosch Frank };
41828ccfb1eSJanosch Frank 
41928ccfb1eSJanosch Frank static void test_invalid(void)
42028ccfb1eSJanosch Frank {
42128ccfb1eSJanosch Frank 	struct uv_cb_header hdr = {};
42228ccfb1eSJanosch Frank 	int i, cc;
42328ccfb1eSJanosch Frank 
42428ccfb1eSJanosch Frank 	report_prefix_push("invalid");
42528ccfb1eSJanosch Frank 	for (i = 0; invalid_cmds[i].name; i++) {
42628ccfb1eSJanosch Frank 		hdr.cmd = invalid_cmds[i].cmd;
42728ccfb1eSJanosch Frank 		hdr.len = invalid_cmds[i].len;
42828ccfb1eSJanosch Frank 		cc = uv_call(0, (uint64_t)&hdr);
42928ccfb1eSJanosch Frank 		report(cc == 1 && hdr.rc == UVC_RC_INV_CMD &&
43028ccfb1eSJanosch Frank 		       (invalid_cmds[i].call_bit == -1 || !uv_query_test_call(invalid_cmds[i].call_bit)),
43128ccfb1eSJanosch Frank 		       "%s", invalid_cmds[i].name);
43228ccfb1eSJanosch Frank 	}
43328ccfb1eSJanosch Frank 	report_prefix_pop();
43428ccfb1eSJanosch Frank }
43528ccfb1eSJanosch Frank 
43628ccfb1eSJanosch Frank static void test_clear(void)
43728ccfb1eSJanosch Frank {
43828ccfb1eSJanosch Frank 	uint64_t *tmp = (void *)uvcb_init.stor_origin;
43928ccfb1eSJanosch Frank 
44028ccfb1eSJanosch Frank 	diag308_load_reset(1);
44128ccfb1eSJanosch Frank 	sclp_console_setup();
44228ccfb1eSJanosch Frank 	report(!*tmp, "memory cleared after reset 1");
44328ccfb1eSJanosch Frank }
44428ccfb1eSJanosch Frank 
44528ccfb1eSJanosch Frank static void setup_vmem(void)
44628ccfb1eSJanosch Frank {
44728ccfb1eSJanosch Frank 	uint64_t asce, mask;
44828ccfb1eSJanosch Frank 
449*0a5b31d2SSean Christopherson 	setup_mmu(get_max_ram_size(), NULL);
45028ccfb1eSJanosch Frank 	asce = stctg(1);
45128ccfb1eSJanosch Frank 	lctlg(13, asce);
45228ccfb1eSJanosch Frank 	mask = extract_psw_mask() | 0x0000C00000000000UL;
45328ccfb1eSJanosch Frank 	load_psw_mask(mask);
45428ccfb1eSJanosch Frank }
45528ccfb1eSJanosch Frank 
45628ccfb1eSJanosch Frank int main(void)
45728ccfb1eSJanosch Frank {
45828ccfb1eSJanosch Frank 	bool has_uvc = test_facility(158);
45928ccfb1eSJanosch Frank 
46028ccfb1eSJanosch Frank 	report_prefix_push("uvc");
46128ccfb1eSJanosch Frank 	if (!has_uvc) {
46228ccfb1eSJanosch Frank 		report_skip("Ultravisor call facility is not available");
46328ccfb1eSJanosch Frank 		goto done;
46428ccfb1eSJanosch Frank 	}
46528ccfb1eSJanosch Frank 
46628ccfb1eSJanosch Frank 	test_priv();
46728ccfb1eSJanosch Frank 	test_invalid();
46828ccfb1eSJanosch Frank 	test_query();
46928ccfb1eSJanosch Frank 	test_init();
47028ccfb1eSJanosch Frank 
47128ccfb1eSJanosch Frank 	setup_vmem();
47228ccfb1eSJanosch Frank 	test_config_create();
47328ccfb1eSJanosch Frank 	test_cpu_create();
47428ccfb1eSJanosch Frank 	test_cpu_destroy();
47528ccfb1eSJanosch Frank 	test_config_destroy();
47628ccfb1eSJanosch Frank 	test_clear();
47728ccfb1eSJanosch Frank 
47828ccfb1eSJanosch Frank done:
47928ccfb1eSJanosch Frank 	return report_summary();
48028ccfb1eSJanosch Frank }
481