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