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