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
81static int ofw_real_init(ofw_t, void *openfirm);
82static int ofw_real_test(ofw_t, const char *name);
83static phandle_t ofw_real_peer(ofw_t, phandle_t node);
84static phandle_t ofw_real_child(ofw_t, phandle_t node);
85static phandle_t ofw_real_parent(ofw_t, phandle_t node);
86static phandle_t ofw_real_instance_to_package(ofw_t, ihandle_t instance);
87static ssize_t ofw_real_getproplen(ofw_t, phandle_t package,
88    const char *propname);
89static ssize_t ofw_real_getprop(ofw_t, phandle_t package, const char *propname,
90    void *buf, size_t buflen);
91static int ofw_real_nextprop(ofw_t, phandle_t package, const char *previous,
92    char *buf, size_t);
93static int ofw_real_setprop(ofw_t, phandle_t package, const char *propname,
94    const void *buf, size_t len);
95static ssize_t ofw_real_canon(ofw_t, const char *device, char *buf, size_t len);
96static phandle_t ofw_real_finddevice(ofw_t, const char *device);
97static ssize_t ofw_real_instance_to_path(ofw_t, ihandle_t instance, char *buf,
98    size_t len);
99static ssize_t ofw_real_package_to_path(ofw_t, phandle_t package, char *buf,
100    size_t len);
101static int ofw_real_call_method(ofw_t, ihandle_t instance, const char *method,
102    int nargs, int nreturns, cell_t *args_and_returns);
103static int ofw_real_interpret(ofw_t ofw, const char *cmd, int nreturns,
104    cell_t *returns);
105static ihandle_t ofw_real_open(ofw_t, const char *device);
106static void ofw_real_close(ofw_t, ihandle_t instance);
107static ssize_t ofw_real_read(ofw_t, ihandle_t instance, void *addr, size_t len);
108static ssize_t ofw_real_write(ofw_t, ihandle_t instance, const void *addr,
109    size_t len);
110static int ofw_real_seek(ofw_t, ihandle_t instance, u_int64_t pos);
111static caddr_t ofw_real_claim(ofw_t, void *virt, size_t size, u_int align);
112static void ofw_real_release(ofw_t, void *virt, size_t size);
113static void ofw_real_enter(ofw_t);
114static void ofw_real_exit(ofw_t);
115
116static 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
146static ofw_def_t ofw_real = {
147	OFW_STD_REAL,
148	ofw_real_methods,
149	0
150};
151OFW_DEF(ofw_real);
152
153static ofw_def_t ofw_32bit = {
154	OFW_STD_32BIT,
155	ofw_real_methods,
156	0
157};
158OFW_DEF(ofw_32bit);
159
160static MALLOC_DEFINE(M_OFWREAL, "ofwreal",
161    "Open Firmware Real Mode Bounce Page");
162
163static int (*openfirmware)(void *);
164
165static vm_offset_t	of_bounce_phys;
166static caddr_t		of_bounce_virt;
167static off_t		of_bounce_offset;
168static 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
206static struct mtx	of_bounce_mtx;
207static struct mtx	of_spin_mtx;
208static struct mtx	*of_real_mtx;
209static void		(*of_mtx_lock)(void);
210static void		(*of_mtx_unlock)(void);
211
212extern int		ofw_real_mode;
213
214/*
215 * After the VM is up, allocate a wired, low memory bounce page.
216 */
217
218static void ofw_real_bounce_alloc(void *);
219
220SYSINIT(ofw_real_bounce_alloc, SI_SUB_KMEM, SI_ORDER_ANY,
221    ofw_real_bounce_alloc, NULL);
222
223static void
224ofw_real_mtx_lock_spin(void)
225{
226	mtx_lock_spin(of_real_mtx);
227}
228
229static void
230ofw_real_mtx_lock(void)
231{
232	mtx_lock(of_real_mtx);
233}
234
235static void
236ofw_real_mtx_unlock_spin(void)
237{
238	mtx_unlock_spin(of_real_mtx);
239}
240
241static void
242ofw_real_mtx_unlock(void)
243{
244	mtx_unlock(of_real_mtx);
245}
246
247static void
248ofw_real_start(void)
249{
250	(*of_mtx_lock)();
251	of_bounce_offset = 0;
252}
253
254static void
255ofw_real_stop(void)
256{
257	(*of_mtx_unlock)();
258}
259
260static void
261ofw_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
300static cell_t
301ofw_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
353static void
354ofw_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
369static int
370ofw_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. */
399static int
400ofw_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. */
433static phandle_t
434ofw_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. */
462static phandle_t
463ofw_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. */
491static phandle_t
492ofw_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. */
520static phandle_t
521ofw_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. */
549static ssize_t
550ofw_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. */
581static ssize_t
582ofw_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. */
621static int
622ofw_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 */
659static int
660ofw_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. */
697static ssize_t
698ofw_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. */
734static phandle_t
735ofw_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. */
765static ssize_t
766ofw_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. */
802static ssize_t
803ofw_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. */
839static int
840ofw_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
886static int
887ofw_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. */
923static ihandle_t
924ofw_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. */
954static void
955ofw_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. */
976static ssize_t
977ofw_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. */
1012static ssize_t
1013ofw_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. */
1046static int
1047ofw_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. */
1083static caddr_t
1084ofw_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. */
1116static void
1117ofw_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. */
1145static void
1146ofw_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. */
1167static void
1168ofw_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