1 /* 2 * Guest Ultravisor Call tests 3 * 4 * Copyright (c) 2020 IBM Corp 5 * 6 * Authors: 7 * Janosch Frank <frankja@linux.ibm.com> 8 * 9 * This code is free software; you can redistribute it and/or modify it 10 * under the terms of the GNU General Public License version 2. 11 */ 12 13 #include <libcflat.h> 14 #include <alloc_page.h> 15 #include <asm/page.h> 16 #include <asm/asm-offsets.h> 17 #include <asm/interrupt.h> 18 #include <asm/facility.h> 19 #include <asm/uv.h> 20 21 static unsigned long page; 22 23 static void test_priv(void) 24 { 25 struct uv_cb_header uvcb = {}; 26 27 report_prefix_push("privileged"); 28 29 report_prefix_push("query"); 30 uvcb.cmd = UVC_CMD_QUI; 31 uvcb.len = sizeof(struct uv_cb_qui); 32 expect_pgm_int(); 33 enter_pstate(); 34 uv_call(0, (u64)&uvcb); 35 check_pgm_int_code(PGM_INT_CODE_PRIVILEGED_OPERATION); 36 report_prefix_pop(); 37 38 report_prefix_push("share"); 39 uvcb.cmd = UVC_CMD_SET_SHARED_ACCESS; 40 uvcb.len = sizeof(struct uv_cb_share); 41 expect_pgm_int(); 42 enter_pstate(); 43 uv_call(0, (u64)&uvcb); 44 check_pgm_int_code(PGM_INT_CODE_PRIVILEGED_OPERATION); 45 report_prefix_pop(); 46 47 report_prefix_push("unshare"); 48 uvcb.cmd = UVC_CMD_REMOVE_SHARED_ACCESS; 49 uvcb.len = sizeof(struct uv_cb_share); 50 expect_pgm_int(); 51 enter_pstate(); 52 uv_call(0, (u64)&uvcb); 53 check_pgm_int_code(PGM_INT_CODE_PRIVILEGED_OPERATION); 54 report_prefix_pop(); 55 56 report_prefix_pop(); 57 } 58 59 static void test_query(void) 60 { 61 struct uv_cb_qui uvcb = { 62 .header.cmd = UVC_CMD_QUI, 63 .header.len = sizeof(uvcb) - 8, 64 }; 65 int cc; 66 67 report_prefix_push("query"); 68 cc = uv_call(0, (u64)&uvcb); 69 report(cc == 1 && uvcb.header.rc == UVC_RC_INV_LEN, "length"); 70 71 uvcb.header.len = sizeof(uvcb); 72 cc = uv_call(0, (u64)&uvcb); 73 report(cc == 0 && uvcb.header.rc == UVC_RC_EXECUTED, "successful query"); 74 75 /* 76 * These bits have been introduced with the very first 77 * Ultravisor version and are expected to always be available 78 * because they are basic building blocks. 79 */ 80 report(uvcb.inst_calls_list[0] & (1UL << (63 - BIT_UVC_CMD_QUI)), 81 "query indicated"); 82 report(uvcb.inst_calls_list[0] & (1UL << (63 - BIT_UVC_CMD_SET_SHARED_ACCESS)), 83 "share indicated"); 84 report(uvcb.inst_calls_list[0] & (1UL << (63 - BIT_UVC_CMD_REMOVE_SHARED_ACCESS)), 85 "unshare indicated"); 86 report_prefix_pop(); 87 } 88 89 static void test_sharing(void) 90 { 91 struct uv_cb_share uvcb = { 92 .header.cmd = UVC_CMD_SET_SHARED_ACCESS, 93 .header.len = sizeof(uvcb) - 8, 94 .paddr = page, 95 }; 96 int cc; 97 98 report_prefix_push("share"); 99 cc = uv_call(0, (u64)&uvcb); 100 report(cc == 1 && uvcb.header.rc == UVC_RC_INV_LEN, "length"); 101 uvcb.header.len = sizeof(uvcb); 102 cc = uv_call(0, (u64)&uvcb); 103 report(cc == 0 && uvcb.header.rc == UVC_RC_EXECUTED, "share"); 104 report_prefix_pop(); 105 106 report_prefix_push("unshare"); 107 uvcb.header.cmd = UVC_CMD_REMOVE_SHARED_ACCESS; 108 uvcb.header.len -= 8; 109 cc = uv_call(0, (u64)&uvcb); 110 report(cc == 1 && uvcb.header.rc == UVC_RC_INV_LEN, "length"); 111 uvcb.header.len = sizeof(uvcb); 112 cc = uv_call(0, (u64)&uvcb); 113 report(cc == 0 && uvcb.header.rc == UVC_RC_EXECUTED, "unshare"); 114 report_prefix_pop(); 115 116 report_prefix_pop(); 117 } 118 119 static void test_invalid(void) 120 { 121 struct uv_cb_header uvcb = { 122 .len = 16, 123 .cmd = 0x4242, 124 }; 125 int cc; 126 127 cc = uv_call(0, (u64)&uvcb); 128 report(cc == 1 && uvcb.rc == UVC_RC_INV_CMD, "invalid command"); 129 } 130 131 int main(void) 132 { 133 bool has_uvc = test_facility(158); 134 135 report_prefix_push("uvc"); 136 if (!has_uvc) { 137 report_skip("Ultravisor call facility is not available"); 138 goto done; 139 } 140 141 page = (unsigned long)alloc_page(); 142 test_priv(); 143 test_invalid(); 144 test_query(); 145 test_sharing(); 146 free_page((void *)page); 147 done: 148 report_prefix_pop(); 149 return report_summary(); 150 } 151