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