1 /* SPDX-License-Identifier: GPL-2.0-only */ 2 /* 3 * Guest Ultravisor Call tests 4 * 5 * Copyright IBM Corp. 2020, 2022 6 * 7 * Authors: 8 * Janosch Frank <frankja@linux.ibm.com> 9 */ 10 11 #include <libcflat.h> 12 #include <alloc_page.h> 13 #include <asm/page.h> 14 #include <asm/asm-offsets.h> 15 #include <asm/interrupt.h> 16 #include <asm/facility.h> 17 #include <asm/uv.h> 18 #include <sclp.h> 19 #include <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_once(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_once(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_once(0, (u64)&uvcb); 53 check_pgm_int_code(PGM_INT_CODE_PRIVILEGED_OPERATION); 54 report_prefix_pop(); 55 56 report_prefix_push("attest"); 57 uvcb.cmd = UVC_CMD_ATTESTATION; 58 uvcb.len = sizeof(struct uv_cb_attest); 59 expect_pgm_int(); 60 enter_pstate(); 61 uv_call_once(0, (uint64_t)&uvcb); 62 check_pgm_int_code(PGM_INT_CODE_PRIVILEGED_OPERATION); 63 report_prefix_pop(); 64 65 report_prefix_pop(); 66 } 67 68 static void test_query(void) 69 { 70 struct uv_cb_qui uvcb = { 71 .header.cmd = UVC_CMD_QUI, 72 /* A dword below the minimum length */ 73 .header.len = 0xa0, 74 }; 75 int cc; 76 77 report_prefix_push("query"); 78 cc = uv_call(0, (u64)&uvcb); 79 report(cc == 1 && uvcb.header.rc == UVC_RC_INV_LEN, "length"); 80 81 /* 82 * BIT_UVC_CMD_QUI, BIT_UVC_CMD_SET_SHARED_ACCESS and 83 * BIT_UVC_CMD_REMOVE_SHARED_ACCESS are always present as they 84 * have been introduced with the first Ultravisor version. 85 * However, we only need to check for QUI as 86 * SET/REMOVE SHARED are used to fence this test to be only 87 * executed by protected guests. 88 */ 89 report(uv_query_test_call(BIT_UVC_CMD_QUI), "query indicated"); 90 report_prefix_pop(); 91 } 92 93 static void test_sharing(void) 94 { 95 struct uv_cb_share uvcb = { 96 .header.cmd = UVC_CMD_SET_SHARED_ACCESS, 97 .header.len = sizeof(uvcb) - 8, 98 .paddr = page, 99 }; 100 int cc; 101 102 report_prefix_push("share"); 103 cc = uv_call(0, (u64)&uvcb); 104 report(cc == 1 && uvcb.header.rc == UVC_RC_INV_LEN, "length"); 105 uvcb.header.len = sizeof(uvcb); 106 cc = uv_call(0, (u64)&uvcb); 107 report(cc == 0 && uvcb.header.rc == UVC_RC_EXECUTED, "share"); 108 uvcb.paddr = get_ram_size() + PAGE_SIZE; 109 cc = uv_call(0, (u64)&uvcb); 110 report(cc == 1 && uvcb.header.rc == 0x101, "invalid memory"); 111 uvcb.paddr = page; 112 report_prefix_pop(); 113 114 report_prefix_push("unshare"); 115 uvcb.header.cmd = UVC_CMD_REMOVE_SHARED_ACCESS; 116 uvcb.header.len -= 8; 117 cc = uv_call(0, (u64)&uvcb); 118 report(cc == 1 && uvcb.header.rc == UVC_RC_INV_LEN, "length"); 119 uvcb.header.len = sizeof(uvcb); 120 cc = uv_call(0, (u64)&uvcb); 121 report(cc == 0 && uvcb.header.rc == UVC_RC_EXECUTED, "unshare"); 122 report_prefix_pop(); 123 } 124 125 static struct { 126 const char *name; 127 uint16_t cmd; 128 uint16_t len; 129 int call_bit; 130 } invalid_cmds[] = { 131 { "bogus", 0x4242, sizeof(struct uv_cb_header), -1 }, 132 { "init", UVC_CMD_INIT_UV, sizeof(struct uv_cb_init), BIT_UVC_CMD_INIT_UV }, 133 { "create conf", UVC_CMD_CREATE_SEC_CONF, sizeof(struct uv_cb_cgc), BIT_UVC_CMD_CREATE_SEC_CONF }, 134 { "destroy conf", UVC_CMD_DESTROY_SEC_CONF, sizeof(struct uv_cb_nodata), BIT_UVC_CMD_DESTROY_SEC_CONF }, 135 { "create cpu", UVC_CMD_CREATE_SEC_CPU, sizeof(struct uv_cb_csc), BIT_UVC_CMD_CREATE_SEC_CPU }, 136 { "destroy cpu", UVC_CMD_DESTROY_SEC_CPU, sizeof(struct uv_cb_nodata), BIT_UVC_CMD_DESTROY_SEC_CPU }, 137 { "conv to", UVC_CMD_CONV_TO_SEC_STOR, sizeof(struct uv_cb_cts), BIT_UVC_CMD_CONV_TO_SEC_STOR }, 138 { "conv from", UVC_CMD_CONV_FROM_SEC_STOR, sizeof(struct uv_cb_cfs), BIT_UVC_CMD_CONV_FROM_SEC_STOR }, 139 { "set sec conf", UVC_CMD_SET_SEC_CONF_PARAMS, sizeof(struct uv_cb_ssc), BIT_UVC_CMD_SET_SEC_PARMS }, 140 { "unpack", UVC_CMD_UNPACK_IMG, sizeof(struct uv_cb_unp), BIT_UVC_CMD_UNPACK_IMG }, 141 { "verify", UVC_CMD_VERIFY_IMG, sizeof(struct uv_cb_nodata), BIT_UVC_CMD_VERIFY_IMG }, 142 { "cpu reset", UVC_CMD_CPU_RESET, sizeof(struct uv_cb_nodata), BIT_UVC_CMD_CPU_RESET }, 143 { "cpu initial reset", UVC_CMD_CPU_RESET_INITIAL, sizeof(struct uv_cb_nodata), BIT_UVC_CMD_CPU_RESET_INITIAL }, 144 { "prepare clear reset", UVC_CMD_PREPARE_RESET, sizeof(struct uv_cb_nodata), BIT_UVC_CMD_PREPARE_RESET }, 145 { "cpu clear reset", UVC_CMD_CPU_RESET_CLEAR, sizeof(struct uv_cb_nodata), BIT_UVC_CMD_CPU_PERFORM_CLEAR_RESET }, 146 { "cpu set state", UVC_CMD_CPU_SET_STATE, sizeof(struct uv_cb_cpu_set_state), BIT_UVC_CMD_CPU_SET_STATE }, 147 { "pin shared", UVC_CMD_PIN_PAGE_SHARED, sizeof(struct uv_cb_cfs), BIT_UVC_CMD_PIN_PAGE_SHARED }, 148 { "unpin shared", UVC_CMD_UNPIN_PAGE_SHARED, sizeof(struct uv_cb_cts), BIT_UVC_CMD_UNPIN_PAGE_SHARED }, 149 { NULL, 0, 0 }, 150 }; 151 152 static void test_invalid(void) 153 { 154 struct uv_cb_header *hdr = (void *)page; 155 int cc, i; 156 157 report_prefix_push("invalid"); 158 for (i = 0; invalid_cmds[i].name; i++) { 159 hdr->cmd = invalid_cmds[i].cmd; 160 hdr->len = invalid_cmds[i].len; 161 cc = uv_call(0, (u64)hdr); 162 report(cc == 1 && hdr->rc == UVC_RC_INV_CMD && 163 (invalid_cmds[i].call_bit == -1 || !uv_query_test_call(invalid_cmds[i].call_bit)), 164 "%s", invalid_cmds[i].name); 165 } 166 report_prefix_pop(); 167 } 168 169 static void test_share_bits(void) 170 { 171 bool unshare = uv_query_test_call(BIT_UVC_CMD_REMOVE_SHARED_ACCESS); 172 bool share = uv_query_test_call(BIT_UVC_CMD_SET_SHARED_ACCESS); 173 174 report_prefix_push("query"); 175 report(!(share ^ unshare), "share bits are identical"); 176 report_prefix_pop(); 177 } 178 179 int main(void) 180 { 181 bool has_uvc = test_facility(158); 182 183 report_prefix_push("uvc"); 184 if (!has_uvc) { 185 report_skip("Ultravisor call facility is not available"); 186 goto done; 187 } 188 189 /* 190 * Needs to be done before the guest-fence, 191 * as the fence tests if both shared bits are present 192 */ 193 test_share_bits(); 194 195 if (!uv_os_is_guest()) { 196 report_skip("Not a protected guest"); 197 goto done; 198 } 199 200 page = (unsigned long)alloc_page(); 201 test_priv(); 202 test_invalid(); 203 test_query(); 204 test_sharing(); 205 free_page((void *)page); 206 done: 207 report_prefix_pop(); 208 return report_summary(); 209 } 210