1 /* SPDX-License-Identifier: GPL-2.0-only */ 2 /* 3 * Guest Ultravisor Call tests 4 * 5 * Copyright (c) 2021 IBM Corp 6 * 7 * Authors: 8 * Janosch Frank <frankja@linux.ibm.com> 9 */ 10 11 #include <libcflat.h> 12 #include <alloc.h> 13 #include <vmalloc.h> 14 #include <sclp.h> 15 #include <smp.h> 16 #include <uv.h> 17 #include <asm/page.h> 18 #include <asm/sigp.h> 19 #include <asm/pgtable.h> 20 #include <asm/asm-offsets.h> 21 #include <asm/interrupt.h> 22 #include <asm/facility.h> 23 #include <asm/uv.h> 24 #include <asm-generic/barrier.h> 25 26 static struct uv_cb_qui uvcb_qui; 27 static struct uv_cb_init uvcb_init; 28 static struct uv_cb_cgc uvcb_cgc; 29 static struct uv_cb_csc uvcb_csc; 30 31 extern int diag308_load_reset(u64 code); 32 33 struct cmd_list{ 34 const char *name; 35 uint16_t cmd; 36 uint16_t len; 37 int call_bit; 38 }; 39 40 static void cpu_loop(void) 41 { 42 for (;;) {} 43 } 44 45 static struct cmd_list cmds[] = { 46 { "init", UVC_CMD_INIT_UV, sizeof(struct uv_cb_init), BIT_UVC_CMD_INIT_UV }, 47 { "create conf", UVC_CMD_CREATE_SEC_CONF, sizeof(struct uv_cb_cgc), BIT_UVC_CMD_CREATE_SEC_CONF }, 48 { "destroy conf", UVC_CMD_DESTROY_SEC_CONF, sizeof(struct uv_cb_nodata), BIT_UVC_CMD_DESTROY_SEC_CONF }, 49 { "create cpu", UVC_CMD_CREATE_SEC_CPU, sizeof(struct uv_cb_csc), BIT_UVC_CMD_CREATE_SEC_CPU }, 50 { "destroy cpu", UVC_CMD_DESTROY_SEC_CPU, sizeof(struct uv_cb_nodata), BIT_UVC_CMD_DESTROY_SEC_CPU }, 51 { "conv to", UVC_CMD_CONV_TO_SEC_STOR, sizeof(struct uv_cb_cts), BIT_UVC_CMD_CONV_TO_SEC_STOR }, 52 { "conv from", UVC_CMD_CONV_FROM_SEC_STOR, sizeof(struct uv_cb_cfs), BIT_UVC_CMD_CONV_FROM_SEC_STOR }, 53 { "set sec conf", UVC_CMD_SET_SEC_CONF_PARAMS, sizeof(struct uv_cb_ssc), BIT_UVC_CMD_SET_SEC_PARMS }, 54 { "unpack", UVC_CMD_UNPACK_IMG, sizeof(struct uv_cb_unp), BIT_UVC_CMD_UNPACK_IMG }, 55 { "verify", UVC_CMD_VERIFY_IMG, sizeof(struct uv_cb_nodata), BIT_UVC_CMD_VERIFY_IMG }, 56 { "cpu reset", UVC_CMD_CPU_RESET, sizeof(struct uv_cb_nodata), BIT_UVC_CMD_CPU_RESET }, 57 { "cpu initial reset", UVC_CMD_CPU_RESET_INITIAL, sizeof(struct uv_cb_nodata), BIT_UVC_CMD_CPU_RESET_INITIAL }, 58 { "conf clear reset", UVC_CMD_PERF_CONF_CLEAR_RESET, sizeof(struct uv_cb_nodata), BIT_UVC_CMD_PREPARE_CLEAR_RESET }, 59 { "cpu clear reset", UVC_CMD_CPU_RESET_CLEAR, sizeof(struct uv_cb_nodata), BIT_UVC_CMD_CPU_PERFORM_CLEAR_RESET }, 60 { "cpu set state", UVC_CMD_CPU_SET_STATE, sizeof(struct uv_cb_cpu_set_state), BIT_UVC_CMD_CPU_SET_STATE }, 61 { "pin shared", UVC_CMD_PIN_PAGE_SHARED, sizeof(struct uv_cb_cfs), BIT_UVC_CMD_PIN_PAGE_SHARED }, 62 { "unpin shared", UVC_CMD_UNPIN_PAGE_SHARED, sizeof(struct uv_cb_cts), BIT_UVC_CMD_UNPIN_PAGE_SHARED }, 63 { NULL, 0, 0 }, 64 }; 65 66 static void test_priv(void) 67 { 68 struct uv_cb_header uvcb = {}; 69 uint16_t pgm; 70 int i; 71 72 report_prefix_push("privileged"); 73 for (i = 0; cmds[i].name; i++) { 74 expect_pgm_int(); 75 uvcb.cmd = cmds[i].cmd; 76 uvcb.len = cmds[i].len; 77 enter_pstate(); 78 uv_call(0, (uint64_t)&uvcb); 79 pgm = clear_pgm_int(); 80 report(pgm == PGM_INT_CODE_PRIVILEGED_OPERATION, "%s", cmds[i].name); 81 } 82 report_prefix_pop(); 83 } 84 85 static void test_config_destroy(void) 86 { 87 int rc; 88 struct uv_cb_nodata uvcb = { 89 .header.cmd = UVC_CMD_DESTROY_SEC_CONF, 90 .header.len = sizeof(uvcb), 91 .handle = uvcb_cgc.guest_handle, 92 }; 93 94 report_prefix_push("dsc"); 95 uvcb.header.len -= 8; 96 rc = uv_call(0, (uint64_t)&uvcb); 97 report(rc == 1 && uvcb.header.rc == UVC_RC_INV_LEN, 98 "hdr invalid length"); 99 uvcb.header.len += 8; 100 101 uvcb.handle += 1; 102 rc = uv_call(0, (uint64_t)&uvcb); 103 report(rc == 1 && uvcb.header.rc == UVC_RC_INV_GHANDLE, "invalid handle"); 104 uvcb.handle -= 1; 105 106 rc = uv_call(0, (uint64_t)&uvcb); 107 report(rc == 0 && uvcb.header.rc == UVC_RC_EXECUTED, "success"); 108 report_prefix_pop(); 109 } 110 111 static void test_cpu_destroy(void) 112 { 113 int rc; 114 struct uv_cb_nodata uvcb = { 115 .header.len = sizeof(uvcb), 116 .header.cmd = UVC_CMD_DESTROY_SEC_CPU, 117 .handle = uvcb_csc.cpu_handle, 118 }; 119 120 report_prefix_push("dcpu"); 121 122 uvcb.header.len -= 8; 123 rc = uv_call(0, (uint64_t)&uvcb); 124 report(rc == 1 && uvcb.header.rc == UVC_RC_INV_LEN, 125 "hdr invalid length"); 126 uvcb.header.len += 8; 127 128 uvcb.handle += 1; 129 rc = uv_call(0, (uint64_t)&uvcb); 130 report(rc == 1 && uvcb.header.rc == UVC_RC_INV_CHANDLE, "invalid handle"); 131 uvcb.handle -= 1; 132 133 rc = uv_call(0, (uint64_t)&uvcb); 134 report(rc == 0 && uvcb.header.rc == UVC_RC_EXECUTED, "success"); 135 136 report_prefix_pop(); 137 } 138 139 static void test_cpu_create(void) 140 { 141 int rc; 142 unsigned long tmp; 143 144 report_prefix_push("csc"); 145 uvcb_csc.header.len = sizeof(uvcb_csc); 146 uvcb_csc.header.cmd = UVC_CMD_CREATE_SEC_CPU; 147 uvcb_csc.guest_handle = uvcb_cgc.guest_handle; 148 uvcb_csc.stor_origin = (unsigned long)memalign(PAGE_SIZE, uvcb_qui.cpu_stor_len); 149 uvcb_csc.state_origin = (unsigned long)memalign(PAGE_SIZE, PAGE_SIZE); 150 151 uvcb_csc.header.len -= 8; 152 rc = uv_call(0, (uint64_t)&uvcb_csc); 153 report(uvcb_csc.header.rc == UVC_RC_INV_LEN && rc == 1 && 154 !uvcb_csc.cpu_handle, "hdr invalid length"); 155 uvcb_csc.header.len += 8; 156 157 uvcb_csc.guest_handle += 1; 158 rc = uv_call(0, (uint64_t)&uvcb_csc); 159 report(uvcb_csc.header.rc == UVC_RC_INV_GHANDLE && rc == 1, 160 "invalid guest handle"); 161 uvcb_csc.guest_handle -= 1; 162 163 uvcb_csc.num = uvcb_qui.max_guest_cpus + 1; 164 rc = uv_call(0, (uint64_t)&uvcb_csc); 165 report(uvcb_csc.header.rc == 0x103 && rc == 1, 166 "invalid cpu #"); 167 uvcb_csc.num = 0; 168 169 tmp = uvcb_csc.stor_origin; 170 uvcb_csc.stor_origin = get_max_ram_size() + PAGE_SIZE; 171 rc = uv_call(0, (uint64_t)&uvcb_csc); 172 report(uvcb_csc.header.rc == 0x105 && rc == 1, 173 "cpu stor inaccessible"); 174 uvcb_csc.stor_origin = tmp; 175 176 tmp = uvcb_csc.stor_origin; 177 uvcb_csc.stor_origin = 0; 178 rc = uv_call(0, (uint64_t)&uvcb_csc); 179 report(uvcb_csc.header.rc == 0x106 && rc == 1, 180 "cpu stor in lowcore"); 181 uvcb_csc.stor_origin = tmp; 182 183 tmp = uvcb_csc.state_origin; 184 uvcb_csc.state_origin = get_max_ram_size() + PAGE_SIZE; 185 rc = uv_call(0, (uint64_t)&uvcb_csc); 186 report(uvcb_csc.header.rc == 0x107 && rc == 1, 187 "SIE SD inaccessible"); 188 uvcb_csc.state_origin = tmp; 189 190 rc = uv_call(0, (uint64_t)&uvcb_csc); 191 report(rc == 0 && uvcb_csc.header.rc == UVC_RC_EXECUTED && 192 uvcb_csc.cpu_handle, "success"); 193 194 tmp = uvcb_csc.stor_origin; 195 uvcb_csc.stor_origin = (unsigned long)memalign(PAGE_SIZE, uvcb_qui.cpu_stor_len); 196 rc = uv_call(0, (uint64_t)&uvcb_csc); 197 report(rc == 1 && uvcb_csc.header.rc == 0x104, "already defined"); 198 uvcb_csc.stor_origin = tmp; 199 report_prefix_pop(); 200 } 201 202 static void test_config_create(void) 203 { 204 int rc; 205 unsigned long vsize, tmp; 206 static struct uv_cb_cgc uvcb; 207 208 uvcb_cgc.header.cmd = UVC_CMD_CREATE_SEC_CONF; 209 uvcb_cgc.header.len = sizeof(uvcb_cgc); 210 report_prefix_push("cgc"); 211 212 uvcb_cgc.guest_stor_origin = 0; 213 uvcb_cgc.guest_stor_len = 42 * (1UL << 20); 214 vsize = uvcb_qui.conf_base_virt_stor_len + 215 ((uvcb_cgc.guest_stor_len / (1UL << 20)) * uvcb_qui.conf_virt_var_stor_len); 216 217 uvcb_cgc.conf_base_stor_origin = (uint64_t)memalign(PAGE_SIZE * 4, uvcb_qui.conf_base_phys_stor_len); 218 uvcb_cgc.conf_var_stor_origin = (uint64_t)memalign(PAGE_SIZE, vsize); 219 uvcb_cgc.guest_asce = (uint64_t)memalign(PAGE_SIZE, 4 * PAGE_SIZE) | ASCE_DT_SEGMENT | REGION_TABLE_LENGTH | ASCE_P; 220 uvcb_cgc.guest_sca = (uint64_t)memalign(PAGE_SIZE * 4, PAGE_SIZE * 4); 221 222 uvcb_cgc.header.len -= 8; 223 rc = uv_call(0, (uint64_t)&uvcb_cgc); 224 report(uvcb_cgc.header.rc == UVC_RC_INV_LEN && rc == 1 && 225 !uvcb_cgc.guest_handle, "hdr invalid length"); 226 uvcb_cgc.header.len += 8; 227 228 uvcb_cgc.guest_stor_origin = uvcb_qui.max_guest_stor_addr + (1UL << 20) * 2 + 1; 229 rc = uv_call(0, (uint64_t)&uvcb_cgc); 230 report(uvcb_cgc.header.rc == 0x101 && rc == 1, 231 "MSO > max guest addr"); 232 uvcb_cgc.guest_stor_origin = 0; 233 234 uvcb_cgc.guest_stor_origin = uvcb_qui.max_guest_stor_addr - (1UL << 20); 235 rc = uv_call(0, (uint64_t)&uvcb_cgc); 236 report(uvcb_cgc.header.rc == 0x102 && rc == 1, 237 "MSO + MSL > max guest addr"); 238 uvcb_cgc.guest_stor_origin = 0; 239 240 uvcb_cgc.guest_asce &= ~ASCE_P; 241 rc = uv_call(0, (uint64_t)&uvcb_cgc); 242 report(uvcb_cgc.header.rc == 0x105 && rc == 1, 243 "ASCE private bit missing"); 244 uvcb_cgc.guest_asce |= ASCE_P; 245 246 uvcb_cgc.guest_asce |= 0x20; 247 rc = uv_call(0, (uint64_t)&uvcb_cgc); 248 report(uvcb_cgc.header.rc == 0x105 && rc == 1, 249 "ASCE bit 58 set"); 250 uvcb_cgc.guest_asce &= ~0x20; 251 252 tmp = uvcb_cgc.conf_base_stor_origin; 253 uvcb_cgc.conf_base_stor_origin = get_max_ram_size() + 8; 254 rc = uv_call(0, (uint64_t)&uvcb_cgc); 255 report(uvcb_cgc.header.rc == 0x108 && rc == 1, 256 "base storage origin > available memory"); 257 uvcb_cgc.conf_base_stor_origin = tmp; 258 259 tmp = uvcb_cgc.conf_base_stor_origin; 260 uvcb_cgc.conf_base_stor_origin = 0x1000; 261 rc = uv_call(0, (uint64_t)&uvcb_cgc); 262 report(uvcb_cgc.header.rc == 0x109 && rc == 1, 263 "base storage origin contains lowcore"); 264 uvcb_cgc.conf_base_stor_origin = tmp; 265 266 if (smp_query_num_cpus() == 1) { 267 sigp_retry(1, SIGP_SET_PREFIX, 268 uvcb_cgc.conf_var_stor_origin + PAGE_SIZE, NULL); 269 rc = uv_call(0, (uint64_t)&uvcb_cgc); 270 report(uvcb_cgc.header.rc == 0x10e && rc == 1 && 271 !uvcb_cgc.guest_handle, "variable storage area contains lowcore"); 272 sigp_retry(1, SIGP_SET_PREFIX, 0x0, NULL); 273 } 274 275 tmp = uvcb_cgc.guest_sca; 276 uvcb_cgc.guest_sca = 0; 277 rc = uv_call(0, (uint64_t)&uvcb_cgc); 278 report(uvcb_cgc.header.rc == 0x10c && rc == 1, 279 "sca == 0"); 280 uvcb_cgc.guest_sca = tmp; 281 282 tmp = uvcb_cgc.guest_sca; 283 uvcb_cgc.guest_sca = get_max_ram_size() + + PAGE_SIZE * 4; 284 rc = uv_call(0, (uint64_t)&uvcb_cgc); 285 report(uvcb_cgc.header.rc == 0x10d && rc == 1, 286 "sca inaccessible"); 287 uvcb_cgc.guest_sca = tmp; 288 289 rc = uv_call(0, (uint64_t)&uvcb_cgc); 290 report(rc == 0 && uvcb_cgc.header.rc == UVC_RC_EXECUTED, "successful"); 291 292 uvcb_cgc.header.rc = 0; 293 uvcb_cgc.header.rrc = 0; 294 tmp = uvcb_cgc.guest_handle; 295 uvcb_cgc.guest_handle = 0; 296 rc = uv_call(0, (uint64_t)&uvcb_cgc); 297 report(uvcb_cgc.header.rc >= 0x100 && rc == 1, "reuse uvcb"); 298 uvcb_cgc.guest_handle = tmp; 299 300 /* Copy over most data from uvcb_cgc, so we have the ASCE that was used. */ 301 memcpy(&uvcb, &uvcb_cgc, sizeof(uvcb)); 302 303 /* Reset the header and handle */ 304 uvcb.header.rc = 0; 305 uvcb.header.rrc = 0; 306 uvcb.guest_handle = 0; 307 308 /* Use new storage areas. */ 309 uvcb.conf_base_stor_origin = (uint64_t)memalign(PAGE_SIZE * 4, uvcb_qui.conf_base_phys_stor_len); 310 uvcb.conf_var_stor_origin = (uint64_t)memalign(PAGE_SIZE, vsize); 311 312 rc = uv_call(0, (uint64_t)&uvcb); 313 report(uvcb.header.rc >= 0x104 && rc == 1 && !uvcb.guest_handle, 314 "reuse ASCE"); 315 free((void *)uvcb.conf_base_stor_origin); 316 free((void *)uvcb.conf_var_stor_origin); 317 318 /* Missing: 106, 10a, a0b */ 319 report_prefix_pop(); 320 } 321 322 static void test_init(void) 323 { 324 int rc; 325 uint64_t mem; 326 struct psw psw; 327 328 /* Donated storage needs to be over 2GB */ 329 mem = (uint64_t)memalign(1UL << 31, uvcb_qui.uv_base_stor_len); 330 331 uvcb_init.header.len = sizeof(uvcb_init); 332 uvcb_init.header.cmd = UVC_CMD_INIT_UV; 333 uvcb_init.stor_origin = mem; 334 uvcb_init.stor_len = uvcb_qui.uv_base_stor_len; 335 336 report_prefix_push("init"); 337 uvcb_init.header.len -= 8; 338 rc = uv_call(0, (uint64_t)&uvcb_init); 339 report(rc == 1 && uvcb_init.header.rc == UVC_RC_INV_LEN, 340 "hdr invalid length"); 341 uvcb_init.header.len += 8; 342 343 uvcb_init.stor_len -= 8; 344 rc = uv_call(0, (uint64_t)&uvcb_init); 345 report(rc == 1 && uvcb_init.header.rc == 0x103, 346 "storage invalid length"); 347 uvcb_init.stor_len += 8; 348 349 uvcb_init.stor_origin = get_max_ram_size() + 8; 350 rc = uv_call(0, (uint64_t)&uvcb_init); 351 report(rc == 1 && uvcb_init.header.rc == 0x104, 352 "storage origin invalid"); 353 uvcb_init.stor_origin = mem; 354 355 uvcb_init.stor_origin = get_max_ram_size() - 8; 356 rc = uv_call(0, (uint64_t)&uvcb_init); 357 report(rc == 1 && uvcb_init.header.rc == 0x105, 358 "storage + length invalid"); 359 uvcb_init.stor_origin = mem; 360 361 uvcb_init.stor_origin = 1UL << 30; 362 rc = uv_call(0, (uint64_t)&uvcb_init); 363 report(rc == 1 && uvcb_init.header.rc == 0x108, 364 "storage below 2GB"); 365 uvcb_init.stor_origin = mem; 366 367 psw.mask = extract_psw_mask(); 368 psw.addr = (unsigned long)cpu_loop; 369 smp_cpu_setup(1, psw); 370 rc = uv_call(0, (uint64_t)&uvcb_init); 371 report(rc == 1 && uvcb_init.header.rc == 0x102, 372 "too many running cpus"); 373 smp_cpu_stop(1); 374 375 rc = uv_call(0, (uint64_t)&uvcb_init); 376 report(rc == 0 && uvcb_init.header.rc == UVC_RC_EXECUTED, "successful"); 377 378 mem = (uint64_t)memalign(1UL << 31, uvcb_qui.uv_base_stor_len); 379 rc = uv_call(0, (uint64_t)&uvcb_init); 380 report(rc == 1 && uvcb_init.header.rc == 0x101, "double init"); 381 free((void *)mem); 382 383 report_prefix_pop(); 384 } 385 386 static void test_query(void) 387 { 388 int i = 0; 389 390 uvcb_qui.header.cmd = UVC_CMD_QUI; 391 uvcb_qui.header.len = sizeof(uvcb_qui); 392 393 report_prefix_push("query"); 394 uvcb_qui.header.len = 0xa0; 395 uv_call(0, (uint64_t)&uvcb_qui); 396 report(uvcb_qui.header.rc == UVC_RC_INV_LEN, "length"); 397 398 uvcb_qui.header.len = 0xa8; 399 uv_call(0, (uint64_t)&uvcb_qui); 400 report(uvcb_qui.header.rc == 0x100, "insf length"); 401 402 uvcb_qui.header.len = sizeof(uvcb_qui); 403 uv_call(0, (uint64_t)&uvcb_qui); 404 report(uvcb_qui.header.rc == UVC_RC_EXECUTED, "successful query"); 405 406 for (i = 0; cmds[i].name; i++) 407 report(uv_query_test_call(cmds[i].call_bit), "%s", cmds[i].name); 408 409 report_prefix_pop(); 410 } 411 412 static struct cmd_list invalid_cmds[] = { 413 { "bogus", 0x4242, sizeof(struct uv_cb_header), -1}, 414 { "share", UVC_CMD_SET_SHARED_ACCESS, sizeof(struct uv_cb_share), BIT_UVC_CMD_SET_SHARED_ACCESS }, 415 { "unshare", UVC_CMD_REMOVE_SHARED_ACCESS, sizeof(struct uv_cb_share), BIT_UVC_CMD_REMOVE_SHARED_ACCESS }, 416 { NULL, 0, 0 }, 417 }; 418 419 static void test_invalid(void) 420 { 421 struct uv_cb_header hdr = {}; 422 int i, cc; 423 424 report_prefix_push("invalid"); 425 for (i = 0; invalid_cmds[i].name; i++) { 426 hdr.cmd = invalid_cmds[i].cmd; 427 hdr.len = invalid_cmds[i].len; 428 cc = uv_call(0, (uint64_t)&hdr); 429 report(cc == 1 && hdr.rc == UVC_RC_INV_CMD && 430 (invalid_cmds[i].call_bit == -1 || !uv_query_test_call(invalid_cmds[i].call_bit)), 431 "%s", invalid_cmds[i].name); 432 } 433 report_prefix_pop(); 434 } 435 436 static void test_clear(void) 437 { 438 uint64_t *tmp = (void *)uvcb_init.stor_origin; 439 440 diag308_load_reset(1); 441 sclp_console_setup(); 442 report(!*tmp, "memory cleared after reset 1"); 443 } 444 445 static void setup_vmem(void) 446 { 447 uint64_t asce, mask; 448 449 setup_mmu(get_max_ram_size()); 450 asce = stctg(1); 451 lctlg(13, asce); 452 mask = extract_psw_mask() | 0x0000C00000000000UL; 453 load_psw_mask(mask); 454 } 455 456 int main(void) 457 { 458 bool has_uvc = test_facility(158); 459 460 report_prefix_push("uvc"); 461 if (!has_uvc) { 462 report_skip("Ultravisor call facility is not available"); 463 goto done; 464 } 465 466 test_priv(); 467 test_invalid(); 468 test_query(); 469 test_init(); 470 471 setup_vmem(); 472 test_config_create(); 473 test_cpu_create(); 474 test_cpu_destroy(); 475 test_config_destroy(); 476 test_clear(); 477 478 done: 479 return report_summary(); 480 } 481