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/timer.h"
14 #include "qemu/range.h"
15 #include "qemu/units.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"
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.
31 #define OF_PROPNAME_LEN_MAX 64
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
45 char *path
; /* the path used to open the instance */
49 static int readstr(hwaddr pa
, char *buf
, int size
)
51 if (VOF_MEM_READ(pa
, buf
, size
) != MEMTX_OK
) {
54 if (strnlen(buf
, size
) == size
) {
56 trace_vof_error_str_truncated(buf
, size
);
62 static bool cmpservice(const char *s
, unsigned nargs
, unsigned nret
,
63 const char *s1
, unsigned nargscheck
, unsigned nretcheck
)
68 if ((nargscheck
&& (nargs
!= nargscheck
)) ||
69 (nretcheck
&& (nret
!= nretcheck
))) {
70 trace_vof_error_param(s
, nargscheck
, nretcheck
, nargs
, nret
);
77 static void prop_format(char *tval
, int tlen
, const void *prop
, int len
)
80 const unsigned char *c
;
82 const char bin
[] = "...";
84 for (i
= 0, c
= prop
; i
< len
; ++i
, ++c
) {
85 if (*c
== '\0' && i
== len
- 1) {
86 strncpy(tval
, prop
, tlen
- 1);
89 if (*c
< 0x20 || *c
>= 0x80) {
94 for (i
= 0, c
= prop
, t
= tval
; i
< len
; ++i
, ++c
) {
95 if (t
>= tval
+ tlen
- sizeof(bin
) - 1 - 2 - 1) {
99 if (i
&& i
% 4 == 0 && i
!= len
- 1) {
103 t
+= sprintf(t
, "%02X", *c
& 0xFF);
107 static int get_path(const void *fdt
, int offset
, char *buf
, int len
)
111 ret
= fdt_get_path(fdt
, offset
, buf
, len
- 1);
118 return strlen(buf
) + 1;
121 static int phandle_to_path(const void *fdt
, uint32_t ph
, char *buf
, int len
)
125 ret
= fdt_node_offset_by_phandle(fdt
, ph
);
130 return get_path(fdt
, ret
, buf
, len
);
133 static int path_offset(const void *fdt
, const char *path
)
135 g_autofree
char *p
= NULL
;
139 * https://www.devicetree.org/open-firmware/bindings/ppc/release/ppc-2_1.html#HDR16
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".
146 for (at
= strchr(p
, '@'); at
&& *at
; ) {
148 at
= strchr(at
, '@');
155 return fdt_path_offset(fdt
, p
);
158 static uint32_t vof_finddevice(const void *fdt
, uint32_t nodeaddr
)
160 char fullnode
[VOF_MAX_PATH
];
161 uint32_t ret
= PROM_ERROR
;
164 if (readstr(nodeaddr
, fullnode
, sizeof(fullnode
))) {
165 return (uint32_t) ret
;
168 offset
= path_offset(fdt
, fullnode
);
170 ret
= fdt_get_phandle(fdt
, offset
);
172 trace_vof_finddevice(fullnode
, ret
);
176 static const void *getprop(const void *fdt
, int nodeoff
, const char *propname
,
177 int *proplen
, bool *write0
)
179 const char *unit
, *prop
;
180 const void *ret
= fdt_getprop(fdt
, nodeoff
, propname
, proplen
);
189 if (strcmp(propname
, "name")) {
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.
196 prop
= fdt_get_name(fdt
, nodeoff
, proplen
);
202 unit
= memchr(prop
, '@', *proplen
);
204 *proplen
= unit
- prop
;
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.
218 static uint32_t vof_getprop(const void *fdt
, uint32_t nodeph
, uint32_t pname
,
219 uint32_t valaddr
, uint32_t vallen
)
221 char propname
[OF_PROPNAME_LEN_MAX
+ 1];
226 int nodeoff
= fdt_node_offset_by_phandle(fdt
, nodeph
);
232 if (readstr(pname
, propname
, sizeof(propname
))) {
235 prop
= getprop(fdt
, nodeoff
, propname
, &proplen
, &write0
);
238 int cb
= MIN(proplen
, vallen
);
240 if (VOF_MEM_WRITE(valaddr
, prop
, cb
) != MEMTX_OK
||
241 /* if that was "name" with a unit address, overwrite '@' with '0' */
244 VOF_MEM_WRITE(valaddr
+ cb
- 1, &zero
, 1) != MEMTX_OK
)) {
249 * "Size is either the actual size of the property, or -1 if name
250 * does not exist", hence returning proplen instead of cb.
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
);
262 trace_vof_getprop(nodeph
, propname
, ret
, trval
);
267 static uint32_t vof_getproplen(const void *fdt
, uint32_t nodeph
, uint32_t pname
)
269 char propname
[OF_PROPNAME_LEN_MAX
+ 1];
273 int nodeoff
= fdt_node_offset_by_phandle(fdt
, nodeph
);
278 if (readstr(pname
, propname
, sizeof(propname
))) {
281 prop
= getprop(fdt
, nodeoff
, propname
, &proplen
, NULL
);
287 trace_vof_getproplen(nodeph
, propname
, ret
);
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
)
296 char propname
[OF_PROPNAME_LEN_MAX
+ 1] = "";
297 uint32_t ret
= PROM_ERROR
;
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
;
305 if (vallen
> VOF_MAX_SETPROPLEN
) {
308 if (readstr(pname
, propname
, sizeof(propname
))) {
311 offset
= fdt_node_offset_by_phandle(fdt
, nodeph
);
315 rc
= get_path(fdt
, offset
, nodepath
, sizeof(nodepath
));
320 val
= g_malloc0(vallen
);
321 if (VOF_MEM_READ(valaddr
, val
, vallen
) != MEMTX_OK
) {
329 vmc
= VOF_MACHINE_GET_CLASS(vmo
);
330 if (!vmc
->setprop
|| !vmc
->setprop(ms
, nodepath
, propname
, val
, vallen
)) {
334 rc
= fdt_setprop(fdt
, offset
, propname
, val
, vallen
);
339 if (trace_event_get_state(TRACE_VOF_SETPROP
) &&
340 qemu_loglevel_mask(LOG_TRACE
)) {
341 prop_format(trval
, sizeof(trval
), val
, vallen
);
346 trace_vof_setprop(nodeph
, propname
, trval
, vallen
, ret
);
351 static uint32_t vof_nextprop(const void *fdt
, uint32_t phandle
,
352 uint32_t prevaddr
, uint32_t nameaddr
)
354 int offset
, nodeoff
= fdt_node_offset_by_phandle(fdt
, phandle
);
355 char prev
[OF_PROPNAME_LEN_MAX
+ 1];
358 if (readstr(prevaddr
, prev
, sizeof(prev
))) {
362 fdt_for_each_property_offset(offset
, fdt
, nodeoff
) {
363 if (!fdt_getprop_by_offset(fdt
, offset
, &tmp
, NULL
)) {
366 if (prev
[0] == '\0' || strcmp(prev
, tmp
) == 0) {
367 if (prev
[0] != '\0') {
368 offset
= fdt_next_property_offset(fdt
, offset
);
373 if (!fdt_getprop_by_offset(fdt
, offset
, &tmp
, NULL
)) {
377 if (VOF_MEM_WRITE(nameaddr
, tmp
, strlen(tmp
) + 1) != MEMTX_OK
) {
387 static uint32_t vof_peer(const void *fdt
, uint32_t phandle
)
393 rc
= fdt_path_offset(fdt
, "/");
395 rc
= fdt_next_subnode(fdt
, fdt_node_offset_by_phandle(fdt
, phandle
));
399 ret
= fdt_get_phandle(fdt
, rc
);
405 static uint32_t vof_child(const void *fdt
, uint32_t phandle
)
408 int rc
= fdt_first_subnode(fdt
, fdt_node_offset_by_phandle(fdt
, phandle
));
411 ret
= fdt_get_phandle(fdt
, rc
);
417 static uint32_t vof_parent(const void *fdt
, uint32_t phandle
)
420 int rc
= fdt_parent_offset(fdt
, fdt_node_offset_by_phandle(fdt
, phandle
));
423 ret
= fdt_get_phandle(fdt
, rc
);
429 static uint32_t vof_do_open(void *fdt
, Vof
*vof
, int offset
, const char *path
)
431 uint32_t ret
= PROM_ERROR
;
432 OfInstance
*inst
= NULL
;
434 if (vof
->of_instance_last
== 0xFFFFFFFF) {
435 /* We do not recycle ihandles yet */
439 inst
= g_new0(OfInstance
, 1);
440 inst
->phandle
= fdt_get_phandle(fdt
, offset
);
441 g_assert(inst
->phandle
);
442 ++vof
->of_instance_last
;
444 inst
->path
= g_strdup(path
);
445 g_hash_table_insert(vof
->of_instances
,
446 GINT_TO_POINTER(vof
->of_instance_last
),
448 ret
= vof
->of_instance_last
;
451 trace_vof_open(path
, inst
? inst
->phandle
: 0, ret
);
456 uint32_t vof_client_open_store(void *fdt
, Vof
*vof
, const char *nodename
,
457 const char *prop
, const char *path
)
459 int offset
, node
= fdt_path_offset(fdt
, nodename
);
462 offset
= fdt_path_offset(fdt
, path
);
464 trace_vof_error_unknown_path(path
);
468 inst
= vof_do_open(fdt
, vof
, offset
, path
);
470 return fdt_setprop_cell(fdt
, node
, prop
, inst
) >= 0 ? 0 : PROM_ERROR
;
473 static uint32_t vof_open(void *fdt
, Vof
*vof
, uint32_t pathaddr
)
475 char path
[VOF_MAX_PATH
];
478 if (readstr(pathaddr
, path
, sizeof(path
))) {
482 offset
= path_offset(fdt
, path
);
484 trace_vof_error_unknown_path(path
);
488 return vof_do_open(fdt
, vof
, offset
, path
);
491 static void vof_close(Vof
*vof
, uint32_t ihandle
)
493 if (!g_hash_table_remove(vof
->of_instances
, GINT_TO_POINTER(ihandle
))) {
494 trace_vof_error_unknown_ihandle_close(ihandle
);
498 static uint32_t vof_instance_to_package(Vof
*vof
, uint32_t ihandle
)
500 gpointer instp
= g_hash_table_lookup(vof
->of_instances
,
501 GINT_TO_POINTER(ihandle
));
502 uint32_t ret
= PROM_ERROR
;
505 ret
= ((OfInstance
*)instp
)->phandle
;
507 trace_vof_instance_to_package(ihandle
, ret
);
512 static uint32_t vof_package_to_path(const void *fdt
, uint32_t phandle
,
513 uint32_t buf
, uint32_t len
)
516 char tmp
[VOF_MAX_PATH
] = "";
518 rc
= phandle_to_path(fdt
, phandle
, tmp
, sizeof(tmp
));
520 if (VOF_MEM_WRITE(buf
, tmp
, rc
) != MEMTX_OK
) {
525 trace_vof_package_to_path(phandle
, tmp
, rc
);
527 return rc
> 0 ? (uint32_t)rc
: PROM_ERROR
;
530 static uint32_t vof_instance_to_path(void *fdt
, Vof
*vof
, uint32_t ihandle
,
531 uint32_t buf
, uint32_t len
)
534 uint32_t phandle
= vof_instance_to_package(vof
, ihandle
);
535 char tmp
[VOF_MAX_PATH
] = "";
538 rc
= phandle_to_path(fdt
, phandle
, tmp
, sizeof(tmp
));
540 if (VOF_MEM_WRITE(buf
, tmp
, rc
) != MEMTX_OK
) {
545 trace_vof_instance_to_path(ihandle
, phandle
, tmp
, rc
);
547 return rc
> 0 ? (uint32_t)rc
: PROM_ERROR
;
550 static uint32_t vof_write(Vof
*vof
, uint32_t ihandle
, uint32_t buf
,
553 char tmp
[VOF_VTY_BUF_SIZE
];
555 OfInstance
*inst
= (OfInstance
*)
556 g_hash_table_lookup(vof
->of_instances
, GINT_TO_POINTER(ihandle
));
559 trace_vof_error_write(ihandle
);
563 for ( ; len
> 0; len
-= cb
) {
564 cb
= MIN(len
, sizeof(tmp
) - 1);
565 if (VOF_MEM_READ(buf
, tmp
, cb
) != MEMTX_OK
) {
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
)) {
573 trace_vof_write(ihandle
, cb
, tmp
);
580 static void vof_claimed_dump(GArray
*claimed
)
585 if (trace_event_get_state(TRACE_VOF_CLAIMED
) &&
586 qemu_loglevel_mask(LOG_TRACE
)) {
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
);
595 static bool vof_claim_avail(GArray
*claimed
, uint64_t virt
, uint64_t size
)
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
)) {
610 static void vof_claim_add(GArray
*claimed
, uint64_t virt
, uint64_t size
)
614 newclaim
.start
= virt
;
615 newclaim
.size
= size
;
616 g_array_append_val(claimed
, newclaim
);
619 static gint
of_claimed_compare_func(gconstpointer a
, gconstpointer b
)
621 return ((OfClaimed
*)a
)->start
- ((OfClaimed
*)b
)->start
;
624 static void vof_dt_memory_available(void *fdt
, GArray
*claimed
, uint64_t base
)
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
;
632 if (!fdt
|| !claimed
) {
636 offset
= fdt_path_offset(fdt
, "/");
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);
643 offset
= fdt_path_offset(fdt
, "/memory@0");
646 mem0_reg
= fdt_getprop(fdt
, offset
, "reg", &proplen
);
647 g_assert(mem0_reg
&& proplen
== sizeof(uint32_t) * (ac
+ sc
));
649 mem0_end
= be64_to_cpu(*(uint64_t *)(mem0_reg
+ sizeof(uint32_t) * ac
));
651 mem0_end
= be32_to_cpu(*(uint32_t *)(mem0_reg
+ sizeof(uint32_t) * ac
));
654 g_array_sort(claimed
, of_claimed_compare_func
);
655 vof_claimed_dump(claimed
);
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
661 g_assert(claimed
->len
&& (g_array_index(claimed
, OfClaimed
, 0).start
== 0));
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
;
668 start
= c
.start
+ c
.size
;
669 if (i
< claimed
->len
- 1) {
670 OfClaimed cn
= g_array_index(claimed
, OfClaimed
, i
+ 1);
672 size
= cn
.start
- start
;
674 size
= mem0_end
- start
;
678 *(uint64_t *) availcur
= cpu_to_be64(start
);
680 *(uint32_t *) availcur
= cpu_to_be32(start
);
682 availcur
+= sizeof(uint32_t) * ac
;
684 *(uint64_t *) availcur
= cpu_to_be64(size
);
686 *(uint32_t *) availcur
= cpu_to_be32(size
);
688 availcur
+= sizeof(uint32_t) * sc
;
691 trace_vof_avail(c
.start
+ c
.size
, c
.start
+ c
.size
+ size
, size
);
695 _FDT((fdt_setprop(fdt
, offset
, "available", avail
, availcur
- avail
)));
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".
704 * In other words, exactly one of @virt and @align is non-zero.
706 uint64_t vof_claim(Vof
*vof
, uint64_t virt
, uint64_t size
,
713 } else if (align
== 0) {
714 if (!vof_claim_avail(vof
->claimed
, virt
, size
)) {
720 vof
->claimed_base
= QEMU_ALIGN_UP(vof
->claimed_base
, align
);
722 if (vof
->claimed_base
>= vof
->top_addr
) {
723 error_report("Out of RMA memory for the OF client");
726 if (vof_claim_avail(vof
->claimed
, vof
->claimed_base
, size
)) {
729 vof
->claimed_base
+= size
;
731 ret
= vof
->claimed_base
;
735 vof
->claimed_base
= MAX(vof
->claimed_base
, ret
+ size
);
736 vof_claim_add(vof
->claimed
, ret
, size
);
738 trace_vof_claim(virt
, size
, align
, ret
);
743 static uint32_t vof_release(Vof
*vof
, uint64_t virt
, uint64_t size
)
745 uint32_t ret
= PROM_ERROR
;
747 GArray
*claimed
= vof
->claimed
;
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
);
759 trace_vof_release(virt
, size
, ret
);
764 static void vof_instantiate_rtas(Error
**errp
)
766 error_setg(errp
, "The firmware should have instantiated RTAS");
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
)
774 uint32_t ret
= PROM_ERROR
;
775 char method
[VOF_MAX_METHODLEN
] = "";
782 inst
= (OfInstance
*)g_hash_table_lookup(vof
->of_instances
,
783 GINT_TO_POINTER(ihandle
));
788 if (readstr(methodaddr
, method
, sizeof(method
))) {
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
);
797 VofMachineIfClass
*vmc
= VOF_MACHINE_GET_CLASS(vmo
);
799 g_assert(vmc
->client_architecture_support
);
800 ret
= (uint32_t)vmc
->client_architecture_support(ms
, first_cpu
,
806 } else if (strcmp(inst
->path
, "/rtas") == 0) {
807 if (strcmp(method
, "instantiate-rtas") == 0) {
808 vof_instantiate_rtas(&error_fatal
);
810 *ret2
= param1
; /* rtas-base */
813 trace_vof_error_unknown_method(method
);
817 trace_vof_method(ihandle
, method
, param1
, ret
, *ret2
);
822 static uint32_t vof_call_interpret(uint32_t cmdaddr
, uint32_t param1
,
823 uint32_t param2
, uint32_t *ret2
)
825 uint32_t ret
= PROM_ERROR
;
826 char cmd
[VOF_MAX_FORTHCODE
] = "";
828 /* No interpret implemented so just call a trace */
829 readstr(cmdaddr
, cmd
, sizeof(cmd
));
830 trace_vof_interpret(cmd
, param1
, param2
, ret
, *ret2
);
835 static void vof_quiesce(MachineState
*ms
, void *fdt
, Vof
*vof
)
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
);
844 VofMachineIfClass
*vmc
= VOF_MACHINE_GET_CLASS(vmo
);
851 vof_claimed_dump(vof
->claimed
);
854 static uint32_t vof_client_handle(MachineState
*ms
, void *fdt
, Vof
*vof
,
856 uint32_t *args
, unsigned nargs
,
857 uint32_t *rets
, unsigned nrets
)
861 /* @nrets includes the value which this function returns */
862 #define cmpserv(s, a, r) \
863 cmpservice(service, nargs, nrets, (s), (a), (r))
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]);
896 if (ret64
< 0x100000000UL
) {
897 vof_dt_memory_available(fdt
, vof
->claimed
, vof
->claimed_base
);
898 ret
= (uint32_t)ret64
;
901 vof_release(vof
, ret
, args
[1]);
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
);
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
);
923 trace_vof_error_unknown_service(service
, nargs
, nrets
);
932 /* Defined as Big Endian */
940 int vof_client_call(MachineState
*ms
, Vof
*vof
, void *fdt
,
941 target_ulong args_real
)
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
;
947 unsigned nargs
, nret
, i
;
949 if (VOF_MEM_READ(args_real
, &args_be
, sizeof(args_be
)) != MEMTX_OK
) {
952 nargs
= be32_to_cpu(args_be
.nargs
);
953 if (nargs
>= ARRAY_SIZE(args_be
.args
)) {
957 if (VOF_MEM_READ(be32_to_cpu(args_be
.service
), service
, sizeof(service
)) !=
961 if (strnlen(service
, sizeof(service
)) == sizeof(service
)) {
962 /* Too long service name */
966 for (i
= 0; i
< nargs
; ++i
) {
967 args
[i
] = be32_to_cpu(args_be
.args
[i
]);
970 nret
= be32_to_cpu(args_be
.nret
);
971 if (nret
> ARRAY_SIZE(args_be
.args
) - nargs
) {
974 ret
= vof_client_handle(ms
, fdt
, vof
, service
, args
, nargs
, rets
, nret
);
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]);
985 if (VOF_MEM_WRITE(args_real
+ offsetof(struct prom_args
, args
[nargs
]),
986 args_be
.args
+ nargs
, sizeof(args_be
.args
[0]) * nret
) !=
994 static void vof_instance_free(gpointer data
)
996 OfInstance
*inst
= (OfInstance
*)data
;
1002 void vof_init(Vof
*vof
, uint64_t top_addr
, Error
**errp
)
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
));
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");
1017 void vof_cleanup(Vof
*vof
)
1020 g_array_unref(vof
->claimed
);
1022 if (vof
->of_instances
) {
1023 g_hash_table_unref(vof
->of_instances
);
1025 vof
->claimed
= NULL
;
1026 vof
->of_instances
= NULL
;
1027 vof
->of_instance_last
= 0;
1028 vof
->claimed_base
= 0;
1031 void vof_build_dt(void *fdt
, Vof
*vof
)
1033 uint32_t phandle
= fdt_get_max_phandle(fdt
);
1034 int offset
, proplen
= 0;
1037 /* Assign phandles to nodes without predefined phandles (like XICS/XIVE) */
1038 for (offset
= fdt_next_node(fdt
, -1, NULL
);
1040 offset
= fdt_next_node(fdt
, offset
, NULL
)) {
1041 prop
= fdt_getprop(fdt
, offset
, "phandle", &proplen
);
1046 _FDT(fdt_setprop_cell(fdt
, offset
, "phandle", phandle
));
1049 vof_dt_memory_available(fdt
, vof
->claimed
, vof
->claimed_base
);
1052 static const TypeInfo vof_machine_if_info
= {
1053 .name
= TYPE_VOF_MACHINE_IF
,
1054 .parent
= TYPE_INTERFACE
,
1055 .class_size
= sizeof(VofMachineIfClass
),
1058 static void vof_machine_if_register_types(void)
1060 type_register_static(&vof_machine_if_info
);
1062 type_init(vof_machine_if_register_types
)