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