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