master
c 1,077 lines 28.7 KB
Raw
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, 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, 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 }
709 }
710 _FDT((fdt_setprop(fdt, offset, "available", avail, availcur - avail)));
711 }
712
713 /*
714 * OF1275:
715 * "Allocates size bytes of memory. If align is zero, the allocated range
716 * begins at the virtual address virt. Otherwise, an aligned address is
717 * automatically chosen and the input argument virt is ignored".
718 *
719 * In other words, exactly one of @virt and @align is non-zero.
720 */
721 uint64_t vof_claim(Vof *vof, uint64_t virt, uint64_t size,
722 uint64_t align)
723 {
724 uint64_t ret;
725
726 if (size == 0) {
727 ret = -1;
728 } else if (align == 0) {
729 if (!vof_claim_avail(vof->claimed, virt, size)) {
730 ret = -1;
731 } else {
732 ret = virt;
733 }
734 } else {
735 vof->claimed_base = QEMU_ALIGN_UP(vof->claimed_base, align);
736 while (1) {
737 if (vof->claimed_base >= vof->top_addr) {
738 error_report("Out of RMA memory for the OF client");
739 return -1;
740 }
741 if (vof_claim_avail(vof->claimed, vof->claimed_base, size)) {
742 break;
743 }
744 vof->claimed_base += size;
745 }
746 ret = vof->claimed_base;
747 }
748
749 if (ret != -1) {
750 vof->claimed_base = MAX(vof->claimed_base, ret + size);
751 vof_claim_add(vof->claimed, ret, size);
752 }
753 trace_vof_claim(virt, size, align, ret);
754
755 return ret;
756 }
757
758 static uint32_t vof_release(Vof *vof, uint64_t virt, uint64_t size)
759 {
760 uint32_t ret = PROM_ERROR;
761 int i;
762 GArray *claimed = vof->claimed;
763 OfClaimed c;
764
765 for (i = 0; i < claimed->len; ++i) {
766 c = g_array_index(claimed, OfClaimed, i);
767 if (c.start == virt && c.size == size) {
768 g_array_remove_index(claimed, i);
769 ret = 0;
770 break;
771 }
772 }
773
774 trace_vof_release(virt, size, ret);
775
776 return ret;
777 }
778
779 static void vof_instantiate_rtas(Error **errp)
780 {
781 error_setg(errp, "The firmware should have instantiated RTAS");
782 }
783
784 static uint32_t vof_call_method(MachineState *ms, Vof *vof, uint32_t methodaddr,
785 uint32_t ihandle, uint32_t param1,
786 uint32_t param2, uint32_t param3,
787 uint32_t param4, uint32_t *ret2)
788 {
789 uint32_t ret = PROM_ERROR;
790 char method[VOF_MAX_METHODLEN] = "";
791 OfInstance *inst;
792
793 if (!ihandle) {
794 goto trace_exit;
795 }
796
797 inst = (OfInstance *)g_hash_table_lookup(vof->of_instances,
798 GINT_TO_POINTER(ihandle));
799 if (!inst) {
800 goto trace_exit;
801 }
802
803 if (readstr(methodaddr, method, sizeof(method))) {
804 goto trace_exit;
805 }
806
807 if (strcmp(inst->path, "/") == 0) {
808 if (strcmp(method, "ibm,client-architecture-support") == 0) {
809 Object *vmo = object_dynamic_cast(OBJECT(ms), TYPE_VOF_MACHINE_IF);
810
811 if (vmo) {
812 VofMachineIfClass *vmc = VOF_MACHINE_GET_CLASS(vmo);
813
814 g_assert(vmc->client_architecture_support);
815 ret = (uint32_t)vmc->client_architecture_support(ms, first_cpu,
816 param1);
817 }
818
819 *ret2 = 0;
820 }
821 } else if (strcmp(inst->path, "/rtas") == 0) {
822 if (strcmp(method, "instantiate-rtas") == 0) {
823 vof_instantiate_rtas(&error_fatal);
824 ret = 0;
825 *ret2 = param1; /* rtas-base */
826 }
827 } else {
828 trace_vof_error_unknown_method(method);
829 }
830
831 trace_exit:
832 trace_vof_method(ihandle, method, param1, ret, *ret2);
833
834 return ret;
835 }
836
837 static uint32_t vof_call_interpret(uint32_t cmdaddr, uint32_t param1,
838 uint32_t param2, uint32_t *ret2)
839 {
840 uint32_t ret = PROM_ERROR;
841 char cmd[VOF_MAX_FORTHCODE] = "";
842
843 /* No interpret implemented so just call a trace */
844 readstr(cmdaddr, cmd, sizeof(cmd));
845 trace_vof_interpret(cmd, param1, param2, ret, *ret2);
846
847 return ret;
848 }
849
850 static void vof_quiesce(MachineState *ms, void *fdt, Vof *vof)
851 {
852 Object *vmo = object_dynamic_cast(OBJECT(ms), TYPE_VOF_MACHINE_IF);
853 /* After "quiesce", no change is expected to the FDT, pack FDT to ensure */
854 int rc = fdt_pack(fdt);
855
856 assert(rc == 0);
857
858 if (vmo) {
859 VofMachineIfClass *vmc = VOF_MACHINE_GET_CLASS(vmo);
860
861 if (vmc->quiesce) {
862 vmc->quiesce(ms);
863 }
864 }
865
866 vof_claimed_dump(vof->claimed);
867 }
868
869 static uint32_t vof_client_handle(MachineState *ms, void *fdt, Vof *vof,
870 const char *service,
871 uint32_t *args, unsigned nargs,
872 uint32_t *rets, unsigned nrets)
873 {
874 uint32_t ret = 0;
875
876 /* @nrets includes the value which this function returns */
877 #define cmpserv(s, a, r) \
878 cmpservice(service, nargs, nrets, (s), (a), (r))
879
880 if (cmpserv("finddevice", 1, 1)) {
881 ret = vof_finddevice(fdt, args[0]);
882 } else if (cmpserv("getprop", 4, 1)) {
883 ret = vof_getprop(fdt, args[0], args[1], args[2], args[3]);
884 } else if (cmpserv("getproplen", 2, 1)) {
885 ret = vof_getproplen(fdt, args[0], args[1]);
886 } else if (cmpserv("setprop", 4, 1)) {
887 ret = vof_setprop(ms, fdt, vof, args[0], args[1], args[2], args[3]);
888 } else if (cmpserv("nextprop", 3, 1)) {
889 ret = vof_nextprop(fdt, args[0], args[1], args[2]);
890 } else if (cmpserv("peer", 1, 1)) {
891 ret = vof_peer(fdt, args[0]);
892 } else if (cmpserv("child", 1, 1)) {
893 ret = vof_child(fdt, args[0]);
894 } else if (cmpserv("parent", 1, 1)) {
895 ret = vof_parent(fdt, args[0]);
896 } else if (cmpserv("open", 1, 1)) {
897 ret = vof_open(fdt, vof, args[0]);
898 } else if (cmpserv("close", 1, 0)) {
899 vof_close(vof, args[0]);
900 } else if (cmpserv("instance-to-package", 1, 1)) {
901 ret = vof_instance_to_package(vof, args[0]);
902 } else if (cmpserv("package-to-path", 3, 1)) {
903 ret = vof_package_to_path(fdt, args[0], args[1], args[2]);
904 } else if (cmpserv("instance-to-path", 3, 1)) {
905 ret = vof_instance_to_path(fdt, vof, args[0], args[1], args[2]);
906 } else if (cmpserv("write", 3, 1)) {
907 ret = vof_write(vof, args[0], args[1], args[2]);
908 } else if (cmpserv("claim", 3, 1)) {
909 uint64_t ret64 = vof_claim(vof, args[0], args[1], args[2]);
910
911 if (ret64 < 0x100000000UL) {
912 vof_dt_memory_available(fdt, vof->claimed, vof->claimed_base);
913 ret = (uint32_t)ret64;
914 } else {
915 if (ret64 != -1) {
916 vof_release(vof, ret, args[1]);
917 }
918 ret = PROM_ERROR;
919 }
920 } else if (cmpserv("release", 2, 0)) {
921 ret = vof_release(vof, args[0], args[1]);
922 if (ret != PROM_ERROR) {
923 vof_dt_memory_available(fdt, vof->claimed, vof->claimed_base);
924 }
925 } else if (cmpserv("call-method", 0, 0)) {
926 ret = vof_call_method(ms, vof, args[0], args[1], args[2], args[3],
927 args[4], args[5], rets);
928 } else if (cmpserv("interpret", 0, 0)) {
929 ret = vof_call_interpret(args[0], args[1], args[2], rets);
930 } else if (cmpserv("milliseconds", 0, 1)) {
931 ret = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL);
932 } else if (cmpserv("quiesce", 0, 0)) {
933 vof_quiesce(ms, fdt, vof);
934 } else if (cmpserv("exit", 0, 0)) {
935 error_report("Stopped as the VM requested \"exit\"");
936 vm_stop(RUN_STATE_PAUSED);
937 } else {
938 trace_vof_error_unknown_service(service, nargs, nrets);
939 ret = -1;
940 }
941
942 #undef cmpserv
943
944 return ret;
945 }
946
947 /* Defined as Big Endian */
948 struct prom_args {
949 uint32_t service;
950 uint32_t nargs;
951 uint32_t nret;
952 uint32_t args[10];
953 } QEMU_PACKED;
954
955 int vof_client_call(MachineState *ms, Vof *vof, void *fdt,
956 target_ulong args_real)
957 {
958 struct prom_args args_be;
959 uint32_t args[ARRAY_SIZE(args_be.args)];
960 uint32_t rets[ARRAY_SIZE(args_be.args)] = { 0 }, ret;
961 char service[64];
962 unsigned nargs, nret, i;
963
964 if (VOF_MEM_READ(args_real, &args_be, sizeof(args_be)) != MEMTX_OK) {
965 return -EINVAL;
966 }
967 nargs = be32_to_cpu(args_be.nargs);
968 if (nargs >= ARRAY_SIZE(args_be.args)) {
969 return -EINVAL;
970 }
971
972 if (VOF_MEM_READ(be32_to_cpu(args_be.service), service, sizeof(service)) !=
973 MEMTX_OK) {
974 return -EINVAL;
975 }
976 if (strnlen(service, sizeof(service)) == sizeof(service)) {
977 /* Too long service name */
978 return -EINVAL;
979 }
980
981 for (i = 0; i < nargs; ++i) {
982 args[i] = be32_to_cpu(args_be.args[i]);
983 }
984
985 nret = be32_to_cpu(args_be.nret);
986 if (nret > ARRAY_SIZE(args_be.args) - nargs) {
987 return -EINVAL;
988 }
989 ret = vof_client_handle(ms, fdt, vof, service, args, nargs, rets, nret);
990 if (!nret) {
991 return 0;
992 }
993
994 /* @nrets includes the value which this function returns */
995 args_be.args[nargs] = cpu_to_be32(ret);
996 for (i = 1; i < nret; ++i) {
997 args_be.args[nargs + i] = cpu_to_be32(rets[i - 1]);
998 }
999
1000 if (VOF_MEM_WRITE(args_real + offsetof(struct prom_args, args[nargs]),
1001 args_be.args + nargs, sizeof(args_be.args[0]) * nret) !=
1002 MEMTX_OK) {
1003 return -EINVAL;
1004 }
1005
1006 return 0;
1007 }
1008
1009 static void vof_instance_free(gpointer data)
1010 {
1011 OfInstance *inst = (OfInstance *)data;
1012
1013 g_free(inst->path);
1014 g_free(inst);
1015 }
1016
1017 void vof_init(Vof *vof, uint64_t top_addr, Error **errp)
1018 {
1019 vof_cleanup(vof);
1020
1021 vof->of_instances = g_hash_table_new_full(g_direct_hash, g_direct_equal,
1022 NULL, vof_instance_free);
1023 vof->claimed = g_array_new(false, false, sizeof(OfClaimed));
1024
1025 /* Keep allocations in 32bit as CLI ABI can only return cells==32bit */
1026 vof->top_addr = MIN(top_addr, 4 * GiB);
1027 if (vof_claim(vof, 0, vof->fw_size, 0) == -1) {
1028 error_setg(errp, "Memory for firmware is in use");
1029 }
1030 }
1031
1032 void vof_cleanup(Vof *vof)
1033 {
1034 if (vof->claimed) {
1035 g_array_unref(vof->claimed);
1036 }
1037 if (vof->of_instances) {
1038 g_hash_table_unref(vof->of_instances);
1039 }
1040 vof->claimed = NULL;
1041 vof->of_instances = NULL;
1042 vof->of_instance_last = 0;
1043 vof->claimed_base = 0;
1044 }
1045
1046 void vof_build_dt(void *fdt, Vof *vof)
1047 {
1048 uint32_t phandle = fdt_get_max_phandle(fdt);
1049 int offset, proplen = 0;
1050 const void *prop;
1051
1052 /* Assign phandles to nodes without predefined phandles (like XICS/XIVE) */
1053 for (offset = fdt_next_node(fdt, -1, NULL);
1054 offset >= 0;
1055 offset = fdt_next_node(fdt, offset, NULL)) {
1056 prop = fdt_getprop(fdt, offset, "phandle", &proplen);
1057 if (prop) {
1058 continue;
1059 }
1060 ++phandle;
1061 _FDT(fdt_setprop_cell(fdt, offset, "phandle", phandle));
1062 }
1063
1064 vof_dt_memory_available(fdt, vof->claimed, vof->claimed_base);
1065 }
1066
1067 static const TypeInfo vof_machine_if_info = {
1068 .name = TYPE_VOF_MACHINE_IF,
1069 .parent = TYPE_INTERFACE,
1070 .class_size = sizeof(VofMachineIfClass),
1071 };
1072
1073 static void vof_machine_if_register_types(void)
1074 {
1075 type_register_static(&vof_machine_if_info);
1076 }
1077 type_init(vof_machine_if_register_types)