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