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