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