ppc/xive: Add support for PQ state bits offload
[qemu.git] / hw / ppc / vof.c
blob2b63a62875612ff7a9ce2110edbc17d6a2753e88
1 /*
2 * QEMU PowerPC Virtual Open Firmware.
4 * This implements client interface from OpenFirmware IEEE1275 on the QEMU
5 * side to leave only a very basic firmware in the VM.
7 * Copyright (c) 2021 IBM Corporation.
9 * SPDX-License-Identifier: GPL-2.0-or-later
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"
26 #include <libfdt.h>
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.
32 #define OF_PROPNAME_LEN_MAX 64
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
40 typedef struct {
41 uint64_t start;
42 uint64_t size;
43 } OfClaimed;
45 typedef struct {
46 char *path; /* the path used to open the instance */
47 uint32_t phandle;
48 } OfInstance;
50 static int readstr(hwaddr pa, char *buf, int size)
52 if (VOF_MEM_READ(pa, buf, size) != MEMTX_OK) {
53 return -1;
55 if (strnlen(buf, size) == size) {
56 buf[size - 1] = '\0';
57 trace_vof_error_str_truncated(buf, size);
58 return -1;
60 return 0;
63 static bool cmpservice(const char *s, unsigned nargs, unsigned nret,
64 const char *s1, unsigned nargscheck, unsigned nretcheck)
66 if (strcmp(s, s1)) {
67 return false;
69 if ((nargscheck && (nargs != nargscheck)) ||
70 (nretcheck && (nret != nretcheck))) {
71 trace_vof_error_param(s, nargscheck, nretcheck, nargs, nret);
72 return false;
75 return true;
78 static void prop_format(char *tval, int tlen, const void *prop, int len)
80 int i;
81 const unsigned char *c;
82 char *t;
83 const char bin[] = "...";
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;
90 if (*c < 0x20 || *c >= 0x80) {
91 break;
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;
100 if (i && i % 4 == 0 && i != len - 1) {
101 strcat(t, " ");
102 ++t;
104 t += sprintf(t, "%02X", *c & 0xFF);
108 static int get_path(const void *fdt, int offset, char *buf, int len)
110 int ret;
112 ret = fdt_get_path(fdt, offset, buf, len - 1);
113 if (ret < 0) {
114 return ret;
117 buf[len - 1] = '\0';
119 return strlen(buf) + 1;
122 static int phandle_to_path(const void *fdt, uint32_t ph, char *buf, int len)
124 int ret;
126 ret = fdt_node_offset_by_phandle(fdt, ph);
127 if (ret < 0) {
128 return ret;
131 return get_path(fdt, ret, buf, len);
134 static int path_offset(const void *fdt, const char *path)
136 g_autofree char *p = NULL;
137 char *at;
140 * https://www.devicetree.org/open-firmware/bindings/ppc/release/ppc-2_1.html#HDR16
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".
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;
156 return fdt_path_offset(fdt, p);
159 static uint32_t vof_finddevice(const void *fdt, uint32_t nodeaddr)
161 char fullnode[VOF_MAX_PATH];
162 uint32_t ret = PROM_ERROR;
163 int offset;
165 if (readstr(nodeaddr, fullnode, sizeof(fullnode))) {
166 return (uint32_t) ret;
169 offset = path_offset(fdt, fullnode);
170 if (offset >= 0) {
171 ret = fdt_get_phandle(fdt, offset);
173 trace_vof_finddevice(fullnode, ret);
174 return ret;
177 static const void *getprop(const void *fdt, int nodeoff, const char *propname,
178 int *proplen, bool *write0)
180 const char *unit, *prop;
181 const void *ret = fdt_getprop(fdt, nodeoff, propname, proplen);
183 if (ret) {
184 if (write0) {
185 *write0 = false;
187 return ret;
190 if (strcmp(propname, "name")) {
191 return NULL;
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.
197 prop = fdt_get_name(fdt, nodeoff, proplen);
198 if (!prop) {
199 *proplen = 0;
200 return NULL;
203 unit = memchr(prop, '@', *proplen);
204 if (unit) {
205 *proplen = unit - prop;
207 *proplen += 1;
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.
213 if (write0) {
214 *write0 = true;
216 return prop;
219 static uint32_t vof_getprop(const void *fdt, uint32_t nodeph, uint32_t pname,
220 uint32_t valaddr, uint32_t vallen)
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;
230 if (nodeoff < 0) {
231 return PROM_ERROR;
233 if (readstr(pname, propname, sizeof(propname))) {
234 return PROM_ERROR;
236 prop = getprop(fdt, nodeoff, propname, &proplen, &write0);
237 if (prop) {
238 const char zero = 0;
239 int cb = MIN(proplen, vallen);
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 {
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.
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);
260 } else {
261 ret = PROM_ERROR;
263 trace_vof_getprop(nodeph, propname, ret, trval);
265 return ret;
268 static uint32_t vof_getproplen(const void *fdt, uint32_t nodeph, uint32_t pname)
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);
276 if (nodeoff < 0) {
277 return PROM_ERROR;
279 if (readstr(pname, propname, sizeof(propname))) {
280 return PROM_ERROR;
282 prop = getprop(fdt, nodeoff, propname, &proplen, NULL);
283 if (prop) {
284 ret = proplen;
285 } else {
286 ret = PROM_ERROR;
288 trace_vof_getproplen(nodeph, propname, ret);
290 return ret;
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)
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;
306 if (vallen > VOF_MAX_SETPROPLEN) {
307 goto trace_exit;
309 if (readstr(pname, propname, sizeof(propname))) {
310 goto trace_exit;
312 offset = fdt_node_offset_by_phandle(fdt, nodeph);
313 if (offset < 0) {
314 goto trace_exit;
316 rc = get_path(fdt, offset, nodepath, sizeof(nodepath));
317 if (rc <= 0) {
318 goto trace_exit;
321 val = g_malloc0(vallen);
322 if (VOF_MEM_READ(valaddr, val, vallen) != MEMTX_OK) {
323 goto trace_exit;
326 if (!vmo) {
327 goto trace_exit;
330 vmc = VOF_MACHINE_GET_CLASS(vmo);
331 if (!vmc->setprop || !vmc->setprop(ms, nodepath, propname, val, vallen)) {
332 goto trace_exit;
335 rc = fdt_setprop(fdt, offset, propname, val, vallen);
336 if (rc) {
337 goto trace_exit;
340 if (trace_event_get_state(TRACE_VOF_SETPROP) &&
341 qemu_loglevel_mask(LOG_TRACE)) {
342 prop_format(trval, sizeof(trval), val, vallen);
344 ret = vallen;
346 trace_exit:
347 trace_vof_setprop(nodeph, propname, trval, vallen, ret);
349 return ret;
352 static uint32_t vof_nextprop(const void *fdt, uint32_t phandle,
353 uint32_t prevaddr, uint32_t nameaddr)
355 int offset, nodeoff = fdt_node_offset_by_phandle(fdt, phandle);
356 char prev[OF_PROPNAME_LEN_MAX + 1];
357 const char *tmp;
359 if (readstr(prevaddr, prev, sizeof(prev))) {
360 return PROM_ERROR;
363 fdt_for_each_property_offset(offset, fdt, nodeoff) {
364 if (!fdt_getprop_by_offset(fdt, offset, &tmp, NULL)) {
365 return 0;
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;
374 if (!fdt_getprop_by_offset(fdt, offset, &tmp, NULL)) {
375 return 0;
378 if (VOF_MEM_WRITE(nameaddr, tmp, strlen(tmp) + 1) != MEMTX_OK) {
379 return PROM_ERROR;
381 return 1;
385 return 0;
388 static uint32_t vof_peer(const void *fdt, uint32_t phandle)
390 uint32_t ret = 0;
391 int rc;
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));
399 if (rc >= 0) {
400 ret = fdt_get_phandle(fdt, rc);
403 return ret;
406 static uint32_t vof_child(const void *fdt, uint32_t phandle)
408 uint32_t ret = 0;
409 int rc = fdt_first_subnode(fdt, fdt_node_offset_by_phandle(fdt, phandle));
411 if (rc >= 0) {
412 ret = fdt_get_phandle(fdt, rc);
415 return ret;
418 static uint32_t vof_parent(const void *fdt, uint32_t phandle)
420 uint32_t ret = 0;
421 int rc = fdt_parent_offset(fdt, fdt_node_offset_by_phandle(fdt, phandle));
423 if (rc >= 0) {
424 ret = fdt_get_phandle(fdt, rc);
427 return ret;
430 static uint32_t vof_do_open(void *fdt, Vof *vof, int offset, const char *path)
432 uint32_t ret = PROM_ERROR;
433 OfInstance *inst = NULL;
435 if (vof->of_instance_last == 0xFFFFFFFF) {
436 /* We do not recycle ihandles yet */
437 goto trace_exit;
440 inst = g_new0(OfInstance, 1);
441 inst->phandle = fdt_get_phandle(fdt, offset);
442 g_assert(inst->phandle);
443 ++vof->of_instance_last;
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;
451 trace_exit:
452 trace_vof_open(path, inst ? inst->phandle : 0, ret);
454 return ret;
457 uint32_t vof_client_open_store(void *fdt, Vof *vof, const char *nodename,
458 const char *prop, const char *path)
460 int offset, node = fdt_path_offset(fdt, nodename);
461 uint32_t inst;
463 offset = fdt_path_offset(fdt, path);
464 if (offset < 0) {
465 trace_vof_error_unknown_path(path);
466 return PROM_ERROR;
469 inst = vof_do_open(fdt, vof, offset, path);
471 return fdt_setprop_cell(fdt, node, prop, inst) >= 0 ? 0 : PROM_ERROR;
474 static uint32_t vof_open(void *fdt, Vof *vof, uint32_t pathaddr)
476 char path[VOF_MAX_PATH];
477 int offset;
479 if (readstr(pathaddr, path, sizeof(path))) {
480 return PROM_ERROR;
483 offset = path_offset(fdt, path);
484 if (offset < 0) {
485 trace_vof_error_unknown_path(path);
486 return PROM_ERROR;
489 return vof_do_open(fdt, vof, offset, path);
492 static void vof_close(Vof *vof, uint32_t ihandle)
494 if (!g_hash_table_remove(vof->of_instances, GINT_TO_POINTER(ihandle))) {
495 trace_vof_error_unknown_ihandle_close(ihandle);
499 static uint32_t vof_instance_to_package(Vof *vof, uint32_t ihandle)
501 gpointer instp = g_hash_table_lookup(vof->of_instances,
502 GINT_TO_POINTER(ihandle));
503 uint32_t ret = PROM_ERROR;
505 if (instp) {
506 ret = ((OfInstance *)instp)->phandle;
508 trace_vof_instance_to_package(ihandle, ret);
510 return ret;
513 static uint32_t vof_package_to_path(const void *fdt, uint32_t phandle,
514 uint32_t buf, uint32_t len)
516 int rc;
517 char tmp[VOF_MAX_PATH] = "";
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;
526 trace_vof_package_to_path(phandle, tmp, rc);
528 return rc > 0 ? (uint32_t)rc : PROM_ERROR;
531 static uint32_t vof_instance_to_path(void *fdt, Vof *vof, uint32_t ihandle,
532 uint32_t buf, uint32_t len)
534 int rc = -1;
535 uint32_t phandle = vof_instance_to_package(vof, ihandle);
536 char tmp[VOF_MAX_PATH] = "";
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;
546 trace_vof_instance_to_path(ihandle, phandle, tmp, rc);
548 return rc > 0 ? (uint32_t)rc : PROM_ERROR;
551 static uint32_t vof_write(Vof *vof, uint32_t ihandle, uint32_t buf,
552 uint32_t len)
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));
559 if (!inst) {
560 trace_vof_error_write(ihandle);
561 return PROM_ERROR;
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;
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);
578 return len;
581 static void vof_claimed_dump(GArray *claimed)
583 int i;
584 OfClaimed c;
586 if (trace_event_get_state(TRACE_VOF_CLAIMED) &&
587 qemu_loglevel_mask(LOG_TRACE)) {
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);
596 static bool vof_claim_avail(GArray *claimed, uint64_t virt, uint64_t size)
598 int i;
599 OfClaimed c;
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;
608 return true;
611 static void vof_claim_add(GArray *claimed, uint64_t virt, uint64_t size)
613 OfClaimed newclaim;
615 newclaim.start = virt;
616 newclaim.size = size;
617 g_array_append_val(claimed, newclaim);
620 static gint of_claimed_compare_func(gconstpointer a, gconstpointer b)
622 return ((OfClaimed *)a)->start - ((OfClaimed *)b)->start;
625 static void vof_dt_memory_available(void *fdt, GArray *claimed, uint64_t base)
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;
633 if (!fdt || !claimed) {
634 return;
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);
644 offset = fdt_path_offset(fdt, "/memory@0");
645 _FDT(offset);
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));
655 g_array_sort(claimed, of_claimed_compare_func);
656 vof_claimed_dump(claimed);
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
662 g_assert(claimed->len && (g_array_index(claimed, OfClaimed, 0).start == 0));
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;
669 start = c.start + c.size;
670 if (i < claimed->len - 1) {
671 OfClaimed cn = g_array_index(claimed, OfClaimed, i + 1);
673 size = cn.start - start;
674 } else {
675 size = mem0_end - start;
678 if (ac == 2) {
679 *(uint64_t *) availcur = cpu_to_be64(start);
680 } else {
681 *(uint32_t *) availcur = cpu_to_be32(start);
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);
689 availcur += sizeof(uint32_t) * sc;
691 if (size) {
692 trace_vof_avail(c.start + c.size, c.start + c.size + size, size);
693 ++n;
696 _FDT((fdt_setprop(fdt, offset, "available", avail, availcur - avail)));
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".
705 * In other words, exactly one of @virt and @align is non-zero.
707 uint64_t vof_claim(Vof *vof, uint64_t virt, uint64_t size,
708 uint64_t align)
710 uint64_t ret;
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;
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;
727 if (vof_claim_avail(vof->claimed, vof->claimed_base, size)) {
728 break;
730 vof->claimed_base += size;
732 ret = vof->claimed_base;
735 if (ret != -1) {
736 vof->claimed_base = MAX(vof->claimed_base, ret + size);
737 vof_claim_add(vof->claimed, ret, size);
739 trace_vof_claim(virt, size, align, ret);
741 return ret;
744 static uint32_t vof_release(Vof *vof, uint64_t virt, uint64_t size)
746 uint32_t ret = PROM_ERROR;
747 int i;
748 GArray *claimed = vof->claimed;
749 OfClaimed c;
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;
760 trace_vof_release(virt, size, ret);
762 return ret;
765 static void vof_instantiate_rtas(Error **errp)
767 error_setg(errp, "The firmware should have instantiated RTAS");
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)
775 uint32_t ret = PROM_ERROR;
776 char method[VOF_MAX_METHODLEN] = "";
777 OfInstance *inst;
779 if (!ihandle) {
780 goto trace_exit;
783 inst = (OfInstance *)g_hash_table_lookup(vof->of_instances,
784 GINT_TO_POINTER(ihandle));
785 if (!inst) {
786 goto trace_exit;
789 if (readstr(methodaddr, method, sizeof(method))) {
790 goto trace_exit;
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);
797 if (vmo) {
798 VofMachineIfClass *vmc = VOF_MACHINE_GET_CLASS(vmo);
800 g_assert(vmc->client_architecture_support);
801 ret = (uint32_t)vmc->client_architecture_support(ms, first_cpu,
802 param1);
805 *ret2 = 0;
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 */
813 } else {
814 trace_vof_error_unknown_method(method);
817 trace_exit:
818 trace_vof_method(ihandle, method, param1, ret, *ret2);
820 return ret;
823 static uint32_t vof_call_interpret(uint32_t cmdaddr, uint32_t param1,
824 uint32_t param2, uint32_t *ret2)
826 uint32_t ret = PROM_ERROR;
827 char cmd[VOF_MAX_FORTHCODE] = "";
829 /* No interpret implemented so just call a trace */
830 readstr(cmdaddr, cmd, sizeof(cmd));
831 trace_vof_interpret(cmd, param1, param2, ret, *ret2);
833 return ret;
836 static void vof_quiesce(MachineState *ms, void *fdt, Vof *vof)
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);
842 assert(rc == 0);
844 if (vmo) {
845 VofMachineIfClass *vmc = VOF_MACHINE_GET_CLASS(vmo);
847 if (vmc->quiesce) {
848 vmc->quiesce(ms);
852 vof_claimed_dump(vof->claimed);
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)
860 uint32_t ret = 0;
862 /* @nrets includes the value which this function returns */
863 #define cmpserv(s, a, r) \
864 cmpservice(service, nargs, nrets, (s), (a), (r))
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]);
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]);
904 ret = PROM_ERROR;
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);
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;
928 #undef cmpserv
930 return ret;
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;
941 int vof_client_call(MachineState *ms, Vof *vof, void *fdt,
942 target_ulong args_real)
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;
950 if (VOF_MEM_READ(args_real, &args_be, sizeof(args_be)) != MEMTX_OK) {
951 return -EINVAL;
953 nargs = be32_to_cpu(args_be.nargs);
954 if (nargs >= ARRAY_SIZE(args_be.args)) {
955 return -EINVAL;
958 if (VOF_MEM_READ(be32_to_cpu(args_be.service), service, sizeof(service)) !=
959 MEMTX_OK) {
960 return -EINVAL;
962 if (strnlen(service, sizeof(service)) == sizeof(service)) {
963 /* Too long service name */
964 return -EINVAL;
967 for (i = 0; i < nargs; ++i) {
968 args[i] = be32_to_cpu(args_be.args[i]);
971 nret = be32_to_cpu(args_be.nret);
972 if (nret > ARRAY_SIZE(args_be.args) - nargs) {
973 return -EINVAL;
975 ret = vof_client_handle(ms, fdt, vof, service, args, nargs, rets, nret);
976 if (!nret) {
977 return 0;
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]);
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;
992 return 0;
995 static void vof_instance_free(gpointer data)
997 OfInstance *inst = (OfInstance *)data;
999 g_free(inst->path);
1000 g_free(inst);
1003 void vof_init(Vof *vof, uint64_t top_addr, Error **errp)
1005 vof_cleanup(vof);
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));
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");
1018 void vof_cleanup(Vof *vof)
1020 if (vof->claimed) {
1021 g_array_unref(vof->claimed);
1023 if (vof->of_instances) {
1024 g_hash_table_unref(vof->of_instances);
1026 vof->claimed = NULL;
1027 vof->of_instances = NULL;
1030 void vof_build_dt(void *fdt, Vof *vof)
1032 uint32_t phandle = fdt_get_max_phandle(fdt);
1033 int offset, proplen = 0;
1034 const void *prop;
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;
1044 ++phandle;
1045 _FDT(fdt_setprop_cell(fdt, offset, "phandle", phandle));
1048 vof_dt_memory_available(fdt, vof->claimed, vof->claimed_base);
1051 static const TypeInfo vof_machine_if_info = {
1052 .name = TYPE_VOF_MACHINE_IF,
1053 .parent = TYPE_INTERFACE,
1054 .class_size = sizeof(VofMachineIfClass),
1057 static void vof_machine_if_register_types(void)
1059 type_register_static(&vof_machine_if_info);
1061 type_init(vof_machine_if_register_types)