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