1fa624cc2SJanosch Frank /* SPDX-License-Identifier: GPL-2.0-only */
22ea7afb6SJanosch Frank /*
32ea7afb6SJanosch Frank * Guest Ultravisor Call tests
42ea7afb6SJanosch Frank *
5*8348b72dSSteffen Eiden * Copyright IBM Corp. 2020, 2022
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
test_priv(void)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
56*8348b72dSSteffen Eiden report_prefix_push("attest");
57*8348b72dSSteffen Eiden uvcb.cmd = UVC_CMD_ATTESTATION;
58*8348b72dSSteffen Eiden uvcb.len = sizeof(struct uv_cb_attest);
59*8348b72dSSteffen Eiden expect_pgm_int();
60*8348b72dSSteffen Eiden enter_pstate();
61*8348b72dSSteffen Eiden uv_call_once(0, (uint64_t)&uvcb);
62*8348b72dSSteffen Eiden check_pgm_int_code(PGM_INT_CODE_PRIVILEGED_OPERATION);
63*8348b72dSSteffen Eiden report_prefix_pop();
64*8348b72dSSteffen Eiden
652ea7afb6SJanosch Frank report_prefix_pop();
662ea7afb6SJanosch Frank }
672ea7afb6SJanosch Frank
test_query(void)682ea7afb6SJanosch Frank static void test_query(void)
692ea7afb6SJanosch Frank {
702ea7afb6SJanosch Frank struct uv_cb_qui uvcb = {
712ea7afb6SJanosch Frank .header.cmd = UVC_CMD_QUI,
7283d815a2SJanosch Frank /* A dword below the minimum length */
7383d815a2SJanosch Frank .header.len = 0xa0,
742ea7afb6SJanosch Frank };
752ea7afb6SJanosch Frank int cc;
762ea7afb6SJanosch Frank
772ea7afb6SJanosch Frank report_prefix_push("query");
782ea7afb6SJanosch Frank cc = uv_call(0, (u64)&uvcb);
792ea7afb6SJanosch Frank report(cc == 1 && uvcb.header.rc == UVC_RC_INV_LEN, "length");
802ea7afb6SJanosch Frank
812ea7afb6SJanosch Frank /*
821b642bffSSteffen Eiden * BIT_UVC_CMD_QUI, BIT_UVC_CMD_SET_SHARED_ACCESS and
831b642bffSSteffen Eiden * BIT_UVC_CMD_REMOVE_SHARED_ACCESS are always present as they
841b642bffSSteffen Eiden * have been introduced with the first Ultravisor version.
851b642bffSSteffen Eiden * However, we only need to check for QUI as
861b642bffSSteffen Eiden * SET/REMOVE SHARED are used to fence this test to be only
871b642bffSSteffen Eiden * executed by protected guests.
882ea7afb6SJanosch Frank */
891b642bffSSteffen Eiden report(uv_query_test_call(BIT_UVC_CMD_QUI), "query indicated");
902ea7afb6SJanosch Frank report_prefix_pop();
912ea7afb6SJanosch Frank }
922ea7afb6SJanosch Frank
test_sharing(void)932ea7afb6SJanosch Frank static void test_sharing(void)
942ea7afb6SJanosch Frank {
952ea7afb6SJanosch Frank struct uv_cb_share uvcb = {
962ea7afb6SJanosch Frank .header.cmd = UVC_CMD_SET_SHARED_ACCESS,
972ea7afb6SJanosch Frank .header.len = sizeof(uvcb) - 8,
982ea7afb6SJanosch Frank .paddr = page,
992ea7afb6SJanosch Frank };
1002ea7afb6SJanosch Frank int cc;
1012ea7afb6SJanosch Frank
1022ea7afb6SJanosch Frank report_prefix_push("share");
1032ea7afb6SJanosch Frank cc = uv_call(0, (u64)&uvcb);
1042ea7afb6SJanosch Frank report(cc == 1 && uvcb.header.rc == UVC_RC_INV_LEN, "length");
1052ea7afb6SJanosch Frank uvcb.header.len = sizeof(uvcb);
1062ea7afb6SJanosch Frank cc = uv_call(0, (u64)&uvcb);
1072ea7afb6SJanosch Frank report(cc == 0 && uvcb.header.rc == UVC_RC_EXECUTED, "share");
108e161cc86SJanosch Frank uvcb.paddr = get_ram_size() + PAGE_SIZE;
109e161cc86SJanosch Frank cc = uv_call(0, (u64)&uvcb);
110e161cc86SJanosch Frank report(cc == 1 && uvcb.header.rc == 0x101, "invalid memory");
111e161cc86SJanosch Frank uvcb.paddr = page;
1122ea7afb6SJanosch Frank report_prefix_pop();
1132ea7afb6SJanosch Frank
1142ea7afb6SJanosch Frank report_prefix_push("unshare");
1152ea7afb6SJanosch Frank uvcb.header.cmd = UVC_CMD_REMOVE_SHARED_ACCESS;
1162ea7afb6SJanosch Frank uvcb.header.len -= 8;
1172ea7afb6SJanosch Frank cc = uv_call(0, (u64)&uvcb);
1182ea7afb6SJanosch Frank report(cc == 1 && uvcb.header.rc == UVC_RC_INV_LEN, "length");
1192ea7afb6SJanosch Frank uvcb.header.len = sizeof(uvcb);
1202ea7afb6SJanosch Frank cc = uv_call(0, (u64)&uvcb);
1212ea7afb6SJanosch Frank report(cc == 0 && uvcb.header.rc == UVC_RC_EXECUTED, "unshare");
1222ea7afb6SJanosch Frank report_prefix_pop();
1232ea7afb6SJanosch Frank }
1242ea7afb6SJanosch Frank
1253c645a43SJanosch Frank static struct {
1263c645a43SJanosch Frank const char *name;
1273c645a43SJanosch Frank uint16_t cmd;
1283c645a43SJanosch Frank uint16_t len;
1293c645a43SJanosch Frank int call_bit;
1303c645a43SJanosch Frank } invalid_cmds[] = {
1313c645a43SJanosch Frank { "bogus", 0x4242, sizeof(struct uv_cb_header), -1 },
1323c645a43SJanosch Frank { "init", UVC_CMD_INIT_UV, sizeof(struct uv_cb_init), BIT_UVC_CMD_INIT_UV },
1333c645a43SJanosch Frank { "create conf", UVC_CMD_CREATE_SEC_CONF, sizeof(struct uv_cb_cgc), BIT_UVC_CMD_CREATE_SEC_CONF },
1343c645a43SJanosch Frank { "destroy conf", UVC_CMD_DESTROY_SEC_CONF, sizeof(struct uv_cb_nodata), BIT_UVC_CMD_DESTROY_SEC_CONF },
1353c645a43SJanosch Frank { "create cpu", UVC_CMD_CREATE_SEC_CPU, sizeof(struct uv_cb_csc), BIT_UVC_CMD_CREATE_SEC_CPU },
1363c645a43SJanosch Frank { "destroy cpu", UVC_CMD_DESTROY_SEC_CPU, sizeof(struct uv_cb_nodata), BIT_UVC_CMD_DESTROY_SEC_CPU },
1373c645a43SJanosch Frank { "conv to", UVC_CMD_CONV_TO_SEC_STOR, sizeof(struct uv_cb_cts), BIT_UVC_CMD_CONV_TO_SEC_STOR },
1383c645a43SJanosch Frank { "conv from", UVC_CMD_CONV_FROM_SEC_STOR, sizeof(struct uv_cb_cfs), BIT_UVC_CMD_CONV_FROM_SEC_STOR },
1393c645a43SJanosch Frank { "set sec conf", UVC_CMD_SET_SEC_CONF_PARAMS, sizeof(struct uv_cb_ssc), BIT_UVC_CMD_SET_SEC_PARMS },
1403c645a43SJanosch Frank { "unpack", UVC_CMD_UNPACK_IMG, sizeof(struct uv_cb_unp), BIT_UVC_CMD_UNPACK_IMG },
1413c645a43SJanosch Frank { "verify", UVC_CMD_VERIFY_IMG, sizeof(struct uv_cb_nodata), BIT_UVC_CMD_VERIFY_IMG },
1423c645a43SJanosch Frank { "cpu reset", UVC_CMD_CPU_RESET, sizeof(struct uv_cb_nodata), BIT_UVC_CMD_CPU_RESET },
1433c645a43SJanosch Frank { "cpu initial reset", UVC_CMD_CPU_RESET_INITIAL, sizeof(struct uv_cb_nodata), BIT_UVC_CMD_CPU_RESET_INITIAL },
1445630c446SJanosch Frank { "prepare clear reset", UVC_CMD_PREPARE_RESET, sizeof(struct uv_cb_nodata), BIT_UVC_CMD_PREPARE_RESET },
1453c645a43SJanosch Frank { "cpu clear reset", UVC_CMD_CPU_RESET_CLEAR, sizeof(struct uv_cb_nodata), BIT_UVC_CMD_CPU_PERFORM_CLEAR_RESET },
1463c645a43SJanosch Frank { "cpu set state", UVC_CMD_CPU_SET_STATE, sizeof(struct uv_cb_cpu_set_state), BIT_UVC_CMD_CPU_SET_STATE },
1473c645a43SJanosch Frank { "pin shared", UVC_CMD_PIN_PAGE_SHARED, sizeof(struct uv_cb_cfs), BIT_UVC_CMD_PIN_PAGE_SHARED },
1483c645a43SJanosch Frank { "unpin shared", UVC_CMD_UNPIN_PAGE_SHARED, sizeof(struct uv_cb_cts), BIT_UVC_CMD_UNPIN_PAGE_SHARED },
1493c645a43SJanosch Frank { NULL, 0, 0 },
1503c645a43SJanosch Frank };
1513c645a43SJanosch Frank
test_invalid(void)1522ea7afb6SJanosch Frank static void test_invalid(void)
1532ea7afb6SJanosch Frank {
1543c645a43SJanosch Frank struct uv_cb_header *hdr = (void *)page;
1553c645a43SJanosch Frank int cc, i;
1562ea7afb6SJanosch Frank
1573c645a43SJanosch Frank report_prefix_push("invalid");
1583c645a43SJanosch Frank for (i = 0; invalid_cmds[i].name; i++) {
1593c645a43SJanosch Frank hdr->cmd = invalid_cmds[i].cmd;
1603c645a43SJanosch Frank hdr->len = invalid_cmds[i].len;
1613c645a43SJanosch Frank cc = uv_call(0, (u64)hdr);
1623c645a43SJanosch Frank report(cc == 1 && hdr->rc == UVC_RC_INV_CMD &&
1633c645a43SJanosch Frank (invalid_cmds[i].call_bit == -1 || !uv_query_test_call(invalid_cmds[i].call_bit)),
1643c645a43SJanosch Frank "%s", invalid_cmds[i].name);
1653c645a43SJanosch Frank }
1663c645a43SJanosch Frank report_prefix_pop();
1672ea7afb6SJanosch Frank }
1682ea7afb6SJanosch Frank
test_share_bits(void)169392d1b67SSteffen Eiden static void test_share_bits(void)
170392d1b67SSteffen Eiden {
171392d1b67SSteffen Eiden bool unshare = uv_query_test_call(BIT_UVC_CMD_REMOVE_SHARED_ACCESS);
172392d1b67SSteffen Eiden bool share = uv_query_test_call(BIT_UVC_CMD_SET_SHARED_ACCESS);
173392d1b67SSteffen Eiden
174392d1b67SSteffen Eiden report_prefix_push("query");
175392d1b67SSteffen Eiden report(!(share ^ unshare), "share bits are identical");
176392d1b67SSteffen Eiden report_prefix_pop();
177392d1b67SSteffen Eiden }
178392d1b67SSteffen Eiden
main(void)1792ea7afb6SJanosch Frank int main(void)
1802ea7afb6SJanosch Frank {
1812ea7afb6SJanosch Frank bool has_uvc = test_facility(158);
1822ea7afb6SJanosch Frank
1832ea7afb6SJanosch Frank report_prefix_push("uvc");
1842ea7afb6SJanosch Frank if (!has_uvc) {
1852ea7afb6SJanosch Frank report_skip("Ultravisor call facility is not available");
1862ea7afb6SJanosch Frank goto done;
1872ea7afb6SJanosch Frank }
1882ea7afb6SJanosch Frank
189392d1b67SSteffen Eiden /*
190392d1b67SSteffen Eiden * Needs to be done before the guest-fence,
191392d1b67SSteffen Eiden * as the fence tests if both shared bits are present
192392d1b67SSteffen Eiden */
193392d1b67SSteffen Eiden test_share_bits();
194392d1b67SSteffen Eiden
195533bbdb3SJanosch Frank if (!uv_os_is_guest()) {
196533bbdb3SJanosch Frank report_skip("Not a protected guest");
197533bbdb3SJanosch Frank goto done;
198533bbdb3SJanosch Frank }
199533bbdb3SJanosch Frank
2002ea7afb6SJanosch Frank page = (unsigned long)alloc_page();
2012ea7afb6SJanosch Frank test_priv();
2022ea7afb6SJanosch Frank test_invalid();
2032ea7afb6SJanosch Frank test_query();
2042ea7afb6SJanosch Frank test_sharing();
2052ea7afb6SJanosch Frank free_page((void *)page);
2062ea7afb6SJanosch Frank done:
2072ea7afb6SJanosch Frank report_prefix_pop();
2082ea7afb6SJanosch Frank return report_summary();
2092ea7afb6SJanosch Frank }
210