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