1 /* 2 * QEMU PowerPC Virtual Open Firmware. 3 * 4 * This implements client interface from OpenFirmware IEEE1275 on the QEMU 5 * side to leave only a very basic firmware in the VM. 6 * 7 * Copyright (c) 2021 IBM Corporation. 8 * 9 * SPDX-License-Identifier: GPL-2.0-or-later 10 */ 11 12 #include "qemu/osdep.h" 13 #include "qemu-common.h" 14 #include "qemu/timer.h" 15 #include "qemu/range.h" 16 #include "qemu/units.h" 17 #include "qemu/log.h" 18 #include "qapi/error.h" 19 #include "exec/address-spaces.h" 20 #include "hw/ppc/vof.h" 21 #include "hw/ppc/fdt.h" 22 #include "sysemu/runstate.h" 23 #include "qom/qom-qobject.h" 24 #include "trace.h" 25 26 #include <libfdt.h> 27 28 /* 29 * OF 1275 "nextprop" description suggests is it 32 bytes max but 30 * LoPAPR defines "ibm,query-interrupt-source-number" which is 33 chars long. 31 */ 32 #define OF_PROPNAME_LEN_MAX 64 33 34 #define VOF_MAX_PATH 256 35 #define VOF_MAX_SETPROPLEN 2048 36 #define VOF_MAX_METHODLEN 256 37 #define VOF_MAX_FORTHCODE 256 38 #define VOF_VTY_BUF_SIZE 256 39 40 typedef struct { 41 uint64_t start; 42 uint64_t size; 43 } OfClaimed; 44 45 typedef struct { 46 char *path; /* the path used to open the instance */ 47 uint32_t phandle; 48 } OfInstance; 49 50 static int readstr(hwaddr pa, char *buf, int size) 51 { 52 if (VOF_MEM_READ(pa, buf, size) != MEMTX_OK) { 53 return -1; 54 } 55 if (strnlen(buf, size) == size) { 56 buf[size - 1] = '\0'; 57 trace_vof_error_str_truncated(buf, size); 58 return -1; 59 } 60 return 0; 61 } 62 63 static bool cmpservice(const char *s, unsigned nargs, unsigned nret, 64 const char *s1, unsigned nargscheck, unsigned nretcheck) 65 { 66 if (strcmp(s, s1)) { 67 return false; 68 } 69 if ((nargscheck && (nargs != nargscheck)) || 70 (nretcheck && (nret != nretcheck))) { 71 trace_vof_error_param(s, nargscheck, nretcheck, nargs, nret); 72 return false; 73 } 74 75 return true; 76 } 77 78 static void prop_format(char *tval, int tlen, const void *prop, int len) 79 { 80 int i; 81 const unsigned char *c; 82 char *t; 83 const char bin[] = "..."; 84 85 for (i = 0, c = prop; i < len; ++i, ++c) { 86 if (*c == '\0' && i == len - 1) { 87 strncpy(tval, prop, tlen - 1); 88 return; 89 } 90 if (*c < 0x20 || *c >= 0x80) { 91 break; 92 } 93 } 94 95 for (i = 0, c = prop, t = tval; i < len; ++i, ++c) { 96 if (t >= tval + tlen - sizeof(bin) - 1 - 2 - 1) { 97 strcpy(t, bin); 98 return; 99 } 100 if (i && i % 4 == 0 && i != len - 1) { 101 strcat(t, " "); 102 ++t; 103 } 104 t += sprintf(t, "%02X", *c & 0xFF); 105 } 106 } 107 108 static int get_path(const void *fdt, int offset, char *buf, int len) 109 { 110 int ret; 111 112 ret = fdt_get_path(fdt, offset, buf, len - 1); 113 if (ret < 0) { 114 return ret; 115 } 116 117 buf[len - 1] = '\0'; 118 119 return strlen(buf) + 1; 120 } 121 122 static int phandle_to_path(const void *fdt, uint32_t ph, char *buf, int len) 123 { 124 int ret; 125 126 ret = fdt_node_offset_by_phandle(fdt, ph); 127 if (ret < 0) { 128 return ret; 129 } 130 131 return get_path(fdt, ret, buf, len); 132 } 133 134 static int path_offset(const void *fdt, const char *path) 135 { 136 g_autofree char *p = NULL; 137 char *at; 138 139 /* 140 * https://www.devicetree.org/open-firmware/bindings/ppc/release/ppc-2_1.html#HDR16 141 * 142 * "Conversion from numeric representation to text representation shall use 143 * the lower case forms of the hexadecimal digits in the range a..f, 144 * suppressing leading zeros". 145 */ 146 p = g_strdup(path); 147 for (at = strchr(p, '@'); at && *at; ) { 148 if (*at == '/') { 149 at = strchr(at, '@'); 150 } else { 151 *at = tolower(*at); 152 ++at; 153 } 154 } 155 156 return fdt_path_offset(fdt, p); 157 } 158 159 static uint32_t vof_finddevice(const void *fdt, uint32_t nodeaddr) 160 { 161 char fullnode[VOF_MAX_PATH]; 162 uint32_t ret = PROM_ERROR; 163 int offset; 164 165 if (readstr(nodeaddr, fullnode, sizeof(fullnode))) { 166 return (uint32_t) ret; 167 } 168 169 offset = path_offset(fdt, fullnode); 170 if (offset >= 0) { 171 ret = fdt_get_phandle(fdt, offset); 172 } 173 trace_vof_finddevice(fullnode, ret); 174 return ret; 175 } 176 177 static const void *getprop(const void *fdt, int nodeoff, const char *propname, 178 int *proplen, bool *write0) 179 { 180 const char *unit, *prop; 181 const void *ret = fdt_getprop(fdt, nodeoff, propname, proplen); 182 183 if (ret) { 184 if (write0) { 185 *write0 = false; 186 } 187 return ret; 188 } 189 190 if (strcmp(propname, "name")) { 191 return NULL; 192 } 193 /* 194 * We return a value for "name" from path if queried but property does not 195 * exist. @proplen does not include the unit part in this case. 196 */ 197 prop = fdt_get_name(fdt, nodeoff, proplen); 198 if (!prop) { 199 *proplen = 0; 200 return NULL; 201 } 202 203 unit = memchr(prop, '@', *proplen); 204 if (unit) { 205 *proplen = unit - prop; 206 } 207 *proplen += 1; 208 209 /* 210 * Since it might be cut at "@" and there will be no trailing zero 211 * in the prop buffer, tell the caller to write zero at the end. 212 */ 213 if (write0) { 214 *write0 = true; 215 } 216 return prop; 217 } 218 219 static uint32_t vof_getprop(const void *fdt, uint32_t nodeph, uint32_t pname, 220 uint32_t valaddr, uint32_t vallen) 221 { 222 char propname[OF_PROPNAME_LEN_MAX + 1]; 223 uint32_t ret = 0; 224 int proplen = 0; 225 const void *prop; 226 char trval[64] = ""; 227 int nodeoff = fdt_node_offset_by_phandle(fdt, nodeph); 228 bool write0; 229 230 if (nodeoff < 0) { 231 return PROM_ERROR; 232 } 233 if (readstr(pname, propname, sizeof(propname))) { 234 return PROM_ERROR; 235 } 236 prop = getprop(fdt, nodeoff, propname, &proplen, &write0); 237 if (prop) { 238 const char zero = 0; 239 int cb = MIN(proplen, vallen); 240 241 if (VOF_MEM_WRITE(valaddr, prop, cb) != MEMTX_OK || 242 /* if that was "name" with a unit address, overwrite '@' with '0' */ 243 (write0 && 244 cb == proplen && 245 VOF_MEM_WRITE(valaddr + cb - 1, &zero, 1) != MEMTX_OK)) { 246 ret = PROM_ERROR; 247 } else { 248 /* 249 * OF1275 says: 250 * "Size is either the actual size of the property, or -1 if name 251 * does not exist", hence returning proplen instead of cb. 252 */ 253 ret = proplen; 254 /* Do not format a value if tracepoint is silent, for performance */ 255 if (trace_event_get_state(TRACE_VOF_GETPROP) && 256 qemu_loglevel_mask(LOG_TRACE)) { 257 prop_format(trval, sizeof(trval), prop, ret); 258 } 259 } 260 } else { 261 ret = PROM_ERROR; 262 } 263 trace_vof_getprop(nodeph, propname, ret, trval); 264 265 return ret; 266 } 267 268 static uint32_t vof_getproplen(const void *fdt, uint32_t nodeph, uint32_t pname) 269 { 270 char propname[OF_PROPNAME_LEN_MAX + 1]; 271 uint32_t ret = 0; 272 int proplen = 0; 273 const void *prop; 274 int nodeoff = fdt_node_offset_by_phandle(fdt, nodeph); 275 276 if (nodeoff < 0) { 277 return PROM_ERROR; 278 } 279 if (readstr(pname, propname, sizeof(propname))) { 280 return PROM_ERROR; 281 } 282 prop = getprop(fdt, nodeoff, propname, &proplen, NULL); 283 if (prop) { 284 ret = proplen; 285 } else { 286 ret = PROM_ERROR; 287 } 288 trace_vof_getproplen(nodeph, propname, ret); 289 290 return ret; 291 } 292 293 static uint32_t vof_setprop(MachineState *ms, void *fdt, Vof *vof, 294 uint32_t nodeph, uint32_t pname, 295 uint32_t valaddr, uint32_t vallen) 296 { 297 char propname[OF_PROPNAME_LEN_MAX + 1]; 298 uint32_t ret = PROM_ERROR; 299 int offset, rc; 300 char trval[64] = ""; 301 char nodepath[VOF_MAX_PATH] = ""; 302 Object *vmo = object_dynamic_cast(OBJECT(ms), TYPE_VOF_MACHINE_IF); 303 VofMachineIfClass *vmc; 304 g_autofree char *val = NULL; 305 306 if (vallen > VOF_MAX_SETPROPLEN) { 307 goto trace_exit; 308 } 309 if (readstr(pname, propname, sizeof(propname))) { 310 goto trace_exit; 311 } 312 offset = fdt_node_offset_by_phandle(fdt, nodeph); 313 if (offset < 0) { 314 goto trace_exit; 315 } 316 rc = get_path(fdt, offset, nodepath, sizeof(nodepath)); 317 if (rc <= 0) { 318 goto trace_exit; 319 } 320 321 val = g_malloc0(vallen); 322 if (VOF_MEM_READ(valaddr, val, vallen) != MEMTX_OK) { 323 goto trace_exit; 324 } 325 326 if (!vmo) { 327 goto trace_exit; 328 } 329 330 vmc = VOF_MACHINE_GET_CLASS(vmo); 331 if (!vmc->setprop || !vmc->setprop(ms, nodepath, propname, val, vallen)) { 332 goto trace_exit; 333 } 334 335 rc = fdt_setprop(fdt, offset, propname, val, vallen); 336 if (rc) { 337 goto trace_exit; 338 } 339 340 if (trace_event_get_state(TRACE_VOF_SETPROP) && 341 qemu_loglevel_mask(LOG_TRACE)) { 342 prop_format(trval, sizeof(trval), val, vallen); 343 } 344 ret = vallen; 345 346 trace_exit: 347 trace_vof_setprop(nodeph, propname, trval, vallen, ret); 348 349 return ret; 350 } 351 352 static uint32_t vof_nextprop(const void *fdt, uint32_t phandle, 353 uint32_t prevaddr, uint32_t nameaddr) 354 { 355 int offset, nodeoff = fdt_node_offset_by_phandle(fdt, phandle); 356 char prev[OF_PROPNAME_LEN_MAX + 1]; 357 const char *tmp; 358 359 if (readstr(prevaddr, prev, sizeof(prev))) { 360 return PROM_ERROR; 361 } 362 363 fdt_for_each_property_offset(offset, fdt, nodeoff) { 364 if (!fdt_getprop_by_offset(fdt, offset, &tmp, NULL)) { 365 return 0; 366 } 367 if (prev[0] == '\0' || strcmp(prev, tmp) == 0) { 368 if (prev[0] != '\0') { 369 offset = fdt_next_property_offset(fdt, offset); 370 if (offset < 0) { 371 return 0; 372 } 373 } 374 if (!fdt_getprop_by_offset(fdt, offset, &tmp, NULL)) { 375 return 0; 376 } 377 378 if (VOF_MEM_WRITE(nameaddr, tmp, strlen(tmp) + 1) != MEMTX_OK) { 379 return PROM_ERROR; 380 } 381 return 1; 382 } 383 } 384 385 return 0; 386 } 387 388 static uint32_t vof_peer(const void *fdt, uint32_t phandle) 389 { 390 uint32_t ret = 0; 391 int rc; 392 393 if (phandle == 0) { 394 rc = fdt_path_offset(fdt, "/"); 395 } else { 396 rc = fdt_next_subnode(fdt, fdt_node_offset_by_phandle(fdt, phandle)); 397 } 398 399 if (rc >= 0) { 400 ret = fdt_get_phandle(fdt, rc); 401 } 402 403 return ret; 404 } 405 406 static uint32_t vof_child(const void *fdt, uint32_t phandle) 407 { 408 uint32_t ret = 0; 409 int rc = fdt_first_subnode(fdt, fdt_node_offset_by_phandle(fdt, phandle)); 410 411 if (rc >= 0) { 412 ret = fdt_get_phandle(fdt, rc); 413 } 414 415 return ret; 416 } 417 418 static uint32_t vof_parent(const void *fdt, uint32_t phandle) 419 { 420 uint32_t ret = 0; 421 int rc = fdt_parent_offset(fdt, fdt_node_offset_by_phandle(fdt, phandle)); 422 423 if (rc >= 0) { 424 ret = fdt_get_phandle(fdt, rc); 425 } 426 427 return ret; 428 } 429 430 static uint32_t vof_do_open(void *fdt, Vof *vof, int offset, const char *path) 431 { 432 uint32_t ret = PROM_ERROR; 433 OfInstance *inst = NULL; 434 435 if (vof->of_instance_last == 0xFFFFFFFF) { 436 /* We do not recycle ihandles yet */ 437 goto trace_exit; 438 } 439 440 inst = g_new0(OfInstance, 1); 441 inst->phandle = fdt_get_phandle(fdt, offset); 442 g_assert(inst->phandle); 443 ++vof->of_instance_last; 444 445 inst->path = g_strdup(path); 446 g_hash_table_insert(vof->of_instances, 447 GINT_TO_POINTER(vof->of_instance_last), 448 inst); 449 ret = vof->of_instance_last; 450 451 trace_exit: 452 trace_vof_open(path, inst ? inst->phandle : 0, ret); 453 454 return ret; 455 } 456 457 uint32_t vof_client_open_store(void *fdt, Vof *vof, const char *nodename, 458 const char *prop, const char *path) 459 { 460 int offset, node = fdt_path_offset(fdt, nodename); 461 uint32_t inst; 462 463 offset = fdt_path_offset(fdt, path); 464 if (offset < 0) { 465 trace_vof_error_unknown_path(path); 466 return PROM_ERROR; 467 } 468 469 inst = vof_do_open(fdt, vof, offset, path); 470 471 return fdt_setprop_cell(fdt, node, prop, inst) >= 0 ? 0 : PROM_ERROR; 472 } 473 474 static uint32_t vof_open(void *fdt, Vof *vof, uint32_t pathaddr) 475 { 476 char path[VOF_MAX_PATH]; 477 int offset; 478 479 if (readstr(pathaddr, path, sizeof(path))) { 480 return PROM_ERROR; 481 } 482 483 offset = path_offset(fdt, path); 484 if (offset < 0) { 485 trace_vof_error_unknown_path(path); 486 return PROM_ERROR; 487 } 488 489 return vof_do_open(fdt, vof, offset, path); 490 } 491 492 static void vof_close(Vof *vof, uint32_t ihandle) 493 { 494 if (!g_hash_table_remove(vof->of_instances, GINT_TO_POINTER(ihandle))) { 495 trace_vof_error_unknown_ihandle_close(ihandle); 496 } 497 } 498 499 static uint32_t vof_instance_to_package(Vof *vof, uint32_t ihandle) 500 { 501 gpointer instp = g_hash_table_lookup(vof->of_instances, 502 GINT_TO_POINTER(ihandle)); 503 uint32_t ret = PROM_ERROR; 504 505 if (instp) { 506 ret = ((OfInstance *)instp)->phandle; 507 } 508 trace_vof_instance_to_package(ihandle, ret); 509 510 return ret; 511 } 512 513 static uint32_t vof_package_to_path(const void *fdt, uint32_t phandle, 514 uint32_t buf, uint32_t len) 515 { 516 int rc; 517 char tmp[VOF_MAX_PATH] = ""; 518 519 rc = phandle_to_path(fdt, phandle, tmp, sizeof(tmp)); 520 if (rc > 0) { 521 if (VOF_MEM_WRITE(buf, tmp, rc) != MEMTX_OK) { 522 rc = -1; 523 } 524 } 525 526 trace_vof_package_to_path(phandle, tmp, rc); 527 528 return rc > 0 ? (uint32_t)rc : PROM_ERROR; 529 } 530 531 static uint32_t vof_instance_to_path(void *fdt, Vof *vof, uint32_t ihandle, 532 uint32_t buf, uint32_t len) 533 { 534 int rc = -1; 535 uint32_t phandle = vof_instance_to_package(vof, ihandle); 536 char tmp[VOF_MAX_PATH] = ""; 537 538 if (phandle != -1) { 539 rc = phandle_to_path(fdt, phandle, tmp, sizeof(tmp)); 540 if (rc > 0) { 541 if (VOF_MEM_WRITE(buf, tmp, rc) != MEMTX_OK) { 542 rc = -1; 543 } 544 } 545 } 546 trace_vof_instance_to_path(ihandle, phandle, tmp, rc); 547 548 return rc > 0 ? (uint32_t)rc : PROM_ERROR; 549 } 550 551 static uint32_t vof_write(Vof *vof, uint32_t ihandle, uint32_t buf, 552 uint32_t len) 553 { 554 char tmp[VOF_VTY_BUF_SIZE]; 555 unsigned cb; 556 OfInstance *inst = (OfInstance *) 557 g_hash_table_lookup(vof->of_instances, GINT_TO_POINTER(ihandle)); 558 559 if (!inst) { 560 trace_vof_error_write(ihandle); 561 return PROM_ERROR; 562 } 563 564 for ( ; len > 0; len -= cb) { 565 cb = MIN(len, sizeof(tmp) - 1); 566 if (VOF_MEM_READ(buf, tmp, cb) != MEMTX_OK) { 567 return PROM_ERROR; 568 } 569 570 /* FIXME: there is no backend(s) yet so just call a trace */ 571 if (trace_event_get_state(TRACE_VOF_WRITE) && 572 qemu_loglevel_mask(LOG_TRACE)) { 573 tmp[cb] = '\0'; 574 trace_vof_write(ihandle, cb, tmp); 575 } 576 } 577 578 return len; 579 } 580 581 static void vof_claimed_dump(GArray *claimed) 582 { 583 int i; 584 OfClaimed c; 585 586 if (trace_event_get_state(TRACE_VOF_CLAIMED) && 587 qemu_loglevel_mask(LOG_TRACE)) { 588 589 for (i = 0; i < claimed->len; ++i) { 590 c = g_array_index(claimed, OfClaimed, i); 591 trace_vof_claimed(c.start, c.start + c.size, c.size); 592 } 593 } 594 } 595 596 static bool vof_claim_avail(GArray *claimed, uint64_t virt, uint64_t size) 597 { 598 int i; 599 OfClaimed c; 600 601 for (i = 0; i < claimed->len; ++i) { 602 c = g_array_index(claimed, OfClaimed, i); 603 if (ranges_overlap(c.start, c.size, virt, size)) { 604 return false; 605 } 606 } 607 608 return true; 609 } 610 611 static void vof_claim_add(GArray *claimed, uint64_t virt, uint64_t size) 612 { 613 OfClaimed newclaim; 614 615 newclaim.start = virt; 616 newclaim.size = size; 617 g_array_append_val(claimed, newclaim); 618 } 619 620 static gint of_claimed_compare_func(gconstpointer a, gconstpointer b) 621 { 622 return ((OfClaimed *)a)->start - ((OfClaimed *)b)->start; 623 } 624 625 static void vof_dt_memory_available(void *fdt, GArray *claimed, uint64_t base) 626 { 627 int i, n, offset, proplen = 0, sc, ac; 628 target_ulong mem0_end; 629 const uint8_t *mem0_reg; 630 g_autofree uint8_t *avail = NULL; 631 uint8_t *availcur; 632 633 if (!fdt || !claimed) { 634 return; 635 } 636 637 offset = fdt_path_offset(fdt, "/"); 638 _FDT(offset); 639 ac = fdt_address_cells(fdt, offset); 640 g_assert(ac == 1 || ac == 2); 641 sc = fdt_size_cells(fdt, offset); 642 g_assert(sc == 1 || sc == 2); 643 644 offset = fdt_path_offset(fdt, "/memory@0"); 645 _FDT(offset); 646 647 mem0_reg = fdt_getprop(fdt, offset, "reg", &proplen); 648 g_assert(mem0_reg && proplen == sizeof(uint32_t) * (ac + sc)); 649 if (sc == 2) { 650 mem0_end = be64_to_cpu(*(uint64_t *)(mem0_reg + sizeof(uint32_t) * ac)); 651 } else { 652 mem0_end = be32_to_cpu(*(uint32_t *)(mem0_reg + sizeof(uint32_t) * ac)); 653 } 654 655 g_array_sort(claimed, of_claimed_compare_func); 656 vof_claimed_dump(claimed); 657 658 /* 659 * VOF resides in the first page so we do not need to check if there is 660 * available memory before the first claimed block 661 */ 662 g_assert(claimed->len && (g_array_index(claimed, OfClaimed, 0).start == 0)); 663 664 avail = g_malloc0(sizeof(uint32_t) * (ac + sc) * claimed->len); 665 for (i = 0, n = 0, availcur = avail; i < claimed->len; ++i) { 666 OfClaimed c = g_array_index(claimed, OfClaimed, i); 667 uint64_t start, size; 668 669 start = c.start + c.size; 670 if (i < claimed->len - 1) { 671 OfClaimed cn = g_array_index(claimed, OfClaimed, i + 1); 672 673 size = cn.start - start; 674 } else { 675 size = mem0_end - start; 676 } 677 678 if (ac == 2) { 679 *(uint64_t *) availcur = cpu_to_be64(start); 680 } else { 681 *(uint32_t *) availcur = cpu_to_be32(start); 682 } 683 availcur += sizeof(uint32_t) * ac; 684 if (sc == 2) { 685 *(uint64_t *) availcur = cpu_to_be64(size); 686 } else { 687 *(uint32_t *) availcur = cpu_to_be32(size); 688 } 689 availcur += sizeof(uint32_t) * sc; 690 691 if (size) { 692 trace_vof_avail(c.start + c.size, c.start + c.size + size, size); 693 ++n; 694 } 695 } 696 _FDT((fdt_setprop(fdt, offset, "available", avail, availcur - avail))); 697 } 698 699 /* 700 * OF1275: 701 * "Allocates size bytes of memory. If align is zero, the allocated range 702 * begins at the virtual address virt. Otherwise, an aligned address is 703 * automatically chosen and the input argument virt is ignored". 704 * 705 * In other words, exactly one of @virt and @align is non-zero. 706 */ 707 uint64_t vof_claim(Vof *vof, uint64_t virt, uint64_t size, 708 uint64_t align) 709 { 710 uint64_t ret; 711 712 if (size == 0) { 713 ret = -1; 714 } else if (align == 0) { 715 if (!vof_claim_avail(vof->claimed, virt, size)) { 716 ret = -1; 717 } else { 718 ret = virt; 719 } 720 } else { 721 vof->claimed_base = QEMU_ALIGN_UP(vof->claimed_base, align); 722 while (1) { 723 if (vof->claimed_base >= vof->top_addr) { 724 error_report("Out of RMA memory for the OF client"); 725 return -1; 726 } 727 if (vof_claim_avail(vof->claimed, vof->claimed_base, size)) { 728 break; 729 } 730 vof->claimed_base += size; 731 } 732 ret = vof->claimed_base; 733 } 734 735 if (ret != -1) { 736 vof->claimed_base = MAX(vof->claimed_base, ret + size); 737 vof_claim_add(vof->claimed, ret, size); 738 } 739 trace_vof_claim(virt, size, align, ret); 740 741 return ret; 742 } 743 744 static uint32_t vof_release(Vof *vof, uint64_t virt, uint64_t size) 745 { 746 uint32_t ret = PROM_ERROR; 747 int i; 748 GArray *claimed = vof->claimed; 749 OfClaimed c; 750 751 for (i = 0; i < claimed->len; ++i) { 752 c = g_array_index(claimed, OfClaimed, i); 753 if (c.start == virt && c.size == size) { 754 g_array_remove_index(claimed, i); 755 ret = 0; 756 break; 757 } 758 } 759 760 trace_vof_release(virt, size, ret); 761 762 return ret; 763 } 764 765 static void vof_instantiate_rtas(Error **errp) 766 { 767 error_setg(errp, "The firmware should have instantiated RTAS"); 768 } 769 770 static uint32_t vof_call_method(MachineState *ms, Vof *vof, uint32_t methodaddr, 771 uint32_t ihandle, uint32_t param1, 772 uint32_t param2, uint32_t param3, 773 uint32_t param4, uint32_t *ret2) 774 { 775 uint32_t ret = PROM_ERROR; 776 char method[VOF_MAX_METHODLEN] = ""; 777 OfInstance *inst; 778 779 if (!ihandle) { 780 goto trace_exit; 781 } 782 783 inst = (OfInstance *)g_hash_table_lookup(vof->of_instances, 784 GINT_TO_POINTER(ihandle)); 785 if (!inst) { 786 goto trace_exit; 787 } 788 789 if (readstr(methodaddr, method, sizeof(method))) { 790 goto trace_exit; 791 } 792 793 if (strcmp(inst->path, "/") == 0) { 794 if (strcmp(method, "ibm,client-architecture-support") == 0) { 795 Object *vmo = object_dynamic_cast(OBJECT(ms), TYPE_VOF_MACHINE_IF); 796 797 if (vmo) { 798 VofMachineIfClass *vmc = VOF_MACHINE_GET_CLASS(vmo); 799 800 g_assert(vmc->client_architecture_support); 801 ret = (uint32_t)vmc->client_architecture_support(ms, first_cpu, 802 param1); 803 } 804 805 *ret2 = 0; 806 } 807 } else if (strcmp(inst->path, "/rtas") == 0) { 808 if (strcmp(method, "instantiate-rtas") == 0) { 809 vof_instantiate_rtas(&error_fatal); 810 ret = 0; 811 *ret2 = param1; /* rtas-base */ 812 } 813 } else { 814 trace_vof_error_unknown_method(method); 815 } 816 817 trace_exit: 818 trace_vof_method(ihandle, method, param1, ret, *ret2); 819 820 return ret; 821 } 822 823 static uint32_t vof_call_interpret(uint32_t cmdaddr, uint32_t param1, 824 uint32_t param2, uint32_t *ret2) 825 { 826 uint32_t ret = PROM_ERROR; 827 char cmd[VOF_MAX_FORTHCODE] = ""; 828 829 /* No interpret implemented so just call a trace */ 830 readstr(cmdaddr, cmd, sizeof(cmd)); 831 trace_vof_interpret(cmd, param1, param2, ret, *ret2); 832 833 return ret; 834 } 835 836 static void vof_quiesce(MachineState *ms, void *fdt, Vof *vof) 837 { 838 Object *vmo = object_dynamic_cast(OBJECT(ms), TYPE_VOF_MACHINE_IF); 839 /* After "quiesce", no change is expected to the FDT, pack FDT to ensure */ 840 int rc = fdt_pack(fdt); 841 842 assert(rc == 0); 843 844 if (vmo) { 845 VofMachineIfClass *vmc = VOF_MACHINE_GET_CLASS(vmo); 846 847 if (vmc->quiesce) { 848 vmc->quiesce(ms); 849 } 850 } 851 852 vof_claimed_dump(vof->claimed); 853 } 854 855 static uint32_t vof_client_handle(MachineState *ms, void *fdt, Vof *vof, 856 const char *service, 857 uint32_t *args, unsigned nargs, 858 uint32_t *rets, unsigned nrets) 859 { 860 uint32_t ret = 0; 861 862 /* @nrets includes the value which this function returns */ 863 #define cmpserv(s, a, r) \ 864 cmpservice(service, nargs, nrets, (s), (a), (r)) 865 866 if (cmpserv("finddevice", 1, 1)) { 867 ret = vof_finddevice(fdt, args[0]); 868 } else if (cmpserv("getprop", 4, 1)) { 869 ret = vof_getprop(fdt, args[0], args[1], args[2], args[3]); 870 } else if (cmpserv("getproplen", 2, 1)) { 871 ret = vof_getproplen(fdt, args[0], args[1]); 872 } else if (cmpserv("setprop", 4, 1)) { 873 ret = vof_setprop(ms, fdt, vof, args[0], args[1], args[2], args[3]); 874 } else if (cmpserv("nextprop", 3, 1)) { 875 ret = vof_nextprop(fdt, args[0], args[1], args[2]); 876 } else if (cmpserv("peer", 1, 1)) { 877 ret = vof_peer(fdt, args[0]); 878 } else if (cmpserv("child", 1, 1)) { 879 ret = vof_child(fdt, args[0]); 880 } else if (cmpserv("parent", 1, 1)) { 881 ret = vof_parent(fdt, args[0]); 882 } else if (cmpserv("open", 1, 1)) { 883 ret = vof_open(fdt, vof, args[0]); 884 } else if (cmpserv("close", 1, 0)) { 885 vof_close(vof, args[0]); 886 } else if (cmpserv("instance-to-package", 1, 1)) { 887 ret = vof_instance_to_package(vof, args[0]); 888 } else if (cmpserv("package-to-path", 3, 1)) { 889 ret = vof_package_to_path(fdt, args[0], args[1], args[2]); 890 } else if (cmpserv("instance-to-path", 3, 1)) { 891 ret = vof_instance_to_path(fdt, vof, args[0], args[1], args[2]); 892 } else if (cmpserv("write", 3, 1)) { 893 ret = vof_write(vof, args[0], args[1], args[2]); 894 } else if (cmpserv("claim", 3, 1)) { 895 uint64_t ret64 = vof_claim(vof, args[0], args[1], args[2]); 896 897 if (ret64 < 0x100000000UL) { 898 vof_dt_memory_available(fdt, vof->claimed, vof->claimed_base); 899 ret = (uint32_t)ret64; 900 } else { 901 if (ret64 != -1) { 902 vof_release(vof, ret, args[1]); 903 } 904 ret = PROM_ERROR; 905 } 906 } else if (cmpserv("release", 2, 0)) { 907 ret = vof_release(vof, args[0], args[1]); 908 if (ret != PROM_ERROR) { 909 vof_dt_memory_available(fdt, vof->claimed, vof->claimed_base); 910 } 911 } else if (cmpserv("call-method", 0, 0)) { 912 ret = vof_call_method(ms, vof, args[0], args[1], args[2], args[3], 913 args[4], args[5], rets); 914 } else if (cmpserv("interpret", 0, 0)) { 915 ret = vof_call_interpret(args[0], args[1], args[2], rets); 916 } else if (cmpserv("milliseconds", 0, 1)) { 917 ret = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL); 918 } else if (cmpserv("quiesce", 0, 0)) { 919 vof_quiesce(ms, fdt, vof); 920 } else if (cmpserv("exit", 0, 0)) { 921 error_report("Stopped as the VM requested \"exit\""); 922 vm_stop(RUN_STATE_PAUSED); 923 } else { 924 trace_vof_error_unknown_service(service, nargs, nrets); 925 ret = -1; 926 } 927 928 #undef cmpserv 929 930 return ret; 931 } 932 933 /* Defined as Big Endian */ 934 struct prom_args { 935 uint32_t service; 936 uint32_t nargs; 937 uint32_t nret; 938 uint32_t args[10]; 939 } QEMU_PACKED; 940 941 int vof_client_call(MachineState *ms, Vof *vof, void *fdt, 942 target_ulong args_real) 943 { 944 struct prom_args args_be; 945 uint32_t args[ARRAY_SIZE(args_be.args)]; 946 uint32_t rets[ARRAY_SIZE(args_be.args)] = { 0 }, ret; 947 char service[64]; 948 unsigned nargs, nret, i; 949 950 if (VOF_MEM_READ(args_real, &args_be, sizeof(args_be)) != MEMTX_OK) { 951 return -EINVAL; 952 } 953 nargs = be32_to_cpu(args_be.nargs); 954 if (nargs >= ARRAY_SIZE(args_be.args)) { 955 return -EINVAL; 956 } 957 958 if (VOF_MEM_READ(be32_to_cpu(args_be.service), service, sizeof(service)) != 959 MEMTX_OK) { 960 return -EINVAL; 961 } 962 if (strnlen(service, sizeof(service)) == sizeof(service)) { 963 /* Too long service name */ 964 return -EINVAL; 965 } 966 967 for (i = 0; i < nargs; ++i) { 968 args[i] = be32_to_cpu(args_be.args[i]); 969 } 970 971 nret = be32_to_cpu(args_be.nret); 972 if (nret > ARRAY_SIZE(args_be.args) - nargs) { 973 return -EINVAL; 974 } 975 ret = vof_client_handle(ms, fdt, vof, service, args, nargs, rets, nret); 976 if (!nret) { 977 return 0; 978 } 979 980 /* @nrets includes the value which this function returns */ 981 args_be.args[nargs] = cpu_to_be32(ret); 982 for (i = 1; i < nret; ++i) { 983 args_be.args[nargs + i] = cpu_to_be32(rets[i - 1]); 984 } 985 986 if (VOF_MEM_WRITE(args_real + offsetof(struct prom_args, args[nargs]), 987 args_be.args + nargs, sizeof(args_be.args[0]) * nret) != 988 MEMTX_OK) { 989 return -EINVAL; 990 } 991 992 return 0; 993 } 994 995 static void vof_instance_free(gpointer data) 996 { 997 OfInstance *inst = (OfInstance *)data; 998 999 g_free(inst->path); 1000 g_free(inst); 1001 } 1002 1003 void vof_init(Vof *vof, uint64_t top_addr, Error **errp) 1004 { 1005 vof_cleanup(vof); 1006 1007 vof->of_instances = g_hash_table_new_full(g_direct_hash, g_direct_equal, 1008 NULL, vof_instance_free); 1009 vof->claimed = g_array_new(false, false, sizeof(OfClaimed)); 1010 1011 /* Keep allocations in 32bit as CLI ABI can only return cells==32bit */ 1012 vof->top_addr = MIN(top_addr, 4 * GiB); 1013 if (vof_claim(vof, 0, vof->fw_size, 0) == -1) { 1014 error_setg(errp, "Memory for firmware is in use"); 1015 } 1016 } 1017 1018 void vof_cleanup(Vof *vof) 1019 { 1020 if (vof->claimed) { 1021 g_array_unref(vof->claimed); 1022 } 1023 if (vof->of_instances) { 1024 g_hash_table_unref(vof->of_instances); 1025 } 1026 vof->claimed = NULL; 1027 vof->of_instances = NULL; 1028 } 1029 1030 void vof_build_dt(void *fdt, Vof *vof) 1031 { 1032 uint32_t phandle = fdt_get_max_phandle(fdt); 1033 int offset, proplen = 0; 1034 const void *prop; 1035 1036 /* Assign phandles to nodes without predefined phandles (like XICS/XIVE) */ 1037 for (offset = fdt_next_node(fdt, -1, NULL); 1038 offset >= 0; 1039 offset = fdt_next_node(fdt, offset, NULL)) { 1040 prop = fdt_getprop(fdt, offset, "phandle", &proplen); 1041 if (prop) { 1042 continue; 1043 } 1044 ++phandle; 1045 _FDT(fdt_setprop_cell(fdt, offset, "phandle", phandle)); 1046 } 1047 1048 vof_dt_memory_available(fdt, vof->claimed, vof->claimed_base); 1049 } 1050 1051 static const TypeInfo vof_machine_if_info = { 1052 .name = TYPE_VOF_MACHINE_IF, 1053 .parent = TYPE_INTERFACE, 1054 .class_size = sizeof(VofMachineIfClass), 1055 }; 1056 1057 static void vof_machine_if_register_types(void) 1058 { 1059 type_register_static(&vof_machine_if_info); 1060 } 1061 type_init(vof_machine_if_register_types) 1062