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