xref: /freebsd/sys/powerpc/ofw/ofw_real.c (revision cdb25d82)
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 MALLOC_DEFINE(M_OFWREAL, "ofwreal", "Open Firmware Real Mode Bounce Page");
162 
163 static int (*openfirmware)(void *);
164 
165 static vm_offset_t	of_bounce_phys;
166 static caddr_t		of_bounce_virt;
167 static off_t		of_bounce_offset;
168 static size_t		of_bounce_size;
169 static struct mtx	of_bounce_mtx;
170 
171 extern int		ofw_real_mode;
172 extern struct pmap	ofw_pmap;
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.
209 	 */
210 
211 	mtx_lock(&of_bounce_mtx);
212 
213 	of_bounce_virt = contigmalloc(PAGE_SIZE, M_OFWREAL, 0,
214 			     0, BUS_SPACE_MAXADDR_32BIT, PAGE_SIZE, PAGE_SIZE);
215 
216 	of_bounce_phys = vtophys(of_bounce_virt);
217 	of_bounce_size = PAGE_SIZE;
218 
219 	/*
220 	 * For virtual-mode OF, direct map this physical address so that
221 	 * we have a 32-bit virtual address to give OF.
222 	 */
223 
224 	if (!ofw_real_mode && !hw_direct_map)
225 		pmap_kenter(of_bounce_phys, of_bounce_phys);
226 
227 	mtx_unlock(&of_bounce_mtx);
228 }
229 
230 static cell_t
231 ofw_real_map(const void *buf, size_t len)
232 {
233 	static char emergency_buffer[255];
234 	cell_t phys;
235 
236 	mtx_assert(&of_bounce_mtx, MA_OWNED);
237 
238 	if (of_bounce_virt == NULL) {
239 		/*
240 		 * If we haven't set up the MMU, then buf is guaranteed
241 		 * to be accessible to OF, because the only memory we
242 		 * can use right now is memory mapped by firmware.
243 		 */
244 		if (!pmap_bootstrapped)
245 			return (cell_t)(uintptr_t)buf;
246 
247 		/*
248 		 * XXX: It is possible for us to get called before the VM has
249 		 * come online, but after the MMU is up. We don't have the
250 		 * bounce buffer yet, but can no longer presume a 1:1 mapping.
251 		 * Copy into the emergency buffer, and reset at the end.
252 		 */
253 		of_bounce_virt = emergency_buffer;
254 		of_bounce_phys = (vm_offset_t)of_bounce_virt;
255 		of_bounce_size = sizeof(emergency_buffer);
256 	}
257 
258 	/*
259 	 * Make sure the bounce page offset satisfies any reasonable
260 	 * alignment constraint.
261 	 */
262 	of_bounce_offset += sizeof(register_t) - (of_bounce_offset % sizeof(register_t));
263 
264 	if (of_bounce_offset + len > of_bounce_size) {
265 		panic("Oversize Open Firmware call!");
266 		return 0;
267 	}
268 
269 	memcpy(of_bounce_virt + of_bounce_offset, buf, len);
270 	phys = of_bounce_phys + of_bounce_offset;
271 
272 	of_bounce_offset += len;
273 
274 	return (phys);
275 }
276 
277 static void
278 ofw_real_unmap(cell_t physaddr, void *buf, size_t len)
279 {
280 	mtx_assert(&of_bounce_mtx, MA_OWNED);
281 
282 	if (of_bounce_virt == NULL)
283 		return;
284 
285 	memcpy(buf,of_bounce_virt + (physaddr - of_bounce_phys),len);
286 }
287 
288 /* Initialiser */
289 
290 static int
291 ofw_real_init(ofw_t ofw, void *openfirm)
292 {
293 	openfirmware = (int (*)(void *))openfirm;
294 
295 	mtx_init(&of_bounce_mtx, "OF Bounce Page", MTX_DEF, 0);
296 	of_bounce_virt = NULL;
297 	return (0);
298 }
299 
300 /*
301  * Generic functions
302  */
303 
304 /* Test to see if a service exists. */
305 static int
306 ofw_real_test(ofw_t ofw, const char *name)
307 {
308 	vm_offset_t argsptr;
309 	struct {
310 		cell_t name;
311 		cell_t nargs;
312 		cell_t nreturns;
313 		cell_t service;
314 		cell_t missing;
315 	} args;
316 
317 	args.name = (cell_t)(uintptr_t)"test";
318 	args.nargs = 1;
319 	args.nreturns = 1;
320 
321 	ofw_real_start();
322 
323 	args.service = ofw_real_map(name, strlen(name) + 1);
324 	argsptr = ofw_real_map(&args, sizeof(args));
325 	if (args.service == 0 || openfirmware((void *)argsptr) == -1) {
326 		ofw_real_stop();
327 		return (-1);
328 	}
329 	ofw_real_unmap(argsptr, &args, sizeof(args));
330 	ofw_real_stop();
331 	return (args.missing);
332 }
333 
334 /*
335  * Device tree functions
336  */
337 
338 /* Return the next sibling of this node or 0. */
339 static phandle_t
340 ofw_real_peer(ofw_t ofw, phandle_t node)
341 {
342 	vm_offset_t argsptr;
343 	struct {
344 		cell_t name;
345 		cell_t nargs;
346 		cell_t nreturns;
347 		cell_t node;
348 		cell_t next;
349 	} args;
350 
351 	args.name = (cell_t)(uintptr_t)"peer";
352 	args.nargs = 1;
353 	args.nreturns = 1;
354 
355 	args.node = node;
356 	ofw_real_start();
357 	argsptr = ofw_real_map(&args, sizeof(args));
358 	if (openfirmware((void *)argsptr) == -1) {
359 		ofw_real_stop();
360 		return (-1);
361 	}
362 	ofw_real_unmap(argsptr, &args, sizeof(args));
363 	ofw_real_stop();
364 	return (args.next);
365 }
366 
367 /* Return the first child of this node or 0. */
368 static phandle_t
369 ofw_real_child(ofw_t ofw, phandle_t node)
370 {
371 	vm_offset_t argsptr;
372 	struct {
373 		cell_t name;
374 		cell_t nargs;
375 		cell_t nreturns;
376 		cell_t node;
377 		cell_t child;
378 	} args;
379 
380 	args.name = (cell_t)(uintptr_t)"child";
381 	args.nargs = 1;
382 	args.nreturns = 1;
383 
384 	args.node = node;
385 	ofw_real_start();
386 	argsptr = ofw_real_map(&args, sizeof(args));
387 	if (openfirmware((void *)argsptr) == -1) {
388 		ofw_real_stop();
389 		return (-1);
390 	}
391 	ofw_real_unmap(argsptr, &args, sizeof(args));
392 	ofw_real_stop();
393 	return (args.child);
394 }
395 
396 /* Return the parent of this node or 0. */
397 static phandle_t
398 ofw_real_parent(ofw_t ofw, phandle_t node)
399 {
400 	vm_offset_t argsptr;
401 	struct {
402 		cell_t name;
403 		cell_t nargs;
404 		cell_t nreturns;
405 		cell_t node;
406 		cell_t parent;
407 	} args;
408 
409 	args.name = (cell_t)(uintptr_t)"parent";
410 	args.nargs = 1;
411 	args.nreturns = 1;
412 
413 	args.node = node;
414 	ofw_real_start();
415 	argsptr = ofw_real_map(&args, sizeof(args));
416 	if (openfirmware((void *)argsptr) == -1) {
417 		ofw_real_stop();
418 		return (-1);
419 	}
420 	ofw_real_unmap(argsptr, &args, sizeof(args));
421 	ofw_real_stop();
422 	return (args.parent);
423 }
424 
425 /* Return the package handle that corresponds to an instance handle. */
426 static phandle_t
427 ofw_real_instance_to_package(ofw_t ofw, ihandle_t instance)
428 {
429 	vm_offset_t argsptr;
430 	struct {
431 		cell_t name;
432 		cell_t nargs;
433 		cell_t nreturns;
434 		cell_t instance;
435 		cell_t package;
436 	} args;
437 
438 	args.name = (cell_t)(uintptr_t)"instance-to-package";
439 	args.nargs = 1;
440 	args.nreturns = 1;
441 
442 	args.instance = instance;
443 	ofw_real_start();
444 	argsptr = ofw_real_map(&args, sizeof(args));
445 	if (openfirmware((void *)argsptr) == -1) {
446 		ofw_real_stop();
447 		return (-1);
448 	}
449 	ofw_real_unmap(argsptr, &args, sizeof(args));
450 	ofw_real_stop();
451 	return (args.package);
452 }
453 
454 /* Get the length of a property of a package. */
455 static ssize_t
456 ofw_real_getproplen(ofw_t ofw, phandle_t package, const char *propname)
457 {
458 	vm_offset_t argsptr;
459 	struct {
460 		cell_t name;
461 		cell_t nargs;
462 		cell_t nreturns;
463 		cell_t package;
464 		cell_t propname;
465 		int32_t proplen;
466 	} args;
467 
468 	args.name = (cell_t)(uintptr_t)"getproplen";
469 	args.nargs = 2;
470 	args.nreturns = 1;
471 
472 	ofw_real_start();
473 
474 	args.package = package;
475 	args.propname = ofw_real_map(propname, strlen(propname) + 1);
476 	argsptr = ofw_real_map(&args, sizeof(args));
477 	if (args.propname == 0 || openfirmware((void *)argsptr) == -1) {
478 		ofw_real_stop();
479 		return (-1);
480 	}
481 	ofw_real_unmap(argsptr, &args, sizeof(args));
482 	ofw_real_stop();
483 	return (args.proplen);
484 }
485 
486 /* Get the value of a property of a package. */
487 static ssize_t
488 ofw_real_getprop(ofw_t ofw, phandle_t package, const char *propname, void *buf,
489     size_t buflen)
490 {
491 	vm_offset_t argsptr;
492 	struct {
493 		cell_t name;
494 		cell_t nargs;
495 		cell_t nreturns;
496 		cell_t package;
497 		cell_t propname;
498 		cell_t buf;
499 		cell_t buflen;
500 		int32_t size;
501 	} args;
502 
503 	args.name = (cell_t)(uintptr_t)"getprop";
504 	args.nargs = 4;
505 	args.nreturns = 1;
506 
507 	ofw_real_start();
508 
509 	args.package = package;
510 	args.propname = ofw_real_map(propname, strlen(propname) + 1);
511 	args.buf = ofw_real_map(buf, buflen);
512 	args.buflen = buflen;
513 	argsptr = ofw_real_map(&args, sizeof(args));
514 	if (args.propname == 0 || args.buf == 0 ||
515 	    openfirmware((void *)argsptr) == -1) {
516 		ofw_real_stop();
517 		return (-1);
518 	}
519 	ofw_real_unmap(argsptr, &args, sizeof(args));
520 	ofw_real_unmap(args.buf, buf, buflen);
521 
522 	ofw_real_stop();
523 	return (args.size);
524 }
525 
526 /* Get the next property of a package. */
527 static int
528 ofw_real_nextprop(ofw_t ofw, phandle_t package, const char *previous,
529     char *buf, size_t size)
530 {
531 	vm_offset_t argsptr;
532 	struct {
533 		cell_t name;
534 		cell_t nargs;
535 		cell_t nreturns;
536 		cell_t package;
537 		cell_t previous;
538 		cell_t buf;
539 		cell_t flag;
540 	} args;
541 
542 	args.name = (cell_t)(uintptr_t)"nextprop";
543 	args.nargs = 3;
544 	args.nreturns = 1;
545 
546 	ofw_real_start();
547 
548 	args.package = package;
549 	args.previous = ofw_real_map(previous, strlen(previous) + 1);
550 	args.buf = ofw_real_map(buf, size);
551 	argsptr = ofw_real_map(&args, sizeof(args));
552 	if (args.previous == 0 || args.buf == 0 ||
553 	    openfirmware((void *)argsptr) == -1) {
554 		ofw_real_stop();
555 		return (-1);
556 	}
557 	ofw_real_unmap(argsptr, &args, sizeof(args));
558 	ofw_real_unmap(args.buf, buf, size);
559 
560 	ofw_real_stop();
561 	return (args.flag);
562 }
563 
564 /* Set the value of a property of a package. */
565 /* XXX Has a bug on FirePower */
566 static int
567 ofw_real_setprop(ofw_t ofw, phandle_t package, const char *propname,
568     const void *buf, size_t len)
569 {
570 	vm_offset_t argsptr;
571 	struct {
572 		cell_t name;
573 		cell_t nargs;
574 		cell_t nreturns;
575 		cell_t package;
576 		cell_t propname;
577 		cell_t buf;
578 		cell_t len;
579 		cell_t size;
580 	} args;
581 
582 	args.name = (cell_t)(uintptr_t)"setprop";
583 	args.nargs = 4;
584 	args.nreturns = 1;
585 
586 	ofw_real_start();
587 
588 	args.package = package;
589 	args.propname = ofw_real_map(propname, strlen(propname) + 1);
590 	args.buf = ofw_real_map(buf, len);
591 	args.len = len;
592 	argsptr = ofw_real_map(&args, sizeof(args));
593 	if (args.propname == 0 || args.buf == 0 ||
594 	    openfirmware((void *)argsptr) == -1) {
595 		ofw_real_stop();
596 		return (-1);
597 	}
598 	ofw_real_unmap(argsptr, &args, sizeof(args));
599 	ofw_real_stop();
600 	return (args.size);
601 }
602 
603 /* Convert a device specifier to a fully qualified pathname. */
604 static ssize_t
605 ofw_real_canon(ofw_t ofw, const char *device, char *buf, size_t len)
606 {
607 	vm_offset_t argsptr;
608 	struct {
609 		cell_t name;
610 		cell_t nargs;
611 		cell_t nreturns;
612 		cell_t device;
613 		cell_t buf;
614 		cell_t len;
615 		int32_t size;
616 	} args;
617 
618 	args.name = (cell_t)(uintptr_t)"canon";
619 	args.nargs = 3;
620 	args.nreturns = 1;
621 
622 	ofw_real_start();
623 
624 	args.device = ofw_real_map(device, strlen(device) + 1);
625 	args.buf = ofw_real_map(buf, len);
626 	args.len = len;
627 	argsptr = ofw_real_map(&args, sizeof(args));
628 	if (args.device == 0 || args.buf == 0 ||
629 	    openfirmware((void *)argsptr) == -1) {
630 		ofw_real_stop();
631 		return (-1);
632 	}
633 	ofw_real_unmap(argsptr, &args, sizeof(args));
634 	ofw_real_unmap(args.buf, buf, len);
635 
636 	ofw_real_stop();
637 	return (args.size);
638 }
639 
640 /* Return a package handle for the specified device. */
641 static phandle_t
642 ofw_real_finddevice(ofw_t ofw, const char *device)
643 {
644 	vm_offset_t argsptr;
645 	struct {
646 		cell_t name;
647 		cell_t nargs;
648 		cell_t nreturns;
649 		cell_t device;
650 		cell_t package;
651 	} args;
652 
653 	args.name = (cell_t)(uintptr_t)"finddevice";
654 	args.nargs = 1;
655 	args.nreturns = 1;
656 
657 	ofw_real_start();
658 
659 	args.device = ofw_real_map(device, strlen(device) + 1);
660 	argsptr = ofw_real_map(&args, sizeof(args));
661 	if (args.device == 0 ||
662 	    openfirmware((void *)argsptr) == -1) {
663 		ofw_real_stop();
664 		return (-1);
665 	}
666 	ofw_real_unmap(argsptr, &args, sizeof(args));
667 	ofw_real_stop();
668 	return (args.package);
669 }
670 
671 /* Return the fully qualified pathname corresponding to an instance. */
672 static ssize_t
673 ofw_real_instance_to_path(ofw_t ofw, ihandle_t instance, char *buf, size_t len)
674 {
675 	vm_offset_t argsptr;
676 	struct {
677 		cell_t name;
678 		cell_t nargs;
679 		cell_t nreturns;
680 		cell_t instance;
681 		cell_t buf;
682 		cell_t len;
683 		int32_t size;
684 	} args;
685 
686 	args.name = (cell_t)(uintptr_t)"instance-to-path";
687 	args.nargs = 3;
688 	args.nreturns = 1;
689 
690 	ofw_real_start();
691 
692 	args.instance = instance;
693 	args.buf = ofw_real_map(buf, len);
694 	args.len = len;
695 	argsptr = ofw_real_map(&args, sizeof(args));
696 	if (args.buf == 0 ||
697 	    openfirmware((void *)argsptr) == -1) {
698 		ofw_real_stop();
699 		return (-1);
700 	}
701 	ofw_real_unmap(argsptr, &args, sizeof(args));
702 	ofw_real_unmap(args.buf, buf, len);
703 
704 	ofw_real_stop();
705 	return (args.size);
706 }
707 
708 /* Return the fully qualified pathname corresponding to a package. */
709 static ssize_t
710 ofw_real_package_to_path(ofw_t ofw, phandle_t package, char *buf, size_t len)
711 {
712 	vm_offset_t argsptr;
713 	struct {
714 		cell_t name;
715 		cell_t nargs;
716 		cell_t nreturns;
717 		cell_t package;
718 		cell_t buf;
719 		cell_t len;
720 		int32_t size;
721 	} args;
722 
723 	args.name = (cell_t)(uintptr_t)"package-to-path";
724 	args.nargs = 3;
725 	args.nreturns = 1;
726 
727 	ofw_real_start();
728 
729 	args.package = package;
730 	args.buf = ofw_real_map(buf, len);
731 	args.len = len;
732 	argsptr = ofw_real_map(&args, sizeof(args));
733 	if (args.buf == 0 ||
734 	    openfirmware((void *)argsptr) == -1) {
735 		ofw_real_stop();
736 		return (-1);
737 	}
738 	ofw_real_unmap(argsptr, &args, sizeof(args));
739 	ofw_real_unmap(args.buf, buf, len);
740 
741 	ofw_real_stop();
742 	return (args.size);
743 }
744 
745 /*  Call the method in the scope of a given instance. */
746 static int
747 ofw_real_call_method(ofw_t ofw, ihandle_t instance, const char *method,
748     int nargs, int nreturns, cell_t *args_and_returns)
749 {
750 	vm_offset_t argsptr;
751 	struct {
752 		cell_t name;
753 		cell_t nargs;
754 		cell_t nreturns;
755 		cell_t method;
756 		cell_t instance;
757 		cell_t args_n_results[12];
758 	} args;
759 	cell_t *ap, *cp;
760 	int n;
761 
762 	args.name = (cell_t)(uintptr_t)"call-method";
763 	args.nargs = 2;
764 	args.nreturns = 1;
765 
766 	if (nargs > 6)
767 		return (-1);
768 
769 	ofw_real_start();
770 	args.nargs = nargs + 2;
771 	args.nreturns = nreturns + 1;
772 	args.method = ofw_real_map(method, strlen(method) + 1);
773 	args.instance = instance;
774 
775 	ap = args_and_returns;
776 	for (cp = args.args_n_results + (n = nargs); --n >= 0;)
777 		*--cp = *(ap++);
778 	argsptr = ofw_real_map(&args, sizeof(args));
779 	if (args.method == 0 ||
780 	    openfirmware((void *)argsptr) == -1) {
781 		ofw_real_stop();
782 		return (-1);
783 	}
784 	ofw_real_unmap(argsptr, &args, sizeof(args));
785 	ofw_real_stop();
786 	if (args.args_n_results[nargs])
787 		return (args.args_n_results[nargs]);
788 	for (cp = args.args_n_results + nargs + (n = args.nreturns); --n > 0;)
789 		*(ap++) = *--cp;
790 	return (0);
791 }
792 
793 static int
794 ofw_real_interpret(ofw_t ofw, const char *cmd, int nreturns, cell_t *returns)
795 {
796 	vm_offset_t argsptr;
797 	struct {
798 		cell_t name;
799 		cell_t nargs;
800 		cell_t nreturns;
801 		cell_t slot[16];
802 	} args;
803 	cell_t status;
804 	int i = 0, j = 0;
805 
806 	args.name = (cell_t)(uintptr_t)"interpret";
807 	args.nargs = 1;
808 
809 	ofw_real_start();
810 	args.nreturns = ++nreturns;
811 	args.slot[i++] = ofw_real_map(cmd, strlen(cmd) + 1);
812 	argsptr = ofw_real_map(&args, sizeof(args));
813 	if (openfirmware((void *)argsptr) == -1) {
814 		ofw_real_stop();
815 		return (-1);
816 	}
817 	ofw_real_unmap(argsptr, &args, sizeof(args));
818 	ofw_real_stop();
819 	status = args.slot[i++];
820 	while (i < 1 + nreturns)
821 		returns[j++] = args.slot[i++];
822 	return (status);
823 }
824 
825 /*
826  * Device I/O functions
827  */
828 
829 /* Open an instance for a device. */
830 static ihandle_t
831 ofw_real_open(ofw_t ofw, const char *device)
832 {
833 	vm_offset_t argsptr;
834 	struct {
835 		cell_t name;
836 		cell_t nargs;
837 		cell_t nreturns;
838 		cell_t device;
839 		cell_t instance;
840 	} args;
841 
842 	args.name = (cell_t)(uintptr_t)"open";
843 	args.nargs = 1;
844 	args.nreturns = 1;
845 
846 	ofw_real_start();
847 
848 	args.device = ofw_real_map(device, strlen(device) + 1);
849 	argsptr = ofw_real_map(&args, sizeof(args));
850 	if (args.device == 0 || openfirmware((void *)argsptr) == -1
851 	    || args.instance == 0) {
852 		ofw_real_stop();
853 		return (-1);
854 	}
855 	ofw_real_unmap(argsptr, &args, sizeof(args));
856 	ofw_real_stop();
857 	return (args.instance);
858 }
859 
860 /* Close an instance. */
861 static void
862 ofw_real_close(ofw_t ofw, ihandle_t instance)
863 {
864 	vm_offset_t argsptr;
865 	struct {
866 		cell_t name;
867 		cell_t nargs;
868 		cell_t nreturns;
869 		cell_t instance;
870 	} args;
871 
872 	args.name = (cell_t)(uintptr_t)"close";
873 	args.nargs = 1;
874 	args.nreturns = 0;
875 	args.instance = instance;
876 	ofw_real_start();
877 	argsptr = ofw_real_map(&args, sizeof(args));
878 	openfirmware((void *)argsptr);
879 	ofw_real_stop();
880 }
881 
882 /* Read from an instance. */
883 static ssize_t
884 ofw_real_read(ofw_t ofw, ihandle_t instance, void *addr, size_t len)
885 {
886 	vm_offset_t argsptr;
887 	struct {
888 		cell_t name;
889 		cell_t nargs;
890 		cell_t nreturns;
891 		cell_t instance;
892 		cell_t addr;
893 		cell_t len;
894 		int32_t actual;
895 	} args;
896 
897 	args.name = (cell_t)(uintptr_t)"read";
898 	args.nargs = 3;
899 	args.nreturns = 1;
900 
901 	ofw_real_start();
902 
903 	args.instance = instance;
904 	args.addr = ofw_real_map(addr, len);
905 	args.len = len;
906 	argsptr = ofw_real_map(&args, sizeof(args));
907 	if (args.addr == 0 || openfirmware((void *)argsptr) == -1) {
908 		ofw_real_stop();
909 		return (-1);
910 	}
911 	ofw_real_unmap(argsptr, &args, sizeof(args));
912 	ofw_real_unmap(args.addr, addr, len);
913 
914 	ofw_real_stop();
915 	return (args.actual);
916 }
917 
918 /* Write to an instance. */
919 static ssize_t
920 ofw_real_write(ofw_t ofw, ihandle_t instance, const void *addr, size_t len)
921 {
922 	vm_offset_t argsptr;
923 	struct {
924 		cell_t name;
925 		cell_t nargs;
926 		cell_t nreturns;
927 		cell_t instance;
928 		cell_t addr;
929 		cell_t len;
930 		int32_t actual;
931 	} args;
932 
933 	args.name = (cell_t)(uintptr_t)"write";
934 	args.nargs = 3;
935 	args.nreturns = 1;
936 
937 	ofw_real_start();
938 
939 	args.instance = instance;
940 	args.addr = ofw_real_map(addr, len);
941 	args.len = len;
942 	argsptr = ofw_real_map(&args, sizeof(args));
943 	if (args.addr == 0 || openfirmware((void *)argsptr) == -1) {
944 		ofw_real_stop();
945 		return (-1);
946 	}
947 	ofw_real_unmap(argsptr, &args, sizeof(args));
948 	ofw_real_stop();
949 	return (args.actual);
950 }
951 
952 /* Seek to a position. */
953 static int
954 ofw_real_seek(ofw_t ofw, ihandle_t instance, u_int64_t pos)
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 		cell_t poshi;
963 		cell_t poslo;
964 		cell_t status;
965 	} args;
966 
967 	args.name = (cell_t)(uintptr_t)"seek";
968 	args.nargs = 3;
969 	args.nreturns = 1;
970 
971 	args.instance = instance;
972 	args.poshi = pos >> 32;
973 	args.poslo = pos;
974 	ofw_real_start();
975 	argsptr = ofw_real_map(&args, sizeof(args));
976 	if (openfirmware((void *)argsptr) == -1) {
977 		ofw_real_stop();
978 		return (-1);
979 	}
980 	ofw_real_unmap(argsptr, &args, sizeof(args));
981 	ofw_real_stop();
982 	return (args.status);
983 }
984 
985 /*
986  * Memory functions
987  */
988 
989 /* Claim an area of memory. */
990 static caddr_t
991 ofw_real_claim(ofw_t ofw, void *virt, size_t size, u_int align)
992 {
993 	vm_offset_t argsptr;
994 	struct {
995 		cell_t name;
996 		cell_t nargs;
997 		cell_t nreturns;
998 		cell_t virt;
999 		cell_t size;
1000 		cell_t align;
1001 		cell_t baseaddr;
1002 	} args;
1003 
1004 	args.name = (cell_t)(uintptr_t)"claim";
1005 	args.nargs = 3;
1006 	args.nreturns = 1;
1007 
1008 	args.virt = (cell_t)(uintptr_t)virt;
1009 	args.size = size;
1010 	args.align = align;
1011 	ofw_real_start();
1012 	argsptr = ofw_real_map(&args, sizeof(args));
1013 	if (openfirmware((void *)argsptr) == -1) {
1014 		ofw_real_stop();
1015 		return ((void *)-1);
1016 	}
1017 	ofw_real_unmap(argsptr, &args, sizeof(args));
1018 	ofw_real_stop();
1019 	return ((void *)(uintptr_t)args.baseaddr);
1020 }
1021 
1022 /* Release an area of memory. */
1023 static void
1024 ofw_real_release(ofw_t ofw, void *virt, size_t size)
1025 {
1026 	vm_offset_t argsptr;
1027 	struct {
1028 		cell_t name;
1029 		cell_t nargs;
1030 		cell_t nreturns;
1031 		cell_t virt;
1032 		cell_t size;
1033 	} args;
1034 
1035 	args.name = (cell_t)(uintptr_t)"release";
1036 	args.nargs = 2;
1037 	args.nreturns = 0;
1038 
1039 	args.virt = (cell_t)(uintptr_t)virt;
1040 	args.size = size;
1041 	ofw_real_start();
1042 	argsptr = ofw_real_map(&args, sizeof(args));
1043 	openfirmware((void *)argsptr);
1044 	ofw_real_stop();
1045 }
1046 
1047 /*
1048  * Control transfer functions
1049  */
1050 
1051 /* Suspend and drop back to the Open Firmware interface. */
1052 static void
1053 ofw_real_enter(ofw_t ofw)
1054 {
1055 	vm_offset_t argsptr;
1056 	struct {
1057 		cell_t name;
1058 		cell_t nargs;
1059 		cell_t nreturns;
1060 	} args;
1061 
1062 	args.name = (cell_t)(uintptr_t)"enter";
1063 	args.nargs = 0;
1064 	args.nreturns = 0;
1065 
1066 	ofw_real_start();
1067 	argsptr = ofw_real_map(&args, sizeof(args));
1068 	openfirmware((void *)argsptr);
1069 	/* We may come back. */
1070 	ofw_real_stop();
1071 }
1072 
1073 /* Shut down and drop back to the Open Firmware interface. */
1074 static void
1075 ofw_real_exit(ofw_t ofw)
1076 {
1077 	vm_offset_t argsptr;
1078 	struct {
1079 		cell_t name;
1080 		cell_t nargs;
1081 		cell_t nreturns;
1082 	} args;
1083 
1084 	args.name = (cell_t)(uintptr_t)"exit";
1085 	args.nargs = 0;
1086 	args.nreturns = 0;
1087 
1088 	ofw_real_start();
1089 	argsptr = ofw_real_map(&args, sizeof(args));
1090 	openfirmware((void *)argsptr);
1091 	for (;;)			/* just in case */
1092 		;
1093 	ofw_real_stop();
1094 }
1095 
1096