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