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