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