ofw_real.c revision 208614
1/*	$NetBSD: Locore.c,v 1.7 2000/08/20 07:04:59 tsubai Exp $	*/
2
3/*-
4 * Copyright (C) 1995, 1996 Wolfgang Solfrank.
5 * Copyright (C) 1995, 1996 TooLs GmbH.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 *    must display the following acknowledgement:
18 *	This product includes software developed by TooLs GmbH.
19 * 4. The name of TooLs GmbH may not be used to endorse or promote products
20 *    derived from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
28 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33/*-
34 * Copyright (C) 2000 Benno Rice.
35 * All rights reserved.
36 *
37 * Redistribution and use in source and binary forms, with or without
38 * modification, are permitted provided that the following conditions
39 * are met:
40 * 1. Redistributions of source code must retain the above copyright
41 *    notice, this list of conditions and the following disclaimer.
42 * 2. Redistributions in binary form must reproduce the above copyright
43 *    notice, this list of conditions and the following disclaimer in the
44 *    documentation and/or other materials provided with the distribution.
45 *
46 * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR
47 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
48 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
49 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
50 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
51 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
52 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
53 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
54 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
55 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
56 */
57
58#include <sys/cdefs.h>
59__FBSDID("$FreeBSD: head/sys/powerpc/ofw/ofw_real.c 208614 2010-05-28 10:43:56Z raj $");
60
61#include <sys/param.h>
62#include <sys/kernel.h>
63#include <sys/lock.h>
64#include <sys/mutex.h>
65#include <sys/systm.h>
66
67#include <vm/vm.h>
68#include <vm/pmap.h>
69
70#include <machine/stdarg.h>
71#include <machine/bus.h>
72#include <machine/pmap.h>
73#include <machine/ofw_machdep.h>
74
75#include <dev/ofw/openfirm.h>
76#include <dev/ofw/ofwvar.h>
77#include "ofw_if.h"
78
79static int ofw_real_init(ofw_t, void *openfirm);
80static int ofw_real_test(ofw_t, const char *name);
81static phandle_t ofw_real_peer(ofw_t, phandle_t node);
82static phandle_t ofw_real_child(ofw_t, phandle_t node);
83static phandle_t ofw_real_parent(ofw_t, phandle_t node);
84static phandle_t ofw_real_instance_to_package(ofw_t, ihandle_t instance);
85static ssize_t ofw_real_getproplen(ofw_t, phandle_t package,
86    const char *propname);
87static ssize_t ofw_real_getprop(ofw_t, phandle_t package, const char *propname,
88    void *buf, size_t buflen);
89static int ofw_real_nextprop(ofw_t, phandle_t package, const char *previous,
90    char *buf, size_t);
91static int ofw_real_setprop(ofw_t, phandle_t package, const char *propname,
92    const void *buf, size_t len);
93static ssize_t ofw_real_canon(ofw_t, const char *device, char *buf, size_t len);
94static phandle_t ofw_real_finddevice(ofw_t, const char *device);
95static ssize_t ofw_real_instance_to_path(ofw_t, ihandle_t instance, char *buf,
96    size_t len);
97static ssize_t ofw_real_package_to_path(ofw_t, phandle_t package, char *buf,
98    size_t len);
99static int ofw_real_call_method(ofw_t, ihandle_t instance, const char *method,
100    int nargs, int nreturns, unsigned long *args_and_returns);
101static ihandle_t ofw_real_open(ofw_t, const char *device);
102static void ofw_real_close(ofw_t, ihandle_t instance);
103static ssize_t ofw_real_read(ofw_t, ihandle_t instance, void *addr, size_t len);
104static ssize_t ofw_real_write(ofw_t, ihandle_t instance, const void *addr,
105    size_t len);
106static int ofw_real_seek(ofw_t, ihandle_t instance, u_int64_t pos);
107static caddr_t ofw_real_claim(ofw_t, void *virt, size_t size, u_int align);
108static void ofw_real_release(ofw_t, void *virt, size_t size);
109static void ofw_real_enter(ofw_t);
110static void ofw_real_exit(ofw_t);
111
112static ofw_method_t ofw_real_methods[] = {
113	OFWMETHOD(ofw_init,			ofw_real_init),
114	OFWMETHOD(ofw_peer,			ofw_real_peer),
115	OFWMETHOD(ofw_child,			ofw_real_child),
116	OFWMETHOD(ofw_parent,			ofw_real_parent),
117	OFWMETHOD(ofw_instance_to_package,	ofw_real_instance_to_package),
118	OFWMETHOD(ofw_getproplen,		ofw_real_getproplen),
119	OFWMETHOD(ofw_getprop,			ofw_real_getprop),
120	OFWMETHOD(ofw_nextprop,			ofw_real_nextprop),
121	OFWMETHOD(ofw_setprop,			ofw_real_setprop),
122	OFWMETHOD(ofw_canon,			ofw_real_canon),
123	OFWMETHOD(ofw_finddevice,		ofw_real_finddevice),
124	OFWMETHOD(ofw_instance_to_path,		ofw_real_instance_to_path),
125	OFWMETHOD(ofw_package_to_path,		ofw_real_package_to_path),
126
127	OFWMETHOD(ofw_test,			ofw_real_test),
128	OFWMETHOD(ofw_call_method,		ofw_real_call_method),
129	OFWMETHOD(ofw_open,			ofw_real_open),
130	OFWMETHOD(ofw_close,			ofw_real_close),
131	OFWMETHOD(ofw_read,			ofw_real_read),
132	OFWMETHOD(ofw_write,			ofw_real_write),
133	OFWMETHOD(ofw_seek,			ofw_real_seek),
134	OFWMETHOD(ofw_claim,			ofw_real_claim),
135	OFWMETHOD(ofw_release,			ofw_real_release),
136	OFWMETHOD(ofw_enter,			ofw_real_enter),
137	OFWMETHOD(ofw_exit,			ofw_real_exit),
138
139	{ 0, 0 }
140};
141
142static ofw_def_t ofw_real = {
143	OFW_STD_REAL,
144	ofw_real_methods,
145	0
146};
147OFW_DEF(ofw_real);
148
149MALLOC_DEFINE(M_OFWREAL, "ofwreal", "Open Firmware Real Mode Bounce Page");
150
151static int (*openfirmware)(void *);
152
153static vm_offset_t	of_bounce_phys;
154static caddr_t		of_bounce_virt;
155static off_t		of_bounce_offset;
156static size_t		of_bounce_size;
157static struct mtx	of_bounce_mtx;
158
159/*
160 * After the VM is up, allocate a wired, low memory bounce page.
161 */
162
163static void ofw_real_bounce_alloc(void *);
164
165SYSINIT(ofw_real_bounce_alloc, SI_SUB_VM, SI_ORDER_ANY,
166    ofw_real_bounce_alloc, NULL);
167
168static void
169ofw_real_start(void)
170{
171	mtx_lock(&of_bounce_mtx);
172	of_bounce_offset = 0;
173}
174
175static void
176ofw_real_stop(void)
177{
178	mtx_unlock(&of_bounce_mtx);
179}
180
181static void
182ofw_real_bounce_alloc(void *junk)
183{
184	/*
185	 * Check that ofw_real is actually in use before allocating wads
186	 * of memory. Do this by checking if our mutex has been set up.
187	 */
188	if (!mtx_initialized(&of_bounce_mtx))
189		return;
190
191	/*
192	 * Allocate a page of contiguous, wired physical memory that can
193	 * fit into a 32-bit address space.
194	 */
195
196	mtx_lock(&of_bounce_mtx);
197
198	of_bounce_virt = contigmalloc(PAGE_SIZE, M_OFWREAL, 0,
199			     0, BUS_SPACE_MAXADDR_32BIT, PAGE_SIZE, PAGE_SIZE);
200	of_bounce_phys = vtophys(of_bounce_virt);
201	of_bounce_size = PAGE_SIZE;
202
203	mtx_unlock(&of_bounce_mtx);
204}
205
206static cell_t
207ofw_real_map(const void *buf, size_t len)
208{
209	cell_t phys;
210
211	mtx_assert(&of_bounce_mtx, MA_OWNED);
212
213	if (of_bounce_virt == NULL) {
214		if (!pmap_bootstrapped)
215			return (cell_t)buf;
216
217		/*
218		 * XXX: It is possible for us to get called before the VM has
219		 * come online, but after the MMU is up. We don't have the
220		 * bounce buffer yet, but can no longer presume a 1:1 mapping.
221		 * Grab the physical address of the buffer, and hope it is
222		 * in range if this happens.
223		 */
224		return (cell_t)vtophys(buf);
225	}
226
227	/*
228	 * Make sure the bounce page offset satisfies any reasonable
229	 * alignment constraint.
230	 */
231	of_bounce_offset += of_bounce_offset % sizeof(register_t);
232
233	if (of_bounce_offset + len > of_bounce_size) {
234		panic("Oversize Open Firmware call!");
235		return 0;
236	}
237
238	memcpy(of_bounce_virt + of_bounce_offset, buf, len);
239	phys = of_bounce_phys + of_bounce_offset;
240
241	of_bounce_offset += len;
242
243	return phys;
244}
245
246static void
247ofw_real_unmap(cell_t physaddr, void *buf, size_t len)
248{
249	mtx_assert(&of_bounce_mtx, MA_OWNED);
250
251	if (of_bounce_virt == NULL)
252		return;
253
254	memcpy(buf,of_bounce_virt + (physaddr - of_bounce_phys),len);
255}
256
257/* Initialiser */
258
259static int
260ofw_real_init(ofw_t ofw, void *openfirm)
261{
262	openfirmware = (int (*)(void *))openfirm;
263
264	mtx_init(&of_bounce_mtx, "OF Bounce Page", MTX_DEF, 0);
265	of_bounce_virt = NULL;
266	return (0);
267}
268
269/*
270 * Generic functions
271 */
272
273/* Test to see if a service exists. */
274static int
275ofw_real_test(ofw_t ofw, const char *name)
276{
277	struct {
278		cell_t name;
279		cell_t nargs;
280		cell_t nreturns;
281		cell_t service;
282		cell_t missing;
283	} args = {
284		(cell_t)"test",
285		1,
286		1,
287	};
288
289	ofw_real_start();
290
291	args.service = ofw_real_map(name, strlen(name) + 1);
292	if (args.service == 0 || openfirmware(&args) == -1) {
293		ofw_real_stop();
294		return (-1);
295	}
296	ofw_real_stop();
297	return (args.missing);
298}
299
300/*
301 * Device tree functions
302 */
303
304/* Return the next sibling of this node or 0. */
305static phandle_t
306ofw_real_peer(ofw_t ofw, phandle_t node)
307{
308	struct {
309		cell_t name;
310		cell_t nargs;
311		cell_t nreturns;
312		cell_t node;
313		cell_t next;
314	} args = {
315		(cell_t)"peer",
316		1,
317		1,
318	};
319
320	args.node = node;
321	if (openfirmware(&args) == -1)
322		return (-1);
323	return (args.next);
324}
325
326/* Return the first child of this node or 0. */
327static phandle_t
328ofw_real_child(ofw_t ofw, phandle_t node)
329{
330	struct {
331		cell_t name;
332		cell_t nargs;
333		cell_t nreturns;
334		cell_t node;
335		cell_t child;
336	} args = {
337		(cell_t)"child",
338		1,
339		1,
340	};
341
342	args.node = node;
343	if (openfirmware(&args) == -1)
344		return (-1);
345	return (args.child);
346}
347
348/* Return the parent of this node or 0. */
349static phandle_t
350ofw_real_parent(ofw_t ofw, phandle_t node)
351{
352	struct {
353		cell_t name;
354		cell_t nargs;
355		cell_t nreturns;
356		cell_t node;
357		cell_t parent;
358	} args = {
359		(cell_t)"parent",
360		1,
361		1,
362	};
363
364	args.node = node;
365	if (openfirmware(&args) == -1)
366		return (-1);
367	return (args.parent);
368}
369
370/* Return the package handle that corresponds to an instance handle. */
371static phandle_t
372ofw_real_instance_to_package(ofw_t ofw, ihandle_t instance)
373{
374	struct {
375		cell_t name;
376		cell_t nargs;
377		cell_t nreturns;
378		cell_t instance;
379		cell_t package;
380	} args = {
381		(cell_t)"instance-to-package",
382		1,
383		1,
384	};
385
386	args.instance = instance;
387	if (openfirmware(&args) == -1)
388		return (-1);
389	return (args.package);
390}
391
392/* Get the length of a property of a package. */
393static ssize_t
394ofw_real_getproplen(ofw_t ofw, phandle_t package, const char *propname)
395{
396	struct {
397		cell_t name;
398		cell_t nargs;
399		cell_t nreturns;
400		cell_t package;
401		cell_t propname;
402		cell_t proplen;
403	} args = {
404		(cell_t)"getproplen",
405		2,
406		1,
407	};
408
409	ofw_real_start();
410
411	args.package = package;
412	args.propname = ofw_real_map(propname, strlen(propname) + 1);
413	if (args.propname == 0 || openfirmware(&args) == -1) {
414		ofw_real_stop();
415		return (-1);
416	}
417	ofw_real_stop();
418	return (args.proplen);
419}
420
421/* Get the value of a property of a package. */
422static ssize_t
423ofw_real_getprop(ofw_t ofw, phandle_t package, const char *propname, void *buf,
424    size_t buflen)
425{
426	struct {
427		cell_t name;
428		cell_t nargs;
429		cell_t nreturns;
430		cell_t package;
431		cell_t propname;
432		cell_t buf;
433		cell_t buflen;
434		cell_t size;
435	} args = {
436		(cell_t)"getprop",
437		4,
438		1,
439	};
440
441	ofw_real_start();
442
443	args.package = package;
444	args.propname = ofw_real_map(propname, strlen(propname) + 1);
445	args.buf = ofw_real_map(buf, buflen);
446	args.buflen = buflen;
447	if (args.propname == 0 || args.buf == 0 || openfirmware(&args) == -1) {
448		ofw_real_stop();
449		return (-1);
450	}
451	ofw_real_unmap(args.buf, buf, buflen);
452
453	ofw_real_stop();
454	return (args.size);
455}
456
457/* Get the next property of a package. */
458static int
459ofw_real_nextprop(ofw_t ofw, phandle_t package, const char *previous,
460    char *buf, size_t size)
461{
462	struct {
463		cell_t name;
464		cell_t nargs;
465		cell_t nreturns;
466		cell_t package;
467		cell_t previous;
468		cell_t buf;
469		cell_t flag;
470	} args = {
471		(cell_t)"nextprop",
472		3,
473		1,
474	};
475
476	ofw_real_start();
477
478	args.package = package;
479	args.previous = ofw_real_map(previous, strlen(previous) + 1);
480	args.buf = ofw_real_map(buf, size);
481	if (args.previous == 0 || args.buf == 0 || openfirmware(&args) == -1) {
482		ofw_real_stop();
483		return (-1);
484	}
485	ofw_real_unmap(args.buf, buf, size);
486
487	ofw_real_stop();
488	return (args.flag);
489}
490
491/* Set the value of a property of a package. */
492/* XXX Has a bug on FirePower */
493static int
494ofw_real_setprop(ofw_t ofw, phandle_t package, const char *propname,
495    const void *buf, size_t len)
496{
497	struct {
498		cell_t name;
499		cell_t nargs;
500		cell_t nreturns;
501		cell_t package;
502		cell_t propname;
503		cell_t buf;
504		cell_t len;
505		cell_t size;
506	} args = {
507		(cell_t)"setprop",
508		4,
509		1,
510	};
511
512	ofw_real_start();
513
514	args.package = package;
515	args.propname = ofw_real_map(propname, strlen(propname) + 1);
516	args.buf = ofw_real_map(buf, len);
517	args.len = len;
518	if (args.propname == 0 || args.buf == 0 || openfirmware(&args) == -1) {
519		ofw_real_stop();
520		return (-1);
521	}
522	ofw_real_stop();
523	return (args.size);
524}
525
526/* Convert a device specifier to a fully qualified pathname. */
527static ssize_t
528ofw_real_canon(ofw_t ofw, const char *device, char *buf, size_t len)
529{
530	struct {
531		cell_t name;
532		cell_t nargs;
533		cell_t nreturns;
534		cell_t device;
535		cell_t buf;
536		cell_t len;
537		cell_t size;
538	} args = {
539		(cell_t)"canon",
540		3,
541		1,
542	};
543
544	ofw_real_start();
545
546	args.device = ofw_real_map(device, strlen(device) + 1);
547	args.buf = ofw_real_map(buf, len);
548	args.len = len;
549	if (args.device == 0 || args.buf == 0 || openfirmware(&args) == -1) {
550		ofw_real_stop();
551		return (-1);
552	}
553	ofw_real_unmap(args.buf, buf, len);
554
555	ofw_real_stop();
556	return (args.size);
557}
558
559/* Return a package handle for the specified device. */
560static phandle_t
561ofw_real_finddevice(ofw_t ofw, const char *device)
562{
563	struct {
564		cell_t name;
565		cell_t nargs;
566		cell_t nreturns;
567		cell_t device;
568		cell_t package;
569	} args = {
570		(cell_t)"finddevice",
571		1,
572		1,
573	};
574
575	ofw_real_start();
576
577	args.device = ofw_real_map(device, strlen(device) + 1);
578	if (args.device == 0 || openfirmware(&args) == -1) {
579		ofw_real_stop();
580		return (-1);
581	}
582	ofw_real_stop();
583	return (args.package);
584}
585
586/* Return the fully qualified pathname corresponding to an instance. */
587static ssize_t
588ofw_real_instance_to_path(ofw_t ofw, ihandle_t instance, char *buf, size_t len)
589{
590	struct {
591		cell_t name;
592		cell_t nargs;
593		cell_t nreturns;
594		cell_t instance;
595		cell_t buf;
596		cell_t len;
597		cell_t size;
598	} args = {
599		(cell_t)"instance-to-path",
600		3,
601		1,
602	};
603
604	ofw_real_start();
605
606	args.instance = instance;
607	args.buf = ofw_real_map(buf, len);
608	args.len = len;
609	if (args.buf == 0 || openfirmware(&args) == -1) {
610		ofw_real_stop();
611		return (-1);
612	}
613	ofw_real_unmap(args.buf, buf, len);
614
615	ofw_real_stop();
616	return (args.size);
617}
618
619/* Return the fully qualified pathname corresponding to a package. */
620static ssize_t
621ofw_real_package_to_path(ofw_t ofw, phandle_t package, char *buf, size_t len)
622{
623	struct {
624		cell_t name;
625		cell_t nargs;
626		cell_t nreturns;
627		cell_t package;
628		cell_t buf;
629		cell_t len;
630		cell_t size;
631	} args = {
632		(cell_t)"package-to-path",
633		3,
634		1,
635	};
636
637	ofw_real_start();
638
639	args.package = package;
640	args.buf = ofw_real_map(buf, len);
641	args.len = len;
642	if (args.buf == 0 || openfirmware(&args) == -1) {
643		ofw_real_stop();
644		return (-1);
645	}
646	ofw_real_unmap(args.buf, buf, len);
647
648	ofw_real_stop();
649	return (args.size);
650}
651
652/*  Call the method in the scope of a given instance. */
653static int
654ofw_real_call_method(ofw_t ofw, ihandle_t instance, const char *method,
655    int nargs, int nreturns, unsigned long *args_and_returns)
656{
657	struct {
658		cell_t name;
659		cell_t nargs;
660		cell_t nreturns;
661		cell_t method;
662		cell_t instance;
663		cell_t args_n_results[12];
664	} args = {
665		(cell_t)"call-method",
666		2,
667		1,
668	};
669	cell_t *cp;
670	unsigned long *ap;
671	int n;
672
673	if (nargs > 6)
674		return (-1);
675
676	ofw_real_start();
677	args.nargs = nargs + 2;
678	args.nreturns = nreturns + 1;
679	args.method = ofw_real_map(method, strlen(method) + 1);
680	args.instance = instance;
681
682	ap = args_and_returns;
683	for (cp = args.args_n_results + (n = nargs); --n >= 0;)
684		*--cp = *(ap++);
685	if (args.method == 0 || openfirmware(&args) == -1) {
686		ofw_real_stop();
687		return (-1);
688	}
689	ofw_real_stop();
690	if (args.args_n_results[nargs])
691		return (args.args_n_results[nargs]);
692	for (cp = args.args_n_results + nargs + (n = args.nreturns); --n > 0;)
693		*(ap++) = *--cp;
694	return (0);
695}
696
697/*
698 * Device I/O functions
699 */
700
701/* Open an instance for a device. */
702static ihandle_t
703ofw_real_open(ofw_t ofw, const char *device)
704{
705	struct {
706		cell_t name;
707		cell_t nargs;
708		cell_t nreturns;
709		cell_t device;
710		cell_t instance;
711	} args = {
712		(cell_t)"open",
713		1,
714		1,
715	};
716
717	ofw_real_start();
718
719	args.device = ofw_real_map(device, strlen(device) + 1);
720	if (args.device == 0 || openfirmware(&args) == -1
721	    || args.instance == 0) {
722		ofw_real_stop();
723		return (-1);
724	}
725	ofw_real_stop();
726	return (args.instance);
727}
728
729/* Close an instance. */
730static void
731ofw_real_close(ofw_t ofw, ihandle_t instance)
732{
733	struct {
734		cell_t name;
735		cell_t nargs;
736		cell_t nreturns;
737		cell_t instance;
738	} args = {
739		(cell_t)"close",
740		1,
741		0,
742	};
743
744	args.instance = instance;
745	openfirmware(&args);
746}
747
748/* Read from an instance. */
749static ssize_t
750ofw_real_read(ofw_t ofw, ihandle_t instance, void *addr, size_t len)
751{
752	struct {
753		cell_t name;
754		cell_t nargs;
755		cell_t nreturns;
756		cell_t instance;
757		cell_t addr;
758		cell_t len;
759		cell_t actual;
760	} args = {
761		(cell_t)"read",
762		3,
763		1,
764	};
765
766	ofw_real_start();
767
768	args.instance = instance;
769	args.addr = ofw_real_map(addr, len);
770	args.len = len;
771	if (args.addr == 0 || openfirmware(&args) == -1) {
772		ofw_real_stop();
773		return (-1);
774	}
775	ofw_real_unmap(args.addr, addr, len);
776
777	ofw_real_stop();
778	return (args.actual);
779}
780
781/* Write to an instance. */
782static ssize_t
783ofw_real_write(ofw_t ofw, ihandle_t instance, const void *addr, size_t len)
784{
785	struct {
786		cell_t name;
787		cell_t nargs;
788		cell_t nreturns;
789		cell_t instance;
790		cell_t addr;
791		cell_t len;
792		cell_t actual;
793	} args = {
794		(cell_t)"write",
795		3,
796		1,
797	};
798
799	ofw_real_start();
800
801	args.instance = instance;
802	args.addr = ofw_real_map(addr, len);
803	args.len = len;
804	if (args.addr == 0 || openfirmware(&args) == -1) {
805		ofw_real_stop();
806		return (-1);
807	}
808	ofw_real_stop();
809	return (args.actual);
810}
811
812/* Seek to a position. */
813static int
814ofw_real_seek(ofw_t ofw, ihandle_t instance, u_int64_t pos)
815{
816	struct {
817		cell_t name;
818		cell_t nargs;
819		cell_t nreturns;
820		cell_t instance;
821		cell_t poshi;
822		cell_t poslo;
823		cell_t status;
824	} args = {
825		(cell_t)"seek",
826		3,
827		1,
828	};
829
830	args.instance = instance;
831	args.poshi = pos >> 32;
832	args.poslo = pos;
833	if (openfirmware(&args) == -1)
834		return (-1);
835	return (args.status);
836}
837
838/*
839 * Memory functions
840 */
841
842/* Claim an area of memory. */
843static caddr_t
844ofw_real_claim(ofw_t ofw, void *virt, size_t size, u_int align)
845{
846	struct {
847		cell_t name;
848		cell_t nargs;
849		cell_t nreturns;
850		cell_t virt;
851		cell_t size;
852		cell_t align;
853		cell_t baseaddr;
854	} args = {
855		(cell_t)"claim",
856		3,
857		1,
858	};
859
860	args.virt = (cell_t)virt;
861	args.size = size;
862	args.align = align;
863	if (openfirmware(&args) == -1)
864		return ((void *)-1);
865	return ((void *)args.baseaddr);
866}
867
868/* Release an area of memory. */
869static void
870ofw_real_release(ofw_t ofw, void *virt, size_t size)
871{
872	struct {
873		cell_t name;
874		cell_t nargs;
875		cell_t nreturns;
876		cell_t virt;
877		cell_t size;
878	} args = {
879		(cell_t)"release",
880		2,
881		0,
882	};
883
884	args.virt = (cell_t)virt;
885	args.size = size;
886	openfirmware(&args);
887}
888
889/*
890 * Control transfer functions
891 */
892
893/* Suspend and drop back to the Open Firmware interface. */
894static void
895ofw_real_enter(ofw_t ofw)
896{
897	struct {
898		cell_t name;
899		cell_t nargs;
900		cell_t nreturns;
901	} args = {
902		(cell_t)"enter",
903		0,
904		0,
905	};
906
907	openfirmware(&args);
908	/* We may come back. */
909}
910
911/* Shut down and drop back to the Open Firmware interface. */
912static void
913ofw_real_exit(ofw_t ofw)
914{
915	struct {
916		cell_t name;
917		cell_t nargs;
918		cell_t nreturns;
919	} args = {
920		(cell_t)"exit",
921		0,
922		0,
923	};
924
925	openfirmware(&args);
926	for (;;)			/* just in case */
927		;
928}
929
930