xref: /openbmc/qemu/hw/ppc/vof.c (revision d2cc2b1dfc35dc32a8ee2e12754c9afc10fc20b4)
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 "system/address-spaces.h"
19 #include "hw/ppc/vof.h"
20 #include "hw/ppc/fdt.h"
21 #include "system/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 = NULL;
357     bool match = false;
358 
359     if (readstr(prevaddr, prev, sizeof(prev))) {
360         return PROM_ERROR;
361     }
362     /*
363      * "name" may or may not be present in fdt but we should still return it.
364      * Do that first and then skip it if seen later.
365      */
366     if (prev[0] == '\0') {
367         tmp = "name";
368     } else {
369         if (strcmp(prev, "name") == 0) {
370             prev[0] = '\0';
371         }
372         fdt_for_each_property_offset(offset, fdt, nodeoff) {
373             if (!fdt_getprop_by_offset(fdt, offset, &tmp, NULL)) {
374                 return 0;
375             }
376             if (strcmp(tmp, "name") == 0) {
377                 continue;
378             }
379             if (match) {
380                 break;
381             }
382             if (strcmp(prev, tmp) == 0) {
383                 match = true;
384                 continue;
385             }
386             if (prev[0] == '\0') {
387                 break;
388             }
389         }
390         if (offset < 0) {
391             return 0;
392         }
393     }
394     if (tmp) {
395         if (VOF_MEM_WRITE(nameaddr, tmp, strlen(tmp) + 1) != MEMTX_OK) {
396             return PROM_ERROR;
397         }
398         return 1;
399     }
400     return 0;
401 }
402 
403 static uint32_t vof_peer(const void *fdt, uint32_t phandle)
404 {
405     uint32_t ret = 0;
406     int rc;
407 
408     if (phandle == 0) {
409         rc = fdt_path_offset(fdt, "/");
410     } else {
411         rc = fdt_next_subnode(fdt, fdt_node_offset_by_phandle(fdt, phandle));
412     }
413 
414     if (rc >= 0) {
415         ret = fdt_get_phandle(fdt, rc);
416     }
417 
418     return ret;
419 }
420 
421 static uint32_t vof_child(const void *fdt, uint32_t phandle)
422 {
423     uint32_t ret = 0;
424     int rc = fdt_first_subnode(fdt, fdt_node_offset_by_phandle(fdt, phandle));
425 
426     if (rc >= 0) {
427         ret = fdt_get_phandle(fdt, rc);
428     }
429 
430     return ret;
431 }
432 
433 static uint32_t vof_parent(const void *fdt, uint32_t phandle)
434 {
435     uint32_t ret = 0;
436     int rc = fdt_parent_offset(fdt, fdt_node_offset_by_phandle(fdt, phandle));
437 
438     if (rc >= 0) {
439         ret = fdt_get_phandle(fdt, rc);
440     }
441 
442     return ret;
443 }
444 
445 static uint32_t vof_do_open(void *fdt, Vof *vof, int offset, const char *path)
446 {
447     uint32_t ret = PROM_ERROR;
448     OfInstance *inst = NULL;
449 
450     if (vof->of_instance_last == 0xFFFFFFFF) {
451         /* We do not recycle ihandles yet */
452         goto trace_exit;
453     }
454 
455     inst = g_new0(OfInstance, 1);
456     inst->phandle = fdt_get_phandle(fdt, offset);
457     g_assert(inst->phandle);
458     ++vof->of_instance_last;
459 
460     inst->path = g_strdup(path);
461     g_hash_table_insert(vof->of_instances,
462                         GINT_TO_POINTER(vof->of_instance_last),
463                         inst);
464     ret = vof->of_instance_last;
465 
466 trace_exit:
467     trace_vof_open(path, inst ? inst->phandle : 0, ret);
468 
469     return ret;
470 }
471 
472 uint32_t vof_client_open_store(void *fdt, Vof *vof, const char *nodename,
473                                const char *prop, const char *path)
474 {
475     int offset, node = fdt_path_offset(fdt, nodename);
476     uint32_t inst;
477 
478     offset = fdt_path_offset(fdt, path);
479     if (offset < 0) {
480         trace_vof_error_unknown_path(path);
481         return PROM_ERROR;
482     }
483 
484     inst = vof_do_open(fdt, vof, offset, path);
485 
486     return fdt_setprop_cell(fdt, node, prop, inst) >= 0 ? 0 : PROM_ERROR;
487 }
488 
489 static uint32_t vof_open(void *fdt, Vof *vof, uint32_t pathaddr)
490 {
491     char path[VOF_MAX_PATH];
492     int offset;
493 
494     if (readstr(pathaddr, path, sizeof(path))) {
495         return PROM_ERROR;
496     }
497 
498     offset = path_offset(fdt, path);
499     if (offset < 0) {
500         trace_vof_error_unknown_path(path);
501         return PROM_ERROR;
502     }
503 
504     return vof_do_open(fdt, vof, offset, path);
505 }
506 
507 static void vof_close(Vof *vof, uint32_t ihandle)
508 {
509     if (!g_hash_table_remove(vof->of_instances, GINT_TO_POINTER(ihandle))) {
510         trace_vof_error_unknown_ihandle_close(ihandle);
511     }
512 }
513 
514 static uint32_t vof_instance_to_package(Vof *vof, uint32_t ihandle)
515 {
516     gpointer instp = g_hash_table_lookup(vof->of_instances,
517                                          GINT_TO_POINTER(ihandle));
518     uint32_t ret = PROM_ERROR;
519 
520     if (instp) {
521         ret = ((OfInstance *)instp)->phandle;
522     }
523     trace_vof_instance_to_package(ihandle, ret);
524 
525     return ret;
526 }
527 
528 static uint32_t vof_package_to_path(const void *fdt, uint32_t phandle,
529                                     uint32_t buf, uint32_t len)
530 {
531     int rc;
532     char tmp[VOF_MAX_PATH] = "";
533 
534     rc = phandle_to_path(fdt, phandle, tmp, sizeof(tmp));
535     if (rc > 0) {
536         if (VOF_MEM_WRITE(buf, tmp, rc) != MEMTX_OK) {
537             rc = -1;
538         }
539     }
540 
541     trace_vof_package_to_path(phandle, tmp, rc);
542 
543     return rc > 0 ? (uint32_t)rc : PROM_ERROR;
544 }
545 
546 static uint32_t vof_instance_to_path(void *fdt, Vof *vof, uint32_t ihandle,
547                                      uint32_t buf, uint32_t len)
548 {
549     int rc = -1;
550     uint32_t phandle = vof_instance_to_package(vof, ihandle);
551     char tmp[VOF_MAX_PATH] = "";
552 
553     if (phandle != -1) {
554         rc = phandle_to_path(fdt, phandle, tmp, sizeof(tmp));
555         if (rc > 0) {
556             if (VOF_MEM_WRITE(buf, tmp, rc) != MEMTX_OK) {
557                 rc = -1;
558             }
559         }
560     }
561     trace_vof_instance_to_path(ihandle, phandle, tmp, rc);
562 
563     return rc > 0 ? (uint32_t)rc : PROM_ERROR;
564 }
565 
566 static uint32_t vof_write(Vof *vof, uint32_t ihandle, uint32_t buf,
567                           uint32_t len)
568 {
569     char tmp[VOF_VTY_BUF_SIZE];
570     unsigned cb;
571     OfInstance *inst = (OfInstance *)
572         g_hash_table_lookup(vof->of_instances, GINT_TO_POINTER(ihandle));
573 
574     if (!inst) {
575         trace_vof_error_write(ihandle);
576         return PROM_ERROR;
577     }
578 
579     for ( ; len > 0; len -= cb) {
580         cb = MIN(len, sizeof(tmp) - 1);
581         if (VOF_MEM_READ(buf, tmp, cb) != MEMTX_OK) {
582             return PROM_ERROR;
583         }
584 
585         /* FIXME: there is no backend(s) yet so just call a trace */
586         if (trace_event_get_state(TRACE_VOF_WRITE) &&
587             qemu_loglevel_mask(LOG_TRACE)) {
588             tmp[cb] = '\0';
589             trace_vof_write(ihandle, cb, tmp);
590         }
591     }
592 
593     return len;
594 }
595 
596 static void vof_claimed_dump(GArray *claimed)
597 {
598     int i;
599     OfClaimed c;
600 
601     if (trace_event_get_state(TRACE_VOF_CLAIMED) &&
602         qemu_loglevel_mask(LOG_TRACE)) {
603 
604         for (i = 0; i < claimed->len; ++i) {
605             c = g_array_index(claimed, OfClaimed, i);
606             trace_vof_claimed(c.start, c.start + c.size, c.size);
607         }
608     }
609 }
610 
611 static bool vof_claim_avail(GArray *claimed, uint64_t virt, uint64_t size)
612 {
613     int i;
614     OfClaimed c;
615 
616     for (i = 0; i < claimed->len; ++i) {
617         c = g_array_index(claimed, OfClaimed, i);
618         if (ranges_overlap(c.start, c.size, virt, size)) {
619             return false;
620         }
621     }
622 
623     return true;
624 }
625 
626 static void vof_claim_add(GArray *claimed, uint64_t virt, uint64_t size)
627 {
628     OfClaimed newclaim;
629 
630     newclaim.start = virt;
631     newclaim.size = size;
632     g_array_append_val(claimed, newclaim);
633 }
634 
635 static gint of_claimed_compare_func(gconstpointer a, gconstpointer b)
636 {
637     return ((OfClaimed *)a)->start - ((OfClaimed *)b)->start;
638 }
639 
640 static void vof_dt_memory_available(void *fdt, GArray *claimed, uint64_t base)
641 {
642     int i, n, offset, proplen = 0, sc, ac;
643     target_ulong mem0_end;
644     const uint8_t *mem0_reg;
645     g_autofree uint8_t *avail = NULL;
646     uint8_t *availcur;
647 
648     if (!fdt || !claimed) {
649         return;
650     }
651 
652     offset = fdt_path_offset(fdt, "/");
653     _FDT(offset);
654     ac = fdt_address_cells(fdt, offset);
655     g_assert(ac == 1 || ac == 2);
656     sc = fdt_size_cells(fdt, offset);
657     g_assert(sc == 1 || sc == 2);
658 
659     offset = fdt_path_offset(fdt, "/memory@0");
660     _FDT(offset);
661 
662     mem0_reg = fdt_getprop(fdt, offset, "reg", &proplen);
663     g_assert(mem0_reg && proplen == sizeof(uint32_t) * (ac + sc));
664     if (sc == 2) {
665         mem0_end = ldq_be_p(mem0_reg + sizeof(uint32_t) * ac);
666     } else {
667         mem0_end = be32_to_cpu(*(uint32_t *)(mem0_reg + sizeof(uint32_t) * ac));
668     }
669 
670     g_array_sort(claimed, of_claimed_compare_func);
671     vof_claimed_dump(claimed);
672 
673     /*
674      * VOF resides in the first page so we do not need to check if there is
675      * available memory before the first claimed block
676      */
677     g_assert(claimed->len && (g_array_index(claimed, OfClaimed, 0).start == 0));
678 
679     avail = g_malloc0(sizeof(uint32_t) * (ac + sc) * claimed->len);
680     for (i = 0, n = 0, availcur = avail; i < claimed->len; ++i) {
681         OfClaimed c = g_array_index(claimed, OfClaimed, i);
682         uint64_t start, size;
683 
684         start = c.start + c.size;
685         if (i < claimed->len - 1) {
686             OfClaimed cn = g_array_index(claimed, OfClaimed, i + 1);
687 
688             size = cn.start - start;
689         } else {
690             size = mem0_end - start;
691         }
692 
693         if (ac == 2) {
694             *(uint64_t *) availcur = cpu_to_be64(start);
695         } else {
696             *(uint32_t *) availcur = cpu_to_be32(start);
697         }
698         availcur += sizeof(uint32_t) * ac;
699         if (sc == 2) {
700             *(uint64_t *) availcur = cpu_to_be64(size);
701         } else {
702             *(uint32_t *) availcur = cpu_to_be32(size);
703         }
704         availcur += sizeof(uint32_t) * sc;
705 
706         if (size) {
707             trace_vof_avail(c.start + c.size, c.start + c.size + size, size);
708             ++n;
709         }
710     }
711     _FDT((fdt_setprop(fdt, offset, "available", avail, availcur - avail)));
712 }
713 
714 /*
715  * OF1275:
716  * "Allocates size bytes of memory. If align is zero, the allocated range
717  * begins at the virtual address virt. Otherwise, an aligned address is
718  * automatically chosen and the input argument virt is ignored".
719  *
720  * In other words, exactly one of @virt and @align is non-zero.
721  */
722 uint64_t vof_claim(Vof *vof, uint64_t virt, uint64_t size,
723                    uint64_t align)
724 {
725     uint64_t ret;
726 
727     if (size == 0) {
728         ret = -1;
729     } else if (align == 0) {
730         if (!vof_claim_avail(vof->claimed, virt, size)) {
731             ret = -1;
732         } else {
733             ret = virt;
734         }
735     } else {
736         vof->claimed_base = QEMU_ALIGN_UP(vof->claimed_base, align);
737         while (1) {
738             if (vof->claimed_base >= vof->top_addr) {
739                 error_report("Out of RMA memory for the OF client");
740                 return -1;
741             }
742             if (vof_claim_avail(vof->claimed, vof->claimed_base, size)) {
743                 break;
744             }
745             vof->claimed_base += size;
746         }
747         ret = vof->claimed_base;
748     }
749 
750     if (ret != -1) {
751         vof->claimed_base = MAX(vof->claimed_base, ret + size);
752         vof_claim_add(vof->claimed, ret, size);
753     }
754     trace_vof_claim(virt, size, align, ret);
755 
756     return ret;
757 }
758 
759 static uint32_t vof_release(Vof *vof, uint64_t virt, uint64_t size)
760 {
761     uint32_t ret = PROM_ERROR;
762     int i;
763     GArray *claimed = vof->claimed;
764     OfClaimed c;
765 
766     for (i = 0; i < claimed->len; ++i) {
767         c = g_array_index(claimed, OfClaimed, i);
768         if (c.start == virt && c.size == size) {
769             g_array_remove_index(claimed, i);
770             ret = 0;
771             break;
772         }
773     }
774 
775     trace_vof_release(virt, size, ret);
776 
777     return ret;
778 }
779 
780 static void vof_instantiate_rtas(Error **errp)
781 {
782     error_setg(errp, "The firmware should have instantiated RTAS");
783 }
784 
785 static uint32_t vof_call_method(MachineState *ms, Vof *vof, uint32_t methodaddr,
786                                 uint32_t ihandle, uint32_t param1,
787                                 uint32_t param2, uint32_t param3,
788                                 uint32_t param4, uint32_t *ret2)
789 {
790     uint32_t ret = PROM_ERROR;
791     char method[VOF_MAX_METHODLEN] = "";
792     OfInstance *inst;
793 
794     if (!ihandle) {
795         goto trace_exit;
796     }
797 
798     inst = (OfInstance *)g_hash_table_lookup(vof->of_instances,
799                                              GINT_TO_POINTER(ihandle));
800     if (!inst) {
801         goto trace_exit;
802     }
803 
804     if (readstr(methodaddr, method, sizeof(method))) {
805         goto trace_exit;
806     }
807 
808     if (strcmp(inst->path, "/") == 0) {
809         if (strcmp(method, "ibm,client-architecture-support") == 0) {
810             Object *vmo = object_dynamic_cast(OBJECT(ms), TYPE_VOF_MACHINE_IF);
811 
812             if (vmo) {
813                 VofMachineIfClass *vmc = VOF_MACHINE_GET_CLASS(vmo);
814 
815                 g_assert(vmc->client_architecture_support);
816                 ret = (uint32_t)vmc->client_architecture_support(ms, first_cpu,
817                                                                  param1);
818             }
819 
820             *ret2 = 0;
821         }
822     } else if (strcmp(inst->path, "/rtas") == 0) {
823         if (strcmp(method, "instantiate-rtas") == 0) {
824             vof_instantiate_rtas(&error_fatal);
825             ret = 0;
826             *ret2 = param1; /* rtas-base */
827         }
828     } else {
829         trace_vof_error_unknown_method(method);
830     }
831 
832 trace_exit:
833     trace_vof_method(ihandle, method, param1, ret, *ret2);
834 
835     return ret;
836 }
837 
838 static uint32_t vof_call_interpret(uint32_t cmdaddr, uint32_t param1,
839                                    uint32_t param2, uint32_t *ret2)
840 {
841     uint32_t ret = PROM_ERROR;
842     char cmd[VOF_MAX_FORTHCODE] = "";
843 
844     /* No interpret implemented so just call a trace */
845     readstr(cmdaddr, cmd, sizeof(cmd));
846     trace_vof_interpret(cmd, param1, param2, ret, *ret2);
847 
848     return ret;
849 }
850 
851 static void vof_quiesce(MachineState *ms, void *fdt, Vof *vof)
852 {
853     Object *vmo = object_dynamic_cast(OBJECT(ms), TYPE_VOF_MACHINE_IF);
854     /* After "quiesce", no change is expected to the FDT, pack FDT to ensure */
855     int rc = fdt_pack(fdt);
856 
857     assert(rc == 0);
858 
859     if (vmo) {
860         VofMachineIfClass *vmc = VOF_MACHINE_GET_CLASS(vmo);
861 
862         if (vmc->quiesce) {
863             vmc->quiesce(ms);
864         }
865     }
866 
867     vof_claimed_dump(vof->claimed);
868 }
869 
870 static uint32_t vof_client_handle(MachineState *ms, void *fdt, Vof *vof,
871                                   const char *service,
872                                   uint32_t *args, unsigned nargs,
873                                   uint32_t *rets, unsigned nrets)
874 {
875     uint32_t ret = 0;
876 
877     /* @nrets includes the value which this function returns */
878 #define cmpserv(s, a, r) \
879     cmpservice(service, nargs, nrets, (s), (a), (r))
880 
881     if (cmpserv("finddevice", 1, 1)) {
882         ret = vof_finddevice(fdt, args[0]);
883     } else if (cmpserv("getprop", 4, 1)) {
884         ret = vof_getprop(fdt, args[0], args[1], args[2], args[3]);
885     } else if (cmpserv("getproplen", 2, 1)) {
886         ret = vof_getproplen(fdt, args[0], args[1]);
887     } else if (cmpserv("setprop", 4, 1)) {
888         ret = vof_setprop(ms, fdt, vof, args[0], args[1], args[2], args[3]);
889     } else if (cmpserv("nextprop", 3, 1)) {
890         ret = vof_nextprop(fdt, args[0], args[1], args[2]);
891     } else if (cmpserv("peer", 1, 1)) {
892         ret = vof_peer(fdt, args[0]);
893     } else if (cmpserv("child", 1, 1)) {
894         ret = vof_child(fdt, args[0]);
895     } else if (cmpserv("parent", 1, 1)) {
896         ret = vof_parent(fdt, args[0]);
897     } else if (cmpserv("open", 1, 1)) {
898         ret = vof_open(fdt, vof, args[0]);
899     } else if (cmpserv("close", 1, 0)) {
900         vof_close(vof, args[0]);
901     } else if (cmpserv("instance-to-package", 1, 1)) {
902         ret = vof_instance_to_package(vof, args[0]);
903     } else if (cmpserv("package-to-path", 3, 1)) {
904         ret = vof_package_to_path(fdt, args[0], args[1], args[2]);
905     } else if (cmpserv("instance-to-path", 3, 1)) {
906         ret = vof_instance_to_path(fdt, vof, args[0], args[1], args[2]);
907     } else if (cmpserv("write", 3, 1)) {
908         ret = vof_write(vof, args[0], args[1], args[2]);
909     } else if (cmpserv("claim", 3, 1)) {
910         uint64_t ret64 = vof_claim(vof, args[0], args[1], args[2]);
911 
912         if (ret64 < 0x100000000UL) {
913             vof_dt_memory_available(fdt, vof->claimed, vof->claimed_base);
914             ret = (uint32_t)ret64;
915         } else {
916             if (ret64 != -1) {
917                 vof_release(vof, ret, args[1]);
918             }
919             ret = PROM_ERROR;
920         }
921     } else if (cmpserv("release", 2, 0)) {
922         ret = vof_release(vof, args[0], args[1]);
923         if (ret != PROM_ERROR) {
924             vof_dt_memory_available(fdt, vof->claimed, vof->claimed_base);
925         }
926     } else if (cmpserv("call-method", 0, 0)) {
927         ret = vof_call_method(ms, vof, args[0], args[1], args[2], args[3],
928                               args[4], args[5], rets);
929     } else if (cmpserv("interpret", 0, 0)) {
930         ret = vof_call_interpret(args[0], args[1], args[2], rets);
931     } else if (cmpserv("milliseconds", 0, 1)) {
932         ret = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL);
933     } else if (cmpserv("quiesce", 0, 0)) {
934         vof_quiesce(ms, fdt, vof);
935     } else if (cmpserv("exit", 0, 0)) {
936         error_report("Stopped as the VM requested \"exit\"");
937         vm_stop(RUN_STATE_PAUSED);
938     } else {
939         trace_vof_error_unknown_service(service, nargs, nrets);
940         ret = -1;
941     }
942 
943 #undef cmpserv
944 
945     return ret;
946 }
947 
948 /* Defined as Big Endian */
949 struct prom_args {
950     uint32_t service;
951     uint32_t nargs;
952     uint32_t nret;
953     uint32_t args[10];
954 } QEMU_PACKED;
955 
956 int vof_client_call(MachineState *ms, Vof *vof, void *fdt,
957                     target_ulong args_real)
958 {
959     struct prom_args args_be;
960     uint32_t args[ARRAY_SIZE(args_be.args)];
961     uint32_t rets[ARRAY_SIZE(args_be.args)] = { 0 }, ret;
962     char service[64];
963     unsigned nargs, nret, i;
964 
965     if (VOF_MEM_READ(args_real, &args_be, sizeof(args_be)) != MEMTX_OK) {
966         return -EINVAL;
967     }
968     nargs = be32_to_cpu(args_be.nargs);
969     if (nargs >= ARRAY_SIZE(args_be.args)) {
970         return -EINVAL;
971     }
972 
973     if (VOF_MEM_READ(be32_to_cpu(args_be.service), service, sizeof(service)) !=
974         MEMTX_OK) {
975         return -EINVAL;
976     }
977     if (strnlen(service, sizeof(service)) == sizeof(service)) {
978         /* Too long service name */
979         return -EINVAL;
980     }
981 
982     for (i = 0; i < nargs; ++i) {
983         args[i] = be32_to_cpu(args_be.args[i]);
984     }
985 
986     nret = be32_to_cpu(args_be.nret);
987     if (nret > ARRAY_SIZE(args_be.args) - nargs) {
988         return -EINVAL;
989     }
990     ret = vof_client_handle(ms, fdt, vof, service, args, nargs, rets, nret);
991     if (!nret) {
992         return 0;
993     }
994 
995     /* @nrets includes the value which this function returns */
996     args_be.args[nargs] = cpu_to_be32(ret);
997     for (i = 1; i < nret; ++i) {
998         args_be.args[nargs + i] = cpu_to_be32(rets[i - 1]);
999     }
1000 
1001     if (VOF_MEM_WRITE(args_real + offsetof(struct prom_args, args[nargs]),
1002                       args_be.args + nargs, sizeof(args_be.args[0]) * nret) !=
1003         MEMTX_OK) {
1004         return -EINVAL;
1005     }
1006 
1007     return 0;
1008 }
1009 
1010 static void vof_instance_free(gpointer data)
1011 {
1012     OfInstance *inst = (OfInstance *)data;
1013 
1014     g_free(inst->path);
1015     g_free(inst);
1016 }
1017 
1018 void vof_init(Vof *vof, uint64_t top_addr, Error **errp)
1019 {
1020     vof_cleanup(vof);
1021 
1022     vof->of_instances = g_hash_table_new_full(g_direct_hash, g_direct_equal,
1023                                               NULL, vof_instance_free);
1024     vof->claimed = g_array_new(false, false, sizeof(OfClaimed));
1025 
1026     /* Keep allocations in 32bit as CLI ABI can only return cells==32bit */
1027     vof->top_addr = MIN(top_addr, 4 * GiB);
1028     if (vof_claim(vof, 0, vof->fw_size, 0) == -1) {
1029         error_setg(errp, "Memory for firmware is in use");
1030     }
1031 }
1032 
1033 void vof_cleanup(Vof *vof)
1034 {
1035     if (vof->claimed) {
1036         g_array_unref(vof->claimed);
1037     }
1038     if (vof->of_instances) {
1039         g_hash_table_unref(vof->of_instances);
1040     }
1041     vof->claimed = NULL;
1042     vof->of_instances = NULL;
1043     vof->of_instance_last = 0;
1044     vof->claimed_base = 0;
1045 }
1046 
1047 void vof_build_dt(void *fdt, Vof *vof)
1048 {
1049     uint32_t phandle = fdt_get_max_phandle(fdt);
1050     int offset, proplen = 0;
1051     const void *prop;
1052 
1053     /* Assign phandles to nodes without predefined phandles (like XICS/XIVE) */
1054     for (offset = fdt_next_node(fdt, -1, NULL);
1055          offset >= 0;
1056          offset = fdt_next_node(fdt, offset, NULL)) {
1057         prop = fdt_getprop(fdt, offset, "phandle", &proplen);
1058         if (prop) {
1059             continue;
1060         }
1061         ++phandle;
1062         _FDT(fdt_setprop_cell(fdt, offset, "phandle", phandle));
1063     }
1064 
1065     vof_dt_memory_available(fdt, vof->claimed, vof->claimed_base);
1066 }
1067 
1068 static const TypeInfo vof_machine_if_info = {
1069     .name = TYPE_VOF_MACHINE_IF,
1070     .parent = TYPE_INTERFACE,
1071     .class_size = sizeof(VofMachineIfClass),
1072 };
1073 
1074 static void vof_machine_if_register_types(void)
1075 {
1076     type_register_static(&vof_machine_if_info);
1077 }
1078 type_init(vof_machine_if_register_types)
1079