qemu/hw/ppc/vof.c
<<
>>
Prefs
   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
  39typedef struct {
  40    uint64_t start;
  41    uint64_t size;
  42} OfClaimed;
  43
  44typedef struct {
  45    char *path; /* the path used to open the instance */
  46    uint32_t phandle;
  47} OfInstance;
  48
  49static 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
  62static 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
  77static 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
 107static 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
 121static 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
 133static 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
 158static 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
 176static 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
 218static 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
 267static 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
 292static 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
 345trace_exit:
 346    trace_vof_setprop(nodeph, propname, trval, vallen, ret);
 347
 348    return ret;
 349}
 350
 351static 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
 387static 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
 405static 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
 417static 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
 429static 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
 450trace_exit:
 451    trace_vof_open(path, inst ? inst->phandle : 0, ret);
 452
 453    return ret;
 454}
 455
 456uint32_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
 473static 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
 491static 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
 498static 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
 512static 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
 530static 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
 550static 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
 580static 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
 595static 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
 610static 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
 619static gint of_claimed_compare_func(gconstpointer a, gconstpointer b)
 620{
 621    return ((OfClaimed *)a)->start - ((OfClaimed *)b)->start;
 622}
 623
 624static 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 */
 706uint64_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
 743static 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
 764static void vof_instantiate_rtas(Error **errp)
 765{
 766    error_setg(errp, "The firmware should have instantiated RTAS");
 767}
 768
 769static 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
 816trace_exit:
 817    trace_vof_method(ihandle, method, param1, ret, *ret2);
 818
 819    return ret;
 820}
 821
 822static 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
 835static 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
 854static 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 */
 933struct prom_args {
 934    uint32_t service;
 935    uint32_t nargs;
 936    uint32_t nret;
 937    uint32_t args[10];
 938} QEMU_PACKED;
 939
 940int 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
 994static void vof_instance_free(gpointer data)
 995{
 996    OfInstance *inst = (OfInstance *)data;
 997
 998    g_free(inst->path);
 999    g_free(inst);
1000}
1001
1002void 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
1017void 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
1029void 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
1050static const TypeInfo vof_machine_if_info = {
1051    .name = TYPE_VOF_MACHINE_IF,
1052    .parent = TYPE_INTERFACE,
1053    .class_size = sizeof(VofMachineIfClass),
1054};
1055
1056static void vof_machine_if_register_types(void)
1057{
1058    type_register_static(&vof_machine_if_info);
1059}
1060type_init(vof_machine_if_register_types)
1061