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