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