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