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 "exec/address-spaces.h" 19 #include "hw/ppc/vof.h" 20 #include "hw/ppc/fdt.h" 21 #include "sysemu/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; 357 358 if (readstr(prevaddr, prev, sizeof(prev))) { 359 return PROM_ERROR; 360 } 361 362 fdt_for_each_property_offset(offset, fdt, nodeoff) { 363 if (!fdt_getprop_by_offset(fdt, offset, &tmp, NULL)) { 364 return 0; 365 } 366 if (prev[0] == '\0' || strcmp(prev, tmp) == 0) { 367 if (prev[0] != '\0') { 368 offset = fdt_next_property_offset(fdt, offset); 369 if (offset < 0) { 370 return 0; 371 } 372 } 373 if (!fdt_getprop_by_offset(fdt, offset, &tmp, NULL)) { 374 return 0; 375 } 376 377 if (VOF_MEM_WRITE(nameaddr, tmp, strlen(tmp) + 1) != MEMTX_OK) { 378 return PROM_ERROR; 379 } 380 return 1; 381 } 382 } 383 384 return 0; 385 } 386 387 static uint32_t vof_peer(const void *fdt, uint32_t phandle) 388 { 389 uint32_t ret = 0; 390 int rc; 391 392 if (phandle == 0) { 393 rc = fdt_path_offset(fdt, "/"); 394 } else { 395 rc = fdt_next_subnode(fdt, fdt_node_offset_by_phandle(fdt, phandle)); 396 } 397 398 if (rc >= 0) { 399 ret = fdt_get_phandle(fdt, rc); 400 } 401 402 return ret; 403 } 404 405 static uint32_t vof_child(const void *fdt, uint32_t phandle) 406 { 407 uint32_t ret = 0; 408 int rc = fdt_first_subnode(fdt, fdt_node_offset_by_phandle(fdt, phandle)); 409 410 if (rc >= 0) { 411 ret = fdt_get_phandle(fdt, rc); 412 } 413 414 return ret; 415 } 416 417 static uint32_t vof_parent(const void *fdt, uint32_t phandle) 418 { 419 uint32_t ret = 0; 420 int rc = fdt_parent_offset(fdt, fdt_node_offset_by_phandle(fdt, phandle)); 421 422 if (rc >= 0) { 423 ret = fdt_get_phandle(fdt, rc); 424 } 425 426 return ret; 427 } 428 429 static uint32_t vof_do_open(void *fdt, Vof *vof, int offset, const char *path) 430 { 431 uint32_t ret = PROM_ERROR; 432 OfInstance *inst = NULL; 433 434 if (vof->of_instance_last == 0xFFFFFFFF) { 435 /* We do not recycle ihandles yet */ 436 goto trace_exit; 437 } 438 439 inst = g_new0(OfInstance, 1); 440 inst->phandle = fdt_get_phandle(fdt, offset); 441 g_assert(inst->phandle); 442 ++vof->of_instance_last; 443 444 inst->path = g_strdup(path); 445 g_hash_table_insert(vof->of_instances, 446 GINT_TO_POINTER(vof->of_instance_last), 447 inst); 448 ret = vof->of_instance_last; 449 450 trace_exit: 451 trace_vof_open(path, inst ? inst->phandle : 0, ret); 452 453 return ret; 454 } 455 456 uint32_t vof_client_open_store(void *fdt, Vof *vof, const char *nodename, 457 const char *prop, const char *path) 458 { 459 int offset, node = fdt_path_offset(fdt, nodename); 460 uint32_t inst; 461 462 offset = fdt_path_offset(fdt, path); 463 if (offset < 0) { 464 trace_vof_error_unknown_path(path); 465 return PROM_ERROR; 466 } 467 468 inst = vof_do_open(fdt, vof, offset, path); 469 470 return fdt_setprop_cell(fdt, node, prop, inst) >= 0 ? 0 : PROM_ERROR; 471 } 472 473 static uint32_t vof_open(void *fdt, Vof *vof, uint32_t pathaddr) 474 { 475 char path[VOF_MAX_PATH]; 476 int offset; 477 478 if (readstr(pathaddr, path, sizeof(path))) { 479 return PROM_ERROR; 480 } 481 482 offset = path_offset(fdt, path); 483 if (offset < 0) { 484 trace_vof_error_unknown_path(path); 485 return PROM_ERROR; 486 } 487 488 return vof_do_open(fdt, vof, offset, path); 489 } 490 491 static void vof_close(Vof *vof, uint32_t ihandle) 492 { 493 if (!g_hash_table_remove(vof->of_instances, GINT_TO_POINTER(ihandle))) { 494 trace_vof_error_unknown_ihandle_close(ihandle); 495 } 496 } 497 498 static uint32_t vof_instance_to_package(Vof *vof, uint32_t ihandle) 499 { 500 gpointer instp = g_hash_table_lookup(vof->of_instances, 501 GINT_TO_POINTER(ihandle)); 502 uint32_t ret = PROM_ERROR; 503 504 if (instp) { 505 ret = ((OfInstance *)instp)->phandle; 506 } 507 trace_vof_instance_to_package(ihandle, ret); 508 509 return ret; 510 } 511 512 static uint32_t vof_package_to_path(const void *fdt, uint32_t phandle, 513 uint32_t buf, uint32_t len) 514 { 515 int rc; 516 char tmp[VOF_MAX_PATH] = ""; 517 518 rc = phandle_to_path(fdt, phandle, tmp, sizeof(tmp)); 519 if (rc > 0) { 520 if (VOF_MEM_WRITE(buf, tmp, rc) != MEMTX_OK) { 521 rc = -1; 522 } 523 } 524 525 trace_vof_package_to_path(phandle, tmp, rc); 526 527 return rc > 0 ? (uint32_t)rc : PROM_ERROR; 528 } 529 530 static uint32_t vof_instance_to_path(void *fdt, Vof *vof, uint32_t ihandle, 531 uint32_t buf, uint32_t len) 532 { 533 int rc = -1; 534 uint32_t phandle = vof_instance_to_package(vof, ihandle); 535 char tmp[VOF_MAX_PATH] = ""; 536 537 if (phandle != -1) { 538 rc = phandle_to_path(fdt, phandle, tmp, sizeof(tmp)); 539 if (rc > 0) { 540 if (VOF_MEM_WRITE(buf, tmp, rc) != MEMTX_OK) { 541 rc = -1; 542 } 543 } 544 } 545 trace_vof_instance_to_path(ihandle, phandle, tmp, rc); 546 547 return rc > 0 ? (uint32_t)rc : PROM_ERROR; 548 } 549 550 static uint32_t vof_write(Vof *vof, uint32_t ihandle, uint32_t buf, 551 uint32_t len) 552 { 553 char tmp[VOF_VTY_BUF_SIZE]; 554 unsigned cb; 555 OfInstance *inst = (OfInstance *) 556 g_hash_table_lookup(vof->of_instances, GINT_TO_POINTER(ihandle)); 557 558 if (!inst) { 559 trace_vof_error_write(ihandle); 560 return PROM_ERROR; 561 } 562 563 for ( ; len > 0; len -= cb) { 564 cb = MIN(len, sizeof(tmp) - 1); 565 if (VOF_MEM_READ(buf, tmp, cb) != MEMTX_OK) { 566 return PROM_ERROR; 567 } 568 569 /* FIXME: there is no backend(s) yet so just call a trace */ 570 if (trace_event_get_state(TRACE_VOF_WRITE) && 571 qemu_loglevel_mask(LOG_TRACE)) { 572 tmp[cb] = '\0'; 573 trace_vof_write(ihandle, cb, tmp); 574 } 575 } 576 577 return len; 578 } 579 580 static void vof_claimed_dump(GArray *claimed) 581 { 582 int i; 583 OfClaimed c; 584 585 if (trace_event_get_state(TRACE_VOF_CLAIMED) && 586 qemu_loglevel_mask(LOG_TRACE)) { 587 588 for (i = 0; i < claimed->len; ++i) { 589 c = g_array_index(claimed, OfClaimed, i); 590 trace_vof_claimed(c.start, c.start + c.size, c.size); 591 } 592 } 593 } 594 595 static bool vof_claim_avail(GArray *claimed, uint64_t virt, uint64_t size) 596 { 597 int i; 598 OfClaimed c; 599 600 for (i = 0; i < claimed->len; ++i) { 601 c = g_array_index(claimed, OfClaimed, i); 602 if (ranges_overlap(c.start, c.size, virt, size)) { 603 return false; 604 } 605 } 606 607 return true; 608 } 609 610 static void vof_claim_add(GArray *claimed, uint64_t virt, uint64_t size) 611 { 612 OfClaimed newclaim; 613 614 newclaim.start = virt; 615 newclaim.size = size; 616 g_array_append_val(claimed, newclaim); 617 } 618 619 static gint of_claimed_compare_func(gconstpointer a, gconstpointer b) 620 { 621 return ((OfClaimed *)a)->start - ((OfClaimed *)b)->start; 622 } 623 624 static void vof_dt_memory_available(void *fdt, GArray *claimed, uint64_t base) 625 { 626 int i, n, offset, proplen = 0, sc, ac; 627 target_ulong mem0_end; 628 const uint8_t *mem0_reg; 629 g_autofree uint8_t *avail = NULL; 630 uint8_t *availcur; 631 632 if (!fdt || !claimed) { 633 return; 634 } 635 636 offset = fdt_path_offset(fdt, "/"); 637 _FDT(offset); 638 ac = fdt_address_cells(fdt, offset); 639 g_assert(ac == 1 || ac == 2); 640 sc = fdt_size_cells(fdt, offset); 641 g_assert(sc == 1 || sc == 2); 642 643 offset = fdt_path_offset(fdt, "/memory@0"); 644 _FDT(offset); 645 646 mem0_reg = fdt_getprop(fdt, offset, "reg", &proplen); 647 g_assert(mem0_reg && proplen == sizeof(uint32_t) * (ac + sc)); 648 if (sc == 2) { 649 mem0_end = be64_to_cpu(*(uint64_t *)(mem0_reg + sizeof(uint32_t) * ac)); 650 } else { 651 mem0_end = be32_to_cpu(*(uint32_t *)(mem0_reg + sizeof(uint32_t) * ac)); 652 } 653 654 g_array_sort(claimed, of_claimed_compare_func); 655 vof_claimed_dump(claimed); 656 657 /* 658 * VOF resides in the first page so we do not need to check if there is 659 * available memory before the first claimed block 660 */ 661 g_assert(claimed->len && (g_array_index(claimed, OfClaimed, 0).start == 0)); 662 663 avail = g_malloc0(sizeof(uint32_t) * (ac + sc) * claimed->len); 664 for (i = 0, n = 0, availcur = avail; i < claimed->len; ++i) { 665 OfClaimed c = g_array_index(claimed, OfClaimed, i); 666 uint64_t start, size; 667 668 start = c.start + c.size; 669 if (i < claimed->len - 1) { 670 OfClaimed cn = g_array_index(claimed, OfClaimed, i + 1); 671 672 size = cn.start - start; 673 } else { 674 size = mem0_end - start; 675 } 676 677 if (ac == 2) { 678 *(uint64_t *) availcur = cpu_to_be64(start); 679 } else { 680 *(uint32_t *) availcur = cpu_to_be32(start); 681 } 682 availcur += sizeof(uint32_t) * ac; 683 if (sc == 2) { 684 *(uint64_t *) availcur = cpu_to_be64(size); 685 } else { 686 *(uint32_t *) availcur = cpu_to_be32(size); 687 } 688 availcur += sizeof(uint32_t) * sc; 689 690 if (size) { 691 trace_vof_avail(c.start + c.size, c.start + c.size + size, size); 692 ++n; 693 } 694 } 695 _FDT((fdt_setprop(fdt, offset, "available", avail, availcur - avail))); 696 } 697 698 /* 699 * OF1275: 700 * "Allocates size bytes of memory. If align is zero, the allocated range 701 * begins at the virtual address virt. Otherwise, an aligned address is 702 * automatically chosen and the input argument virt is ignored". 703 * 704 * In other words, exactly one of @virt and @align is non-zero. 705 */ 706 uint64_t vof_claim(Vof *vof, uint64_t virt, uint64_t size, 707 uint64_t align) 708 { 709 uint64_t ret; 710 711 if (size == 0) { 712 ret = -1; 713 } else if (align == 0) { 714 if (!vof_claim_avail(vof->claimed, virt, size)) { 715 ret = -1; 716 } else { 717 ret = virt; 718 } 719 } else { 720 vof->claimed_base = QEMU_ALIGN_UP(vof->claimed_base, align); 721 while (1) { 722 if (vof->claimed_base >= vof->top_addr) { 723 error_report("Out of RMA memory for the OF client"); 724 return -1; 725 } 726 if (vof_claim_avail(vof->claimed, vof->claimed_base, size)) { 727 break; 728 } 729 vof->claimed_base += size; 730 } 731 ret = vof->claimed_base; 732 } 733 734 if (ret != -1) { 735 vof->claimed_base = MAX(vof->claimed_base, ret + size); 736 vof_claim_add(vof->claimed, ret, size); 737 } 738 trace_vof_claim(virt, size, align, ret); 739 740 return ret; 741 } 742 743 static uint32_t vof_release(Vof *vof, uint64_t virt, uint64_t size) 744 { 745 uint32_t ret = PROM_ERROR; 746 int i; 747 GArray *claimed = vof->claimed; 748 OfClaimed c; 749 750 for (i = 0; i < claimed->len; ++i) { 751 c = g_array_index(claimed, OfClaimed, i); 752 if (c.start == virt && c.size == size) { 753 g_array_remove_index(claimed, i); 754 ret = 0; 755 break; 756 } 757 } 758 759 trace_vof_release(virt, size, ret); 760 761 return ret; 762 } 763 764 static void vof_instantiate_rtas(Error **errp) 765 { 766 error_setg(errp, "The firmware should have instantiated RTAS"); 767 } 768 769 static uint32_t vof_call_method(MachineState *ms, Vof *vof, uint32_t methodaddr, 770 uint32_t ihandle, uint32_t param1, 771 uint32_t param2, uint32_t param3, 772 uint32_t param4, uint32_t *ret2) 773 { 774 uint32_t ret = PROM_ERROR; 775 char method[VOF_MAX_METHODLEN] = ""; 776 OfInstance *inst; 777 778 if (!ihandle) { 779 goto trace_exit; 780 } 781 782 inst = (OfInstance *)g_hash_table_lookup(vof->of_instances, 783 GINT_TO_POINTER(ihandle)); 784 if (!inst) { 785 goto trace_exit; 786 } 787 788 if (readstr(methodaddr, method, sizeof(method))) { 789 goto trace_exit; 790 } 791 792 if (strcmp(inst->path, "/") == 0) { 793 if (strcmp(method, "ibm,client-architecture-support") == 0) { 794 Object *vmo = object_dynamic_cast(OBJECT(ms), TYPE_VOF_MACHINE_IF); 795 796 if (vmo) { 797 VofMachineIfClass *vmc = VOF_MACHINE_GET_CLASS(vmo); 798 799 g_assert(vmc->client_architecture_support); 800 ret = (uint32_t)vmc->client_architecture_support(ms, first_cpu, 801 param1); 802 } 803 804 *ret2 = 0; 805 } 806 } else if (strcmp(inst->path, "/rtas") == 0) { 807 if (strcmp(method, "instantiate-rtas") == 0) { 808 vof_instantiate_rtas(&error_fatal); 809 ret = 0; 810 *ret2 = param1; /* rtas-base */ 811 } 812 } else { 813 trace_vof_error_unknown_method(method); 814 } 815 816 trace_exit: 817 trace_vof_method(ihandle, method, param1, ret, *ret2); 818 819 return ret; 820 } 821 822 static uint32_t vof_call_interpret(uint32_t cmdaddr, uint32_t param1, 823 uint32_t param2, uint32_t *ret2) 824 { 825 uint32_t ret = PROM_ERROR; 826 char cmd[VOF_MAX_FORTHCODE] = ""; 827 828 /* No interpret implemented so just call a trace */ 829 readstr(cmdaddr, cmd, sizeof(cmd)); 830 trace_vof_interpret(cmd, param1, param2, ret, *ret2); 831 832 return ret; 833 } 834 835 static void vof_quiesce(MachineState *ms, void *fdt, Vof *vof) 836 { 837 Object *vmo = object_dynamic_cast(OBJECT(ms), TYPE_VOF_MACHINE_IF); 838 /* After "quiesce", no change is expected to the FDT, pack FDT to ensure */ 839 int rc = fdt_pack(fdt); 840 841 assert(rc == 0); 842 843 if (vmo) { 844 VofMachineIfClass *vmc = VOF_MACHINE_GET_CLASS(vmo); 845 846 if (vmc->quiesce) { 847 vmc->quiesce(ms); 848 } 849 } 850 851 vof_claimed_dump(vof->claimed); 852 } 853 854 static uint32_t vof_client_handle(MachineState *ms, void *fdt, Vof *vof, 855 const char *service, 856 uint32_t *args, unsigned nargs, 857 uint32_t *rets, unsigned nrets) 858 { 859 uint32_t ret = 0; 860 861 /* @nrets includes the value which this function returns */ 862 #define cmpserv(s, a, r) \ 863 cmpservice(service, nargs, nrets, (s), (a), (r)) 864 865 if (cmpserv("finddevice", 1, 1)) { 866 ret = vof_finddevice(fdt, args[0]); 867 } else if (cmpserv("getprop", 4, 1)) { 868 ret = vof_getprop(fdt, args[0], args[1], args[2], args[3]); 869 } else if (cmpserv("getproplen", 2, 1)) { 870 ret = vof_getproplen(fdt, args[0], args[1]); 871 } else if (cmpserv("setprop", 4, 1)) { 872 ret = vof_setprop(ms, fdt, vof, args[0], args[1], args[2], args[3]); 873 } else if (cmpserv("nextprop", 3, 1)) { 874 ret = vof_nextprop(fdt, args[0], args[1], args[2]); 875 } else if (cmpserv("peer", 1, 1)) { 876 ret = vof_peer(fdt, args[0]); 877 } else if (cmpserv("child", 1, 1)) { 878 ret = vof_child(fdt, args[0]); 879 } else if (cmpserv("parent", 1, 1)) { 880 ret = vof_parent(fdt, args[0]); 881 } else if (cmpserv("open", 1, 1)) { 882 ret = vof_open(fdt, vof, args[0]); 883 } else if (cmpserv("close", 1, 0)) { 884 vof_close(vof, args[0]); 885 } else if (cmpserv("instance-to-package", 1, 1)) { 886 ret = vof_instance_to_package(vof, args[0]); 887 } else if (cmpserv("package-to-path", 3, 1)) { 888 ret = vof_package_to_path(fdt, args[0], args[1], args[2]); 889 } else if (cmpserv("instance-to-path", 3, 1)) { 890 ret = vof_instance_to_path(fdt, vof, args[0], args[1], args[2]); 891 } else if (cmpserv("write", 3, 1)) { 892 ret = vof_write(vof, args[0], args[1], args[2]); 893 } else if (cmpserv("claim", 3, 1)) { 894 uint64_t ret64 = vof_claim(vof, args[0], args[1], args[2]); 895 896 if (ret64 < 0x100000000UL) { 897 vof_dt_memory_available(fdt, vof->claimed, vof->claimed_base); 898 ret = (uint32_t)ret64; 899 } else { 900 if (ret64 != -1) { 901 vof_release(vof, ret, args[1]); 902 } 903 ret = PROM_ERROR; 904 } 905 } else if (cmpserv("release", 2, 0)) { 906 ret = vof_release(vof, args[0], args[1]); 907 if (ret != PROM_ERROR) { 908 vof_dt_memory_available(fdt, vof->claimed, vof->claimed_base); 909 } 910 } else if (cmpserv("call-method", 0, 0)) { 911 ret = vof_call_method(ms, vof, args[0], args[1], args[2], args[3], 912 args[4], args[5], rets); 913 } else if (cmpserv("interpret", 0, 0)) { 914 ret = vof_call_interpret(args[0], args[1], args[2], rets); 915 } else if (cmpserv("milliseconds", 0, 1)) { 916 ret = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL); 917 } else if (cmpserv("quiesce", 0, 0)) { 918 vof_quiesce(ms, fdt, vof); 919 } else if (cmpserv("exit", 0, 0)) { 920 error_report("Stopped as the VM requested \"exit\""); 921 vm_stop(RUN_STATE_PAUSED); 922 } else { 923 trace_vof_error_unknown_service(service, nargs, nrets); 924 ret = -1; 925 } 926 927 #undef cmpserv 928 929 return ret; 930 } 931 932 /* Defined as Big Endian */ 933 struct prom_args { 934 uint32_t service; 935 uint32_t nargs; 936 uint32_t nret; 937 uint32_t args[10]; 938 } QEMU_PACKED; 939 940 int vof_client_call(MachineState *ms, Vof *vof, void *fdt, 941 target_ulong args_real) 942 { 943 struct prom_args args_be; 944 uint32_t args[ARRAY_SIZE(args_be.args)]; 945 uint32_t rets[ARRAY_SIZE(args_be.args)] = { 0 }, ret; 946 char service[64]; 947 unsigned nargs, nret, i; 948 949 if (VOF_MEM_READ(args_real, &args_be, sizeof(args_be)) != MEMTX_OK) { 950 return -EINVAL; 951 } 952 nargs = be32_to_cpu(args_be.nargs); 953 if (nargs >= ARRAY_SIZE(args_be.args)) { 954 return -EINVAL; 955 } 956 957 if (VOF_MEM_READ(be32_to_cpu(args_be.service), service, sizeof(service)) != 958 MEMTX_OK) { 959 return -EINVAL; 960 } 961 if (strnlen(service, sizeof(service)) == sizeof(service)) { 962 /* Too long service name */ 963 return -EINVAL; 964 } 965 966 for (i = 0; i < nargs; ++i) { 967 args[i] = be32_to_cpu(args_be.args[i]); 968 } 969 970 nret = be32_to_cpu(args_be.nret); 971 if (nret > ARRAY_SIZE(args_be.args) - nargs) { 972 return -EINVAL; 973 } 974 ret = vof_client_handle(ms, fdt, vof, service, args, nargs, rets, nret); 975 if (!nret) { 976 return 0; 977 } 978 979 /* @nrets includes the value which this function returns */ 980 args_be.args[nargs] = cpu_to_be32(ret); 981 for (i = 1; i < nret; ++i) { 982 args_be.args[nargs + i] = cpu_to_be32(rets[i - 1]); 983 } 984 985 if (VOF_MEM_WRITE(args_real + offsetof(struct prom_args, args[nargs]), 986 args_be.args + nargs, sizeof(args_be.args[0]) * nret) != 987 MEMTX_OK) { 988 return -EINVAL; 989 } 990 991 return 0; 992 } 993 994 static void vof_instance_free(gpointer data) 995 { 996 OfInstance *inst = (OfInstance *)data; 997 998 g_free(inst->path); 999 g_free(inst); 1000 } 1001 1002 void vof_init(Vof *vof, uint64_t top_addr, Error **errp) 1003 { 1004 vof_cleanup(vof); 1005 1006 vof->of_instances = g_hash_table_new_full(g_direct_hash, g_direct_equal, 1007 NULL, vof_instance_free); 1008 vof->claimed = g_array_new(false, false, sizeof(OfClaimed)); 1009 1010 /* Keep allocations in 32bit as CLI ABI can only return cells==32bit */ 1011 vof->top_addr = MIN(top_addr, 4 * GiB); 1012 if (vof_claim(vof, 0, vof->fw_size, 0) == -1) { 1013 error_setg(errp, "Memory for firmware is in use"); 1014 } 1015 } 1016 1017 void vof_cleanup(Vof *vof) 1018 { 1019 if (vof->claimed) { 1020 g_array_unref(vof->claimed); 1021 } 1022 if (vof->of_instances) { 1023 g_hash_table_unref(vof->of_instances); 1024 } 1025 vof->claimed = NULL; 1026 vof->of_instances = NULL; 1027 } 1028 1029 void vof_build_dt(void *fdt, Vof *vof) 1030 { 1031 uint32_t phandle = fdt_get_max_phandle(fdt); 1032 int offset, proplen = 0; 1033 const void *prop; 1034 1035 /* Assign phandles to nodes without predefined phandles (like XICS/XIVE) */ 1036 for (offset = fdt_next_node(fdt, -1, NULL); 1037 offset >= 0; 1038 offset = fdt_next_node(fdt, offset, NULL)) { 1039 prop = fdt_getprop(fdt, offset, "phandle", &proplen); 1040 if (prop) { 1041 continue; 1042 } 1043 ++phandle; 1044 _FDT(fdt_setprop_cell(fdt, offset, "phandle", phandle)); 1045 } 1046 1047 vof_dt_memory_available(fdt, vof->claimed, vof->claimed_base); 1048 } 1049 1050 static const TypeInfo vof_machine_if_info = { 1051 .name = TYPE_VOF_MACHINE_IF, 1052 .parent = TYPE_INTERFACE, 1053 .class_size = sizeof(VofMachineIfClass), 1054 }; 1055 1056 static void vof_machine_if_register_types(void) 1057 { 1058 type_register_static(&vof_machine_if_info); 1059 } 1060 type_init(vof_machine_if_register_types) 1061