xref: /openbmc/qemu/hw/ppc/vof.c (revision 6016b7b4)
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 
41 typedef struct {
42     uint64_t start;
43     uint64_t size;
44 } OfClaimed;
45 
46 typedef struct {
47     char *path; /* the path used to open the instance */
48     uint32_t phandle;
49 } OfInstance;
50 
51 static 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 
64 static 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 
79 static 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 
109 static 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 
123 static 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 
135 static 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 
160 static 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 
178 static 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 
220 static 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 
269 static 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 
294 static 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 
347 trace_exit:
348     trace_vof_setprop(nodeph, propname, trval, vallen, ret);
349 
350     return ret;
351 }
352 
353 static 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 
389 static 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 
407 static 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 
419 static 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 
431 static 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 
452 trace_exit:
453     trace_vof_open(path, inst ? inst->phandle : 0, ret);
454 
455     return ret;
456 }
457 
458 uint32_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 
475 static 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 
493 static 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 
500 static 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 
514 static 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 
532 static 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 
552 static 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 
582 static 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 
597 static 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 
612 static 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 
621 static gint of_claimed_compare_func(gconstpointer a, gconstpointer b)
622 {
623     return ((OfClaimed *)a)->start - ((OfClaimed *)b)->start;
624 }
625 
626 static 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  */
708 uint64_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 
745 static 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 
766 static void vof_instantiate_rtas(Error **errp)
767 {
768     error_setg(errp, "The firmware should have instantiated RTAS");
769 }
770 
771 static 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 
818 trace_exit:
819     trace_vof_method(ihandle, method, param1, ret, *ret2);
820 
821     return ret;
822 }
823 
824 static 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 
837 static 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 
856 static 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 */
935 struct prom_args {
936     uint32_t service;
937     uint32_t nargs;
938     uint32_t nret;
939     uint32_t args[10];
940 } QEMU_PACKED;
941 
942 int 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 
996 static void vof_instance_free(gpointer data)
997 {
998     OfInstance *inst = (OfInstance *)data;
999 
1000     g_free(inst->path);
1001     g_free(inst);
1002 }
1003 
1004 void 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 
1019 void 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 
1031 void 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 
1052 static const TypeInfo vof_machine_if_info = {
1053     .name = TYPE_VOF_MACHINE_IF,
1054     .parent = TYPE_INTERFACE,
1055     .class_size = sizeof(VofMachineIfClass),
1056 };
1057 
1058 static void vof_machine_if_register_types(void)
1059 {
1060     type_register_static(&vof_machine_if_info);
1061 }
1062 type_init(vof_machine_if_register_types)
1063