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