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