cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

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)