/* SPDX-License-Identifier: GPL-2.0-only */ /* * Guest Ultravisor Call tests * * Copyright (c) 2020 IBM Corp * * Authors: * Janosch Frank */ #include #include #include #include #include #include #include static unsigned long page; static void test_priv(void) { struct uv_cb_header uvcb = {}; report_prefix_push("privileged"); report_prefix_push("query"); uvcb.cmd = UVC_CMD_QUI; uvcb.len = sizeof(struct uv_cb_qui); expect_pgm_int(); enter_pstate(); uv_call_once(0, (u64)&uvcb); check_pgm_int_code(PGM_INT_CODE_PRIVILEGED_OPERATION); report_prefix_pop(); report_prefix_push("share"); uvcb.cmd = UVC_CMD_SET_SHARED_ACCESS; uvcb.len = sizeof(struct uv_cb_share); expect_pgm_int(); enter_pstate(); uv_call_once(0, (u64)&uvcb); check_pgm_int_code(PGM_INT_CODE_PRIVILEGED_OPERATION); report_prefix_pop(); report_prefix_push("unshare"); uvcb.cmd = UVC_CMD_REMOVE_SHARED_ACCESS; uvcb.len = sizeof(struct uv_cb_share); expect_pgm_int(); enter_pstate(); uv_call_once(0, (u64)&uvcb); check_pgm_int_code(PGM_INT_CODE_PRIVILEGED_OPERATION); report_prefix_pop(); report_prefix_pop(); } static void test_query(void) { struct uv_cb_qui uvcb = { .header.cmd = UVC_CMD_QUI, .header.len = sizeof(uvcb) - 8, }; int cc; report_prefix_push("query"); cc = uv_call(0, (u64)&uvcb); report(cc == 1 && uvcb.header.rc == UVC_RC_INV_LEN, "length"); uvcb.header.len = sizeof(uvcb); cc = uv_call(0, (u64)&uvcb); report(cc == 0 && uvcb.header.rc == UVC_RC_EXECUTED, "successful query"); /* * These bits have been introduced with the very first * Ultravisor version and are expected to always be available * because they are basic building blocks. */ report(test_bit_inv(BIT_UVC_CMD_QUI, &uvcb.inst_calls_list[0]), "query indicated"); report(test_bit_inv(BIT_UVC_CMD_SET_SHARED_ACCESS, &uvcb.inst_calls_list[0]), "share indicated"); report(test_bit_inv(BIT_UVC_CMD_REMOVE_SHARED_ACCESS, &uvcb.inst_calls_list[0]), "unshare indicated"); report_prefix_pop(); } static void test_sharing(void) { struct uv_cb_share uvcb = { .header.cmd = UVC_CMD_SET_SHARED_ACCESS, .header.len = sizeof(uvcb) - 8, .paddr = page, }; int cc; report_prefix_push("share"); cc = uv_call(0, (u64)&uvcb); report(cc == 1 && uvcb.header.rc == UVC_RC_INV_LEN, "length"); uvcb.header.len = sizeof(uvcb); cc = uv_call(0, (u64)&uvcb); report(cc == 0 && uvcb.header.rc == UVC_RC_EXECUTED, "share"); report_prefix_pop(); report_prefix_push("unshare"); uvcb.header.cmd = UVC_CMD_REMOVE_SHARED_ACCESS; uvcb.header.len -= 8; cc = uv_call(0, (u64)&uvcb); report(cc == 1 && uvcb.header.rc == UVC_RC_INV_LEN, "length"); uvcb.header.len = sizeof(uvcb); cc = uv_call(0, (u64)&uvcb); report(cc == 0 && uvcb.header.rc == UVC_RC_EXECUTED, "unshare"); report_prefix_pop(); report_prefix_pop(); } static void test_invalid(void) { struct uv_cb_header uvcb = { .len = 16, .cmd = 0x4242, }; int cc; cc = uv_call(0, (u64)&uvcb); report(cc == 1 && uvcb.rc == UVC_RC_INV_CMD, "invalid command"); } int main(void) { bool has_uvc = test_facility(158); report_prefix_push("uvc"); if (!has_uvc) { report_skip("Ultravisor call facility is not available"); goto done; } page = (unsigned long)alloc_page(); test_priv(); test_invalid(); test_query(); test_sharing(); free_page((void *)page); done: report_prefix_pop(); return report_summary(); }