128ccfb1eSJanosch Frank /* SPDX-License-Identifier: GPL-2.0-only */
228ccfb1eSJanosch Frank /*
318d05511SJanosch Frank * Host 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>
125bf29e09SClaudio Imbrenda #include <hardware.h>
1328ccfb1eSJanosch Frank #include <alloc.h>
1428ccfb1eSJanosch Frank #include <vmalloc.h>
1528ccfb1eSJanosch Frank #include <sclp.h>
1628ccfb1eSJanosch Frank #include <smp.h>
1728ccfb1eSJanosch Frank #include <uv.h>
1890704fe2SJanosch Frank #include <snippet.h>
1991d18441SJanosch Frank #include <mmu.h>
2028ccfb1eSJanosch Frank #include <asm/page.h>
2128ccfb1eSJanosch Frank #include <asm/pgtable.h>
2228ccfb1eSJanosch Frank #include <asm/asm-offsets.h>
2328ccfb1eSJanosch Frank #include <asm/interrupt.h>
2428ccfb1eSJanosch Frank #include <asm/facility.h>
2591d18441SJanosch Frank #include <asm/pgtable.h>
2628ccfb1eSJanosch Frank #include <asm/uv.h>
2728ccfb1eSJanosch Frank #include <asm-generic/barrier.h>
2828ccfb1eSJanosch Frank
2928ccfb1eSJanosch Frank static struct uv_cb_qui uvcb_qui;
3028ccfb1eSJanosch Frank static struct uv_cb_init uvcb_init;
3128ccfb1eSJanosch Frank static struct uv_cb_cgc uvcb_cgc;
3228ccfb1eSJanosch Frank static struct uv_cb_csc uvcb_csc;
3328ccfb1eSJanosch Frank
3428ccfb1eSJanosch Frank extern int diag308_load_reset(u64 code);
3528ccfb1eSJanosch Frank
3628ccfb1eSJanosch Frank struct cmd_list {
3728ccfb1eSJanosch Frank const char *name;
3828ccfb1eSJanosch Frank uint16_t cmd;
3928ccfb1eSJanosch Frank uint16_t len;
4028ccfb1eSJanosch Frank int call_bit;
4128ccfb1eSJanosch Frank };
4228ccfb1eSJanosch Frank
cpu_loop(void)4328ccfb1eSJanosch Frank static void cpu_loop(void)
4428ccfb1eSJanosch Frank {
4528ccfb1eSJanosch Frank for (;;) {}
4628ccfb1eSJanosch Frank }
4728ccfb1eSJanosch Frank
48b9ff8da5SJanosch Frank /*
49b9ff8da5SJanosch Frank * Checks if a memory area is protected as secure memory.
50b9ff8da5SJanosch Frank * Will return true if all pages are protected, false otherwise.
51b9ff8da5SJanosch Frank */
access_check_3d(uint8_t * access_ptr,uint64_t len)52b9ff8da5SJanosch Frank static bool access_check_3d(uint8_t *access_ptr, uint64_t len)
53b9ff8da5SJanosch Frank {
54b9ff8da5SJanosch Frank assert(!(len & ~PAGE_MASK));
55b9ff8da5SJanosch Frank assert(!((uint64_t)access_ptr & ~PAGE_MASK));
56b9ff8da5SJanosch Frank
57b9ff8da5SJanosch Frank while (len) {
58b9ff8da5SJanosch Frank expect_pgm_int();
59b9ff8da5SJanosch Frank READ_ONCE(*access_ptr);
60b9ff8da5SJanosch Frank if (clear_pgm_int() != PGM_INT_CODE_SECURE_STOR_ACCESS)
61b9ff8da5SJanosch Frank return false;
62b9ff8da5SJanosch Frank expect_pgm_int();
63b9ff8da5SJanosch Frank WRITE_ONCE(*access_ptr, 42);
64b9ff8da5SJanosch Frank if (clear_pgm_int() != PGM_INT_CODE_SECURE_STOR_ACCESS)
65b9ff8da5SJanosch Frank return false;
66b9ff8da5SJanosch Frank
67b9ff8da5SJanosch Frank access_ptr += PAGE_SIZE;
68b9ff8da5SJanosch Frank len -= PAGE_SIZE;
69b9ff8da5SJanosch Frank }
70b9ff8da5SJanosch Frank
71b9ff8da5SJanosch Frank return true;
72b9ff8da5SJanosch Frank }
73b9ff8da5SJanosch Frank
7428ccfb1eSJanosch Frank static struct cmd_list cmds[] = {
7528ccfb1eSJanosch Frank { "init", UVC_CMD_INIT_UV, sizeof(struct uv_cb_init), BIT_UVC_CMD_INIT_UV },
7628ccfb1eSJanosch Frank { "create conf", UVC_CMD_CREATE_SEC_CONF, sizeof(struct uv_cb_cgc), BIT_UVC_CMD_CREATE_SEC_CONF },
7728ccfb1eSJanosch Frank { "destroy conf", UVC_CMD_DESTROY_SEC_CONF, sizeof(struct uv_cb_nodata), BIT_UVC_CMD_DESTROY_SEC_CONF },
7828ccfb1eSJanosch Frank { "create cpu", UVC_CMD_CREATE_SEC_CPU, sizeof(struct uv_cb_csc), BIT_UVC_CMD_CREATE_SEC_CPU },
7928ccfb1eSJanosch Frank { "destroy cpu", UVC_CMD_DESTROY_SEC_CPU, sizeof(struct uv_cb_nodata), BIT_UVC_CMD_DESTROY_SEC_CPU },
8028ccfb1eSJanosch Frank { "conv to", UVC_CMD_CONV_TO_SEC_STOR, sizeof(struct uv_cb_cts), BIT_UVC_CMD_CONV_TO_SEC_STOR },
8128ccfb1eSJanosch Frank { "conv from", UVC_CMD_CONV_FROM_SEC_STOR, sizeof(struct uv_cb_cfs), BIT_UVC_CMD_CONV_FROM_SEC_STOR },
8228ccfb1eSJanosch Frank { "set sec conf", UVC_CMD_SET_SEC_CONF_PARAMS, sizeof(struct uv_cb_ssc), BIT_UVC_CMD_SET_SEC_PARMS },
8328ccfb1eSJanosch Frank { "unpack", UVC_CMD_UNPACK_IMG, sizeof(struct uv_cb_unp), BIT_UVC_CMD_UNPACK_IMG },
8428ccfb1eSJanosch Frank { "verify", UVC_CMD_VERIFY_IMG, sizeof(struct uv_cb_nodata), BIT_UVC_CMD_VERIFY_IMG },
8528ccfb1eSJanosch Frank { "cpu reset", UVC_CMD_CPU_RESET, sizeof(struct uv_cb_nodata), BIT_UVC_CMD_CPU_RESET },
8628ccfb1eSJanosch Frank { "cpu initial reset", UVC_CMD_CPU_RESET_INITIAL, sizeof(struct uv_cb_nodata), BIT_UVC_CMD_CPU_RESET_INITIAL },
875630c446SJanosch Frank { "conf clear reset", UVC_CMD_PREPARE_RESET, sizeof(struct uv_cb_nodata), BIT_UVC_CMD_PREPARE_RESET },
8828ccfb1eSJanosch Frank { "cpu clear reset", UVC_CMD_CPU_RESET_CLEAR, sizeof(struct uv_cb_nodata), BIT_UVC_CMD_CPU_PERFORM_CLEAR_RESET },
8928ccfb1eSJanosch Frank { "cpu set state", UVC_CMD_CPU_SET_STATE, sizeof(struct uv_cb_cpu_set_state), BIT_UVC_CMD_CPU_SET_STATE },
9028ccfb1eSJanosch Frank { "pin shared", UVC_CMD_PIN_PAGE_SHARED, sizeof(struct uv_cb_cfs), BIT_UVC_CMD_PIN_PAGE_SHARED },
9128ccfb1eSJanosch Frank { "unpin shared", UVC_CMD_UNPIN_PAGE_SHARED, sizeof(struct uv_cb_cts), BIT_UVC_CMD_UNPIN_PAGE_SHARED },
9228ccfb1eSJanosch Frank { NULL, 0, 0 },
9328ccfb1eSJanosch Frank };
9428ccfb1eSJanosch Frank
test_i3(void)955078e7a7SJanosch Frank static void test_i3(void)
965078e7a7SJanosch Frank {
975078e7a7SJanosch Frank struct uv_cb_header uvcb = {
985078e7a7SJanosch Frank .cmd = UVC_CMD_INIT_UV,
995078e7a7SJanosch Frank .len = sizeof(struct uv_cb_init),
1005078e7a7SJanosch Frank };
1015078e7a7SJanosch Frank unsigned long r1 = 0;
1025078e7a7SJanosch Frank int cc;
1035078e7a7SJanosch Frank
1045078e7a7SJanosch Frank report_prefix_push("i3");
1055078e7a7SJanosch Frank expect_pgm_int();
1065078e7a7SJanosch Frank asm volatile(
1075078e7a7SJanosch Frank "0: .insn rrf,0xB9A40000,%[r1],%[r2],4,2\n"
1085078e7a7SJanosch Frank " ipm %[cc]\n"
1095078e7a7SJanosch Frank " srl %[cc],28\n"
1105078e7a7SJanosch Frank : [cc] "=d" (cc)
1115078e7a7SJanosch Frank : [r1] "a" (r1), [r2] "a" (&uvcb)
1125078e7a7SJanosch Frank : "memory", "cc");
1135078e7a7SJanosch Frank check_pgm_int_code(PGM_INT_CODE_SPECIFICATION);
1145078e7a7SJanosch Frank report_prefix_pop();
1155078e7a7SJanosch Frank }
1165078e7a7SJanosch Frank
test_priv(void)11728ccfb1eSJanosch Frank static void test_priv(void)
11828ccfb1eSJanosch Frank {
11928ccfb1eSJanosch Frank struct uv_cb_header uvcb = {};
12028ccfb1eSJanosch Frank uint16_t pgm;
12128ccfb1eSJanosch Frank int i;
12228ccfb1eSJanosch Frank
12328ccfb1eSJanosch Frank report_prefix_push("privileged");
12428ccfb1eSJanosch Frank for (i = 0; cmds[i].name; i++) {
12528ccfb1eSJanosch Frank expect_pgm_int();
12628ccfb1eSJanosch Frank uvcb.cmd = cmds[i].cmd;
12728ccfb1eSJanosch Frank uvcb.len = cmds[i].len;
12828ccfb1eSJanosch Frank enter_pstate();
129bf0e1689SJanosch Frank uv_call_once(0, (uint64_t)&uvcb);
13028ccfb1eSJanosch Frank pgm = clear_pgm_int();
13128ccfb1eSJanosch Frank report(pgm == PGM_INT_CODE_PRIVILEGED_OPERATION, "%s", cmds[i].name);
13228ccfb1eSJanosch Frank }
13328ccfb1eSJanosch Frank report_prefix_pop();
13428ccfb1eSJanosch Frank }
13528ccfb1eSJanosch Frank
test_uv_uninitialized(void)136b744815eSJanosch Frank static void test_uv_uninitialized(void)
137b744815eSJanosch Frank {
138b744815eSJanosch Frank struct uv_cb_header uvcb = {};
139b744815eSJanosch Frank int i;
140b744815eSJanosch Frank
141b744815eSJanosch Frank report_prefix_push("uninitialized");
142b744815eSJanosch Frank
143b744815eSJanosch Frank for (i = 0; cmds[i].name; i++) {
144b744815eSJanosch Frank if (cmds[i].cmd == UVC_CMD_INIT_UV)
145b744815eSJanosch Frank continue;
146b744815eSJanosch Frank expect_pgm_int();
147b744815eSJanosch Frank uvcb.cmd = cmds[i].cmd;
148b744815eSJanosch Frank uvcb.len = cmds[i].len;
149b744815eSJanosch Frank uv_call_once(0, (uint64_t)&uvcb);
150b744815eSJanosch Frank report(uvcb.rc == UVC_RC_INV_STATE, "%s", cmds[i].name);
151b744815eSJanosch Frank }
152b744815eSJanosch Frank report_prefix_pop();
153b744815eSJanosch Frank }
154b744815eSJanosch Frank
test_access(void)15591d18441SJanosch Frank static void test_access(void)
15691d18441SJanosch Frank {
15791d18441SJanosch Frank struct uv_cb_header *uvcb;
15891d18441SJanosch Frank void *pages = alloc_pages(1);
15991d18441SJanosch Frank uint16_t pgm;
16091d18441SJanosch Frank int i;
16191d18441SJanosch Frank
16291d18441SJanosch Frank /* Put UVCB on second page which we will protect later */
16391d18441SJanosch Frank uvcb = pages + PAGE_SIZE;
16491d18441SJanosch Frank
16591d18441SJanosch Frank report_prefix_push("access");
16691d18441SJanosch Frank
167*e8ad989eSJanosch Frank /*
168*e8ad989eSJanosch Frank * If debug is enabled info from the uv header is printed
169*e8ad989eSJanosch Frank * which would lead to a second exception and a test abort.
170*e8ad989eSJanosch Frank */
171*e8ad989eSJanosch Frank if (UVC_ERR_DEBUG) {
172*e8ad989eSJanosch Frank report_skip("Debug doesn't work with access tests");
173*e8ad989eSJanosch Frank goto out;
174*e8ad989eSJanosch Frank }
175*e8ad989eSJanosch Frank
17691d18441SJanosch Frank report_prefix_push("non-crossing");
17791d18441SJanosch Frank protect_page(uvcb, PAGE_ENTRY_I);
17891d18441SJanosch Frank for (i = 0; cmds[i].name; i++) {
17991d18441SJanosch Frank expect_pgm_int();
18091d18441SJanosch Frank mb();
18191d18441SJanosch Frank uv_call_once(0, (uint64_t)uvcb);
18291d18441SJanosch Frank pgm = clear_pgm_int();
18391d18441SJanosch Frank report(pgm == PGM_INT_CODE_PAGE_TRANSLATION, "%s", cmds[i].name);
18491d18441SJanosch Frank }
18591d18441SJanosch Frank report_prefix_pop();
18691d18441SJanosch Frank
18791d18441SJanosch Frank report_prefix_push("crossing");
18891d18441SJanosch Frank /*
18991d18441SJanosch Frank * Put the header into the readable page 1, everything after
19091d18441SJanosch Frank * the header will be on the second, invalid page.
19191d18441SJanosch Frank */
19291d18441SJanosch Frank uvcb -= 1;
19391d18441SJanosch Frank for (i = 0; cmds[i].name; i++) {
19491d18441SJanosch Frank uvcb->cmd = cmds[i].cmd;
19591d18441SJanosch Frank uvcb->len = cmds[i].len;
19691d18441SJanosch Frank
19791d18441SJanosch Frank expect_pgm_int();
19891d18441SJanosch Frank mb();
19991d18441SJanosch Frank uv_call_once(0, (uint64_t)uvcb);
20091d18441SJanosch Frank pgm = clear_pgm_int();
20191d18441SJanosch Frank report(pgm == PGM_INT_CODE_PAGE_TRANSLATION, "%s", cmds[i].name);
20291d18441SJanosch Frank }
20391d18441SJanosch Frank report_prefix_pop();
20491d18441SJanosch Frank
20591d18441SJanosch Frank uvcb += 1;
20691d18441SJanosch Frank unprotect_page(uvcb, PAGE_ENTRY_I);
20791d18441SJanosch Frank
208*e8ad989eSJanosch Frank out:
20991d18441SJanosch Frank free_pages(pages);
21091d18441SJanosch Frank report_prefix_pop();
21191d18441SJanosch Frank }
21291d18441SJanosch Frank
test_config_destroy(void)21328ccfb1eSJanosch Frank static void test_config_destroy(void)
21428ccfb1eSJanosch Frank {
21528ccfb1eSJanosch Frank int rc;
21628ccfb1eSJanosch Frank struct uv_cb_nodata uvcb = {
21728ccfb1eSJanosch Frank .header.cmd = UVC_CMD_DESTROY_SEC_CONF,
21828ccfb1eSJanosch Frank .header.len = sizeof(uvcb),
21928ccfb1eSJanosch Frank .handle = uvcb_cgc.guest_handle,
22028ccfb1eSJanosch Frank };
22128ccfb1eSJanosch Frank
22228ccfb1eSJanosch Frank report_prefix_push("dsc");
22328ccfb1eSJanosch Frank uvcb.header.len -= 8;
22428ccfb1eSJanosch Frank rc = uv_call(0, (uint64_t)&uvcb);
22528ccfb1eSJanosch Frank report(rc == 1 && uvcb.header.rc == UVC_RC_INV_LEN,
22628ccfb1eSJanosch Frank "hdr invalid length");
22728ccfb1eSJanosch Frank uvcb.header.len += 8;
22828ccfb1eSJanosch Frank
22928ccfb1eSJanosch Frank uvcb.handle += 1;
23028ccfb1eSJanosch Frank rc = uv_call(0, (uint64_t)&uvcb);
23128ccfb1eSJanosch Frank report(rc == 1 && uvcb.header.rc == UVC_RC_INV_GHANDLE, "invalid handle");
23228ccfb1eSJanosch Frank uvcb.handle -= 1;
23328ccfb1eSJanosch Frank
23428ccfb1eSJanosch Frank rc = uv_call(0, (uint64_t)&uvcb);
23528ccfb1eSJanosch Frank report(rc == 0 && uvcb.header.rc == UVC_RC_EXECUTED, "success");
23628ccfb1eSJanosch Frank report_prefix_pop();
23728ccfb1eSJanosch Frank }
23828ccfb1eSJanosch Frank
test_cpu_destroy(void)23928ccfb1eSJanosch Frank static void test_cpu_destroy(void)
24028ccfb1eSJanosch Frank {
24128ccfb1eSJanosch Frank int rc;
24228ccfb1eSJanosch Frank struct uv_cb_nodata uvcb = {
24328ccfb1eSJanosch Frank .header.len = sizeof(uvcb),
24428ccfb1eSJanosch Frank .header.cmd = UVC_CMD_DESTROY_SEC_CPU,
24528ccfb1eSJanosch Frank .handle = uvcb_csc.cpu_handle,
24628ccfb1eSJanosch Frank };
24728ccfb1eSJanosch Frank
24828ccfb1eSJanosch Frank report_prefix_push("dcpu");
24928ccfb1eSJanosch Frank
25028ccfb1eSJanosch Frank uvcb.header.len -= 8;
25128ccfb1eSJanosch Frank rc = uv_call(0, (uint64_t)&uvcb);
25228ccfb1eSJanosch Frank report(rc == 1 && uvcb.header.rc == UVC_RC_INV_LEN,
25328ccfb1eSJanosch Frank "hdr invalid length");
25428ccfb1eSJanosch Frank uvcb.header.len += 8;
25528ccfb1eSJanosch Frank
2565bf29e09SClaudio Imbrenda if (!machine_is_z15()) {
25728ccfb1eSJanosch Frank uvcb.handle += 1;
25828ccfb1eSJanosch Frank rc = uv_call(0, (uint64_t)&uvcb);
25928ccfb1eSJanosch Frank report(rc == 1 && uvcb.header.rc == UVC_RC_INV_CHANDLE, "invalid handle");
26028ccfb1eSJanosch Frank uvcb.handle -= 1;
261c73cc92dSJanosch Frank }
26228ccfb1eSJanosch Frank
26328ccfb1eSJanosch Frank rc = uv_call(0, (uint64_t)&uvcb);
26428ccfb1eSJanosch Frank report(rc == 0 && uvcb.header.rc == UVC_RC_EXECUTED, "success");
26528ccfb1eSJanosch Frank
26628ccfb1eSJanosch Frank report_prefix_pop();
26728ccfb1eSJanosch Frank }
26828ccfb1eSJanosch Frank
test_set_se_header(void)269692447f2SJanosch Frank static void test_set_se_header(void)
270692447f2SJanosch Frank {
271692447f2SJanosch Frank struct uv_cb_ssc uvcb = {
272692447f2SJanosch Frank .header.cmd = UVC_CMD_SET_SEC_CONF_PARAMS,
273692447f2SJanosch Frank .header.len = sizeof(uvcb),
274692447f2SJanosch Frank .guest_handle = uvcb_cgc.guest_handle,
275692447f2SJanosch Frank .sec_header_origin = 0,
276692447f2SJanosch Frank .sec_header_len = 0x1000,
277692447f2SJanosch Frank };
278692447f2SJanosch Frank void *pages = alloc_pages(1);
279692447f2SJanosch Frank void *inv;
280692447f2SJanosch Frank int rc;
281692447f2SJanosch Frank
282692447f2SJanosch Frank report_prefix_push("sscp");
283692447f2SJanosch Frank
284692447f2SJanosch Frank uvcb.header.len -= 8;
285692447f2SJanosch Frank rc = uv_call(0, (uint64_t)&uvcb);
286692447f2SJanosch Frank report(rc == 1 && uvcb.header.rc == UVC_RC_INV_LEN,
287692447f2SJanosch Frank "hdr invalid length");
288692447f2SJanosch Frank uvcb.header.len += 8;
289692447f2SJanosch Frank
290692447f2SJanosch Frank uvcb.guest_handle += 1;
291692447f2SJanosch Frank rc = uv_call(0, (uint64_t)&uvcb);
292692447f2SJanosch Frank report(rc == 1 && uvcb.header.rc == UVC_RC_INV_GHANDLE, "invalid handle");
293692447f2SJanosch Frank uvcb.guest_handle -= 1;
294692447f2SJanosch Frank
295692447f2SJanosch Frank inv = pages + PAGE_SIZE;
296692447f2SJanosch Frank uvcb.sec_header_origin = (uint64_t)inv;
297692447f2SJanosch Frank protect_page(inv, PAGE_ENTRY_I);
298692447f2SJanosch Frank rc = uv_call(0, (uint64_t)&uvcb);
299692447f2SJanosch Frank report(rc == 1 && uvcb.header.rc == 0x103,
300692447f2SJanosch Frank "se hdr access exception");
301692447f2SJanosch Frank
302692447f2SJanosch Frank /*
303692447f2SJanosch Frank * Shift the ptr so the first few DWORDs are accessible but
304692447f2SJanosch Frank * the following are on an invalid page.
305692447f2SJanosch Frank */
306692447f2SJanosch Frank uvcb.sec_header_origin -= 0x20;
307692447f2SJanosch Frank rc = uv_call(0, (uint64_t)&uvcb);
308692447f2SJanosch Frank report(rc == 1 && uvcb.header.rc == 0x103,
309692447f2SJanosch Frank "se hdr access exception crossing");
310692447f2SJanosch Frank unprotect_page(inv, PAGE_ENTRY_I);
311692447f2SJanosch Frank
312692447f2SJanosch Frank free_pages(pages);
313692447f2SJanosch Frank report_prefix_pop();
314692447f2SJanosch Frank }
315692447f2SJanosch Frank
test_cpu_create(void)31628ccfb1eSJanosch Frank static void test_cpu_create(void)
31728ccfb1eSJanosch Frank {
31828ccfb1eSJanosch Frank int rc;
31928ccfb1eSJanosch Frank unsigned long tmp;
32028ccfb1eSJanosch Frank
32128ccfb1eSJanosch Frank report_prefix_push("csc");
32228ccfb1eSJanosch Frank uvcb_csc.header.len = sizeof(uvcb_csc);
32328ccfb1eSJanosch Frank uvcb_csc.header.cmd = UVC_CMD_CREATE_SEC_CPU;
32428ccfb1eSJanosch Frank uvcb_csc.guest_handle = uvcb_cgc.guest_handle;
32528ccfb1eSJanosch Frank uvcb_csc.stor_origin = (unsigned long)memalign(PAGE_SIZE, uvcb_qui.cpu_stor_len);
32628ccfb1eSJanosch Frank uvcb_csc.state_origin = (unsigned long)memalign(PAGE_SIZE, PAGE_SIZE);
32728ccfb1eSJanosch Frank
32828ccfb1eSJanosch Frank uvcb_csc.header.len -= 8;
32928ccfb1eSJanosch Frank rc = uv_call(0, (uint64_t)&uvcb_csc);
33028ccfb1eSJanosch Frank report(uvcb_csc.header.rc == UVC_RC_INV_LEN && rc == 1 &&
33128ccfb1eSJanosch Frank !uvcb_csc.cpu_handle, "hdr invalid length");
33228ccfb1eSJanosch Frank uvcb_csc.header.len += 8;
33328ccfb1eSJanosch Frank
33428ccfb1eSJanosch Frank uvcb_csc.guest_handle += 1;
33528ccfb1eSJanosch Frank rc = uv_call(0, (uint64_t)&uvcb_csc);
33628ccfb1eSJanosch Frank report(uvcb_csc.header.rc == UVC_RC_INV_GHANDLE && rc == 1,
33728ccfb1eSJanosch Frank "invalid guest handle");
33828ccfb1eSJanosch Frank uvcb_csc.guest_handle -= 1;
33928ccfb1eSJanosch Frank
34028ccfb1eSJanosch Frank uvcb_csc.num = uvcb_qui.max_guest_cpus + 1;
34128ccfb1eSJanosch Frank rc = uv_call(0, (uint64_t)&uvcb_csc);
34228ccfb1eSJanosch Frank report(uvcb_csc.header.rc == 0x103 && rc == 1,
34328ccfb1eSJanosch Frank "invalid cpu #");
34428ccfb1eSJanosch Frank uvcb_csc.num = 0;
34528ccfb1eSJanosch Frank
34628ccfb1eSJanosch Frank tmp = uvcb_csc.stor_origin;
34728ccfb1eSJanosch Frank uvcb_csc.stor_origin = get_max_ram_size() + PAGE_SIZE;
34828ccfb1eSJanosch Frank rc = uv_call(0, (uint64_t)&uvcb_csc);
34928ccfb1eSJanosch Frank report(uvcb_csc.header.rc == 0x105 && rc == 1,
35028ccfb1eSJanosch Frank "cpu stor inaccessible");
35128ccfb1eSJanosch Frank uvcb_csc.stor_origin = tmp;
35228ccfb1eSJanosch Frank
35328ccfb1eSJanosch Frank tmp = uvcb_csc.stor_origin;
35428ccfb1eSJanosch Frank uvcb_csc.stor_origin = 0;
35528ccfb1eSJanosch Frank rc = uv_call(0, (uint64_t)&uvcb_csc);
35628ccfb1eSJanosch Frank report(uvcb_csc.header.rc == 0x106 && rc == 1,
35728ccfb1eSJanosch Frank "cpu stor in lowcore");
35828ccfb1eSJanosch Frank uvcb_csc.stor_origin = tmp;
35928ccfb1eSJanosch Frank
36028ccfb1eSJanosch Frank tmp = uvcb_csc.state_origin;
36128ccfb1eSJanosch Frank uvcb_csc.state_origin = get_max_ram_size() + PAGE_SIZE;
36228ccfb1eSJanosch Frank rc = uv_call(0, (uint64_t)&uvcb_csc);
36328ccfb1eSJanosch Frank report(uvcb_csc.header.rc == 0x107 && rc == 1,
36428ccfb1eSJanosch Frank "SIE SD inaccessible");
36528ccfb1eSJanosch Frank uvcb_csc.state_origin = tmp;
36628ccfb1eSJanosch Frank
36728ccfb1eSJanosch Frank rc = uv_call(0, (uint64_t)&uvcb_csc);
36828ccfb1eSJanosch Frank report(rc == 0 && uvcb_csc.header.rc == UVC_RC_EXECUTED &&
36928ccfb1eSJanosch Frank uvcb_csc.cpu_handle, "success");
37028ccfb1eSJanosch Frank
371b9ff8da5SJanosch Frank rc = access_check_3d((uint8_t *)uvcb_csc.stor_origin,
372b9ff8da5SJanosch Frank uvcb_qui.cpu_stor_len);
373b9ff8da5SJanosch Frank report(rc, "Storage protection");
374b9ff8da5SJanosch Frank
37528ccfb1eSJanosch Frank tmp = uvcb_csc.stor_origin;
37628ccfb1eSJanosch Frank uvcb_csc.stor_origin = (unsigned long)memalign(PAGE_SIZE, uvcb_qui.cpu_stor_len);
37728ccfb1eSJanosch Frank rc = uv_call(0, (uint64_t)&uvcb_csc);
37828ccfb1eSJanosch Frank report(rc == 1 && uvcb_csc.header.rc == 0x104, "already defined");
37928ccfb1eSJanosch Frank uvcb_csc.stor_origin = tmp;
38028ccfb1eSJanosch Frank report_prefix_pop();
38128ccfb1eSJanosch Frank }
38228ccfb1eSJanosch Frank
383484ab8dcSJanosch Frank /*
384484ab8dcSJanosch Frank * If the first bit of the rc is set we need to destroy the
385484ab8dcSJanosch Frank * configuration before testing other create config errors.
386484ab8dcSJanosch Frank */
cgc_destroy_if_needed(struct uv_cb_cgc * uvcb)387484ab8dcSJanosch Frank static void cgc_destroy_if_needed(struct uv_cb_cgc *uvcb)
388484ab8dcSJanosch Frank {
389484ab8dcSJanosch Frank uint16_t rc, rrc;
390484ab8dcSJanosch Frank
391484ab8dcSJanosch Frank if (uvcb->header.rc != UVC_RC_EXECUTED &&
392484ab8dcSJanosch Frank !(uvcb->header.rc & UVC_RC_DSTR_NEEDED_FLG))
393484ab8dcSJanosch Frank return;
394484ab8dcSJanosch Frank
395484ab8dcSJanosch Frank assert(uvcb->guest_handle);
396484ab8dcSJanosch Frank assert(!uv_cmd_nodata(uvcb->guest_handle, UVC_CMD_DESTROY_SEC_CONF,
397484ab8dcSJanosch Frank &rc, &rrc));
398484ab8dcSJanosch Frank
399484ab8dcSJanosch Frank /* We need to zero it for the next test */
400484ab8dcSJanosch Frank uvcb->guest_handle = 0;
401484ab8dcSJanosch Frank }
402484ab8dcSJanosch Frank
cgc_check_data(struct uv_cb_cgc * uvcb,uint16_t rc_expected)403484ab8dcSJanosch Frank static bool cgc_check_data(struct uv_cb_cgc *uvcb, uint16_t rc_expected)
404484ab8dcSJanosch Frank {
405484ab8dcSJanosch Frank /* This function purely checks for error rcs */
406484ab8dcSJanosch Frank if (uvcb->header.rc == UVC_RC_EXECUTED)
407484ab8dcSJanosch Frank return false;
408484ab8dcSJanosch Frank
409484ab8dcSJanosch Frank /*
410484ab8dcSJanosch Frank * We should only receive a handle when the rc is 1 or the
411484ab8dcSJanosch Frank * first bit is set.
412484ab8dcSJanosch Frank */
413484ab8dcSJanosch Frank if (!(uvcb->header.rc & UVC_RC_DSTR_NEEDED_FLG) && uvcb->guest_handle)
414484ab8dcSJanosch Frank report_abort("Received a handle when we didn't expect one");
415484ab8dcSJanosch Frank
416484ab8dcSJanosch Frank return (uvcb->header.rc & ~UVC_RC_DSTR_NEEDED_FLG) == rc_expected;
417484ab8dcSJanosch Frank }
418484ab8dcSJanosch Frank
test_config_create(void)41928ccfb1eSJanosch Frank static void test_config_create(void)
42028ccfb1eSJanosch Frank {
42128ccfb1eSJanosch Frank int rc;
42228ccfb1eSJanosch Frank unsigned long vsize, tmp;
42328ccfb1eSJanosch Frank static struct uv_cb_cgc uvcb;
42428ccfb1eSJanosch Frank
42528ccfb1eSJanosch Frank uvcb_cgc.header.cmd = UVC_CMD_CREATE_SEC_CONF;
42628ccfb1eSJanosch Frank uvcb_cgc.header.len = sizeof(uvcb_cgc);
42728ccfb1eSJanosch Frank report_prefix_push("cgc");
42828ccfb1eSJanosch Frank
42928ccfb1eSJanosch Frank uvcb_cgc.guest_stor_origin = 0;
43028ccfb1eSJanosch Frank uvcb_cgc.guest_stor_len = 42 * (1UL << 20);
43128ccfb1eSJanosch Frank vsize = uvcb_qui.conf_base_virt_stor_len +
43228ccfb1eSJanosch Frank ((uvcb_cgc.guest_stor_len / (1UL << 20)) * uvcb_qui.conf_virt_var_stor_len);
43328ccfb1eSJanosch Frank
43428ccfb1eSJanosch Frank uvcb_cgc.conf_base_stor_origin = (uint64_t)memalign(PAGE_SIZE * 4, uvcb_qui.conf_base_phys_stor_len);
43528ccfb1eSJanosch Frank uvcb_cgc.conf_var_stor_origin = (uint64_t)memalign(PAGE_SIZE, vsize);
43628ccfb1eSJanosch Frank uvcb_cgc.guest_asce = (uint64_t)memalign(PAGE_SIZE, 4 * PAGE_SIZE) | ASCE_DT_SEGMENT | REGION_TABLE_LENGTH | ASCE_P;
43728ccfb1eSJanosch Frank uvcb_cgc.guest_sca = (uint64_t)memalign(PAGE_SIZE * 4, PAGE_SIZE * 4);
43828ccfb1eSJanosch Frank
43928ccfb1eSJanosch Frank uvcb_cgc.header.len -= 8;
44028ccfb1eSJanosch Frank rc = uv_call(0, (uint64_t)&uvcb_cgc);
44128ccfb1eSJanosch Frank report(uvcb_cgc.header.rc == UVC_RC_INV_LEN && rc == 1 &&
44228ccfb1eSJanosch Frank !uvcb_cgc.guest_handle, "hdr invalid length");
443484ab8dcSJanosch Frank cgc_destroy_if_needed(&uvcb_cgc);
44428ccfb1eSJanosch Frank uvcb_cgc.header.len += 8;
44528ccfb1eSJanosch Frank
44628ccfb1eSJanosch Frank uvcb_cgc.guest_stor_origin = uvcb_qui.max_guest_stor_addr + (1UL << 20) * 2 + 1;
44728ccfb1eSJanosch Frank rc = uv_call(0, (uint64_t)&uvcb_cgc);
448484ab8dcSJanosch Frank report(cgc_check_data(&uvcb_cgc, 0x101) && rc == 1,
44928ccfb1eSJanosch Frank "MSO > max guest addr");
450484ab8dcSJanosch Frank cgc_destroy_if_needed(&uvcb_cgc);
45128ccfb1eSJanosch Frank uvcb_cgc.guest_stor_origin = 0;
45228ccfb1eSJanosch Frank
45328ccfb1eSJanosch Frank uvcb_cgc.guest_stor_origin = uvcb_qui.max_guest_stor_addr - (1UL << 20);
45428ccfb1eSJanosch Frank rc = uv_call(0, (uint64_t)&uvcb_cgc);
455484ab8dcSJanosch Frank report(cgc_check_data(&uvcb_cgc, 0x102) && rc == 1,
45628ccfb1eSJanosch Frank "MSO + MSL > max guest addr");
457484ab8dcSJanosch Frank cgc_destroy_if_needed(&uvcb_cgc);
45828ccfb1eSJanosch Frank uvcb_cgc.guest_stor_origin = 0;
45928ccfb1eSJanosch Frank
46028ccfb1eSJanosch Frank uvcb_cgc.guest_asce &= ~ASCE_P;
46128ccfb1eSJanosch Frank rc = uv_call(0, (uint64_t)&uvcb_cgc);
462484ab8dcSJanosch Frank report(cgc_check_data(&uvcb_cgc, 0x105) && rc == 1,
46328ccfb1eSJanosch Frank "ASCE private bit missing");
464484ab8dcSJanosch Frank cgc_destroy_if_needed(&uvcb_cgc);
46528ccfb1eSJanosch Frank uvcb_cgc.guest_asce |= ASCE_P;
46628ccfb1eSJanosch Frank
46728ccfb1eSJanosch Frank uvcb_cgc.guest_asce |= 0x20;
46828ccfb1eSJanosch Frank rc = uv_call(0, (uint64_t)&uvcb_cgc);
469484ab8dcSJanosch Frank report(cgc_check_data(&uvcb_cgc, 0x105) && rc == 1,
47028ccfb1eSJanosch Frank "ASCE bit 58 set");
471484ab8dcSJanosch Frank cgc_destroy_if_needed(&uvcb_cgc);
47228ccfb1eSJanosch Frank uvcb_cgc.guest_asce &= ~0x20;
47328ccfb1eSJanosch Frank
47428ccfb1eSJanosch Frank tmp = uvcb_cgc.conf_base_stor_origin;
47528ccfb1eSJanosch Frank uvcb_cgc.conf_base_stor_origin = get_max_ram_size() + 8;
47628ccfb1eSJanosch Frank rc = uv_call(0, (uint64_t)&uvcb_cgc);
477484ab8dcSJanosch Frank report(cgc_check_data(&uvcb_cgc, 0x108) && rc == 1,
47828ccfb1eSJanosch Frank "base storage origin > available memory");
479484ab8dcSJanosch Frank cgc_destroy_if_needed(&uvcb_cgc);
48028ccfb1eSJanosch Frank uvcb_cgc.conf_base_stor_origin = tmp;
48128ccfb1eSJanosch Frank
48228ccfb1eSJanosch Frank tmp = uvcb_cgc.conf_base_stor_origin;
48328ccfb1eSJanosch Frank uvcb_cgc.conf_base_stor_origin = 0x1000;
48428ccfb1eSJanosch Frank rc = uv_call(0, (uint64_t)&uvcb_cgc);
485484ab8dcSJanosch Frank report(cgc_check_data(&uvcb_cgc, 0x109) && rc == 1,
486484ab8dcSJanosch Frank "base storage origin contains lowcore %x", uvcb_cgc.header.rc);
487484ab8dcSJanosch Frank cgc_destroy_if_needed(&uvcb_cgc);
48828ccfb1eSJanosch Frank uvcb_cgc.conf_base_stor_origin = tmp;
48928ccfb1eSJanosch Frank
49028ccfb1eSJanosch Frank tmp = uvcb_cgc.guest_sca;
49128ccfb1eSJanosch Frank uvcb_cgc.guest_sca = 0;
49228ccfb1eSJanosch Frank rc = uv_call(0, (uint64_t)&uvcb_cgc);
493484ab8dcSJanosch Frank report(cgc_check_data(&uvcb_cgc, 0x10c) && rc == 1,
49428ccfb1eSJanosch Frank "sca == 0");
495484ab8dcSJanosch Frank cgc_destroy_if_needed(&uvcb_cgc);
49628ccfb1eSJanosch Frank uvcb_cgc.guest_sca = tmp;
49728ccfb1eSJanosch Frank
49828ccfb1eSJanosch Frank tmp = uvcb_cgc.guest_sca;
4995e83f9d0SJanosch Frank uvcb_cgc.guest_sca = get_max_ram_size() + PAGE_SIZE * 4;
50028ccfb1eSJanosch Frank rc = uv_call(0, (uint64_t)&uvcb_cgc);
501484ab8dcSJanosch Frank report(cgc_check_data(&uvcb_cgc, 0x10d) && rc == 1,
50228ccfb1eSJanosch Frank "sca inaccessible");
503484ab8dcSJanosch Frank cgc_destroy_if_needed(&uvcb_cgc);
50428ccfb1eSJanosch Frank uvcb_cgc.guest_sca = tmp;
50528ccfb1eSJanosch Frank
50628ccfb1eSJanosch Frank rc = uv_call(0, (uint64_t)&uvcb_cgc);
50728ccfb1eSJanosch Frank report(rc == 0 && uvcb_cgc.header.rc == UVC_RC_EXECUTED, "successful");
50828ccfb1eSJanosch Frank
509b9ff8da5SJanosch Frank rc = access_check_3d((uint8_t *)uvcb_cgc.conf_base_stor_origin,
510b9ff8da5SJanosch Frank uvcb_qui.conf_base_phys_stor_len);
511b9ff8da5SJanosch Frank report(rc, "Base storage protection");
512b9ff8da5SJanosch Frank
513b9ff8da5SJanosch Frank rc = access_check_3d((uint8_t *)uvcb_cgc.conf_var_stor_origin, vsize);
514b9ff8da5SJanosch Frank report(rc, "Variable storage protection");
515b9ff8da5SJanosch Frank
51628ccfb1eSJanosch Frank uvcb_cgc.header.rc = 0;
51728ccfb1eSJanosch Frank uvcb_cgc.header.rrc = 0;
51828ccfb1eSJanosch Frank tmp = uvcb_cgc.guest_handle;
51928ccfb1eSJanosch Frank uvcb_cgc.guest_handle = 0;
52028ccfb1eSJanosch Frank rc = uv_call(0, (uint64_t)&uvcb_cgc);
52128ccfb1eSJanosch Frank report(uvcb_cgc.header.rc >= 0x100 && rc == 1, "reuse uvcb");
522484ab8dcSJanosch Frank cgc_destroy_if_needed(&uvcb_cgc);
52328ccfb1eSJanosch Frank uvcb_cgc.guest_handle = tmp;
52428ccfb1eSJanosch Frank
52528ccfb1eSJanosch Frank /* Copy over most data from uvcb_cgc, so we have the ASCE that was used. */
52628ccfb1eSJanosch Frank memcpy(&uvcb, &uvcb_cgc, sizeof(uvcb));
52728ccfb1eSJanosch Frank
52828ccfb1eSJanosch Frank /* Reset the header and handle */
52928ccfb1eSJanosch Frank uvcb.header.rc = 0;
53028ccfb1eSJanosch Frank uvcb.header.rrc = 0;
53128ccfb1eSJanosch Frank uvcb.guest_handle = 0;
53228ccfb1eSJanosch Frank
53328ccfb1eSJanosch Frank /* Use new storage areas. */
53428ccfb1eSJanosch Frank uvcb.conf_base_stor_origin = (uint64_t)memalign(PAGE_SIZE * 4, uvcb_qui.conf_base_phys_stor_len);
53528ccfb1eSJanosch Frank uvcb.conf_var_stor_origin = (uint64_t)memalign(PAGE_SIZE, vsize);
53628ccfb1eSJanosch Frank
53728ccfb1eSJanosch Frank rc = uv_call(0, (uint64_t)&uvcb);
53828ccfb1eSJanosch Frank report(uvcb.header.rc >= 0x104 && rc == 1 && !uvcb.guest_handle,
53928ccfb1eSJanosch Frank "reuse ASCE");
540484ab8dcSJanosch Frank cgc_destroy_if_needed(&uvcb);
54128ccfb1eSJanosch Frank free((void *)uvcb.conf_base_stor_origin);
54228ccfb1eSJanosch Frank free((void *)uvcb.conf_var_stor_origin);
54328ccfb1eSJanosch Frank
54428ccfb1eSJanosch Frank /* Missing: 106, 10a, a0b */
54528ccfb1eSJanosch Frank report_prefix_pop();
54628ccfb1eSJanosch Frank }
54728ccfb1eSJanosch Frank
test_init(void)54828ccfb1eSJanosch Frank static void test_init(void)
54928ccfb1eSJanosch Frank {
55028ccfb1eSJanosch Frank int rc;
5514033c512SJanosch Frank uint64_t tmp;
55228ccfb1eSJanosch Frank
5534033c512SJanosch Frank /*
5544033c512SJanosch Frank * Donated storage needs to be over 2GB, AREA_NORMAL does that
5554033c512SJanosch Frank * on s390x.
5564033c512SJanosch Frank */
5574033c512SJanosch Frank tmp = (uint64_t)memalign_pages_flags(SZ_1M, uvcb_qui.uv_base_stor_len, AREA_NORMAL);
55828ccfb1eSJanosch Frank
55928ccfb1eSJanosch Frank uvcb_init.header.len = sizeof(uvcb_init);
56028ccfb1eSJanosch Frank uvcb_init.header.cmd = UVC_CMD_INIT_UV;
5614033c512SJanosch Frank uvcb_init.stor_origin = tmp;
56228ccfb1eSJanosch Frank uvcb_init.stor_len = uvcb_qui.uv_base_stor_len;
56328ccfb1eSJanosch Frank
56428ccfb1eSJanosch Frank report_prefix_push("init");
56528ccfb1eSJanosch Frank uvcb_init.header.len -= 8;
56628ccfb1eSJanosch Frank rc = uv_call(0, (uint64_t)&uvcb_init);
56728ccfb1eSJanosch Frank report(rc == 1 && uvcb_init.header.rc == UVC_RC_INV_LEN,
56828ccfb1eSJanosch Frank "hdr invalid length");
56928ccfb1eSJanosch Frank uvcb_init.header.len += 8;
57028ccfb1eSJanosch Frank
57128ccfb1eSJanosch Frank uvcb_init.stor_len -= 8;
57228ccfb1eSJanosch Frank rc = uv_call(0, (uint64_t)&uvcb_init);
57328ccfb1eSJanosch Frank report(rc == 1 && uvcb_init.header.rc == 0x103,
57428ccfb1eSJanosch Frank "storage invalid length");
57528ccfb1eSJanosch Frank uvcb_init.stor_len += 8;
57628ccfb1eSJanosch Frank
577fa61eb8eSJanosch Frank /* Storage origin is 1MB aligned, the length is 4KB aligned */
578fa61eb8eSJanosch Frank uvcb_init.stor_origin = get_max_ram_size();
57928ccfb1eSJanosch Frank rc = uv_call(0, (uint64_t)&uvcb_init);
580fa61eb8eSJanosch Frank report(rc == 1 && (uvcb_init.header.rc == 0x104 || uvcb_init.header.rc == 0x105),
58128ccfb1eSJanosch Frank "storage origin invalid");
5824033c512SJanosch Frank uvcb_init.stor_origin = tmp;
58328ccfb1eSJanosch Frank
584fa61eb8eSJanosch Frank if (uvcb_init.stor_len >= HPAGE_SIZE) {
585fa61eb8eSJanosch Frank uvcb_init.stor_origin = get_max_ram_size() - HPAGE_SIZE;
58628ccfb1eSJanosch Frank rc = uv_call(0, (uint64_t)&uvcb_init);
58728ccfb1eSJanosch Frank report(rc == 1 && uvcb_init.header.rc == 0x105,
58828ccfb1eSJanosch Frank "storage + length invalid");
5894033c512SJanosch Frank uvcb_init.stor_origin = tmp;
590fa61eb8eSJanosch Frank } else {
591fa61eb8eSJanosch Frank report_skip("storage + length invalid, stor_len < HPAGE_SIZE");
592fa61eb8eSJanosch Frank }
59328ccfb1eSJanosch Frank
59428ccfb1eSJanosch Frank uvcb_init.stor_origin = 1UL << 30;
59528ccfb1eSJanosch Frank rc = uv_call(0, (uint64_t)&uvcb_init);
59628ccfb1eSJanosch Frank report(rc == 1 && uvcb_init.header.rc == 0x108,
59728ccfb1eSJanosch Frank "storage below 2GB");
5984033c512SJanosch Frank uvcb_init.stor_origin = tmp;
59928ccfb1eSJanosch Frank
600333011bbSJanosch Frank if (smp_query_num_cpus() > 1) {
601f514b4f7SClaudio Imbrenda smp_cpu_setup(1, PSW_WITH_CUR_MASK(cpu_loop));
60228ccfb1eSJanosch Frank rc = uv_call(0, (uint64_t)&uvcb_init);
60328ccfb1eSJanosch Frank report(rc == 1 && uvcb_init.header.rc == 0x102,
60428ccfb1eSJanosch Frank "too many running cpus");
60528ccfb1eSJanosch Frank smp_cpu_stop(1);
606333011bbSJanosch Frank } else {
607333011bbSJanosch Frank report_skip("Not enough cpus for 0x102 test");
608333011bbSJanosch Frank }
60928ccfb1eSJanosch Frank
61028ccfb1eSJanosch Frank rc = uv_call(0, (uint64_t)&uvcb_init);
61128ccfb1eSJanosch Frank report(rc == 0 && uvcb_init.header.rc == UVC_RC_EXECUTED, "successful");
61228ccfb1eSJanosch Frank
6134033c512SJanosch Frank tmp = uvcb_init.stor_origin;
6144033c512SJanosch Frank uvcb_init.stor_origin = (uint64_t)memalign_pages_flags(HPAGE_SIZE, uvcb_qui.uv_base_stor_len, AREA_NORMAL);
61528ccfb1eSJanosch Frank rc = uv_call(0, (uint64_t)&uvcb_init);
61628ccfb1eSJanosch Frank report(rc == 1 && uvcb_init.header.rc == 0x101, "double init");
6174033c512SJanosch Frank free((void *)uvcb_init.stor_origin);
6184033c512SJanosch Frank uvcb_init.stor_origin = tmp;
61928ccfb1eSJanosch Frank
62028ccfb1eSJanosch Frank report_prefix_pop();
62128ccfb1eSJanosch Frank }
62228ccfb1eSJanosch Frank
test_query(void)62328ccfb1eSJanosch Frank static void test_query(void)
62428ccfb1eSJanosch Frank {
625cde26b62SJanosch Frank int i = 0, cc;
62628ccfb1eSJanosch Frank
62728ccfb1eSJanosch Frank uvcb_qui.header.cmd = UVC_CMD_QUI;
62828ccfb1eSJanosch Frank uvcb_qui.header.len = sizeof(uvcb_qui);
62928ccfb1eSJanosch Frank
63028ccfb1eSJanosch Frank report_prefix_push("query");
63128ccfb1eSJanosch Frank uvcb_qui.header.len = 0xa0;
63228ccfb1eSJanosch Frank uv_call(0, (uint64_t)&uvcb_qui);
63328ccfb1eSJanosch Frank report(uvcb_qui.header.rc == UVC_RC_INV_LEN, "length");
63428ccfb1eSJanosch Frank
63528ccfb1eSJanosch Frank uvcb_qui.header.len = 0xa8;
63628ccfb1eSJanosch Frank uv_call(0, (uint64_t)&uvcb_qui);
63728ccfb1eSJanosch Frank report(uvcb_qui.header.rc == 0x100, "insf length");
63828ccfb1eSJanosch Frank
63928ccfb1eSJanosch Frank uvcb_qui.header.len = sizeof(uvcb_qui);
640cde26b62SJanosch Frank cc = uv_call(0, (uint64_t)&uvcb_qui);
641cde26b62SJanosch Frank report((!cc && uvcb_qui.header.rc == UVC_RC_EXECUTED) ||
642cde26b62SJanosch Frank (cc == 1 && uvcb_qui.header.rc == 0x100),
643cde26b62SJanosch Frank "successful query");
64428ccfb1eSJanosch Frank
64528ccfb1eSJanosch Frank for (i = 0; cmds[i].name; i++)
64628ccfb1eSJanosch Frank report(uv_query_test_call(cmds[i].call_bit), "%s", cmds[i].name);
64728ccfb1eSJanosch Frank
64828ccfb1eSJanosch Frank report_prefix_pop();
64928ccfb1eSJanosch Frank }
65028ccfb1eSJanosch Frank
65128ccfb1eSJanosch Frank static struct cmd_list invalid_cmds[] = {
65228ccfb1eSJanosch Frank { "bogus", 0x4242, sizeof(struct uv_cb_header), -1},
65328ccfb1eSJanosch Frank { "share", UVC_CMD_SET_SHARED_ACCESS, sizeof(struct uv_cb_share), BIT_UVC_CMD_SET_SHARED_ACCESS },
65428ccfb1eSJanosch Frank { "unshare", UVC_CMD_REMOVE_SHARED_ACCESS, sizeof(struct uv_cb_share), BIT_UVC_CMD_REMOVE_SHARED_ACCESS },
6556a87e02cSSteffen Eiden { "attest", UVC_CMD_ATTESTATION, sizeof(struct uv_cb_attest), BIT_UVC_CMD_ATTESTATION },
65628ccfb1eSJanosch Frank { NULL, 0, 0 },
65728ccfb1eSJanosch Frank };
65828ccfb1eSJanosch Frank
test_invalid(void)65928ccfb1eSJanosch Frank static void test_invalid(void)
66028ccfb1eSJanosch Frank {
66128ccfb1eSJanosch Frank struct uv_cb_header hdr = {};
66228ccfb1eSJanosch Frank int i, cc;
66328ccfb1eSJanosch Frank
66428ccfb1eSJanosch Frank report_prefix_push("invalid");
66528ccfb1eSJanosch Frank for (i = 0; invalid_cmds[i].name; i++) {
66628ccfb1eSJanosch Frank hdr.cmd = invalid_cmds[i].cmd;
66728ccfb1eSJanosch Frank hdr.len = invalid_cmds[i].len;
66828ccfb1eSJanosch Frank cc = uv_call(0, (uint64_t)&hdr);
66928ccfb1eSJanosch Frank report(cc == 1 && hdr.rc == UVC_RC_INV_CMD &&
67028ccfb1eSJanosch Frank (invalid_cmds[i].call_bit == -1 || !uv_query_test_call(invalid_cmds[i].call_bit)),
67128ccfb1eSJanosch Frank "%s", invalid_cmds[i].name);
67228ccfb1eSJanosch Frank }
67328ccfb1eSJanosch Frank report_prefix_pop();
67428ccfb1eSJanosch Frank }
67528ccfb1eSJanosch Frank
setup_test_clear(void)676b744815eSJanosch Frank static void setup_test_clear(void)
677b744815eSJanosch Frank {
678b744815eSJanosch Frank unsigned long vsize;
679b744815eSJanosch Frank int rc;
680b744815eSJanosch Frank
681b744815eSJanosch Frank uvcb_cgc.header.cmd = UVC_CMD_CREATE_SEC_CONF;
682b744815eSJanosch Frank uvcb_cgc.header.len = sizeof(uvcb_cgc);
683b744815eSJanosch Frank
684b744815eSJanosch Frank uvcb_cgc.guest_stor_origin = 0;
685b744815eSJanosch Frank uvcb_cgc.guest_stor_len = 42 * (1UL << 20);
686b744815eSJanosch Frank vsize = uvcb_qui.conf_base_virt_stor_len +
687b744815eSJanosch Frank ((uvcb_cgc.guest_stor_len / (1UL << 20)) * uvcb_qui.conf_virt_var_stor_len);
688b744815eSJanosch Frank
689b744815eSJanosch Frank uvcb_cgc.conf_base_stor_origin = (uint64_t)memalign(PAGE_SIZE * 4, uvcb_qui.conf_base_phys_stor_len);
690b744815eSJanosch Frank uvcb_cgc.conf_var_stor_origin = (uint64_t)memalign(PAGE_SIZE, vsize);
691b744815eSJanosch Frank uvcb_cgc.guest_asce = (uint64_t)memalign(PAGE_SIZE, 4 * PAGE_SIZE) | ASCE_DT_SEGMENT | REGION_TABLE_LENGTH | ASCE_P;
692b744815eSJanosch Frank uvcb_cgc.guest_sca = (uint64_t)memalign(PAGE_SIZE * 4, PAGE_SIZE * 4);
693b744815eSJanosch Frank
694b744815eSJanosch Frank rc = uv_call(0, (uint64_t)&uvcb_cgc);
695b744815eSJanosch Frank assert(rc == 0);
696b744815eSJanosch Frank
697b744815eSJanosch Frank uvcb_csc.header.len = sizeof(uvcb_csc);
698b744815eSJanosch Frank uvcb_csc.header.cmd = UVC_CMD_CREATE_SEC_CPU;
699b744815eSJanosch Frank uvcb_csc.guest_handle = uvcb_cgc.guest_handle;
700b744815eSJanosch Frank uvcb_csc.stor_origin = (unsigned long)memalign(PAGE_SIZE, uvcb_qui.cpu_stor_len);
701b744815eSJanosch Frank uvcb_csc.state_origin = (unsigned long)memalign(PAGE_SIZE, PAGE_SIZE);
702b744815eSJanosch Frank
703b744815eSJanosch Frank rc = uv_call(0, (uint64_t)&uvcb_csc);
704b744815eSJanosch Frank assert(rc == 0);
705b744815eSJanosch Frank }
706b744815eSJanosch Frank
test_clear(void)70728ccfb1eSJanosch Frank static void test_clear(void)
70828ccfb1eSJanosch Frank {
709b744815eSJanosch Frank uint64_t *tmp;
710b744815eSJanosch Frank
711b744815eSJanosch Frank report_prefix_push("load normal reset");
712b744815eSJanosch Frank
713b744815eSJanosch Frank /*
714b744815eSJanosch Frank * Setup a config and a cpu so we can check if a diag308 reset
715b744815eSJanosch Frank * clears the donated memory and makes the pages unsecure.
716b744815eSJanosch Frank */
717b744815eSJanosch Frank setup_test_clear();
71828ccfb1eSJanosch Frank
71928ccfb1eSJanosch Frank diag308_load_reset(1);
72028ccfb1eSJanosch Frank sclp_console_setup();
721b744815eSJanosch Frank
722b744815eSJanosch Frank tmp = (void *)uvcb_init.stor_origin;
723b744815eSJanosch Frank report(!*tmp, "uv init donated memory cleared");
724b744815eSJanosch Frank
725b744815eSJanosch Frank tmp = (void *)uvcb_cgc.conf_base_stor_origin;
726b744815eSJanosch Frank report(!*tmp, "config base donated memory cleared");
727b744815eSJanosch Frank
728b744815eSJanosch Frank tmp = (void *)uvcb_cgc.conf_base_stor_origin;
729b744815eSJanosch Frank report(!*tmp, "config variable donated memory cleared");
730b744815eSJanosch Frank
731b744815eSJanosch Frank tmp = (void *)uvcb_csc.stor_origin;
732b744815eSJanosch Frank report(!*tmp, "cpu donated memory cleared after reset 1");
733b744815eSJanosch Frank
734b744815eSJanosch Frank /* Check if uninitialized after reset */
735b744815eSJanosch Frank test_uv_uninitialized();
736b744815eSJanosch Frank
737b744815eSJanosch Frank report_prefix_pop();
73828ccfb1eSJanosch Frank }
73928ccfb1eSJanosch Frank
setup_vmem(void)74028ccfb1eSJanosch Frank static void setup_vmem(void)
74128ccfb1eSJanosch Frank {
742136d73e3SJanosch Frank uint64_t asce;
74328ccfb1eSJanosch Frank
7440a5b31d2SSean Christopherson setup_mmu(get_max_ram_size(), NULL);
745136d73e3SJanosch Frank /*
746136d73e3SJanosch Frank * setup_mmu() will enable DAT and set the primary address
747136d73e3SJanosch Frank * space but we need to have a valid home space since UV calls
748136d73e3SJanosch Frank * take home space virtual addresses.
749136d73e3SJanosch Frank *
750136d73e3SJanosch Frank * Hence we just copy the primary asce into the home space.
751136d73e3SJanosch Frank */
75228ccfb1eSJanosch Frank asce = stctg(1);
75328ccfb1eSJanosch Frank lctlg(13, asce);
75428ccfb1eSJanosch Frank }
75528ccfb1eSJanosch Frank
main(void)75628ccfb1eSJanosch Frank int main(void)
75728ccfb1eSJanosch Frank {
75828ccfb1eSJanosch Frank bool has_uvc = test_facility(158);
75928ccfb1eSJanosch Frank
76028ccfb1eSJanosch Frank report_prefix_push("uvc");
76128ccfb1eSJanosch Frank if (!has_uvc) {
76228ccfb1eSJanosch Frank report_skip("Ultravisor call facility is not available");
76328ccfb1eSJanosch Frank goto done;
76428ccfb1eSJanosch Frank }
7654762a72eSJanosch Frank if (!uv_os_is_host()) {
7664762a72eSJanosch Frank report_skip("This test needs to be run in a UV host environment");
7674762a72eSJanosch Frank goto done;
7684762a72eSJanosch Frank }
76928ccfb1eSJanosch Frank
7705078e7a7SJanosch Frank test_i3();
77128ccfb1eSJanosch Frank test_priv();
77228ccfb1eSJanosch Frank test_invalid();
773b744815eSJanosch Frank test_uv_uninitialized();
77428ccfb1eSJanosch Frank test_query();
77590704fe2SJanosch Frank
77690704fe2SJanosch Frank if (get_ram_size() < SNIPPET_PV_MIN_MEM_SIZE) {
77790704fe2SJanosch Frank report_skip("Not enough memory. This test needs about %ld MB of memory",
77890704fe2SJanosch Frank SNIPPET_PV_MIN_MEM_SIZE / SZ_1M);
77990704fe2SJanosch Frank goto done;
78090704fe2SJanosch Frank }
78190704fe2SJanosch Frank
78228ccfb1eSJanosch Frank test_init();
78328ccfb1eSJanosch Frank
78428ccfb1eSJanosch Frank setup_vmem();
78591d18441SJanosch Frank test_access();
78691d18441SJanosch Frank
78728ccfb1eSJanosch Frank test_config_create();
78828ccfb1eSJanosch Frank test_cpu_create();
789692447f2SJanosch Frank test_set_se_header();
79028ccfb1eSJanosch Frank test_cpu_destroy();
79128ccfb1eSJanosch Frank test_config_destroy();
79228ccfb1eSJanosch Frank test_clear();
79328ccfb1eSJanosch Frank
79428ccfb1eSJanosch Frank done:
79528ccfb1eSJanosch Frank return report_summary();
79628ccfb1eSJanosch Frank }
797