1 /* $NetBSD: Locore.c,v 1.7 2000/08/20 07:04:59 tsubai Exp $ */
2
3 /*-
4 * SPDX-License-Identifier:BSD-4-Clause AND BSD-2-Clause-FreeBSD
5 *
6 * Copyright (C) 1995, 1996 Wolfgang Solfrank.
7 * Copyright (C) 1995, 1996 TooLs GmbH.
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by TooLs GmbH.
21 * 4. The name of TooLs GmbH may not be used to endorse or promote products
22 * derived from this software without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
25 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
29 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
30 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
31 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
32 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
33 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 */
35 /*-
36 * Copyright (C) 2000 Benno Rice.
37 * All rights reserved.
38 *
39 * Redistribution and use in source and binary forms, with or without
40 * modification, are permitted provided that the following conditions
41 * are met:
42 * 1. Redistributions of source code must retain the above copyright
43 * notice, this list of conditions and the following disclaimer.
44 * 2. Redistributions in binary form must reproduce the above copyright
45 * notice, this list of conditions and the following disclaimer in the
46 * documentation and/or other materials provided with the distribution.
47 *
48 * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR
49 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
50 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
51 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
52 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
53 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
54 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
55 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
56 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
57 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
58 */
59
60 #include <sys/cdefs.h>
61 __FBSDID("$FreeBSD$");
62
63 #include <sys/endian.h>
64 #include <sys/param.h>
65 #include <sys/kernel.h>
66 #include <sys/lock.h>
67 #include <sys/mutex.h>
68 #include <sys/systm.h>
69
70 #include <vm/vm.h>
71 #include <vm/vm_page.h>
72 #include <vm/pmap.h>
73
74 #include <machine/bus.h>
75 #include <machine/md_var.h>
76 #include <machine/ofw_machdep.h>
77 #include <machine/stdarg.h>
78
79 #include <dev/ofw/openfirm.h>
80 #include <dev/ofw/ofwvar.h>
81 #include "ofw_if.h"
82
83 static int ofw_real_init(ofw_t, void *openfirm);
84 static int ofw_real_test(ofw_t, const char *name);
85 static phandle_t ofw_real_peer(ofw_t, phandle_t node);
86 static phandle_t ofw_real_child(ofw_t, phandle_t node);
87 static phandle_t ofw_real_parent(ofw_t, phandle_t node);
88 static phandle_t ofw_real_instance_to_package(ofw_t, ihandle_t instance);
89 static ssize_t ofw_real_getproplen(ofw_t, phandle_t package,
90 const char *propname);
91 static ssize_t ofw_real_getprop(ofw_t, phandle_t package, const char *propname,
92 void *buf, size_t buflen);
93 static int ofw_real_nextprop(ofw_t, phandle_t package, const char *previous,
94 char *buf, size_t);
95 static int ofw_real_setprop(ofw_t, phandle_t package, const char *propname,
96 const void *buf, size_t len);
97 static ssize_t ofw_real_canon(ofw_t, const char *device, char *buf, size_t len);
98 static phandle_t ofw_real_finddevice(ofw_t, const char *device);
99 static ssize_t ofw_real_instance_to_path(ofw_t, ihandle_t instance, char *buf,
100 size_t len);
101 static ssize_t ofw_real_package_to_path(ofw_t, phandle_t package, char *buf,
102 size_t len);
103 static int ofw_real_call_method(ofw_t, ihandle_t instance, const char *method,
104 int nargs, int nreturns, cell_t *args_and_returns);
105 static int ofw_real_interpret(ofw_t ofw, const char *cmd, int nreturns,
106 cell_t *returns);
107 static ihandle_t ofw_real_open(ofw_t, const char *device);
108 static void ofw_real_close(ofw_t, ihandle_t instance);
109 static ssize_t ofw_real_read(ofw_t, ihandle_t instance, void *addr, size_t len);
110 static ssize_t ofw_real_write(ofw_t, ihandle_t instance, const void *addr,
111 size_t len);
112 static int ofw_real_seek(ofw_t, ihandle_t instance, u_int64_t pos);
113 static caddr_t ofw_real_claim(ofw_t, void *virt, size_t size, u_int align);
114 static void ofw_real_release(ofw_t, void *virt, size_t size);
115 static void ofw_real_enter(ofw_t);
116 static void ofw_real_exit(ofw_t);
117
118 static ofw_method_t ofw_real_methods[] = {
119 OFWMETHOD(ofw_init, ofw_real_init),
120 OFWMETHOD(ofw_peer, ofw_real_peer),
121 OFWMETHOD(ofw_child, ofw_real_child),
122 OFWMETHOD(ofw_parent, ofw_real_parent),
123 OFWMETHOD(ofw_instance_to_package, ofw_real_instance_to_package),
124 OFWMETHOD(ofw_getproplen, ofw_real_getproplen),
125 OFWMETHOD(ofw_getprop, ofw_real_getprop),
126 OFWMETHOD(ofw_nextprop, ofw_real_nextprop),
127 OFWMETHOD(ofw_setprop, ofw_real_setprop),
128 OFWMETHOD(ofw_canon, ofw_real_canon),
129 OFWMETHOD(ofw_finddevice, ofw_real_finddevice),
130 OFWMETHOD(ofw_instance_to_path, ofw_real_instance_to_path),
131 OFWMETHOD(ofw_package_to_path, ofw_real_package_to_path),
132
133 OFWMETHOD(ofw_test, ofw_real_test),
134 OFWMETHOD(ofw_call_method, ofw_real_call_method),
135 OFWMETHOD(ofw_interpret, ofw_real_interpret),
136 OFWMETHOD(ofw_open, ofw_real_open),
137 OFWMETHOD(ofw_close, ofw_real_close),
138 OFWMETHOD(ofw_read, ofw_real_read),
139 OFWMETHOD(ofw_write, ofw_real_write),
140 OFWMETHOD(ofw_seek, ofw_real_seek),
141 OFWMETHOD(ofw_claim, ofw_real_claim),
142 OFWMETHOD(ofw_release, ofw_real_release),
143 OFWMETHOD(ofw_enter, ofw_real_enter),
144 OFWMETHOD(ofw_exit, ofw_real_exit),
145 { 0, 0 }
146 };
147
148 static ofw_def_t ofw_real = {
149 OFW_STD_REAL,
150 ofw_real_methods,
151 0
152 };
153 OFW_DEF(ofw_real);
154
155 static ofw_def_t ofw_32bit = {
156 OFW_STD_32BIT,
157 ofw_real_methods,
158 0
159 };
160 OFW_DEF(ofw_32bit);
161
162 static MALLOC_DEFINE(M_OFWREAL, "ofwreal",
163 "Open Firmware Real Mode Bounce Page");
164
165 static int (*openfirmware)(void *);
166
167 static vm_offset_t of_bounce_phys;
168 static caddr_t of_bounce_virt;
169 static off_t of_bounce_offset;
170 static size_t of_bounce_size;
171
172 #define IN(x) htobe32(x)
173 #define OUT(x) be32toh(x)
174
175 /*
176 * To be able to use OFW console on PPC, that requires real mode OFW,
177 * the mutex that guards the mapping/unmapping of virtual to physical
178 * buffers (of_real_mtx) must be of SPIN type. This is needed because
179 * kernel console first locks a SPIN mutex before calling OFW real.
180 * By default, of_real_mtx is a sleepable mutex. To make it of SPIN
181 * type, use the following tunnable:
182 * machdep.ofw.mtx_spin=1
183 *
184 * Besides that, a few more tunables are needed to select and use the
185 * OFW console with real mode OFW.
186 *
187 * In order to disable the use of OFW FrameBuffer and fallback to the
188 * OFW console, use:
189 * hw.ofwfb.disable=1
190 *
191 * To disable the use of FDT (that doesn't support OFW read/write methods)
192 * and use real OFW instead, unset the following loader variable:
193 * unset usefdt
194 *
195 * OFW is put in quiesce state in early kernel boot, which usually disables
196 * OFW read/write capabilities (in QEMU write continue to work, but
197 * read doesn't). To avoid OFW quiesce, use:
198 * debug.quiesce_ofw=0
199 *
200 * Note that disabling OFW quiesce can cause conflicts between kernel and
201 * OFW trying to control the same hardware. Thus, it must be used with care.
202 * Some conflicts can be avoided by disabling kernel drivers with hints.
203 * For instance, to disable a xhci controller and an USB keyboard connected
204 * to it, that may be already being used for input by OFW, use:
205 * hint.xhci.0.disabled=1
206 */
207
208 static struct mtx of_bounce_mtx;
209 static struct mtx of_spin_mtx;
210 static struct mtx *of_real_mtx;
211 static void (*of_mtx_lock)(void);
212 static void (*of_mtx_unlock)(void);
213
214 extern int ofw_real_mode;
215
216 /*
217 * After the VM is up, allocate a wired, low memory bounce page.
218 */
219
220 static void ofw_real_bounce_alloc(void *);
221
222 SYSINIT(ofw_real_bounce_alloc, SI_SUB_KMEM, SI_ORDER_ANY,
223 ofw_real_bounce_alloc, NULL);
224
225 static void
226 ofw_real_mtx_lock_spin(void)
227 {
228 mtx_lock_spin(of_real_mtx);
229 }
230
231 static void
232 ofw_real_mtx_lock(void)
233 {
234 mtx_lock(of_real_mtx);
235 }
236
237 static void
238 ofw_real_mtx_unlock_spin(void)
239 {
240 mtx_unlock_spin(of_real_mtx);
241 }
242
243 static void
244 ofw_real_mtx_unlock(void)
245 {
246 mtx_unlock(of_real_mtx);
247 }
248
249 static void
250 ofw_real_start(void)
251 {
252 (*of_mtx_lock)();
253 of_bounce_offset = 0;
254 }
255
256 static void
257 ofw_real_stop(void)
258 {
259 (*of_mtx_unlock)();
260 }
261
262 static void
263 ofw_real_bounce_alloc(void *junk)
264 {
265 caddr_t temp;
266
267 /*
268 * Check that ofw_real is actually in use before allocating wads
269 * of memory. Do this by checking if our mutex has been set up.
270 */
271 if (!mtx_initialized(&of_bounce_mtx))
272 return;
273
274 /*
275 * Allocate a page of contiguous, wired physical memory that can
276 * fit into a 32-bit address space and accessed from real mode.
277 */
278 temp = contigmalloc(4 * PAGE_SIZE, M_OFWREAL, 0, 0,
279 ulmin(platform_real_maxaddr(), BUS_SPACE_MAXADDR_32BIT), PAGE_SIZE,
280 4 * PAGE_SIZE);
281 if (temp == NULL)
282 panic("%s: Not able to allocated contiguous memory\n", __func__);
283
284 mtx_lock(&of_bounce_mtx);
285
286 of_bounce_virt = temp;
287
288 of_bounce_phys = vtophys(of_bounce_virt);
289 of_bounce_size = 4 * PAGE_SIZE;
290
291 /*
292 * For virtual-mode OF, direct map this physical address so that
293 * we have a 32-bit virtual address to give OF.
294 */
295
296 if (!ofw_real_mode && (!hw_direct_map || DMAP_BASE_ADDRESS != 0))
297 pmap_kenter(of_bounce_phys, of_bounce_phys);
298
299 mtx_unlock(&of_bounce_mtx);
300 }
301
302 static cell_t
303 ofw_real_map(const void *buf, size_t len)
304 {
305 static char emergency_buffer[255];
306 cell_t phys;
307
308 mtx_assert(of_real_mtx, MA_OWNED);
309
310 if (of_bounce_virt == NULL) {
311 /*
312 * If we haven't set up the MMU, then buf is guaranteed
313 * to be accessible to OF, because the only memory we
314 * can use right now is memory mapped by firmware.
315 */
316 if (!pmap_bootstrapped)
317 return (cell_t)((uintptr_t)buf & ~DMAP_BASE_ADDRESS);
318
319 /*
320 * XXX: It is possible for us to get called before the VM has
321 * come online, but after the MMU is up. We don't have the
322 * bounce buffer yet, but can no longer presume a 1:1 mapping.
323 * Copy into the emergency buffer, and reset at the end.
324 */
325 of_bounce_virt = emergency_buffer;
326 of_bounce_phys = (vm_offset_t)of_bounce_virt &
327 ~DMAP_BASE_ADDRESS;
328 of_bounce_size = sizeof(emergency_buffer);
329 }
330
331 /*
332 * Make sure the bounce page offset satisfies any reasonable
333 * alignment constraint.
334 */
335 of_bounce_offset += sizeof(register_t) -
336 (of_bounce_offset % sizeof(register_t));
337
338 if (of_bounce_offset + len > of_bounce_size) {
339 panic("Oversize Open Firmware call!");
340 return 0;
341 }
342
343 if (buf != NULL)
344 memcpy(of_bounce_virt + of_bounce_offset, buf, len);
345 else
346 return (0);
347
348 phys = of_bounce_phys + of_bounce_offset;
349
350 of_bounce_offset += len;
351
352 return (phys);
353 }
354
355 static void
356 ofw_real_unmap(cell_t physaddr, void *buf, size_t len)
357 {
358 mtx_assert(of_real_mtx, MA_OWNED);
359
360 if (of_bounce_virt == NULL)
361 return;
362
363 if (physaddr == 0)
364 return;
365
366 memcpy(buf,of_bounce_virt + (physaddr - of_bounce_phys),len);
367 }
368
369 /* Initialiser */
370
371 static int
372 ofw_real_init(ofw_t ofw, void *openfirm)
373 {
374 int mtx_spin;
375
376 openfirmware = (int (*)(void *))openfirm;
377 mtx_init(&of_bounce_mtx, "OF Bounce Page", NULL, MTX_DEF);
378
379 mtx_spin = 0;
380 TUNABLE_INT_FETCH("machdep.ofw.mtx_spin", &mtx_spin);
381 if (mtx_spin) {
382 mtx_init(&of_spin_mtx, "OF Real", NULL, MTX_SPIN);
383 of_real_mtx = &of_spin_mtx;
384 of_mtx_lock = ofw_real_mtx_lock_spin;
385 of_mtx_unlock = ofw_real_mtx_unlock_spin;
386 } else {
387 of_real_mtx = &of_bounce_mtx;
388 of_mtx_lock = ofw_real_mtx_lock;
389 of_mtx_unlock = ofw_real_mtx_unlock;
390 }
391
392 of_bounce_virt = NULL;
393 return (0);
394 }
395
396 /*
397 * Generic functions
398 */
399
400 /* Test to see if a service exists. */
401 static int
402 ofw_real_test(ofw_t ofw, const char *name)
403 {
404 vm_offset_t argsptr;
405 struct {
406 cell_t name;
407 cell_t nargs;
408 cell_t nreturns;
409 cell_t service;
410 cell_t missing;
411 } args;
412
413 args.name = IN((cell_t)(uintptr_t)"test");
414 args.nargs = IN(1);
415 args.nreturns = IN(1);
416
417 ofw_real_start();
418
419 args.service = IN(ofw_real_map(name, strlen(name) + 1));
420 argsptr = ofw_real_map(&args, sizeof(args));
421 if (args.service == 0 || openfirmware((void *)argsptr) == -1) {
422 ofw_real_stop();
423 return (-1);
424 }
425 ofw_real_unmap(argsptr, &args, sizeof(args));
426 ofw_real_stop();
427 return (OUT(args.missing));
428 }
429
430 /*
431 * Device tree functions
432 */
433
434 /* Return the next sibling of this node or 0. */
435 static phandle_t
436 ofw_real_peer(ofw_t ofw, phandle_t node)
437 {
438 vm_offset_t argsptr;
439 struct {
440 cell_t name;
441 cell_t nargs;
442 cell_t nreturns;
443 cell_t node;
444 cell_t next;
445 } args;
446
447 args.name = IN((cell_t)(uintptr_t)"peer");
448 args.nargs = IN(1);
449 args.nreturns = IN(1);
450
451 args.node = IN(node);
452 ofw_real_start();
453 argsptr = ofw_real_map(&args, sizeof(args));
454 if (openfirmware((void *)argsptr) == -1) {
455 ofw_real_stop();
456 return (0);
457 }
458 ofw_real_unmap(argsptr, &args, sizeof(args));
459 ofw_real_stop();
460 return (OUT(args.next));
461 }
462
463 /* Return the first child of this node or 0. */
464 static phandle_t
465 ofw_real_child(ofw_t ofw, phandle_t node)
466 {
467 vm_offset_t argsptr;
468 struct {
469 cell_t name;
470 cell_t nargs;
471 cell_t nreturns;
472 cell_t node;
473 cell_t child;
474 } args;
475
476 args.name = IN((cell_t)(uintptr_t)"child");
477 args.nargs = IN(1);
478 args.nreturns = IN(1);
479
480 args.node = IN(node);
481 ofw_real_start();
482 argsptr = ofw_real_map(&args, sizeof(args));
483 if (openfirmware((void *)argsptr) == -1) {
484 ofw_real_stop();
485 return (0);
486 }
487 ofw_real_unmap(argsptr, &args, sizeof(args));
488 ofw_real_stop();
489 return (OUT(args.child));
490 }
491
492 /* Return the parent of this node or 0. */
493 static phandle_t
494 ofw_real_parent(ofw_t ofw, phandle_t node)
495 {
496 vm_offset_t argsptr;
497 struct {
498 cell_t name;
499 cell_t nargs;
500 cell_t nreturns;
501 cell_t node;
502 cell_t parent;
503 } args;
504
505 args.name = IN((cell_t)(uintptr_t)"parent");
506 args.nargs = IN(1);
507 args.nreturns = IN(1);
508
509 args.node = IN(node);
510 ofw_real_start();
511 argsptr = ofw_real_map(&args, sizeof(args));
512 if (openfirmware((void *)argsptr) == -1) {
513 ofw_real_stop();
514 return (0);
515 }
516 ofw_real_unmap(argsptr, &args, sizeof(args));
517 ofw_real_stop();
518 return (OUT(args.parent));
519 }
520
521 /* Return the package handle that corresponds to an instance handle. */
522 static phandle_t
523 ofw_real_instance_to_package(ofw_t ofw, ihandle_t instance)
524 {
525 vm_offset_t argsptr;
526 struct {
527 cell_t name;
528 cell_t nargs;
529 cell_t nreturns;
530 cell_t instance;
531 cell_t package;
532 } args;
533
534 args.name = IN((cell_t)(uintptr_t)"instance-to-package");
535 args.nargs = IN(1);
536 args.nreturns = IN(1);
537
538 args.instance = IN(instance);
539 ofw_real_start();
540 argsptr = ofw_real_map(&args, sizeof(args));
541 if (openfirmware((void *)argsptr) == -1) {
542 ofw_real_stop();
543 return (-1);
544 }
545 ofw_real_unmap(argsptr, &args, sizeof(args));
546 ofw_real_stop();
547 return (OUT(args.package));
548 }
549
550 /* Get the length of a property of a package. */
551 static ssize_t
552 ofw_real_getproplen(ofw_t ofw, phandle_t package, const char *propname)
553 {
554 vm_offset_t argsptr;
555 struct {
556 cell_t name;
557 cell_t nargs;
558 cell_t nreturns;
559 cell_t package;
560 cell_t propname;
561 int32_t proplen;
562 } args;
563
564 args.name = IN((cell_t)(uintptr_t)"getproplen");
565 args.nargs = IN(2);
566 args.nreturns = IN(1);
567
568 ofw_real_start();
569
570 args.package = IN(package);
571 args.propname = IN(ofw_real_map(propname, strlen(propname) + 1));
572 argsptr = ofw_real_map(&args, sizeof(args));
573 if (args.propname == 0 || openfirmware((void *)argsptr) == -1) {
574 ofw_real_stop();
575 return (-1);
576 }
577 ofw_real_unmap(argsptr, &args, sizeof(args));
578 ofw_real_stop();
579 return ((ssize_t)(int32_t)OUT(args.proplen));
580 }
581
582 /* Get the value of a property of a package. */
583 static ssize_t
584 ofw_real_getprop(ofw_t ofw, phandle_t package, const char *propname, void *buf,
585 size_t buflen)
586 {
587 vm_offset_t argsptr;
588 struct {
589 cell_t name;
590 cell_t nargs;
591 cell_t nreturns;
592 cell_t package;
593 cell_t propname;
594 cell_t buf;
595 cell_t buflen;
596 int32_t size;
597 } args;
598
599 args.name = IN((cell_t)(uintptr_t)"getprop");
600 args.nargs = IN(4);
601 args.nreturns = IN(1);
602
603 ofw_real_start();
604
605 args.package = IN(package);
606 args.propname = IN(ofw_real_map(propname, strlen(propname) + 1));
607 args.buf = IN(ofw_real_map(buf, buflen));
608 args.buflen = IN(buflen);
609 argsptr = ofw_real_map(&args, sizeof(args));
610 if (args.propname == 0 || args.buf == 0 ||
611 openfirmware((void *)argsptr) == -1) {
612 ofw_real_stop();
613 return (-1);
614 }
615 ofw_real_unmap(argsptr, &args, sizeof(args));
616 ofw_real_unmap(OUT(args.buf), buf, buflen);
617
618 ofw_real_stop();
619 return ((ssize_t)(int32_t)OUT(args.size));
620 }
621
622 /* Get the next property of a package. */
623 static int
624 ofw_real_nextprop(ofw_t ofw, phandle_t package, const char *previous,
625 char *buf, size_t size)
626 {
627 vm_offset_t argsptr;
628 struct {
629 cell_t name;
630 cell_t nargs;
631 cell_t nreturns;
632 cell_t package;
633 cell_t previous;
634 cell_t buf;
635 cell_t flag;
636 } args;
637
638 args.name = IN((cell_t)(uintptr_t)"nextprop");
639 args.nargs = IN(3);
640 args.nreturns = IN(1);
641
642 ofw_real_start();
643
644 args.package = IN(package);
645 args.previous = IN(ofw_real_map(previous, (previous != NULL) ? (strlen(previous) + 1) : 0));
646 args.buf = IN(ofw_real_map(buf, size));
647 argsptr = ofw_real_map(&args, sizeof(args));
648 if (args.buf == 0 || openfirmware((void *)argsptr) == -1) {
649 ofw_real_stop();
650 return (-1);
651 }
652 ofw_real_unmap(argsptr, &args, sizeof(args));
653 ofw_real_unmap(OUT(args.buf), buf, size);
654
655 ofw_real_stop();
656 return (OUT(args.flag));
657 }
658
659 /* Set the value of a property of a package. */
660 /* XXX Has a bug on FirePower */
661 static int
662 ofw_real_setprop(ofw_t ofw, phandle_t package, const char *propname,
663 const void *buf, size_t len)
664 {
665 vm_offset_t argsptr;
666 struct {
667 cell_t name;
668 cell_t nargs;
669 cell_t nreturns;
670 cell_t package;
671 cell_t propname;
672 cell_t buf;
673 cell_t len;
674 cell_t size;
675 } args;
676
677 args.name = IN((cell_t)(uintptr_t)"setprop");
678 args.nargs = IN(4);
679 args.nreturns = IN(1);
680
681 ofw_real_start();
682
683 args.package = IN(package);
684 args.propname = IN(ofw_real_map(propname, strlen(propname) + 1));
685 args.buf = IN(ofw_real_map(buf, len));
686 args.len = IN(len);
687 argsptr = ofw_real_map(&args, sizeof(args));
688 if (args.propname == 0 || args.buf == 0 ||
689 openfirmware((void *)argsptr) == -1) {
690 ofw_real_stop();
691 return (-1);
692 }
693 ofw_real_unmap(argsptr, &args, sizeof(args));
694 ofw_real_stop();
695 return (OUT(args.size));
696 }
697
698 /* Convert a device specifier to a fully qualified pathname. */
699 static ssize_t
700 ofw_real_canon(ofw_t ofw, const char *device, char *buf, size_t len)
701 {
702 vm_offset_t argsptr;
703 struct {
704 cell_t name;
705 cell_t nargs;
706 cell_t nreturns;
707 cell_t device;
708 cell_t buf;
709 cell_t len;
710 int32_t size;
711 } args;
712
713 args.name = IN((cell_t)(uintptr_t)"canon");
714 args.nargs = IN(3);
715 args.nreturns = IN(1);
716
717 ofw_real_start();
718
719 args.device = IN(ofw_real_map(device, strlen(device) + 1));
720 args.buf = IN(ofw_real_map(buf, len));
721 args.len = IN(len);
722 argsptr = ofw_real_map(&args, sizeof(args));
723 if (args.device == 0 || args.buf == 0 ||
724 openfirmware((void *)argsptr) == -1) {
725 ofw_real_stop();
726 return (-1);
727 }
728 ofw_real_unmap(argsptr, &args, sizeof(args));
729 ofw_real_unmap(OUT(args.buf), buf, len);
730
731 ofw_real_stop();
732 return ((ssize_t)(int32_t)OUT(args.size));
733 }
734
735 /* Return a package handle for the specified device. */
736 static phandle_t
737 ofw_real_finddevice(ofw_t ofw, const char *device)
738 {
739 vm_offset_t argsptr;
740 struct {
741 cell_t name;
742 cell_t nargs;
743 cell_t nreturns;
744 cell_t device;
745 cell_t package;
746 } args;
747
748 args.name = IN((cell_t)(uintptr_t)"finddevice");
749 args.nargs = IN(1);
750 args.nreturns = IN(1);
751
752 ofw_real_start();
753
754 args.device = IN(ofw_real_map(device, strlen(device) + 1));
755 argsptr = ofw_real_map(&args, sizeof(args));
756 if (args.device == 0 ||
757 openfirmware((void *)argsptr) == -1) {
758 ofw_real_stop();
759 return (-1);
760 }
761 ofw_real_unmap(argsptr, &args, sizeof(args));
762 ofw_real_stop();
763 return (OUT(args.package));
764 }
765
766 /* Return the fully qualified pathname corresponding to an instance. */
767 static ssize_t
768 ofw_real_instance_to_path(ofw_t ofw, ihandle_t instance, char *buf, size_t len)
769 {
770 vm_offset_t argsptr;
771 struct {
772 cell_t name;
773 cell_t nargs;
774 cell_t nreturns;
775 cell_t instance;
776 cell_t buf;
777 cell_t len;
778 int32_t size;
779 } args;
780
781 args.name = IN((cell_t)(uintptr_t)"instance-to-path");
782 args.nargs = IN(3);
783 args.nreturns = IN(1);
784
785 ofw_real_start();
786
787 args.instance = IN(instance);
788 args.buf = IN(ofw_real_map(buf, len));
789 args.len = IN(len);
790 argsptr = ofw_real_map(&args, sizeof(args));
791 if (args.buf == 0 ||
792 openfirmware((void *)argsptr) == -1) {
793 ofw_real_stop();
794 return (-1);
795 }
796 ofw_real_unmap(argsptr, &args, sizeof(args));
797 ofw_real_unmap(OUT(args.buf), buf, len);
798
799 ofw_real_stop();
800 return ((ssize_t)(int32_t)OUT(args.size));
801 }
802
803 /* Return the fully qualified pathname corresponding to a package. */
804 static ssize_t
805 ofw_real_package_to_path(ofw_t ofw, phandle_t package, char *buf, size_t len)
806 {
807 vm_offset_t argsptr;
808 struct {
809 cell_t name;
810 cell_t nargs;
811 cell_t nreturns;
812 cell_t package;
813 cell_t buf;
814 cell_t len;
815 int32_t size;
816 } args;
817
818 args.name = IN((cell_t)(uintptr_t)"package-to-path");
819 args.nargs = IN(3);
820 args.nreturns = IN(1);
821
822 ofw_real_start();
823
824 args.package = IN(package);
825 args.buf = IN(ofw_real_map(buf, len));
826 args.len = IN(len);
827 argsptr = ofw_real_map(&args, sizeof(args));
828 if (args.buf == 0 ||
829 openfirmware((void *)argsptr) == -1) {
830 ofw_real_stop();
831 return (-1);
832 }
833 ofw_real_unmap(argsptr, &args, sizeof(args));
834 ofw_real_unmap(OUT(args.buf), buf, len);
835
836 ofw_real_stop();
837 return ((ssize_t)(int32_t)OUT(args.size));
838 }
839
840 /* Call the method in the scope of a given instance. */
841 static int
842 ofw_real_call_method(ofw_t ofw, ihandle_t instance, const char *method,
843 int nargs, int nreturns, cell_t *args_and_returns)
844 {
845 vm_offset_t argsptr;
846 struct {
847 cell_t name;
848 cell_t nargs;
849 cell_t nreturns;
850 cell_t method;
851 cell_t instance;
852 cell_t args_n_results[12];
853 } args;
854 cell_t *ap, *cp;
855 int n;
856
857 args.name = IN((cell_t)(uintptr_t)"call-method");
858 args.nargs = IN(2);
859 args.nreturns = IN(1);
860
861 if (nargs > 6)
862 return (-1);
863
864 ofw_real_start();
865 args.nargs = IN(nargs + 2);
866 args.nreturns = IN(nreturns + 1);
867 args.method = IN(ofw_real_map(method, strlen(method) + 1));
868 args.instance = IN(instance);
869
870 ap = args_and_returns;
871 for (cp = args.args_n_results + (n = nargs); --n >= 0;)
872 *--cp = IN(*(ap++));
873 argsptr = ofw_real_map(&args, sizeof(args));
874 if (args.method == 0 ||
875 openfirmware((void *)argsptr) == -1) {
876 ofw_real_stop();
877 return (-1);
878 }
879 ofw_real_unmap(argsptr, &args, sizeof(args));
880 ofw_real_stop();
881 if (OUT(args.args_n_results[nargs]))
882 return (OUT(args.args_n_results[nargs]));
883 for (cp = args.args_n_results + nargs + (n = OUT(args.nreturns)); --n > 0;)
884 *(ap++) = OUT(*--cp);
885 return (0);
886 }
887
888 static int
889 ofw_real_interpret(ofw_t ofw, const char *cmd, int nreturns, cell_t *returns)
890 {
891 vm_offset_t argsptr;
892 struct {
893 cell_t name;
894 cell_t nargs;
895 cell_t nreturns;
896 cell_t slot[16];
897 } args;
898 cell_t status;
899 int i = 0, j = 0;
900
901 args.name = IN((cell_t)(uintptr_t)"interpret");
902 args.nargs = IN(1);
903
904 ofw_real_start();
905 args.nreturns = IN(++nreturns);
906 args.slot[i++] = IN(ofw_real_map(cmd, strlen(cmd) + 1));
907 argsptr = ofw_real_map(&args, sizeof(args));
908 if (openfirmware((void *)argsptr) == -1) {
909 ofw_real_stop();
910 return (-1);
911 }
912 ofw_real_unmap(argsptr, &args, sizeof(args));
913 ofw_real_stop();
914 status = OUT(args.slot[i++]);
915 while (i < 1 + nreturns)
916 returns[j++] = OUT(args.slot[i++]);
917 return (status);
918 }
919
920 /*
921 * Device I/O functions
922 */
923
924 /* Open an instance for a device. */
925 static ihandle_t
926 ofw_real_open(ofw_t ofw, const char *device)
927 {
928 vm_offset_t argsptr;
929 struct {
930 cell_t name;
931 cell_t nargs;
932 cell_t nreturns;
933 cell_t device;
934 cell_t instance;
935 } args;
936
937 args.name = IN((cell_t)(uintptr_t)"open");
938 args.nargs = IN(1);
939 args.nreturns = IN(1);
940
941 ofw_real_start();
942
943 args.device = IN(ofw_real_map(device, strlen(device) + 1));
944 argsptr = ofw_real_map(&args, sizeof(args));
945 if (args.device == 0 || openfirmware((void *)argsptr) == -1
946 || args.instance == 0) {
947 ofw_real_stop();
948 return (-1);
949 }
950 ofw_real_unmap(argsptr, &args, sizeof(args));
951 ofw_real_stop();
952 return (OUT(args.instance));
953 }
954
955 /* Close an instance. */
956 static void
957 ofw_real_close(ofw_t ofw, ihandle_t instance)
958 {
959 vm_offset_t argsptr;
960 struct {
961 cell_t name;
962 cell_t nargs;
963 cell_t nreturns;
964 cell_t instance;
965 } args;
966
967 args.name = IN((cell_t)(uintptr_t)"close");
968 args.nargs = IN(1);
969 args.nreturns = IN(0);
970 args.instance = IN(instance);
971 ofw_real_start();
972 argsptr = ofw_real_map(&args, sizeof(args));
973 openfirmware((void *)argsptr);
974 ofw_real_stop();
975 }
976
977 /* Read from an instance. */
978 static ssize_t
979 ofw_real_read(ofw_t ofw, ihandle_t instance, void *addr, size_t len)
980 {
981 vm_offset_t argsptr;
982 struct {
983 cell_t name;
984 cell_t nargs;
985 cell_t nreturns;
986 cell_t instance;
987 cell_t addr;
988 cell_t len;
989 int32_t actual;
990 } args;
991
992 args.name = IN((cell_t)(uintptr_t)"read");
993 args.nargs = IN(3);
994 args.nreturns = IN(1);
995
996 ofw_real_start();
997
998 args.instance = IN(instance);
999 args.addr = IN(ofw_real_map(addr, len));
1000 args.len = IN(len);
1001 argsptr = ofw_real_map(&args, sizeof(args));
1002 if (args.addr == 0 || openfirmware((void *)argsptr) == -1) {
1003 ofw_real_stop();
1004 return (-1);
1005 }
1006 ofw_real_unmap(argsptr, &args, sizeof(args));
1007 ofw_real_unmap(OUT(args.addr), addr, len);
1008
1009 ofw_real_stop();
1010 return ((ssize_t)(int32_t)OUT(args.actual));
1011 }
1012
1013 /* Write to an instance. */
1014 static ssize_t
1015 ofw_real_write(ofw_t ofw, ihandle_t instance, const void *addr, size_t len)
1016 {
1017 vm_offset_t argsptr;
1018 struct {
1019 cell_t name;
1020 cell_t nargs;
1021 cell_t nreturns;
1022 cell_t instance;
1023 cell_t addr;
1024 cell_t len;
1025 int32_t actual;
1026 } args;
1027
1028 args.name = IN((cell_t)(uintptr_t)"write");
1029 args.nargs = IN(3);
1030 args.nreturns = IN(1);
1031
1032 ofw_real_start();
1033
1034 args.instance = IN(instance);
1035 args.addr = IN(ofw_real_map(addr, len));
1036 args.len = IN(len);
1037 argsptr = ofw_real_map(&args, sizeof(args));
1038 if (args.addr == 0 || openfirmware((void *)argsptr) == -1) {
1039 ofw_real_stop();
1040 return (-1);
1041 }
1042 ofw_real_unmap(argsptr, &args, sizeof(args));
1043 ofw_real_stop();
1044 return ((ssize_t)(int32_t)OUT(args.actual));
1045 }
1046
1047 /* Seek to a position. */
1048 static int
1049 ofw_real_seek(ofw_t ofw, ihandle_t instance, u_int64_t pos)
1050 {
1051 vm_offset_t argsptr;
1052 struct {
1053 cell_t name;
1054 cell_t nargs;
1055 cell_t nreturns;
1056 cell_t instance;
1057 cell_t poshi;
1058 cell_t poslo;
1059 cell_t status;
1060 } args;
1061
1062 args.name = IN((cell_t)(uintptr_t)"seek");
1063 args.nargs = IN(3);
1064 args.nreturns = IN(1);
1065
1066 args.instance = IN(instance);
1067 args.poshi = IN(pos >> 32);
1068 args.poslo = IN(pos);
1069 ofw_real_start();
1070 argsptr = ofw_real_map(&args, sizeof(args));
1071 if (openfirmware((void *)argsptr) == -1) {
1072 ofw_real_stop();
1073 return (-1);
1074 }
1075 ofw_real_unmap(argsptr, &args, sizeof(args));
1076 ofw_real_stop();
1077 return (OUT(args.status));
1078 }
1079
1080 /*
1081 * Memory functions
1082 */
1083
1084 /* Claim an area of memory. */
1085 static caddr_t
1086 ofw_real_claim(ofw_t ofw, void *virt, size_t size, u_int align)
1087 {
1088 vm_offset_t argsptr;
1089 struct {
1090 cell_t name;
1091 cell_t nargs;
1092 cell_t nreturns;
1093 cell_t virt;
1094 cell_t size;
1095 cell_t align;
1096 cell_t baseaddr;
1097 } args;
1098
1099 args.name = IN((cell_t)(uintptr_t)"claim");
1100 args.nargs = IN(3);
1101 args.nreturns = IN(1);
1102
1103 args.virt = IN((cell_t)(uintptr_t)virt);
1104 args.size = IN(size);
1105 args.align = IN(align);
1106 ofw_real_start();
1107 argsptr = ofw_real_map(&args, sizeof(args));
1108 if (openfirmware((void *)argsptr) == -1) {
1109 ofw_real_stop();
1110 return ((void *)-1);
1111 }
1112 ofw_real_unmap(argsptr, &args, sizeof(args));
1113 ofw_real_stop();
1114 return ((void *)(uintptr_t)(OUT(args.baseaddr)));
1115 }
1116
1117 /* Release an area of memory. */
1118 static void
1119 ofw_real_release(ofw_t ofw, void *virt, size_t size)
1120 {
1121 vm_offset_t argsptr;
1122 struct {
1123 cell_t name;
1124 cell_t nargs;
1125 cell_t nreturns;
1126 cell_t virt;
1127 cell_t size;
1128 } args;
1129
1130 args.name = IN((cell_t)(uintptr_t)"release");
1131 args.nargs = IN(2);
1132 args.nreturns = IN(0);
1133
1134 args.virt = IN((cell_t)(uintptr_t)virt);
1135 args.size = IN(size);
1136 ofw_real_start();
1137 argsptr = ofw_real_map(&args, sizeof(args));
1138 openfirmware((void *)argsptr);
1139 ofw_real_stop();
1140 }
1141
1142 /*
1143 * Control transfer functions
1144 */
1145
1146 /* Suspend and drop back to the Open Firmware interface. */
1147 static void
1148 ofw_real_enter(ofw_t ofw)
1149 {
1150 vm_offset_t argsptr;
1151 struct {
1152 cell_t name;
1153 cell_t nargs;
1154 cell_t nreturns;
1155 } args;
1156
1157 args.name = IN((cell_t)(uintptr_t)"enter");
1158 args.nargs = IN(0);
1159 args.nreturns = IN(0);
1160
1161 ofw_real_start();
1162 argsptr = ofw_real_map(&args, sizeof(args));
1163 openfirmware((void *)argsptr);
1164 /* We may come back. */
1165 ofw_real_stop();
1166 }
1167
1168 /* Shut down and drop back to the Open Firmware interface. */
1169 static void
1170 ofw_real_exit(ofw_t ofw)
1171 {
1172 vm_offset_t argsptr;
1173 struct {
1174 cell_t name;
1175 cell_t nargs;
1176 cell_t nreturns;
1177 } args;
1178
1179 args.name = IN((cell_t)(uintptr_t)"exit");
1180 args.nargs = IN(0);
1181 args.nreturns = IN(0);
1182
1183 ofw_real_start();
1184 argsptr = ofw_real_map(&args, sizeof(args));
1185 openfirmware((void *)argsptr);
1186 for (;;) /* just in case */
1187 ;
1188 ofw_real_stop();
1189 }
Cache object: 34aa34baaddd6b6abd15fe7a88369679
|