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-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/ram_addr.h"
20 #include "exec/address-spaces.h"
21 #include "hw/ppc/vof.h"
22 #include "hw/ppc/fdt.h"
23 #include "sysemu/runstate.h"
24 #include "qom/qom-qobject.h"
25 #include "trace.h"
26
27 #include <libfdt.h>
28
29 /*
30 * OF 1275 "nextprop" description suggests is it 32 bytes max but
31 * LoPAPR defines "ibm,query-interrupt-source-number" which is 33 chars long.
32 */
33 #define OF_PROPNAME_LEN_MAX 64
34
35 #define VOF_MAX_PATH 256
36 #define VOF_MAX_SETPROPLEN 2048
37 #define VOF_MAX_METHODLEN 256
38 #define VOF_MAX_FORTHCODE 256
39 #define VOF_VTY_BUF_SIZE 256
40
41 typedef struct {
42 uint64_t start;
43 uint64_t size;
44 } OfClaimed;
45
46 typedef struct {
47 char *path; /* the path used to open the instance */
48 uint32_t phandle;
49 } OfInstance;
50
readstr(hwaddr pa,char * buf,int size)51 static int readstr(hwaddr pa, char *buf, int size)
52 {
53 if (VOF_MEM_READ(pa, buf, size) != MEMTX_OK) {
54 return -1;
55 }
56 if (strnlen(buf, size) == size) {
57 buf[size - 1] = '\0';
58 trace_vof_error_str_truncated(buf, size);
59 return -1;
60 }
61 return 0;
62 }
63
cmpservice(const char * s,unsigned nargs,unsigned nret,const char * s1,unsigned nargscheck,unsigned nretcheck)64 static bool cmpservice(const char *s, unsigned nargs, unsigned nret,
65 const char *s1, unsigned nargscheck, unsigned nretcheck)
66 {
67 if (strcmp(s, s1)) {
68 return false;
69 }
70 if ((nargscheck && (nargs != nargscheck)) ||
71 (nretcheck && (nret != nretcheck))) {
72 trace_vof_error_param(s, nargscheck, nretcheck, nargs, nret);
73 return false;
74 }
75
76 return true;
77 }
78
prop_format(char * tval,int tlen,const void * prop,int len)79 static void prop_format(char *tval, int tlen, const void *prop, int len)
80 {
81 int i;
82 const unsigned char *c;
83 char *t;
84 const char bin[] = "...";
85
86 for (i = 0, c = prop; i < len; ++i, ++c) {
87 if (*c == '\0' && i == len - 1) {
88 strncpy(tval, prop, tlen - 1);
89 return;
90 }
91 if (*c < 0x20 || *c >= 0x80) {
92 break;
93 }
94 }
95
96 for (i = 0, c = prop, t = tval; i < len; ++i, ++c) {
97 if (t >= tval + tlen - sizeof(bin) - 1 - 2 - 1) {
98 strcpy(t, bin);
99 return;
100 }
101 if (i && i % 4 == 0 && i != len - 1) {
102 strcat(t, " ");
103 ++t;
104 }
105 t += sprintf(t, "%02X", *c & 0xFF);
106 }
107 }
108
get_path(const void * fdt,int offset,char * buf,int len)109 static int get_path(const void *fdt, int offset, char *buf, int len)
110 {
111 int ret;
112
113 ret = fdt_get_path(fdt, offset, buf, len - 1);
114 if (ret < 0) {
115 return ret;
116 }
117
118 buf[len - 1] = '\0';
119
120 return strlen(buf) + 1;
121 }
122
phandle_to_path(const void * fdt,uint32_t ph,char * buf,int len)123 static int phandle_to_path(const void *fdt, uint32_t ph, char *buf, int len)
124 {
125 int ret;
126
127 ret = fdt_node_offset_by_phandle(fdt, ph);
128 if (ret < 0) {
129 return ret;
130 }
131
132 return get_path(fdt, ret, buf, len);
133 }
134
path_offset(const void * fdt,const char * path)135 static int path_offset(const void *fdt, const char *path)
136 {
137 g_autofree char *p = NULL;
138 char *at;
139
140 /*
141 * https://www.devicetree.org/open-firmware/bindings/ppc/release/ppc-2_1.html#HDR16
142 *
143 * "Conversion from numeric representation to text representation shall use
144 * the lower case forms of the hexadecimal digits in the range a..f,
145 * suppressing leading zeros".
146 */
147 p = g_strdup(path);
148 for (at = strchr(p, '@'); at && *at; ) {
149 if (*at == '/') {
150 at = strchr(at, '@');
151 } else {
152 *at = tolower(*at);
153 ++at;
154 }
155 }
156
157 return fdt_path_offset(fdt, p);
158 }
159
vof_finddevice(const void * fdt,uint32_t nodeaddr)160 static uint32_t vof_finddevice(const void *fdt, uint32_t nodeaddr)
161 {
162 char fullnode[VOF_MAX_PATH];
163 uint32_t ret = PROM_ERROR;
164 int offset;
165
166 if (readstr(nodeaddr, fullnode, sizeof(fullnode))) {
167 return (uint32_t) ret;
168 }
169
170 offset = path_offset(fdt, fullnode);
171 if (offset >= 0) {
172 ret = fdt_get_phandle(fdt, offset);
173 }
174 trace_vof_finddevice(fullnode, ret);
175 return ret;
176 }
177
getprop(const void * fdt,int nodeoff,const char * propname,int * proplen,bool * write0)178 static const void *getprop(const void *fdt, int nodeoff, const char *propname,
179 int *proplen, bool *write0)
180 {
181 const char *unit, *prop;
182 const void *ret = fdt_getprop(fdt, nodeoff, propname, proplen);
183
184 if (ret) {
185 if (write0) {
186 *write0 = false;
187 }
188 return ret;
189 }
190
191 if (strcmp(propname, "name")) {
192 return NULL;
193 }
194 /*
195 * We return a value for "name" from path if queried but property does not
196 * exist. @proplen does not include the unit part in this case.
197 */
198 prop = fdt_get_name(fdt, nodeoff, proplen);
199 if (!prop) {
200 *proplen = 0;
201 return NULL;
202 }
203
204 unit = memchr(prop, '@', *proplen);
205 if (unit) {
206 *proplen = unit - prop;
207 }
208 *proplen += 1;
209
210 /*
211 * Since it might be cut at "@" and there will be no trailing zero
212 * in the prop buffer, tell the caller to write zero at the end.
213 */
214 if (write0) {
215 *write0 = true;
216 }
217 return prop;
218 }
219
vof_getprop(const void * fdt,uint32_t nodeph,uint32_t pname,uint32_t valaddr,uint32_t vallen)220 static uint32_t vof_getprop(const void *fdt, uint32_t nodeph, uint32_t pname,
221 uint32_t valaddr, uint32_t vallen)
222 {
223 char propname[OF_PROPNAME_LEN_MAX + 1];
224 uint32_t ret = 0;
225 int proplen = 0;
226 const void *prop;
227 char trval[64] = "";
228 int nodeoff = fdt_node_offset_by_phandle(fdt, nodeph);
229 bool write0;
230
231 if (nodeoff < 0) {
232 return PROM_ERROR;
233 }
234 if (readstr(pname, propname, sizeof(propname))) {
235 return PROM_ERROR;
236 }
237 prop = getprop(fdt, nodeoff, propname, &proplen, &write0);
238 if (prop) {
239 const char zero = 0;
240 int cb = MIN(proplen, vallen);
241
242 if (VOF_MEM_WRITE(valaddr, prop, cb) != MEMTX_OK ||
243 /* if that was "name" with a unit address, overwrite '@' with '0' */
244 (write0 &&
245 cb == proplen &&
246 VOF_MEM_WRITE(valaddr + cb - 1, &zero, 1) != MEMTX_OK)) {
247 ret = PROM_ERROR;
248 } else {
249 /*
250 * OF1275 says:
251 * "Size is either the actual size of the property, or -1 if name
252 * does not exist", hence returning proplen instead of cb.
253 */
254 ret = proplen;
255 /* Do not format a value if tracepoint is silent, for performance */
256 if (trace_event_get_state(TRACE_VOF_GETPROP) &&
257 qemu_loglevel_mask(LOG_TRACE)) {
258 prop_format(trval, sizeof(trval), prop, ret);
259 }
260 }
261 } else {
262 ret = PROM_ERROR;
263 }
264 trace_vof_getprop(nodeph, propname, ret, trval);
265
266 return ret;
267 }
268
vof_getproplen(const void * fdt,uint32_t nodeph,uint32_t pname)269 static uint32_t vof_getproplen(const void *fdt, uint32_t nodeph, uint32_t pname)
270 {
271 char propname[OF_PROPNAME_LEN_MAX + 1];
272 uint32_t ret = 0;
273 int proplen = 0;
274 const void *prop;
275 int nodeoff = fdt_node_offset_by_phandle(fdt, nodeph);
276
277 if (nodeoff < 0) {
278 return PROM_ERROR;
279 }
280 if (readstr(pname, propname, sizeof(propname))) {
281 return PROM_ERROR;
282 }
283 prop = getprop(fdt, nodeoff, propname, &proplen, NULL);
284 if (prop) {
285 ret = proplen;
286 } else {
287 ret = PROM_ERROR;
288 }
289 trace_vof_getproplen(nodeph, propname, ret);
290
291 return ret;
292 }
293
vof_setprop(MachineState * ms,void * fdt,Vof * vof,uint32_t nodeph,uint32_t pname,uint32_t valaddr,uint32_t vallen)294 static uint32_t vof_setprop(MachineState *ms, void *fdt, Vof *vof,
295 uint32_t nodeph, uint32_t pname,
296 uint32_t valaddr, uint32_t vallen)
297 {
298 char propname[OF_PROPNAME_LEN_MAX + 1];
299 uint32_t ret = PROM_ERROR;
300 int offset, rc;
301 char trval[64] = "";
302 char nodepath[VOF_MAX_PATH] = "";
303 Object *vmo = object_dynamic_cast(OBJECT(ms), TYPE_VOF_MACHINE_IF);
304 VofMachineIfClass *vmc;
305 g_autofree char *val = NULL;
306
307 if (vallen > VOF_MAX_SETPROPLEN) {
308 goto trace_exit;
309 }
310 if (readstr(pname, propname, sizeof(propname))) {
311 goto trace_exit;
312 }
313 offset = fdt_node_offset_by_phandle(fdt, nodeph);
314 if (offset < 0) {
315 goto trace_exit;
316 }
317 rc = get_path(fdt, offset, nodepath, sizeof(nodepath));
318 if (rc <= 0) {
319 goto trace_exit;
320 }
321
322 val = g_malloc0(vallen);
323 if (VOF_MEM_READ(valaddr, val, vallen) != MEMTX_OK) {
324 goto trace_exit;
325 }
326
327 if (!vmo) {
328 goto trace_exit;
329 }
330
331 vmc = VOF_MACHINE_GET_CLASS(vmo);
332 if (!vmc->setprop || !vmc->setprop(ms, nodepath, propname, val, vallen)) {
333 goto trace_exit;
334 }
335
336 rc = fdt_setprop(fdt, offset, propname, val, vallen);
337 if (rc) {
338 goto trace_exit;
339 }
340
341 if (trace_event_get_state(TRACE_VOF_SETPROP) &&
342 qemu_loglevel_mask(LOG_TRACE)) {
343 prop_format(trval, sizeof(trval), val, vallen);
344 }
345 ret = vallen;
346
347 trace_exit:
348 trace_vof_setprop(nodeph, propname, trval, vallen, ret);
349
350 return ret;
351 }
352
vof_nextprop(const void * fdt,uint32_t phandle,uint32_t prevaddr,uint32_t nameaddr)353 static uint32_t vof_nextprop(const void *fdt, uint32_t phandle,
354 uint32_t prevaddr, uint32_t nameaddr)
355 {
356 int offset, nodeoff = fdt_node_offset_by_phandle(fdt, phandle);
357 char prev[OF_PROPNAME_LEN_MAX + 1];
358 const char *tmp;
359
360 if (readstr(prevaddr, prev, sizeof(prev))) {
361 return PROM_ERROR;
362 }
363
364 fdt_for_each_property_offset(offset, fdt, nodeoff) {
365 if (!fdt_getprop_by_offset(fdt, offset, &tmp, NULL)) {
366 return 0;
367 }
368 if (prev[0] == '\0' || strcmp(prev, tmp) == 0) {
369 if (prev[0] != '\0') {
370 offset = fdt_next_property_offset(fdt, offset);
371 if (offset < 0) {
372 return 0;
373 }
374 }
375 if (!fdt_getprop_by_offset(fdt, offset, &tmp, NULL)) {
376 return 0;
377 }
378
379 if (VOF_MEM_WRITE(nameaddr, tmp, strlen(tmp) + 1) != MEMTX_OK) {
380 return PROM_ERROR;
381 }
382 return 1;
383 }
384 }
385
386 return 0;
387 }
388
vof_peer(const void * fdt,uint32_t phandle)389 static uint32_t vof_peer(const void *fdt, uint32_t phandle)
390 {
391 uint32_t ret = 0;
392 int rc;
393
394 if (phandle == 0) {
395 rc = fdt_path_offset(fdt, "/");
396 } else {
397 rc = fdt_next_subnode(fdt, fdt_node_offset_by_phandle(fdt, phandle));
398 }
399
400 if (rc >= 0) {
401 ret = fdt_get_phandle(fdt, rc);
402 }
403
404 return ret;
405 }
406
vof_child(const void * fdt,uint32_t phandle)407 static uint32_t vof_child(const void *fdt, uint32_t phandle)
408 {
409 uint32_t ret = 0;
410 int rc = fdt_first_subnode(fdt, fdt_node_offset_by_phandle(fdt, phandle));
411
412 if (rc >= 0) {
413 ret = fdt_get_phandle(fdt, rc);
414 }
415
416 return ret;
417 }
418
vof_parent(const void * fdt,uint32_t phandle)419 static uint32_t vof_parent(const void *fdt, uint32_t phandle)
420 {
421 uint32_t ret = 0;
422 int rc = fdt_parent_offset(fdt, fdt_node_offset_by_phandle(fdt, phandle));
423
424 if (rc >= 0) {
425 ret = fdt_get_phandle(fdt, rc);
426 }
427
428 return ret;
429 }
430
vof_do_open(void * fdt,Vof * vof,int offset,const char * path)431 static uint32_t vof_do_open(void *fdt, Vof *vof, int offset, const char *path)
432 {
433 uint32_t ret = PROM_ERROR;
434 OfInstance *inst = NULL;
435
436 if (vof->of_instance_last == 0xFFFFFFFF) {
437 /* We do not recycle ihandles yet */
438 goto trace_exit;
439 }
440
441 inst = g_new0(OfInstance, 1);
442 inst->phandle = fdt_get_phandle(fdt, offset);
443 g_assert(inst->phandle);
444 ++vof->of_instance_last;
445
446 inst->path = g_strdup(path);
447 g_hash_table_insert(vof->of_instances,
448 GINT_TO_POINTER(vof->of_instance_last),
449 inst);
450 ret = vof->of_instance_last;
451
452 trace_exit:
453 trace_vof_open(path, inst ? inst->phandle : 0, ret);
454
455 return ret;
456 }
457
vof_client_open_store(void * fdt,Vof * vof,const char * nodename,const char * prop,const char * path)458 uint32_t vof_client_open_store(void *fdt, Vof *vof, const char *nodename,
459 const char *prop, const char *path)
460 {
461 int offset, node = fdt_path_offset(fdt, nodename);
462 uint32_t inst;
463
464 offset = fdt_path_offset(fdt, path);
465 if (offset < 0) {
466 trace_vof_error_unknown_path(path);
467 return PROM_ERROR;
468 }
469
470 inst = vof_do_open(fdt, vof, offset, path);
471
472 return fdt_setprop_cell(fdt, node, prop, inst) >= 0 ? 0 : PROM_ERROR;
473 }
474
vof_open(void * fdt,Vof * vof,uint32_t pathaddr)475 static uint32_t vof_open(void *fdt, Vof *vof, uint32_t pathaddr)
476 {
477 char path[VOF_MAX_PATH];
478 int offset;
479
480 if (readstr(pathaddr, path, sizeof(path))) {
481 return PROM_ERROR;
482 }
483
484 offset = path_offset(fdt, path);
485 if (offset < 0) {
486 trace_vof_error_unknown_path(path);
487 return PROM_ERROR;
488 }
489
490 return vof_do_open(fdt, vof, offset, path);
491 }
492
vof_close(Vof * vof,uint32_t ihandle)493 static void vof_close(Vof *vof, uint32_t ihandle)
494 {
495 if (!g_hash_table_remove(vof->of_instances, GINT_TO_POINTER(ihandle))) {
496 trace_vof_error_unknown_ihandle_close(ihandle);
497 }
498 }
499
vof_instance_to_package(Vof * vof,uint32_t ihandle)500 static uint32_t vof_instance_to_package(Vof *vof, uint32_t ihandle)
501 {
502 gpointer instp = g_hash_table_lookup(vof->of_instances,
503 GINT_TO_POINTER(ihandle));
504 uint32_t ret = PROM_ERROR;
505
506 if (instp) {
507 ret = ((OfInstance *)instp)->phandle;
508 }
509 trace_vof_instance_to_package(ihandle, ret);
510
511 return ret;
512 }
513
vof_package_to_path(const void * fdt,uint32_t phandle,uint32_t buf,uint32_t len)514 static uint32_t vof_package_to_path(const void *fdt, uint32_t phandle,
515 uint32_t buf, uint32_t len)
516 {
517 int rc;
518 char tmp[VOF_MAX_PATH] = "";
519
520 rc = phandle_to_path(fdt, phandle, tmp, sizeof(tmp));
521 if (rc > 0) {
522 if (VOF_MEM_WRITE(buf, tmp, rc) != MEMTX_OK) {
523 rc = -1;
524 }
525 }
526
527 trace_vof_package_to_path(phandle, tmp, rc);
528
529 return rc > 0 ? (uint32_t)rc : PROM_ERROR;
530 }
531
vof_instance_to_path(void * fdt,Vof * vof,uint32_t ihandle,uint32_t buf,uint32_t len)532 static uint32_t vof_instance_to_path(void *fdt, Vof *vof, uint32_t ihandle,
533 uint32_t buf, uint32_t len)
534 {
535 int rc = -1;
536 uint32_t phandle = vof_instance_to_package(vof, ihandle);
537 char tmp[VOF_MAX_PATH] = "";
538
539 if (phandle != -1) {
540 rc = phandle_to_path(fdt, phandle, tmp, sizeof(tmp));
541 if (rc > 0) {
542 if (VOF_MEM_WRITE(buf, tmp, rc) != MEMTX_OK) {
543 rc = -1;
544 }
545 }
546 }
547 trace_vof_instance_to_path(ihandle, phandle, tmp, rc);
548
549 return rc > 0 ? (uint32_t)rc : PROM_ERROR;
550 }
551
vof_write(Vof * vof,uint32_t ihandle,uint32_t buf,uint32_t len)552 static uint32_t vof_write(Vof *vof, uint32_t ihandle, uint32_t buf,
553 uint32_t len)
554 {
555 char tmp[VOF_VTY_BUF_SIZE];
556 unsigned cb;
557 OfInstance *inst = (OfInstance *)
558 g_hash_table_lookup(vof->of_instances, GINT_TO_POINTER(ihandle));
559
560 if (!inst) {
561 trace_vof_error_write(ihandle);
562 return PROM_ERROR;
563 }
564
565 for ( ; len > 0; len -= cb) {
566 cb = MIN(len, sizeof(tmp) - 1);
567 if (VOF_MEM_READ(buf, tmp, cb) != MEMTX_OK) {
568 return PROM_ERROR;
569 }
570
571 /* FIXME: there is no backend(s) yet so just call a trace */
572 if (trace_event_get_state(TRACE_VOF_WRITE) &&
573 qemu_loglevel_mask(LOG_TRACE)) {
574 tmp[cb] = '\0';
575 trace_vof_write(ihandle, cb, tmp);
576 }
577 }
578
579 return len;
580 }
581
vof_claimed_dump(GArray * claimed)582 static void vof_claimed_dump(GArray *claimed)
583 {
584 int i;
585 OfClaimed c;
586
587 if (trace_event_get_state(TRACE_VOF_CLAIMED) &&
588 qemu_loglevel_mask(LOG_TRACE)) {
589
590 for (i = 0; i < claimed->len; ++i) {
591 c = g_array_index(claimed, OfClaimed, i);
592 trace_vof_claimed(c.start, c.start + c.size, c.size);
593 }
594 }
595 }
596
vof_claim_avail(GArray * claimed,uint64_t virt,uint64_t size)597 static bool vof_claim_avail(GArray *claimed, uint64_t virt, uint64_t size)
598 {
599 int i;
600 OfClaimed c;
601
602 for (i = 0; i < claimed->len; ++i) {
603 c = g_array_index(claimed, OfClaimed, i);
604 if (ranges_overlap(c.start, c.size, virt, size)) {
605 return false;
606 }
607 }
608
609 return true;
610 }
611
vof_claim_add(GArray * claimed,uint64_t virt,uint64_t size)612 static void vof_claim_add(GArray *claimed, uint64_t virt, uint64_t size)
613 {
614 OfClaimed newclaim;
615
616 newclaim.start = virt;
617 newclaim.size = size;
618 g_array_append_val(claimed, newclaim);
619 }
620
of_claimed_compare_func(gconstpointer a,gconstpointer b)621 static gint of_claimed_compare_func(gconstpointer a, gconstpointer b)
622 {
623 return ((OfClaimed *)a)->start - ((OfClaimed *)b)->start;
624 }
625
vof_dt_memory_available(void * fdt,GArray * claimed,uint64_t base)626 static void vof_dt_memory_available(void *fdt, GArray *claimed, uint64_t base)
627 {
628 int i, n, offset, proplen = 0, sc, ac;
629 target_ulong mem0_end;
630 const uint8_t *mem0_reg;
631 g_autofree uint8_t *avail = NULL;
632 uint8_t *availcur;
633
634 if (!fdt || !claimed) {
635 return;
636 }
637
638 offset = fdt_path_offset(fdt, "/");
639 _FDT(offset);
640 ac = fdt_address_cells(fdt, offset);
641 g_assert(ac == 1 || ac == 2);
642 sc = fdt_size_cells(fdt, offset);
643 g_assert(sc == 1 || sc == 2);
644
645 offset = fdt_path_offset(fdt, "/memory@0");
646 _FDT(offset);
647
648 mem0_reg = fdt_getprop(fdt, offset, "reg", &proplen);
649 g_assert(mem0_reg && proplen == sizeof(uint32_t) * (ac + sc));
650 if (sc == 2) {
651 mem0_end = be64_to_cpu(*(uint64_t *)(mem0_reg + sizeof(uint32_t) * ac));
652 } else {
653 mem0_end = be32_to_cpu(*(uint32_t *)(mem0_reg + sizeof(uint32_t) * ac));
654 }
655
656 g_array_sort(claimed, of_claimed_compare_func);
657 vof_claimed_dump(claimed);
658
659 /*
660 * VOF resides in the first page so we do not need to check if there is
661 * available memory before the first claimed block
662 */
663 g_assert(claimed->len && (g_array_index(claimed, OfClaimed, 0).start == 0));
664
665 avail = g_malloc0(sizeof(uint32_t) * (ac + sc) * claimed->len);
666 for (i = 0, n = 0, availcur = avail; i < claimed->len; ++i) {
667 OfClaimed c = g_array_index(claimed, OfClaimed, i);
668 uint64_t start, size;
669
670 start = c.start + c.size;
671 if (i < claimed->len - 1) {
672 OfClaimed cn = g_array_index(claimed, OfClaimed, i + 1);
673
674 size = cn.start - start;
675 } else {
676 size = mem0_end - start;
677 }
678
679 if (ac == 2) {
680 *(uint64_t *) availcur = cpu_to_be64(start);
681 } else {
682 *(uint32_t *) availcur = cpu_to_be32(start);
683 }
684 availcur += sizeof(uint32_t) * ac;
685 if (sc == 2) {
686 *(uint64_t *) availcur = cpu_to_be64(size);
687 } else {
688 *(uint32_t *) availcur = cpu_to_be32(size);
689 }
690 availcur += sizeof(uint32_t) * sc;
691
692 if (size) {
693 trace_vof_avail(c.start + c.size, c.start + c.size + size, size);
694 ++n;
695 }
696 }
697 _FDT((fdt_setprop(fdt, offset, "available", avail, availcur - avail)));
698 }
699
700 /*
701 * OF1275:
702 * "Allocates size bytes of memory. If align is zero, the allocated range
703 * begins at the virtual address virt. Otherwise, an aligned address is
704 * automatically chosen and the input argument virt is ignored".
705 *
706 * In other words, exactly one of @virt and @align is non-zero.
707 */
vof_claim(Vof * vof,uint64_t virt,uint64_t size,uint64_t align)708 uint64_t vof_claim(Vof *vof, uint64_t virt, uint64_t size,
709 uint64_t align)
710 {
711 uint64_t ret;
712
713 if (size == 0) {
714 ret = -1;
715 } else if (align == 0) {
716 if (!vof_claim_avail(vof->claimed, virt, size)) {
717 ret = -1;
718 } else {
719 ret = virt;
720 }
721 } else {
722 vof->claimed_base = QEMU_ALIGN_UP(vof->claimed_base, align);
723 while (1) {
724 if (vof->claimed_base >= vof->top_addr) {
725 error_report("Out of RMA memory for the OF client");
726 return -1;
727 }
728 if (vof_claim_avail(vof->claimed, vof->claimed_base, size)) {
729 break;
730 }
731 vof->claimed_base += size;
732 }
733 ret = vof->claimed_base;
734 }
735
736 if (ret != -1) {
737 vof->claimed_base = MAX(vof->claimed_base, ret + size);
738 vof_claim_add(vof->claimed, ret, size);
739 }
740 trace_vof_claim(virt, size, align, ret);
741
742 return ret;
743 }
744
vof_release(Vof * vof,uint64_t virt,uint64_t size)745 static uint32_t vof_release(Vof *vof, uint64_t virt, uint64_t size)
746 {
747 uint32_t ret = PROM_ERROR;
748 int i;
749 GArray *claimed = vof->claimed;
750 OfClaimed c;
751
752 for (i = 0; i < claimed->len; ++i) {
753 c = g_array_index(claimed, OfClaimed, i);
754 if (c.start == virt && c.size == size) {
755 g_array_remove_index(claimed, i);
756 ret = 0;
757 break;
758 }
759 }
760
761 trace_vof_release(virt, size, ret);
762
763 return ret;
764 }
765
vof_instantiate_rtas(Error ** errp)766 static void vof_instantiate_rtas(Error **errp)
767 {
768 error_setg(errp, "The firmware should have instantiated RTAS");
769 }
770
vof_call_method(MachineState * ms,Vof * vof,uint32_t methodaddr,uint32_t ihandle,uint32_t param1,uint32_t param2,uint32_t param3,uint32_t param4,uint32_t * ret2)771 static uint32_t vof_call_method(MachineState *ms, Vof *vof, uint32_t methodaddr,
772 uint32_t ihandle, uint32_t param1,
773 uint32_t param2, uint32_t param3,
774 uint32_t param4, uint32_t *ret2)
775 {
776 uint32_t ret = PROM_ERROR;
777 char method[VOF_MAX_METHODLEN] = "";
778 OfInstance *inst;
779
780 if (!ihandle) {
781 goto trace_exit;
782 }
783
784 inst = (OfInstance *)g_hash_table_lookup(vof->of_instances,
785 GINT_TO_POINTER(ihandle));
786 if (!inst) {
787 goto trace_exit;
788 }
789
790 if (readstr(methodaddr, method, sizeof(method))) {
791 goto trace_exit;
792 }
793
794 if (strcmp(inst->path, "/") == 0) {
795 if (strcmp(method, "ibm,client-architecture-support") == 0) {
796 Object *vmo = object_dynamic_cast(OBJECT(ms), TYPE_VOF_MACHINE_IF);
797
798 if (vmo) {
799 VofMachineIfClass *vmc = VOF_MACHINE_GET_CLASS(vmo);
800
801 g_assert(vmc->client_architecture_support);
802 ret = (uint32_t)vmc->client_architecture_support(ms, first_cpu,
803 param1);
804 }
805
806 *ret2 = 0;
807 }
808 } else if (strcmp(inst->path, "/rtas") == 0) {
809 if (strcmp(method, "instantiate-rtas") == 0) {
810 vof_instantiate_rtas(&error_fatal);
811 ret = 0;
812 *ret2 = param1; /* rtas-base */
813 }
814 } else {
815 trace_vof_error_unknown_method(method);
816 }
817
818 trace_exit:
819 trace_vof_method(ihandle, method, param1, ret, *ret2);
820
821 return ret;
822 }
823
vof_call_interpret(uint32_t cmdaddr,uint32_t param1,uint32_t param2,uint32_t * ret2)824 static uint32_t vof_call_interpret(uint32_t cmdaddr, uint32_t param1,
825 uint32_t param2, uint32_t *ret2)
826 {
827 uint32_t ret = PROM_ERROR;
828 char cmd[VOF_MAX_FORTHCODE] = "";
829
830 /* No interpret implemented so just call a trace */
831 readstr(cmdaddr, cmd, sizeof(cmd));
832 trace_vof_interpret(cmd, param1, param2, ret, *ret2);
833
834 return ret;
835 }
836
vof_quiesce(MachineState * ms,void * fdt,Vof * vof)837 static void vof_quiesce(MachineState *ms, void *fdt, Vof *vof)
838 {
839 Object *vmo = object_dynamic_cast(OBJECT(ms), TYPE_VOF_MACHINE_IF);
840 /* After "quiesce", no change is expected to the FDT, pack FDT to ensure */
841 int rc = fdt_pack(fdt);
842
843 assert(rc == 0);
844
845 if (vmo) {
846 VofMachineIfClass *vmc = VOF_MACHINE_GET_CLASS(vmo);
847
848 if (vmc->quiesce) {
849 vmc->quiesce(ms);
850 }
851 }
852
853 vof_claimed_dump(vof->claimed);
854 }
855
vof_client_handle(MachineState * ms,void * fdt,Vof * vof,const char * service,uint32_t * args,unsigned nargs,uint32_t * rets,unsigned nrets)856 static uint32_t vof_client_handle(MachineState *ms, void *fdt, Vof *vof,
857 const char *service,
858 uint32_t *args, unsigned nargs,
859 uint32_t *rets, unsigned nrets)
860 {
861 uint32_t ret = 0;
862
863 /* @nrets includes the value which this function returns */
864 #define cmpserv(s, a, r) \
865 cmpservice(service, nargs, nrets, (s), (a), (r))
866
867 if (cmpserv("finddevice", 1, 1)) {
868 ret = vof_finddevice(fdt, args[0]);
869 } else if (cmpserv("getprop", 4, 1)) {
870 ret = vof_getprop(fdt, args[0], args[1], args[2], args[3]);
871 } else if (cmpserv("getproplen", 2, 1)) {
872 ret = vof_getproplen(fdt, args[0], args[1]);
873 } else if (cmpserv("setprop", 4, 1)) {
874 ret = vof_setprop(ms, fdt, vof, args[0], args[1], args[2], args[3]);
875 } else if (cmpserv("nextprop", 3, 1)) {
876 ret = vof_nextprop(fdt, args[0], args[1], args[2]);
877 } else if (cmpserv("peer", 1, 1)) {
878 ret = vof_peer(fdt, args[0]);
879 } else if (cmpserv("child", 1, 1)) {
880 ret = vof_child(fdt, args[0]);
881 } else if (cmpserv("parent", 1, 1)) {
882 ret = vof_parent(fdt, args[0]);
883 } else if (cmpserv("open", 1, 1)) {
884 ret = vof_open(fdt, vof, args[0]);
885 } else if (cmpserv("close", 1, 0)) {
886 vof_close(vof, args[0]);
887 } else if (cmpserv("instance-to-package", 1, 1)) {
888 ret = vof_instance_to_package(vof, args[0]);
889 } else if (cmpserv("package-to-path", 3, 1)) {
890 ret = vof_package_to_path(fdt, args[0], args[1], args[2]);
891 } else if (cmpserv("instance-to-path", 3, 1)) {
892 ret = vof_instance_to_path(fdt, vof, args[0], args[1], args[2]);
893 } else if (cmpserv("write", 3, 1)) {
894 ret = vof_write(vof, args[0], args[1], args[2]);
895 } else if (cmpserv("claim", 3, 1)) {
896 uint64_t ret64 = vof_claim(vof, args[0], args[1], args[2]);
897
898 if (ret64 < 0x100000000UL) {
899 vof_dt_memory_available(fdt, vof->claimed, vof->claimed_base);
900 ret = (uint32_t)ret64;
901 } else {
902 if (ret64 != -1) {
903 vof_release(vof, ret, args[1]);
904 }
905 ret = PROM_ERROR;
906 }
907 } else if (cmpserv("release", 2, 0)) {
908 ret = vof_release(vof, args[0], args[1]);
909 if (ret != PROM_ERROR) {
910 vof_dt_memory_available(fdt, vof->claimed, vof->claimed_base);
911 }
912 } else if (cmpserv("call-method", 0, 0)) {
913 ret = vof_call_method(ms, vof, args[0], args[1], args[2], args[3],
914 args[4], args[5], rets);
915 } else if (cmpserv("interpret", 0, 0)) {
916 ret = vof_call_interpret(args[0], args[1], args[2], rets);
917 } else if (cmpserv("milliseconds", 0, 1)) {
918 ret = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL);
919 } else if (cmpserv("quiesce", 0, 0)) {
920 vof_quiesce(ms, fdt, vof);
921 } else if (cmpserv("exit", 0, 0)) {
922 error_report("Stopped as the VM requested \"exit\"");
923 vm_stop(RUN_STATE_PAUSED);
924 } else {
925 trace_vof_error_unknown_service(service, nargs, nrets);
926 ret = -1;
927 }
928
929 #undef cmpserv
930
931 return ret;
932 }
933
934 /* Defined as Big Endian */
935 struct prom_args {
936 uint32_t service;
937 uint32_t nargs;
938 uint32_t nret;
939 uint32_t args[10];
940 } QEMU_PACKED;
941
vof_client_call(MachineState * ms,Vof * vof,void * fdt,target_ulong args_real)942 int vof_client_call(MachineState *ms, Vof *vof, void *fdt,
943 target_ulong args_real)
944 {
945 struct prom_args args_be;
946 uint32_t args[ARRAY_SIZE(args_be.args)];
947 uint32_t rets[ARRAY_SIZE(args_be.args)] = { 0 }, ret;
948 char service[64];
949 unsigned nargs, nret, i;
950
951 if (VOF_MEM_READ(args_real, &args_be, sizeof(args_be)) != MEMTX_OK) {
952 return -EINVAL;
953 }
954 nargs = be32_to_cpu(args_be.nargs);
955 if (nargs >= ARRAY_SIZE(args_be.args)) {
956 return -EINVAL;
957 }
958
959 if (VOF_MEM_READ(be32_to_cpu(args_be.service), service, sizeof(service)) !=
960 MEMTX_OK) {
961 return -EINVAL;
962 }
963 if (strnlen(service, sizeof(service)) == sizeof(service)) {
964 /* Too long service name */
965 return -EINVAL;
966 }
967
968 for (i = 0; i < nargs; ++i) {
969 args[i] = be32_to_cpu(args_be.args[i]);
970 }
971
972 nret = be32_to_cpu(args_be.nret);
973 if (nret > ARRAY_SIZE(args_be.args) - nargs) {
974 return -EINVAL;
975 }
976 ret = vof_client_handle(ms, fdt, vof, service, args, nargs, rets, nret);
977 if (!nret) {
978 return 0;
979 }
980
981 /* @nrets includes the value which this function returns */
982 args_be.args[nargs] = cpu_to_be32(ret);
983 for (i = 1; i < nret; ++i) {
984 args_be.args[nargs + i] = cpu_to_be32(rets[i - 1]);
985 }
986
987 if (VOF_MEM_WRITE(args_real + offsetof(struct prom_args, args[nargs]),
988 args_be.args + nargs, sizeof(args_be.args[0]) * nret) !=
989 MEMTX_OK) {
990 return -EINVAL;
991 }
992
993 return 0;
994 }
995
vof_instance_free(gpointer data)996 static void vof_instance_free(gpointer data)
997 {
998 OfInstance *inst = (OfInstance *)data;
999
1000 g_free(inst->path);
1001 g_free(inst);
1002 }
1003
vof_init(Vof * vof,uint64_t top_addr,Error ** errp)1004 void vof_init(Vof *vof, uint64_t top_addr, Error **errp)
1005 {
1006 vof_cleanup(vof);
1007
1008 vof->of_instances = g_hash_table_new_full(g_direct_hash, g_direct_equal,
1009 NULL, vof_instance_free);
1010 vof->claimed = g_array_new(false, false, sizeof(OfClaimed));
1011
1012 /* Keep allocations in 32bit as CLI ABI can only return cells==32bit */
1013 vof->top_addr = MIN(top_addr, 4 * GiB);
1014 if (vof_claim(vof, 0, vof->fw_size, 0) == -1) {
1015 error_setg(errp, "Memory for firmware is in use");
1016 }
1017 }
1018
vof_cleanup(Vof * vof)1019 void vof_cleanup(Vof *vof)
1020 {
1021 if (vof->claimed) {
1022 g_array_unref(vof->claimed);
1023 }
1024 if (vof->of_instances) {
1025 g_hash_table_unref(vof->of_instances);
1026 }
1027 vof->claimed = NULL;
1028 vof->of_instances = NULL;
1029 }
1030
vof_build_dt(void * fdt,Vof * vof)1031 void vof_build_dt(void *fdt, Vof *vof)
1032 {
1033 uint32_t phandle = fdt_get_max_phandle(fdt);
1034 int offset, proplen = 0;
1035 const void *prop;
1036
1037 /* Assign phandles to nodes without predefined phandles (like XICS/XIVE) */
1038 for (offset = fdt_next_node(fdt, -1, NULL);
1039 offset >= 0;
1040 offset = fdt_next_node(fdt, offset, NULL)) {
1041 prop = fdt_getprop(fdt, offset, "phandle", &proplen);
1042 if (prop) {
1043 continue;
1044 }
1045 ++phandle;
1046 _FDT(fdt_setprop_cell(fdt, offset, "phandle", phandle));
1047 }
1048
1049 vof_dt_memory_available(fdt, vof->claimed, vof->claimed_base);
1050 }
1051
1052 static const TypeInfo vof_machine_if_info = {
1053 .name = TYPE_VOF_MACHINE_IF,
1054 .parent = TYPE_INTERFACE,
1055 .class_size = sizeof(VofMachineIfClass),
1056 };
1057
vof_machine_if_register_types(void)1058 static void vof_machine_if_register_types(void)
1059 {
1060 type_register_static(&vof_machine_if_info);
1061 }
1062 type_init(vof_machine_if_register_types)
1063