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