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