xref: /freebsd/sys/powerpc/ofw/ofw_real.c (revision 79bf3fcd)
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/pmap.h>
69 
70 #include <machine/stdarg.h>
71 #include <machine/bus.h>
72 #include <machine/pmap.h>
73 #include <machine/ofw_machdep.h>
74 
75 #include <dev/ofw/openfirm.h>
76 #include <dev/ofw/ofwvar.h>
77 #include "ofw_if.h"
78 
79 static void ofw_real_init(ofw_t, void *openfirm);
80 static int ofw_real_test(ofw_t, const char *name);
81 static phandle_t ofw_real_peer(ofw_t, phandle_t node);
82 static phandle_t ofw_real_child(ofw_t, phandle_t node);
83 static phandle_t ofw_real_parent(ofw_t, phandle_t node);
84 static phandle_t ofw_real_instance_to_package(ofw_t, ihandle_t instance);
85 static ssize_t ofw_real_getproplen(ofw_t, phandle_t package,
86     const char *propname);
87 static ssize_t ofw_real_getprop(ofw_t, phandle_t package, const char *propname,
88     void *buf, size_t buflen);
89 static int ofw_real_nextprop(ofw_t, phandle_t package, const char *previous,
90     char *buf, size_t);
91 static int ofw_real_setprop(ofw_t, phandle_t package, const char *propname,
92     const void *buf, size_t len);
93 static ssize_t ofw_real_canon(ofw_t, const char *device, char *buf, size_t len);
94 static phandle_t ofw_real_finddevice(ofw_t, const char *device);
95 static ssize_t ofw_real_instance_to_path(ofw_t, ihandle_t instance, char *buf,
96     size_t len);
97 static ssize_t ofw_real_package_to_path(ofw_t, phandle_t package, char *buf,
98     size_t len);
99 static int ofw_real_call_method(ofw_t, ihandle_t instance, const char *method,
100     int nargs, int nreturns, unsigned long *args_and_returns);
101 static ihandle_t ofw_real_open(ofw_t, const char *device);
102 static void ofw_real_close(ofw_t, ihandle_t instance);
103 static ssize_t ofw_real_read(ofw_t, ihandle_t instance, void *addr, size_t len);
104 static ssize_t ofw_real_write(ofw_t, ihandle_t instance, const void *addr,
105     size_t len);
106 static int ofw_real_seek(ofw_t, ihandle_t instance, u_int64_t pos);
107 static caddr_t ofw_real_claim(ofw_t, void *virt, size_t size, u_int align);
108 static void ofw_real_release(ofw_t, void *virt, size_t size);
109 static void ofw_real_quiesce(ofw_t);
110 static void ofw_real_enter(ofw_t);
111 static void ofw_real_exit(ofw_t);
112 
113 static ofw_method_t ofw_real_methods[] = {
114 	OFWMETHOD(ofw_init,			ofw_real_init),
115 	OFWMETHOD(ofw_peer,			ofw_real_peer),
116 	OFWMETHOD(ofw_child,			ofw_real_child),
117 	OFWMETHOD(ofw_parent,			ofw_real_parent),
118 	OFWMETHOD(ofw_instance_to_package,	ofw_real_instance_to_package),
119 	OFWMETHOD(ofw_getproplen,		ofw_real_getproplen),
120 	OFWMETHOD(ofw_getprop,			ofw_real_getprop),
121 	OFWMETHOD(ofw_nextprop,			ofw_real_nextprop),
122 	OFWMETHOD(ofw_setprop,			ofw_real_setprop),
123 	OFWMETHOD(ofw_canon,			ofw_real_canon),
124 	OFWMETHOD(ofw_finddevice,		ofw_real_finddevice),
125 	OFWMETHOD(ofw_instance_to_path,		ofw_real_instance_to_path),
126 	OFWMETHOD(ofw_package_to_path,		ofw_real_package_to_path),
127 
128 	OFWMETHOD(ofw_test,			ofw_real_test),
129 	OFWMETHOD(ofw_call_method,		ofw_real_call_method),
130 	OFWMETHOD(ofw_open,			ofw_real_open),
131 	OFWMETHOD(ofw_close,			ofw_real_close),
132 	OFWMETHOD(ofw_read,			ofw_real_read),
133 	OFWMETHOD(ofw_write,			ofw_real_write),
134 	OFWMETHOD(ofw_seek,			ofw_real_seek),
135 	OFWMETHOD(ofw_claim,			ofw_real_claim),
136 	OFWMETHOD(ofw_release,			ofw_real_release),
137 	OFWMETHOD(ofw_quiesce,			ofw_real_quiesce),
138 	OFWMETHOD(ofw_enter,			ofw_real_enter),
139 	OFWMETHOD(ofw_exit,			ofw_real_exit),
140 
141 	{ 0, 0 }
142 };
143 
144 static ofw_def_t ofw_real = {
145 	OFW_STD_REAL,
146 	ofw_real_methods,
147 	0
148 };
149 OFW_DEF(ofw_real);
150 
151 MALLOC_DEFINE(M_OFWREAL, "ofwreal", "Open Firmware Real Mode Bounce Page");
152 
153 static int (*openfirmware)(void *);
154 
155 static vm_offset_t	of_bounce_phys;
156 static caddr_t		of_bounce_virt;
157 static off_t		of_bounce_offset;
158 static size_t		of_bounce_size;
159 static struct mtx	of_bounce_mtx;
160 
161 /*
162  * After the VM is up, allocate a wired, low memory bounce page.
163  */
164 
165 static void ofw_real_bounce_alloc(void *);
166 
167 SYSINIT(ofw_real_bounce_alloc, SI_SUB_VM, SI_ORDER_ANY,
168     ofw_real_bounce_alloc, NULL);
169 
170 static void
171 ofw_real_start(void)
172 {
173 	mtx_lock(&of_bounce_mtx);
174 	of_bounce_offset = 0;
175 }
176 
177 static void
178 ofw_real_stop(void)
179 {
180 	mtx_unlock(&of_bounce_mtx);
181 }
182 
183 static void
184 ofw_real_bounce_alloc(void *junk)
185 {
186 	/*
187 	 * Check that ofw_real is actually in use before allocating wads
188 	 * of memory. Do this by checking if our mutex has been set up.
189 	 */
190 	if (!mtx_initialized(&of_bounce_mtx))
191 		return;
192 
193 	/*
194 	 * Allocate a page of contiguous, wired physical memory that can
195 	 * fit into a 32-bit address space.
196 	 */
197 
198 	mtx_lock(&of_bounce_mtx);
199 
200 	of_bounce_virt = contigmalloc(PAGE_SIZE, M_OFWREAL, 0,
201 			     0, BUS_SPACE_MAXADDR_32BIT, PAGE_SIZE, PAGE_SIZE);
202 	of_bounce_phys = vtophys(of_bounce_virt);
203 	of_bounce_size = PAGE_SIZE;
204 
205 	mtx_unlock(&of_bounce_mtx);
206 }
207 
208 static cell_t
209 ofw_real_map(const void *buf, size_t len)
210 {
211 	cell_t phys;
212 
213 	mtx_assert(&of_bounce_mtx, MA_OWNED);
214 
215 	if (of_bounce_virt == NULL) {
216 		if (!pmap_bootstrapped)
217 			return (cell_t)buf;
218 
219 		/*
220 		 * XXX: It is possible for us to get called before the VM has
221 		 * come online, but after the MMU is up. We don't have the
222 		 * bounce buffer yet, but can no longer presume a 1:1 mapping.
223 		 * Grab the physical address of the buffer, and hope it is
224 		 * in range if this happens.
225 		 */
226 		return (cell_t)vtophys(buf);
227 	}
228 
229 	/*
230 	 * Make sure the bounce page offset satisfies any reasonable
231 	 * alignment constraint.
232 	 */
233 	of_bounce_offset += of_bounce_offset % sizeof(register_t);
234 
235 	if (of_bounce_offset + len > of_bounce_size) {
236 		panic("Oversize Open Firmware call!");
237 		return 0;
238 	}
239 
240 	memcpy(of_bounce_virt + of_bounce_offset, buf, len);
241 	phys = of_bounce_phys + of_bounce_offset;
242 
243 	of_bounce_offset += len;
244 
245 	return phys;
246 }
247 
248 static void
249 ofw_real_unmap(cell_t physaddr, void *buf, size_t len)
250 {
251 	mtx_assert(&of_bounce_mtx, MA_OWNED);
252 
253 	if (of_bounce_virt == NULL)
254 		return;
255 
256 	memcpy(buf,of_bounce_virt + (physaddr - of_bounce_phys),len);
257 }
258 
259 /* Initialiser */
260 
261 static void
262 ofw_real_init(ofw_t ofw, void *openfirm)
263 {
264 	openfirmware = (int (*)(void *))openfirm;
265 
266 	mtx_init(&of_bounce_mtx, "OF Bounce Page", MTX_DEF, 0);
267 	of_bounce_virt = NULL;
268 }
269 
270 /*
271  * Generic functions
272  */
273 
274 /* Test to see if a service exists. */
275 static int
276 ofw_real_test(ofw_t ofw, const char *name)
277 {
278 	struct {
279 		cell_t name;
280 		cell_t nargs;
281 		cell_t nreturns;
282 		cell_t service;
283 		cell_t missing;
284 	} args = {
285 		(cell_t)"test",
286 		1,
287 		1,
288 	};
289 
290 	ofw_real_start();
291 
292 	args.service = ofw_real_map(name, strlen(name) + 1);
293 	if (args.service == 0 || openfirmware(&args) == -1) {
294 		ofw_real_stop();
295 		return (-1);
296 	}
297 	ofw_real_stop();
298 	return (args.missing);
299 }
300 
301 /*
302  * Device tree functions
303  */
304 
305 /* Return the next sibling of this node or 0. */
306 static phandle_t
307 ofw_real_peer(ofw_t ofw, phandle_t node)
308 {
309 	struct {
310 		cell_t name;
311 		cell_t nargs;
312 		cell_t nreturns;
313 		cell_t node;
314 		cell_t next;
315 	} args = {
316 		(cell_t)"peer",
317 		1,
318 		1,
319 	};
320 
321 	args.node = node;
322 	if (openfirmware(&args) == -1)
323 		return (-1);
324 	return (args.next);
325 }
326 
327 /* Return the first child of this node or 0. */
328 static phandle_t
329 ofw_real_child(ofw_t ofw, phandle_t node)
330 {
331 	struct {
332 		cell_t name;
333 		cell_t nargs;
334 		cell_t nreturns;
335 		cell_t node;
336 		cell_t child;
337 	} args = {
338 		(cell_t)"child",
339 		1,
340 		1,
341 	};
342 
343 	args.node = node;
344 	if (openfirmware(&args) == -1)
345 		return (-1);
346 	return (args.child);
347 }
348 
349 /* Return the parent of this node or 0. */
350 static phandle_t
351 ofw_real_parent(ofw_t ofw, phandle_t node)
352 {
353 	struct {
354 		cell_t name;
355 		cell_t nargs;
356 		cell_t nreturns;
357 		cell_t node;
358 		cell_t parent;
359 	} args = {
360 		(cell_t)"parent",
361 		1,
362 		1,
363 	};
364 
365 	args.node = node;
366 	if (openfirmware(&args) == -1)
367 		return (-1);
368 	return (args.parent);
369 }
370 
371 /* Return the package handle that corresponds to an instance handle. */
372 static phandle_t
373 ofw_real_instance_to_package(ofw_t ofw, ihandle_t instance)
374 {
375 	struct {
376 		cell_t name;
377 		cell_t nargs;
378 		cell_t nreturns;
379 		cell_t instance;
380 		cell_t package;
381 	} args = {
382 		(cell_t)"instance-to-package",
383 		1,
384 		1,
385 	};
386 
387 	args.instance = instance;
388 	if (openfirmware(&args) == -1)
389 		return (-1);
390 	return (args.package);
391 }
392 
393 /* Get the length of a property of a package. */
394 static ssize_t
395 ofw_real_getproplen(ofw_t ofw, phandle_t package, const char *propname)
396 {
397 	struct {
398 		cell_t name;
399 		cell_t nargs;
400 		cell_t nreturns;
401 		cell_t package;
402 		cell_t propname;
403 		cell_t proplen;
404 	} args = {
405 		(cell_t)"getproplen",
406 		2,
407 		1,
408 	};
409 
410 	ofw_real_start();
411 
412 	args.package = package;
413 	args.propname = ofw_real_map(propname, strlen(propname) + 1);
414 	if (args.propname == 0 || openfirmware(&args) == -1) {
415 		ofw_real_stop();
416 		return (-1);
417 	}
418 	ofw_real_stop();
419 	return (args.proplen);
420 }
421 
422 /* Get the value of a property of a package. */
423 static ssize_t
424 ofw_real_getprop(ofw_t ofw, phandle_t package, const char *propname, void *buf,
425     size_t buflen)
426 {
427 	struct {
428 		cell_t name;
429 		cell_t nargs;
430 		cell_t nreturns;
431 		cell_t package;
432 		cell_t propname;
433 		cell_t buf;
434 		cell_t buflen;
435 		cell_t size;
436 	} args = {
437 		(cell_t)"getprop",
438 		4,
439 		1,
440 	};
441 
442 	ofw_real_start();
443 
444 	args.package = package;
445 	args.propname = ofw_real_map(propname, strlen(propname) + 1);
446 	args.buf = ofw_real_map(buf, buflen);
447 	args.buflen = buflen;
448 	if (args.propname == 0 || args.buf == 0 || openfirmware(&args) == -1) {
449 		ofw_real_stop();
450 		return (-1);
451 	}
452 	ofw_real_unmap(args.buf, buf, buflen);
453 
454 	ofw_real_stop();
455 	return (args.size);
456 }
457 
458 /* Get the next property of a package. */
459 static int
460 ofw_real_nextprop(ofw_t ofw, phandle_t package, const char *previous,
461     char *buf, size_t size)
462 {
463 	struct {
464 		cell_t name;
465 		cell_t nargs;
466 		cell_t nreturns;
467 		cell_t package;
468 		cell_t previous;
469 		cell_t buf;
470 		cell_t flag;
471 	} args = {
472 		(cell_t)"nextprop",
473 		3,
474 		1,
475 	};
476 
477 	ofw_real_start();
478 
479 	args.package = package;
480 	args.previous = ofw_real_map(previous, strlen(previous) + 1);
481 	args.buf = ofw_real_map(buf, size);
482 	if (args.previous == 0 || args.buf == 0 || openfirmware(&args) == -1) {
483 		ofw_real_stop();
484 		return (-1);
485 	}
486 	ofw_real_unmap(args.buf, buf, size);
487 
488 	ofw_real_stop();
489 	return (args.flag);
490 }
491 
492 /* Set the value of a property of a package. */
493 /* XXX Has a bug on FirePower */
494 static int
495 ofw_real_setprop(ofw_t ofw, phandle_t package, const char *propname,
496     const void *buf, size_t len)
497 {
498 	struct {
499 		cell_t name;
500 		cell_t nargs;
501 		cell_t nreturns;
502 		cell_t package;
503 		cell_t propname;
504 		cell_t buf;
505 		cell_t len;
506 		cell_t size;
507 	} args = {
508 		(cell_t)"setprop",
509 		4,
510 		1,
511 	};
512 
513 	ofw_real_start();
514 
515 	args.package = package;
516 	args.propname = ofw_real_map(propname, strlen(propname) + 1);
517 	args.buf = ofw_real_map(buf, len);
518 	args.len = len;
519 	if (args.propname == 0 || args.buf == 0 || openfirmware(&args) == -1) {
520 		ofw_real_stop();
521 		return (-1);
522 	}
523 	ofw_real_stop();
524 	return (args.size);
525 }
526 
527 /* Convert a device specifier to a fully qualified pathname. */
528 static ssize_t
529 ofw_real_canon(ofw_t ofw, const char *device, char *buf, size_t len)
530 {
531 	struct {
532 		cell_t name;
533 		cell_t nargs;
534 		cell_t nreturns;
535 		cell_t device;
536 		cell_t buf;
537 		cell_t len;
538 		cell_t size;
539 	} args = {
540 		(cell_t)"canon",
541 		3,
542 		1,
543 	};
544 
545 	ofw_real_start();
546 
547 	args.device = ofw_real_map(device, strlen(device) + 1);
548 	args.buf = ofw_real_map(buf, len);
549 	args.len = len;
550 	if (args.device == 0 || args.buf == 0 || openfirmware(&args) == -1) {
551 		ofw_real_stop();
552 		return (-1);
553 	}
554 	ofw_real_unmap(args.buf, buf, len);
555 
556 	ofw_real_stop();
557 	return (args.size);
558 }
559 
560 /* Return a package handle for the specified device. */
561 static phandle_t
562 ofw_real_finddevice(ofw_t ofw, const char *device)
563 {
564 	struct {
565 		cell_t name;
566 		cell_t nargs;
567 		cell_t nreturns;
568 		cell_t device;
569 		cell_t package;
570 	} args = {
571 		(cell_t)"finddevice",
572 		1,
573 		1,
574 	};
575 
576 	ofw_real_start();
577 
578 	args.device = ofw_real_map(device, strlen(device) + 1);
579 	if (args.device == 0 || openfirmware(&args) == -1) {
580 		ofw_real_stop();
581 		return (-1);
582 	}
583 	ofw_real_stop();
584 	return (args.package);
585 }
586 
587 /* Return the fully qualified pathname corresponding to an instance. */
588 static ssize_t
589 ofw_real_instance_to_path(ofw_t ofw, ihandle_t instance, char *buf, size_t len)
590 {
591 	struct {
592 		cell_t name;
593 		cell_t nargs;
594 		cell_t nreturns;
595 		cell_t instance;
596 		cell_t buf;
597 		cell_t len;
598 		cell_t size;
599 	} args = {
600 		(cell_t)"instance-to-path",
601 		3,
602 		1,
603 	};
604 
605 	ofw_real_start();
606 
607 	args.instance = instance;
608 	args.buf = ofw_real_map(buf, len);
609 	args.len = len;
610 	if (args.buf == 0 || openfirmware(&args) == -1) {
611 		ofw_real_stop();
612 		return (-1);
613 	}
614 	ofw_real_unmap(args.buf, buf, len);
615 
616 	ofw_real_stop();
617 	return (args.size);
618 }
619 
620 /* Return the fully qualified pathname corresponding to a package. */
621 static ssize_t
622 ofw_real_package_to_path(ofw_t ofw, phandle_t package, char *buf, size_t len)
623 {
624 	struct {
625 		cell_t name;
626 		cell_t nargs;
627 		cell_t nreturns;
628 		cell_t package;
629 		cell_t buf;
630 		cell_t len;
631 		cell_t size;
632 	} args = {
633 		(cell_t)"package-to-path",
634 		3,
635 		1,
636 	};
637 
638 	ofw_real_start();
639 
640 	args.package = package;
641 	args.buf = ofw_real_map(buf, len);
642 	args.len = len;
643 	if (args.buf == 0 || openfirmware(&args) == -1) {
644 		ofw_real_stop();
645 		return (-1);
646 	}
647 	ofw_real_unmap(args.buf, buf, len);
648 
649 	ofw_real_stop();
650 	return (args.size);
651 }
652 
653 /*  Call the method in the scope of a given instance. */
654 static int
655 ofw_real_call_method(ofw_t ofw, ihandle_t instance, const char *method,
656     int nargs, int nreturns, unsigned long *args_and_returns)
657 {
658 	struct {
659 		cell_t name;
660 		cell_t nargs;
661 		cell_t nreturns;
662 		cell_t method;
663 		cell_t instance;
664 		cell_t args_n_results[12];
665 	} args = {
666 		(cell_t)"call-method",
667 		2,
668 		1,
669 	};
670 	cell_t *cp;
671 	unsigned long *ap;
672 	int n;
673 
674 	if (nargs > 6)
675 		return (-1);
676 
677 	ofw_real_start();
678 	args.nargs = nargs + 2;
679 	args.nreturns = nreturns + 1;
680 	args.method = ofw_real_map(method, strlen(method) + 1);
681 	args.instance = instance;
682 
683 	ap = args_and_returns;
684 	for (cp = args.args_n_results + (n = nargs); --n >= 0;)
685 		*--cp = *(ap++);
686 	if (args.method == 0 || openfirmware(&args) == -1) {
687 		ofw_real_stop();
688 		return (-1);
689 	}
690 	ofw_real_stop();
691 	if (args.args_n_results[nargs])
692 		return (args.args_n_results[nargs]);
693 	for (cp = args.args_n_results + nargs + (n = args.nreturns); --n > 0;)
694 		*(ap++) = *--cp;
695 	return (0);
696 }
697 
698 /*
699  * Device I/O functions
700  */
701 
702 /* Open an instance for a device. */
703 static ihandle_t
704 ofw_real_open(ofw_t ofw, const char *device)
705 {
706 	struct {
707 		cell_t name;
708 		cell_t nargs;
709 		cell_t nreturns;
710 		cell_t device;
711 		cell_t instance;
712 	} args = {
713 		(cell_t)"open",
714 		1,
715 		1,
716 	};
717 
718 	ofw_real_start();
719 
720 	args.device = ofw_real_map(device, strlen(device) + 1);
721 	if (args.device == 0 || openfirmware(&args) == -1
722 	    || args.instance == 0) {
723 		ofw_real_stop();
724 		return (-1);
725 	}
726 	ofw_real_stop();
727 	return (args.instance);
728 }
729 
730 /* Close an instance. */
731 static void
732 ofw_real_close(ofw_t ofw, ihandle_t instance)
733 {
734 	struct {
735 		cell_t name;
736 		cell_t nargs;
737 		cell_t nreturns;
738 		cell_t instance;
739 	} args = {
740 		(cell_t)"close",
741 		1,
742 		0,
743 	};
744 
745 	args.instance = instance;
746 	openfirmware(&args);
747 }
748 
749 /* Read from an instance. */
750 static ssize_t
751 ofw_real_read(ofw_t ofw, ihandle_t instance, void *addr, size_t len)
752 {
753 	struct {
754 		cell_t name;
755 		cell_t nargs;
756 		cell_t nreturns;
757 		cell_t instance;
758 		cell_t addr;
759 		cell_t len;
760 		cell_t actual;
761 	} args = {
762 		(cell_t)"read",
763 		3,
764 		1,
765 	};
766 
767 	ofw_real_start();
768 
769 	args.instance = instance;
770 	args.addr = ofw_real_map(addr, len);
771 	args.len = len;
772 	if (args.addr == 0 || openfirmware(&args) == -1) {
773 		ofw_real_stop();
774 		return (-1);
775 	}
776 	ofw_real_unmap(args.addr, addr, len);
777 
778 	ofw_real_stop();
779 	return (args.actual);
780 }
781 
782 /* Write to an instance. */
783 static ssize_t
784 ofw_real_write(ofw_t ofw, ihandle_t instance, const void *addr, size_t len)
785 {
786 	struct {
787 		cell_t name;
788 		cell_t nargs;
789 		cell_t nreturns;
790 		cell_t instance;
791 		cell_t addr;
792 		cell_t len;
793 		cell_t actual;
794 	} args = {
795 		(cell_t)"write",
796 		3,
797 		1,
798 	};
799 
800 	ofw_real_start();
801 
802 	args.instance = instance;
803 	args.addr = ofw_real_map(addr, len);
804 	args.len = len;
805 	if (args.addr == 0 || openfirmware(&args) == -1) {
806 		ofw_real_stop();
807 		return (-1);
808 	}
809 	ofw_real_stop();
810 	return (args.actual);
811 }
812 
813 /* Seek to a position. */
814 static int
815 ofw_real_seek(ofw_t ofw, ihandle_t instance, u_int64_t pos)
816 {
817 	struct {
818 		cell_t name;
819 		cell_t nargs;
820 		cell_t nreturns;
821 		cell_t instance;
822 		cell_t poshi;
823 		cell_t poslo;
824 		cell_t status;
825 	} args = {
826 		(cell_t)"seek",
827 		3,
828 		1,
829 	};
830 
831 	args.instance = instance;
832 	args.poshi = pos >> 32;
833 	args.poslo = pos;
834 	if (openfirmware(&args) == -1)
835 		return (-1);
836 	return (args.status);
837 }
838 
839 /*
840  * Memory functions
841  */
842 
843 /* Claim an area of memory. */
844 static caddr_t
845 ofw_real_claim(ofw_t ofw, void *virt, size_t size, u_int align)
846 {
847 	struct {
848 		cell_t name;
849 		cell_t nargs;
850 		cell_t nreturns;
851 		cell_t virt;
852 		cell_t size;
853 		cell_t align;
854 		cell_t baseaddr;
855 	} args = {
856 		(cell_t)"claim",
857 		3,
858 		1,
859 	};
860 
861 	args.virt = (cell_t)virt;
862 	args.size = size;
863 	args.align = align;
864 	if (openfirmware(&args) == -1)
865 		return ((void *)-1);
866 	return ((void *)args.baseaddr);
867 }
868 
869 /* Release an area of memory. */
870 static void
871 ofw_real_release(ofw_t ofw, void *virt, size_t size)
872 {
873 	struct {
874 		cell_t name;
875 		cell_t nargs;
876 		cell_t nreturns;
877 		cell_t virt;
878 		cell_t size;
879 	} args = {
880 		(cell_t)"release",
881 		2,
882 		0,
883 	};
884 
885 	args.virt = (cell_t)virt;
886 	args.size = size;
887 	openfirmware(&args);
888 }
889 
890 /*
891  * Control transfer functions
892  */
893 
894 /* Turn off OF background tasks */
895 static void
896 ofw_real_quiesce(ofw_t ofw)
897 {
898 	vm_offset_t argsptr;
899 	struct {
900 		cell_t name;
901 		cell_t nargs;
902 		cell_t nreturns;
903 	} args;
904 
905 	args.name = (cell_t)(uintptr_t)"quiesce";
906 	args.nargs = 0;
907 	args.nreturns = 0;
908 
909 	ofw_real_start();
910 	argsptr = ofw_real_map(&args, sizeof(args));
911 	openfirmware((void *)argsptr);
912 	ofw_real_stop();
913 }
914 
915 /* Suspend and drop back to the Open Firmware interface. */
916 static void
917 ofw_real_enter(ofw_t ofw)
918 {
919 	struct {
920 		cell_t name;
921 		cell_t nargs;
922 		cell_t nreturns;
923 	} args = {
924 		(cell_t)"enter",
925 		0,
926 		0,
927 	};
928 
929 	openfirmware(&args);
930 	/* We may come back. */
931 }
932 
933 /* Shut down and drop back to the Open Firmware interface. */
934 static void
935 ofw_real_exit(ofw_t ofw)
936 {
937 	struct {
938 		cell_t name;
939 		cell_t nargs;
940 		cell_t nreturns;
941 	} args = {
942 		(cell_t)"exit",
943 		0,
944 		0,
945 	};
946 
947 	openfirmware(&args);
948 	for (;;)			/* just in case */
949 		;
950 }
951 
952