qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

vof.c (29053B)


      1 /*
      2  * QEMU PowerPC Virtual Open Firmware.
      3  *
      4  * This implements client interface from OpenFirmware IEEE1275 on the QEMU
      5  * side to leave only a very basic firmware in the VM.
      6  *
      7  * Copyright (c) 2021 IBM Corporation.
      8  *
      9  * SPDX-License-Identifier: GPL-2.0-or-later
     10  */
     11 
     12 #include "qemu/osdep.h"
     13 #include "qemu/timer.h"
     14 #include "qemu/range.h"
     15 #include "qemu/units.h"
     16 #include "qemu/log.h"
     17 #include "qapi/error.h"
     18 #include "exec/address-spaces.h"
     19 #include "hw/ppc/vof.h"
     20 #include "hw/ppc/fdt.h"
     21 #include "sysemu/runstate.h"
     22 #include "qom/qom-qobject.h"
     23 #include "trace.h"
     24 
     25 #include <libfdt.h>
     26 
     27 /*
     28  * OF 1275 "nextprop" description suggests is it 32 bytes max but
     29  * LoPAPR defines "ibm,query-interrupt-source-number" which is 33 chars long.
     30  */
     31 #define OF_PROPNAME_LEN_MAX 64
     32 
     33 #define VOF_MAX_PATH        256
     34 #define VOF_MAX_SETPROPLEN  2048
     35 #define VOF_MAX_METHODLEN   256
     36 #define VOF_MAX_FORTHCODE   256
     37 #define VOF_VTY_BUF_SIZE    256
     38 
     39 typedef struct {
     40     uint64_t start;
     41     uint64_t size;
     42 } OfClaimed;
     43 
     44 typedef struct {
     45     char *path; /* the path used to open the instance */
     46     uint32_t phandle;
     47 } OfInstance;
     48 
     49 static int readstr(hwaddr pa, char *buf, int size)
     50 {
     51     if (VOF_MEM_READ(pa, buf, size) != MEMTX_OK) {
     52         return -1;
     53     }
     54     if (strnlen(buf, size) == size) {
     55         buf[size - 1] = '\0';
     56         trace_vof_error_str_truncated(buf, size);
     57         return -1;
     58     }
     59     return 0;
     60 }
     61 
     62 static bool cmpservice(const char *s, unsigned nargs, unsigned nret,
     63                        const char *s1, unsigned nargscheck, unsigned nretcheck)
     64 {
     65     if (strcmp(s, s1)) {
     66         return false;
     67     }
     68     if ((nargscheck && (nargs != nargscheck)) ||
     69         (nretcheck && (nret != nretcheck))) {
     70         trace_vof_error_param(s, nargscheck, nretcheck, nargs, nret);
     71         return false;
     72     }
     73 
     74     return true;
     75 }
     76 
     77 static void prop_format(char *tval, int tlen, const void *prop, int len)
     78 {
     79     int i;
     80     const unsigned char *c;
     81     char *t;
     82     const char bin[] = "...";
     83 
     84     for (i = 0, c = prop; i < len; ++i, ++c) {
     85         if (*c == '\0' && i == len - 1) {
     86             strncpy(tval, prop, tlen - 1);
     87             return;
     88         }
     89         if (*c < 0x20 || *c >= 0x80) {
     90             break;
     91         }
     92     }
     93 
     94     for (i = 0, c = prop, t = tval; i < len; ++i, ++c) {
     95         if (t >= tval + tlen - sizeof(bin) - 1 - 2 - 1) {
     96             strcpy(t, bin);
     97             return;
     98         }
     99         if (i && i % 4 == 0 && i != len - 1) {
    100             strcat(t, " ");
    101             ++t;
    102         }
    103         t += sprintf(t, "%02X", *c & 0xFF);
    104     }
    105 }
    106 
    107 static int get_path(const void *fdt, int offset, char *buf, int len)
    108 {
    109     int ret;
    110 
    111     ret = fdt_get_path(fdt, offset, buf, len - 1);
    112     if (ret < 0) {
    113         return ret;
    114     }
    115 
    116     buf[len - 1] = '\0';
    117 
    118     return strlen(buf) + 1;
    119 }
    120 
    121 static int phandle_to_path(const void *fdt, uint32_t ph, char *buf, int len)
    122 {
    123     int ret;
    124 
    125     ret = fdt_node_offset_by_phandle(fdt, ph);
    126     if (ret < 0) {
    127         return ret;
    128     }
    129 
    130     return get_path(fdt, ret, buf, len);
    131 }
    132 
    133 static int path_offset(const void *fdt, const char *path)
    134 {
    135     g_autofree char *p = NULL;
    136     char *at;
    137 
    138     /*
    139      * https://www.devicetree.org/open-firmware/bindings/ppc/release/ppc-2_1.html#HDR16
    140      *
    141      * "Conversion from numeric representation to text representation shall use
    142      * the lower case forms of the hexadecimal digits in the range a..f,
    143      * suppressing leading zeros".
    144      */
    145     p = g_strdup(path);
    146     for (at = strchr(p, '@'); at && *at; ) {
    147             if (*at == '/') {
    148                 at = strchr(at, '@');
    149             } else {
    150                 *at = tolower(*at);
    151                 ++at;
    152             }
    153     }
    154 
    155     return fdt_path_offset(fdt, p);
    156 }
    157 
    158 static uint32_t vof_finddevice(const void *fdt, uint32_t nodeaddr)
    159 {
    160     char fullnode[VOF_MAX_PATH];
    161     uint32_t ret = PROM_ERROR;
    162     int offset;
    163 
    164     if (readstr(nodeaddr, fullnode, sizeof(fullnode))) {
    165         return (uint32_t) ret;
    166     }
    167 
    168     offset = path_offset(fdt, fullnode);
    169     if (offset >= 0) {
    170         ret = fdt_get_phandle(fdt, offset);
    171     }
    172     trace_vof_finddevice(fullnode, ret);
    173     return ret;
    174 }
    175 
    176 static const void *getprop(const void *fdt, int nodeoff, const char *propname,
    177                            int *proplen, bool *write0)
    178 {
    179     const char *unit, *prop;
    180     const void *ret = fdt_getprop(fdt, nodeoff, propname, proplen);
    181 
    182     if (ret) {
    183         if (write0) {
    184             *write0 = false;
    185         }
    186         return ret;
    187     }
    188 
    189     if (strcmp(propname, "name")) {
    190         return NULL;
    191     }
    192     /*
    193      * We return a value for "name" from path if queried but property does not
    194      * exist. @proplen does not include the unit part in this case.
    195      */
    196     prop = fdt_get_name(fdt, nodeoff, proplen);
    197     if (!prop) {
    198         *proplen = 0;
    199         return NULL;
    200     }
    201 
    202     unit = memchr(prop, '@', *proplen);
    203     if (unit) {
    204         *proplen = unit - prop;
    205     }
    206     *proplen += 1;
    207 
    208     /*
    209      * Since it might be cut at "@" and there will be no trailing zero
    210      * in the prop buffer, tell the caller to write zero at the end.
    211      */
    212     if (write0) {
    213         *write0 = true;
    214     }
    215     return prop;
    216 }
    217 
    218 static uint32_t vof_getprop(const void *fdt, uint32_t nodeph, uint32_t pname,
    219                             uint32_t valaddr, uint32_t vallen)
    220 {
    221     char propname[OF_PROPNAME_LEN_MAX + 1];
    222     uint32_t ret = 0;
    223     int proplen = 0;
    224     const void *prop;
    225     char trval[64] = "";
    226     int nodeoff = fdt_node_offset_by_phandle(fdt, nodeph);
    227     bool write0;
    228 
    229     if (nodeoff < 0) {
    230         return PROM_ERROR;
    231     }
    232     if (readstr(pname, propname, sizeof(propname))) {
    233         return PROM_ERROR;
    234     }
    235     prop = getprop(fdt, nodeoff, propname, &proplen, &write0);
    236     if (prop) {
    237         const char zero = 0;
    238         int cb = MIN(proplen, vallen);
    239 
    240         if (VOF_MEM_WRITE(valaddr, prop, cb) != MEMTX_OK ||
    241             /* if that was "name" with a unit address, overwrite '@' with '0' */
    242             (write0 &&
    243              cb == proplen &&
    244              VOF_MEM_WRITE(valaddr + cb - 1, &zero, 1) != MEMTX_OK)) {
    245             ret = PROM_ERROR;
    246         } else {
    247             /*
    248              * OF1275 says:
    249              * "Size is either the actual size of the property, or -1 if name
    250              * does not exist", hence returning proplen instead of cb.
    251              */
    252             ret = proplen;
    253             /* Do not format a value if tracepoint is silent, for performance */
    254             if (trace_event_get_state(TRACE_VOF_GETPROP) &&
    255                 qemu_loglevel_mask(LOG_TRACE)) {
    256                 prop_format(trval, sizeof(trval), prop, ret);
    257             }
    258         }
    259     } else {
    260         ret = PROM_ERROR;
    261     }
    262     trace_vof_getprop(nodeph, propname, ret, trval);
    263 
    264     return ret;
    265 }
    266 
    267 static uint32_t vof_getproplen(const void *fdt, uint32_t nodeph, uint32_t pname)
    268 {
    269     char propname[OF_PROPNAME_LEN_MAX + 1];
    270     uint32_t ret = 0;
    271     int proplen = 0;
    272     const void *prop;
    273     int nodeoff = fdt_node_offset_by_phandle(fdt, nodeph);
    274 
    275     if (nodeoff < 0) {
    276         return PROM_ERROR;
    277     }
    278     if (readstr(pname, propname, sizeof(propname))) {
    279         return PROM_ERROR;
    280     }
    281     prop = getprop(fdt, nodeoff, propname, &proplen, NULL);
    282     if (prop) {
    283         ret = proplen;
    284     } else {
    285         ret = PROM_ERROR;
    286     }
    287     trace_vof_getproplen(nodeph, propname, ret);
    288 
    289     return ret;
    290 }
    291 
    292 static uint32_t vof_setprop(MachineState *ms, void *fdt, Vof *vof,
    293                             uint32_t nodeph, uint32_t pname,
    294                             uint32_t valaddr, uint32_t vallen)
    295 {
    296     char propname[OF_PROPNAME_LEN_MAX + 1] = "";
    297     uint32_t ret = PROM_ERROR;
    298     int offset, rc;
    299     char trval[64] = "";
    300     char nodepath[VOF_MAX_PATH] = "";
    301     Object *vmo = object_dynamic_cast(OBJECT(ms), TYPE_VOF_MACHINE_IF);
    302     VofMachineIfClass *vmc;
    303     g_autofree char *val = NULL;
    304 
    305     if (vallen > VOF_MAX_SETPROPLEN) {
    306         goto trace_exit;
    307     }
    308     if (readstr(pname, propname, sizeof(propname))) {
    309         goto trace_exit;
    310     }
    311     offset = fdt_node_offset_by_phandle(fdt, nodeph);
    312     if (offset < 0) {
    313         goto trace_exit;
    314     }
    315     rc = get_path(fdt, offset, nodepath, sizeof(nodepath));
    316     if (rc <= 0) {
    317         goto trace_exit;
    318     }
    319 
    320     val = g_malloc0(vallen);
    321     if (VOF_MEM_READ(valaddr, val, vallen) != MEMTX_OK) {
    322         goto trace_exit;
    323     }
    324 
    325     if (!vmo) {
    326         goto trace_exit;
    327     }
    328 
    329     vmc = VOF_MACHINE_GET_CLASS(vmo);
    330     if (!vmc->setprop || !vmc->setprop(ms, nodepath, propname, val, vallen)) {
    331         goto trace_exit;
    332     }
    333 
    334     rc = fdt_setprop(fdt, offset, propname, val, vallen);
    335     if (rc) {
    336         goto trace_exit;
    337     }
    338 
    339     if (trace_event_get_state(TRACE_VOF_SETPROP) &&
    340         qemu_loglevel_mask(LOG_TRACE)) {
    341         prop_format(trval, sizeof(trval), val, vallen);
    342     }
    343     ret = vallen;
    344 
    345 trace_exit:
    346     trace_vof_setprop(nodeph, propname, trval, vallen, ret);
    347 
    348     return ret;
    349 }
    350 
    351 static uint32_t vof_nextprop(const void *fdt, uint32_t phandle,
    352                              uint32_t prevaddr, uint32_t nameaddr)
    353 {
    354     int offset, nodeoff = fdt_node_offset_by_phandle(fdt, phandle);
    355     char prev[OF_PROPNAME_LEN_MAX + 1];
    356     const char *tmp;
    357 
    358     if (readstr(prevaddr, prev, sizeof(prev))) {
    359         return PROM_ERROR;
    360     }
    361 
    362     fdt_for_each_property_offset(offset, fdt, nodeoff) {
    363         if (!fdt_getprop_by_offset(fdt, offset, &tmp, NULL)) {
    364             return 0;
    365         }
    366         if (prev[0] == '\0' || strcmp(prev, tmp) == 0) {
    367             if (prev[0] != '\0') {
    368                 offset = fdt_next_property_offset(fdt, offset);
    369                 if (offset < 0) {
    370                     return 0;
    371                 }
    372             }
    373             if (!fdt_getprop_by_offset(fdt, offset, &tmp, NULL)) {
    374                 return 0;
    375             }
    376 
    377             if (VOF_MEM_WRITE(nameaddr, tmp, strlen(tmp) + 1) != MEMTX_OK) {
    378                 return PROM_ERROR;
    379             }
    380             return 1;
    381         }
    382     }
    383 
    384     return 0;
    385 }
    386 
    387 static uint32_t vof_peer(const void *fdt, uint32_t phandle)
    388 {
    389     uint32_t ret = 0;
    390     int rc;
    391 
    392     if (phandle == 0) {
    393         rc = fdt_path_offset(fdt, "/");
    394     } else {
    395         rc = fdt_next_subnode(fdt, fdt_node_offset_by_phandle(fdt, phandle));
    396     }
    397 
    398     if (rc >= 0) {
    399         ret = fdt_get_phandle(fdt, rc);
    400     }
    401 
    402     return ret;
    403 }
    404 
    405 static uint32_t vof_child(const void *fdt, uint32_t phandle)
    406 {
    407     uint32_t ret = 0;
    408     int rc = fdt_first_subnode(fdt, fdt_node_offset_by_phandle(fdt, phandle));
    409 
    410     if (rc >= 0) {
    411         ret = fdt_get_phandle(fdt, rc);
    412     }
    413 
    414     return ret;
    415 }
    416 
    417 static uint32_t vof_parent(const void *fdt, uint32_t phandle)
    418 {
    419     uint32_t ret = 0;
    420     int rc = fdt_parent_offset(fdt, fdt_node_offset_by_phandle(fdt, phandle));
    421 
    422     if (rc >= 0) {
    423         ret = fdt_get_phandle(fdt, rc);
    424     }
    425 
    426     return ret;
    427 }
    428 
    429 static uint32_t vof_do_open(void *fdt, Vof *vof, int offset, const char *path)
    430 {
    431     uint32_t ret = PROM_ERROR;
    432     OfInstance *inst = NULL;
    433 
    434     if (vof->of_instance_last == 0xFFFFFFFF) {
    435         /* We do not recycle ihandles yet */
    436         goto trace_exit;
    437     }
    438 
    439     inst = g_new0(OfInstance, 1);
    440     inst->phandle = fdt_get_phandle(fdt, offset);
    441     g_assert(inst->phandle);
    442     ++vof->of_instance_last;
    443 
    444     inst->path = g_strdup(path);
    445     g_hash_table_insert(vof->of_instances,
    446                         GINT_TO_POINTER(vof->of_instance_last),
    447                         inst);
    448     ret = vof->of_instance_last;
    449 
    450 trace_exit:
    451     trace_vof_open(path, inst ? inst->phandle : 0, ret);
    452 
    453     return ret;
    454 }
    455 
    456 uint32_t vof_client_open_store(void *fdt, Vof *vof, const char *nodename,
    457                                const char *prop, const char *path)
    458 {
    459     int offset, node = fdt_path_offset(fdt, nodename);
    460     uint32_t inst;
    461 
    462     offset = fdt_path_offset(fdt, path);
    463     if (offset < 0) {
    464         trace_vof_error_unknown_path(path);
    465         return PROM_ERROR;
    466     }
    467 
    468     inst = vof_do_open(fdt, vof, offset, path);
    469 
    470     return fdt_setprop_cell(fdt, node, prop, inst) >= 0 ? 0 : PROM_ERROR;
    471 }
    472 
    473 static uint32_t vof_open(void *fdt, Vof *vof, uint32_t pathaddr)
    474 {
    475     char path[VOF_MAX_PATH];
    476     int offset;
    477 
    478     if (readstr(pathaddr, path, sizeof(path))) {
    479         return PROM_ERROR;
    480     }
    481 
    482     offset = path_offset(fdt, path);
    483     if (offset < 0) {
    484         trace_vof_error_unknown_path(path);
    485         return PROM_ERROR;
    486     }
    487 
    488     return vof_do_open(fdt, vof, offset, path);
    489 }
    490 
    491 static void vof_close(Vof *vof, uint32_t ihandle)
    492 {
    493     if (!g_hash_table_remove(vof->of_instances, GINT_TO_POINTER(ihandle))) {
    494         trace_vof_error_unknown_ihandle_close(ihandle);
    495     }
    496 }
    497 
    498 static uint32_t vof_instance_to_package(Vof *vof, uint32_t ihandle)
    499 {
    500     gpointer instp = g_hash_table_lookup(vof->of_instances,
    501                                          GINT_TO_POINTER(ihandle));
    502     uint32_t ret = PROM_ERROR;
    503 
    504     if (instp) {
    505         ret = ((OfInstance *)instp)->phandle;
    506     }
    507     trace_vof_instance_to_package(ihandle, ret);
    508 
    509     return ret;
    510 }
    511 
    512 static uint32_t vof_package_to_path(const void *fdt, uint32_t phandle,
    513                                     uint32_t buf, uint32_t len)
    514 {
    515     int rc;
    516     char tmp[VOF_MAX_PATH] = "";
    517 
    518     rc = phandle_to_path(fdt, phandle, tmp, sizeof(tmp));
    519     if (rc > 0) {
    520         if (VOF_MEM_WRITE(buf, tmp, rc) != MEMTX_OK) {
    521             rc = -1;
    522         }
    523     }
    524 
    525     trace_vof_package_to_path(phandle, tmp, rc);
    526 
    527     return rc > 0 ? (uint32_t)rc : PROM_ERROR;
    528 }
    529 
    530 static uint32_t vof_instance_to_path(void *fdt, Vof *vof, uint32_t ihandle,
    531                                      uint32_t buf, uint32_t len)
    532 {
    533     int rc = -1;
    534     uint32_t phandle = vof_instance_to_package(vof, ihandle);
    535     char tmp[VOF_MAX_PATH] = "";
    536 
    537     if (phandle != -1) {
    538         rc = phandle_to_path(fdt, phandle, tmp, sizeof(tmp));
    539         if (rc > 0) {
    540             if (VOF_MEM_WRITE(buf, tmp, rc) != MEMTX_OK) {
    541                 rc = -1;
    542             }
    543         }
    544     }
    545     trace_vof_instance_to_path(ihandle, phandle, tmp, rc);
    546 
    547     return rc > 0 ? (uint32_t)rc : PROM_ERROR;
    548 }
    549 
    550 static uint32_t vof_write(Vof *vof, uint32_t ihandle, uint32_t buf,
    551                           uint32_t len)
    552 {
    553     char tmp[VOF_VTY_BUF_SIZE];
    554     unsigned cb;
    555     OfInstance *inst = (OfInstance *)
    556         g_hash_table_lookup(vof->of_instances, GINT_TO_POINTER(ihandle));
    557 
    558     if (!inst) {
    559         trace_vof_error_write(ihandle);
    560         return PROM_ERROR;
    561     }
    562 
    563     for ( ; len > 0; len -= cb) {
    564         cb = MIN(len, sizeof(tmp) - 1);
    565         if (VOF_MEM_READ(buf, tmp, cb) != MEMTX_OK) {
    566             return PROM_ERROR;
    567         }
    568 
    569         /* FIXME: there is no backend(s) yet so just call a trace */
    570         if (trace_event_get_state(TRACE_VOF_WRITE) &&
    571             qemu_loglevel_mask(LOG_TRACE)) {
    572             tmp[cb] = '\0';
    573             trace_vof_write(ihandle, cb, tmp);
    574         }
    575     }
    576 
    577     return len;
    578 }
    579 
    580 static void vof_claimed_dump(GArray *claimed)
    581 {
    582     int i;
    583     OfClaimed c;
    584 
    585     if (trace_event_get_state(TRACE_VOF_CLAIMED) &&
    586         qemu_loglevel_mask(LOG_TRACE)) {
    587 
    588         for (i = 0; i < claimed->len; ++i) {
    589             c = g_array_index(claimed, OfClaimed, i);
    590             trace_vof_claimed(c.start, c.start + c.size, c.size);
    591         }
    592     }
    593 }
    594 
    595 static bool vof_claim_avail(GArray *claimed, uint64_t virt, uint64_t size)
    596 {
    597     int i;
    598     OfClaimed c;
    599 
    600     for (i = 0; i < claimed->len; ++i) {
    601         c = g_array_index(claimed, OfClaimed, i);
    602         if (ranges_overlap(c.start, c.size, virt, size)) {
    603             return false;
    604         }
    605     }
    606 
    607     return true;
    608 }
    609 
    610 static void vof_claim_add(GArray *claimed, uint64_t virt, uint64_t size)
    611 {
    612     OfClaimed newclaim;
    613 
    614     newclaim.start = virt;
    615     newclaim.size = size;
    616     g_array_append_val(claimed, newclaim);
    617 }
    618 
    619 static gint of_claimed_compare_func(gconstpointer a, gconstpointer b)
    620 {
    621     return ((OfClaimed *)a)->start - ((OfClaimed *)b)->start;
    622 }
    623 
    624 static void vof_dt_memory_available(void *fdt, GArray *claimed, uint64_t base)
    625 {
    626     int i, n, offset, proplen = 0, sc, ac;
    627     target_ulong mem0_end;
    628     const uint8_t *mem0_reg;
    629     g_autofree uint8_t *avail = NULL;
    630     uint8_t *availcur;
    631 
    632     if (!fdt || !claimed) {
    633         return;
    634     }
    635 
    636     offset = fdt_path_offset(fdt, "/");
    637     _FDT(offset);
    638     ac = fdt_address_cells(fdt, offset);
    639     g_assert(ac == 1 || ac == 2);
    640     sc = fdt_size_cells(fdt, offset);
    641     g_assert(sc == 1 || sc == 2);
    642 
    643     offset = fdt_path_offset(fdt, "/memory@0");
    644     _FDT(offset);
    645 
    646     mem0_reg = fdt_getprop(fdt, offset, "reg", &proplen);
    647     g_assert(mem0_reg && proplen == sizeof(uint32_t) * (ac + sc));
    648     if (sc == 2) {
    649         mem0_end = be64_to_cpu(*(uint64_t *)(mem0_reg + sizeof(uint32_t) * ac));
    650     } else {
    651         mem0_end = be32_to_cpu(*(uint32_t *)(mem0_reg + sizeof(uint32_t) * ac));
    652     }
    653 
    654     g_array_sort(claimed, of_claimed_compare_func);
    655     vof_claimed_dump(claimed);
    656 
    657     /*
    658      * VOF resides in the first page so we do not need to check if there is
    659      * available memory before the first claimed block
    660      */
    661     g_assert(claimed->len && (g_array_index(claimed, OfClaimed, 0).start == 0));
    662 
    663     avail = g_malloc0(sizeof(uint32_t) * (ac + sc) * claimed->len);
    664     for (i = 0, n = 0, availcur = avail; i < claimed->len; ++i) {
    665         OfClaimed c = g_array_index(claimed, OfClaimed, i);
    666         uint64_t start, size;
    667 
    668         start = c.start + c.size;
    669         if (i < claimed->len - 1) {
    670             OfClaimed cn = g_array_index(claimed, OfClaimed, i + 1);
    671 
    672             size = cn.start - start;
    673         } else {
    674             size = mem0_end - start;
    675         }
    676 
    677         if (ac == 2) {
    678             *(uint64_t *) availcur = cpu_to_be64(start);
    679         } else {
    680             *(uint32_t *) availcur = cpu_to_be32(start);
    681         }
    682         availcur += sizeof(uint32_t) * ac;
    683         if (sc == 2) {
    684             *(uint64_t *) availcur = cpu_to_be64(size);
    685         } else {
    686             *(uint32_t *) availcur = cpu_to_be32(size);
    687         }
    688         availcur += sizeof(uint32_t) * sc;
    689 
    690         if (size) {
    691             trace_vof_avail(c.start + c.size, c.start + c.size + size, size);
    692             ++n;
    693         }
    694     }
    695     _FDT((fdt_setprop(fdt, offset, "available", avail, availcur - avail)));
    696 }
    697 
    698 /*
    699  * OF1275:
    700  * "Allocates size bytes of memory. If align is zero, the allocated range
    701  * begins at the virtual address virt. Otherwise, an aligned address is
    702  * automatically chosen and the input argument virt is ignored".
    703  *
    704  * In other words, exactly one of @virt and @align is non-zero.
    705  */
    706 uint64_t vof_claim(Vof *vof, uint64_t virt, uint64_t size,
    707                    uint64_t align)
    708 {
    709     uint64_t ret;
    710 
    711     if (size == 0) {
    712         ret = -1;
    713     } else if (align == 0) {
    714         if (!vof_claim_avail(vof->claimed, virt, size)) {
    715             ret = -1;
    716         } else {
    717             ret = virt;
    718         }
    719     } else {
    720         vof->claimed_base = QEMU_ALIGN_UP(vof->claimed_base, align);
    721         while (1) {
    722             if (vof->claimed_base >= vof->top_addr) {
    723                 error_report("Out of RMA memory for the OF client");
    724                 return -1;
    725             }
    726             if (vof_claim_avail(vof->claimed, vof->claimed_base, size)) {
    727                 break;
    728             }
    729             vof->claimed_base += size;
    730         }
    731         ret = vof->claimed_base;
    732     }
    733 
    734     if (ret != -1) {
    735         vof->claimed_base = MAX(vof->claimed_base, ret + size);
    736         vof_claim_add(vof->claimed, ret, size);
    737     }
    738     trace_vof_claim(virt, size, align, ret);
    739 
    740     return ret;
    741 }
    742 
    743 static uint32_t vof_release(Vof *vof, uint64_t virt, uint64_t size)
    744 {
    745     uint32_t ret = PROM_ERROR;
    746     int i;
    747     GArray *claimed = vof->claimed;
    748     OfClaimed c;
    749 
    750     for (i = 0; i < claimed->len; ++i) {
    751         c = g_array_index(claimed, OfClaimed, i);
    752         if (c.start == virt && c.size == size) {
    753             g_array_remove_index(claimed, i);
    754             ret = 0;
    755             break;
    756         }
    757     }
    758 
    759     trace_vof_release(virt, size, ret);
    760 
    761     return ret;
    762 }
    763 
    764 static void vof_instantiate_rtas(Error **errp)
    765 {
    766     error_setg(errp, "The firmware should have instantiated RTAS");
    767 }
    768 
    769 static uint32_t vof_call_method(MachineState *ms, Vof *vof, uint32_t methodaddr,
    770                                 uint32_t ihandle, uint32_t param1,
    771                                 uint32_t param2, uint32_t param3,
    772                                 uint32_t param4, uint32_t *ret2)
    773 {
    774     uint32_t ret = PROM_ERROR;
    775     char method[VOF_MAX_METHODLEN] = "";
    776     OfInstance *inst;
    777 
    778     if (!ihandle) {
    779         goto trace_exit;
    780     }
    781 
    782     inst = (OfInstance *)g_hash_table_lookup(vof->of_instances,
    783                                              GINT_TO_POINTER(ihandle));
    784     if (!inst) {
    785         goto trace_exit;
    786     }
    787 
    788     if (readstr(methodaddr, method, sizeof(method))) {
    789         goto trace_exit;
    790     }
    791 
    792     if (strcmp(inst->path, "/") == 0) {
    793         if (strcmp(method, "ibm,client-architecture-support") == 0) {
    794             Object *vmo = object_dynamic_cast(OBJECT(ms), TYPE_VOF_MACHINE_IF);
    795 
    796             if (vmo) {
    797                 VofMachineIfClass *vmc = VOF_MACHINE_GET_CLASS(vmo);
    798 
    799                 g_assert(vmc->client_architecture_support);
    800                 ret = (uint32_t)vmc->client_architecture_support(ms, first_cpu,
    801                                                                  param1);
    802             }
    803 
    804             *ret2 = 0;
    805         }
    806     } else if (strcmp(inst->path, "/rtas") == 0) {
    807         if (strcmp(method, "instantiate-rtas") == 0) {
    808             vof_instantiate_rtas(&error_fatal);
    809             ret = 0;
    810             *ret2 = param1; /* rtas-base */
    811         }
    812     } else {
    813         trace_vof_error_unknown_method(method);
    814     }
    815 
    816 trace_exit:
    817     trace_vof_method(ihandle, method, param1, ret, *ret2);
    818 
    819     return ret;
    820 }
    821 
    822 static uint32_t vof_call_interpret(uint32_t cmdaddr, uint32_t param1,
    823                                    uint32_t param2, uint32_t *ret2)
    824 {
    825     uint32_t ret = PROM_ERROR;
    826     char cmd[VOF_MAX_FORTHCODE] = "";
    827 
    828     /* No interpret implemented so just call a trace */
    829     readstr(cmdaddr, cmd, sizeof(cmd));
    830     trace_vof_interpret(cmd, param1, param2, ret, *ret2);
    831 
    832     return ret;
    833 }
    834 
    835 static void vof_quiesce(MachineState *ms, void *fdt, Vof *vof)
    836 {
    837     Object *vmo = object_dynamic_cast(OBJECT(ms), TYPE_VOF_MACHINE_IF);
    838     /* After "quiesce", no change is expected to the FDT, pack FDT to ensure */
    839     int rc = fdt_pack(fdt);
    840 
    841     assert(rc == 0);
    842 
    843     if (vmo) {
    844         VofMachineIfClass *vmc = VOF_MACHINE_GET_CLASS(vmo);
    845 
    846         if (vmc->quiesce) {
    847             vmc->quiesce(ms);
    848         }
    849     }
    850 
    851     vof_claimed_dump(vof->claimed);
    852 }
    853 
    854 static uint32_t vof_client_handle(MachineState *ms, void *fdt, Vof *vof,
    855                                   const char *service,
    856                                   uint32_t *args, unsigned nargs,
    857                                   uint32_t *rets, unsigned nrets)
    858 {
    859     uint32_t ret = 0;
    860 
    861     /* @nrets includes the value which this function returns */
    862 #define cmpserv(s, a, r) \
    863     cmpservice(service, nargs, nrets, (s), (a), (r))
    864 
    865     if (cmpserv("finddevice", 1, 1)) {
    866         ret = vof_finddevice(fdt, args[0]);
    867     } else if (cmpserv("getprop", 4, 1)) {
    868         ret = vof_getprop(fdt, args[0], args[1], args[2], args[3]);
    869     } else if (cmpserv("getproplen", 2, 1)) {
    870         ret = vof_getproplen(fdt, args[0], args[1]);
    871     } else if (cmpserv("setprop", 4, 1)) {
    872         ret = vof_setprop(ms, fdt, vof, args[0], args[1], args[2], args[3]);
    873     } else if (cmpserv("nextprop", 3, 1)) {
    874         ret = vof_nextprop(fdt, args[0], args[1], args[2]);
    875     } else if (cmpserv("peer", 1, 1)) {
    876         ret = vof_peer(fdt, args[0]);
    877     } else if (cmpserv("child", 1, 1)) {
    878         ret = vof_child(fdt, args[0]);
    879     } else if (cmpserv("parent", 1, 1)) {
    880         ret = vof_parent(fdt, args[0]);
    881     } else if (cmpserv("open", 1, 1)) {
    882         ret = vof_open(fdt, vof, args[0]);
    883     } else if (cmpserv("close", 1, 0)) {
    884         vof_close(vof, args[0]);
    885     } else if (cmpserv("instance-to-package", 1, 1)) {
    886         ret = vof_instance_to_package(vof, args[0]);
    887     } else if (cmpserv("package-to-path", 3, 1)) {
    888         ret = vof_package_to_path(fdt, args[0], args[1], args[2]);
    889     } else if (cmpserv("instance-to-path", 3, 1)) {
    890         ret = vof_instance_to_path(fdt, vof, args[0], args[1], args[2]);
    891     } else if (cmpserv("write", 3, 1)) {
    892         ret = vof_write(vof, args[0], args[1], args[2]);
    893     } else if (cmpserv("claim", 3, 1)) {
    894         uint64_t ret64 = vof_claim(vof, args[0], args[1], args[2]);
    895 
    896         if (ret64 < 0x100000000UL) {
    897             vof_dt_memory_available(fdt, vof->claimed, vof->claimed_base);
    898             ret = (uint32_t)ret64;
    899         } else {
    900             if (ret64 != -1) {
    901                 vof_release(vof, ret, args[1]);
    902             }
    903             ret = PROM_ERROR;
    904         }
    905     } else if (cmpserv("release", 2, 0)) {
    906         ret = vof_release(vof, args[0], args[1]);
    907         if (ret != PROM_ERROR) {
    908             vof_dt_memory_available(fdt, vof->claimed, vof->claimed_base);
    909         }
    910     } else if (cmpserv("call-method", 0, 0)) {
    911         ret = vof_call_method(ms, vof, args[0], args[1], args[2], args[3],
    912                               args[4], args[5], rets);
    913     } else if (cmpserv("interpret", 0, 0)) {
    914         ret = vof_call_interpret(args[0], args[1], args[2], rets);
    915     } else if (cmpserv("milliseconds", 0, 1)) {
    916         ret = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL);
    917     } else if (cmpserv("quiesce", 0, 0)) {
    918         vof_quiesce(ms, fdt, vof);
    919     } else if (cmpserv("exit", 0, 0)) {
    920         error_report("Stopped as the VM requested \"exit\"");
    921         vm_stop(RUN_STATE_PAUSED);
    922     } else {
    923         trace_vof_error_unknown_service(service, nargs, nrets);
    924         ret = -1;
    925     }
    926 
    927 #undef cmpserv
    928 
    929     return ret;
    930 }
    931 
    932 /* Defined as Big Endian */
    933 struct prom_args {
    934     uint32_t service;
    935     uint32_t nargs;
    936     uint32_t nret;
    937     uint32_t args[10];
    938 } QEMU_PACKED;
    939 
    940 int vof_client_call(MachineState *ms, Vof *vof, void *fdt,
    941                     target_ulong args_real)
    942 {
    943     struct prom_args args_be;
    944     uint32_t args[ARRAY_SIZE(args_be.args)];
    945     uint32_t rets[ARRAY_SIZE(args_be.args)] = { 0 }, ret;
    946     char service[64];
    947     unsigned nargs, nret, i;
    948 
    949     if (VOF_MEM_READ(args_real, &args_be, sizeof(args_be)) != MEMTX_OK) {
    950         return -EINVAL;
    951     }
    952     nargs = be32_to_cpu(args_be.nargs);
    953     if (nargs >= ARRAY_SIZE(args_be.args)) {
    954         return -EINVAL;
    955     }
    956 
    957     if (VOF_MEM_READ(be32_to_cpu(args_be.service), service, sizeof(service)) !=
    958         MEMTX_OK) {
    959         return -EINVAL;
    960     }
    961     if (strnlen(service, sizeof(service)) == sizeof(service)) {
    962         /* Too long service name */
    963         return -EINVAL;
    964     }
    965 
    966     for (i = 0; i < nargs; ++i) {
    967         args[i] = be32_to_cpu(args_be.args[i]);
    968     }
    969 
    970     nret = be32_to_cpu(args_be.nret);
    971     if (nret > ARRAY_SIZE(args_be.args) - nargs) {
    972         return -EINVAL;
    973     }
    974     ret = vof_client_handle(ms, fdt, vof, service, args, nargs, rets, nret);
    975     if (!nret) {
    976         return 0;
    977     }
    978 
    979     /* @nrets includes the value which this function returns */
    980     args_be.args[nargs] = cpu_to_be32(ret);
    981     for (i = 1; i < nret; ++i) {
    982         args_be.args[nargs + i] = cpu_to_be32(rets[i - 1]);
    983     }
    984 
    985     if (VOF_MEM_WRITE(args_real + offsetof(struct prom_args, args[nargs]),
    986                       args_be.args + nargs, sizeof(args_be.args[0]) * nret) !=
    987         MEMTX_OK) {
    988         return -EINVAL;
    989     }
    990 
    991     return 0;
    992 }
    993 
    994 static void vof_instance_free(gpointer data)
    995 {
    996     OfInstance *inst = (OfInstance *)data;
    997 
    998     g_free(inst->path);
    999     g_free(inst);
   1000 }
   1001 
   1002 void vof_init(Vof *vof, uint64_t top_addr, Error **errp)
   1003 {
   1004     vof_cleanup(vof);
   1005 
   1006     vof->of_instances = g_hash_table_new_full(g_direct_hash, g_direct_equal,
   1007                                               NULL, vof_instance_free);
   1008     vof->claimed = g_array_new(false, false, sizeof(OfClaimed));
   1009 
   1010     /* Keep allocations in 32bit as CLI ABI can only return cells==32bit */
   1011     vof->top_addr = MIN(top_addr, 4 * GiB);
   1012     if (vof_claim(vof, 0, vof->fw_size, 0) == -1) {
   1013         error_setg(errp, "Memory for firmware is in use");
   1014     }
   1015 }
   1016 
   1017 void vof_cleanup(Vof *vof)
   1018 {
   1019     if (vof->claimed) {
   1020         g_array_unref(vof->claimed);
   1021     }
   1022     if (vof->of_instances) {
   1023         g_hash_table_unref(vof->of_instances);
   1024     }
   1025     vof->claimed = NULL;
   1026     vof->of_instances = NULL;
   1027 }
   1028 
   1029 void vof_build_dt(void *fdt, Vof *vof)
   1030 {
   1031     uint32_t phandle = fdt_get_max_phandle(fdt);
   1032     int offset, proplen = 0;
   1033     const void *prop;
   1034 
   1035     /* Assign phandles to nodes without predefined phandles (like XICS/XIVE) */
   1036     for (offset = fdt_next_node(fdt, -1, NULL);
   1037          offset >= 0;
   1038          offset = fdt_next_node(fdt, offset, NULL)) {
   1039         prop = fdt_getprop(fdt, offset, "phandle", &proplen);
   1040         if (prop) {
   1041             continue;
   1042         }
   1043         ++phandle;
   1044         _FDT(fdt_setprop_cell(fdt, offset, "phandle", phandle));
   1045     }
   1046 
   1047     vof_dt_memory_available(fdt, vof->claimed, vof->claimed_base);
   1048 }
   1049 
   1050 static const TypeInfo vof_machine_if_info = {
   1051     .name = TYPE_VOF_MACHINE_IF,
   1052     .parent = TYPE_INTERFACE,
   1053     .class_size = sizeof(VofMachineIfClass),
   1054 };
   1055 
   1056 static void vof_machine_if_register_types(void)
   1057 {
   1058     type_register_static(&vof_machine_if_info);
   1059 }
   1060 type_init(vof_machine_if_register_types)