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