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-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)
1063