xref: /openbmc/qemu/hw/ppc/vof.c (revision 2b74dd91)
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 = ldq_be_p(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     vof->of_instance_last = 0;
1028     vof->claimed_base = 0;
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