]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - stand/libofw/openfirm.c
libarchive: merge from vendor branch
[FreeBSD/FreeBSD.git] / stand / libofw / openfirm.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/endian.h>
59
60 #include <machine/stdarg.h>
61
62 #include <stand.h>
63
64 #include "openfirm.h"
65
66 int (*openfirmware)(void *);
67
68 phandle_t chosen;
69 ihandle_t mmu;
70 ihandle_t memory;
71 int       real_mode = 0;
72
73 #define IN(x)           htobe32((cell_t)x)
74 #define OUT(x)          be32toh(x)
75 #define SETUP(a, b, c, d)               \
76         a.name = IN( (b) );             \
77         a.nargs = IN( (c) );            \
78         a.nreturns = IN( (d) );
79
80 /* Initialiser */
81
82 void
83 OF_init(int (*openfirm)(void *))
84 {
85         phandle_t options;
86         char      mode[sizeof("true")];
87
88         openfirmware = openfirm;
89
90         if ((chosen = OF_finddevice("/chosen")) == -1)
91                 OF_exit();
92         if (OF_getprop(chosen, "memory", &memory, sizeof(memory)) == -1) {
93                 memory = OF_open("/memory");
94                 if (memory == -1)
95                         memory = OF_open("/memory@0");
96                 if (memory == -1)
97                         OF_exit();
98         }
99         if (OF_getprop(chosen, "mmu", &mmu, sizeof(mmu)) == -1)
100                 OF_exit();
101
102         /*
103          * Check if we run in real mode. If so, we do not need to map
104          * memory later on.
105          */
106         options = OF_finddevice("/options");
107         if (OF_getprop(options, "real-mode?", mode, sizeof(mode)) > 0 &&
108             strcmp(mode, "true") == 0)
109                 real_mode = 1;
110 }
111
112 /*
113  * Generic functions
114  */
115
116 /* Test to see if a service exists. */
117 int
118 OF_test(char *name)
119 {
120         static struct {
121                 cell_t name;
122                 cell_t nargs;
123                 cell_t nreturns;
124                 cell_t service;
125                 cell_t missing;
126         } args = {};
127         SETUP(args, "test", 1, 1);
128
129         args.service = IN(name);
130         if (openfirmware(&args) == -1)
131                 return (-1);
132         return (OUT(args.missing));
133 }
134
135 /* Return firmware millisecond count. */
136 int
137 OF_milliseconds(void)
138 {
139         static struct {
140                 cell_t name;
141                 cell_t nargs;
142                 cell_t nreturns;
143                 cell_t ms;
144         } args = {};
145         SETUP(args, "milliseconds", 0, 1);
146
147         openfirmware(&args);
148         return (OUT(args.ms));
149 }
150
151 /*
152  * Device tree functions
153  */
154
155 /* Return the next sibling of this node or 0. */
156 phandle_t
157 OF_peer(phandle_t node)
158 {
159         static struct {
160                 cell_t name;
161                 cell_t nargs;
162                 cell_t nreturns;
163                 cell_t node;
164                 cell_t next;
165         } args = {};
166         SETUP(args, "peer", 1, 1);
167
168         args.node = node;
169         if (openfirmware(&args) == -1)
170                 return (-1);
171         return (args.next);
172 }
173
174 /* Return the first child of this node or 0. */
175 phandle_t
176 OF_child(phandle_t node)
177 {
178         static struct {
179                 cell_t name;
180                 cell_t nargs;
181                 cell_t nreturns;
182                 cell_t node;
183                 cell_t child;
184         } args = {};
185         SETUP(args, "child", 1, 1);
186
187         args.node = node;
188         if (openfirmware(&args) == -1)
189                 return (-1);
190         return (args.child);
191 }
192
193 /* Return the parent of this node or 0. */
194 phandle_t
195 OF_parent(phandle_t node)
196 {
197         static struct {
198                 cell_t name;
199                 cell_t nargs;
200                 cell_t nreturns;
201                 cell_t node;
202                 cell_t parent;
203         } args = {};
204         SETUP(args, "parent", 1, 1);
205
206         args.node = node;
207         if (openfirmware(&args) == -1)
208                 return (-1);
209         return (args.parent);
210 }
211
212 /* Return the package handle that corresponds to an instance handle. */
213 phandle_t
214 OF_instance_to_package(ihandle_t instance)
215 {
216         static struct {
217                 cell_t name;
218                 cell_t nargs;
219                 cell_t nreturns;
220                 cell_t instance;
221                 cell_t package;
222         } args = {};
223         SETUP(args, "instance-to-package", 1, 1);
224
225         args.instance = instance;
226         if (openfirmware(&args) == -1)
227                 return (-1);
228         return (args.package);
229 }
230
231 /* Get the length of a property of a package. */
232 int
233 OF_getproplen(phandle_t package, const char *propname)
234 {
235         static struct {
236                 cell_t name;
237                 cell_t nargs;
238                 cell_t nreturns;
239                 cell_t package;
240                 cell_t propname;
241                 cell_t proplen;
242         } args = {};
243         SETUP(args, "getproplen", 2, 1);
244
245         args.package = package;
246         args.propname = IN(propname);
247         if (openfirmware(&args) == -1)
248                 return (-1);
249         return (OUT(args.proplen));
250 }
251
252 /* Get the value of a property of a package. */
253 int
254 OF_getprop(phandle_t package, const char *propname, void *buf, int buflen)
255 {
256         static struct {
257                 cell_t name;
258                 cell_t nargs;
259                 cell_t nreturns;
260                 cell_t package;
261                 cell_t propname;
262                 cell_t buf;
263                 cell_t buflen;
264                 cell_t size;
265         } args = {};
266         SETUP(args, "getprop", 4, 1);
267
268         args.package = package;
269         args.propname = IN(propname);
270         args.buf = IN(buf);
271         args.buflen = IN(buflen);
272         if (openfirmware(&args) == -1)
273                 return (-1);
274         return (OUT(args.size));
275 }
276
277 /* Decode a binary property from a package. */
278 int
279 OF_getencprop(phandle_t package, const char *propname, cell_t *buf, int buflen)
280 {
281         int retval, i;
282         retval = OF_getprop(package, propname, buf, buflen);
283         if (retval == -1)
284                 return (retval);
285
286         for (i = 0; i < buflen/4; i++)
287                 buf[i] = be32toh((uint32_t)buf[i]);
288
289         return (retval);
290 }
291
292 /* Get the next property of a package. */
293 int
294 OF_nextprop(phandle_t package, const char *previous, char *buf)
295 {
296         static struct {
297                 cell_t name;
298                 cell_t nargs;
299                 cell_t nreturns;
300                 cell_t package;
301                 cell_t previous;
302                 cell_t buf;
303                 cell_t flag;
304         } args = {};
305         SETUP(args, "nextprop", 3, 1);
306
307         args.package = package;
308         args.previous = IN(previous);
309         args.buf = IN(buf);
310         if (openfirmware(&args) == -1)
311                 return (-1);
312         return (OUT(args.flag));
313 }
314
315 /* Set the value of a property of a package. */
316 /* XXX Has a bug on FirePower */
317 int
318 OF_setprop(phandle_t package, const char *propname, void *buf, int len)
319 {
320         static struct {
321                 cell_t name;
322                 cell_t nargs;
323                 cell_t nreturns;
324                 cell_t package;
325                 cell_t propname;
326                 cell_t buf;
327                 cell_t len;
328                 cell_t size;
329         } args = {};
330         SETUP(args, "setprop", 4, 1);
331
332         args.package = package;
333         args.propname = IN(propname);
334         args.buf = IN(buf);
335         args.len = IN(len);
336         if (openfirmware(&args) == -1)
337                 return (-1);
338         return (OUT(args.size));
339 }
340
341 /* Convert a device specifier to a fully qualified pathname. */
342 int
343 OF_canon(const char *device, char *buf, int len)
344 {
345         static struct {
346                 cell_t name;
347                 cell_t nargs;
348                 cell_t nreturns;
349                 cell_t device;
350                 cell_t buf;
351                 cell_t len;
352                 cell_t size;
353         } args = {};
354         SETUP(args, "canon", 3, 1);
355
356         args.device = IN(device);
357         args.buf = IN(buf);
358         args.len = IN(len);
359         if (openfirmware(&args) == -1)
360                 return (-1);
361         return (OUT(args.size));
362 }
363
364 /* Return a package handle for the specified device. */
365 phandle_t
366 OF_finddevice(const char *device)
367 {
368         static struct {
369                 cell_t name;
370                 cell_t nargs;
371                 cell_t nreturns;
372                 cell_t device;
373                 cell_t package;
374         } args = {};
375         SETUP(args, "finddevice", 1, 1);
376
377         args.device = IN(device);
378         if (openfirmware(&args) == -1)
379                 return (-1);
380         return (args.package);
381 }
382
383 /* Return the fully qualified pathname corresponding to an instance. */
384 int
385 OF_instance_to_path(ihandle_t instance, char *buf, int len)
386 {
387         static struct {
388                 cell_t name;
389                 cell_t nargs;
390                 cell_t nreturns;
391                 cell_t instance;
392                 cell_t buf;
393                 cell_t len;
394                 cell_t size;
395         } args = {};
396         SETUP(args, "instance-to-path", 3, 1);
397
398         args.instance = instance;
399         args.buf = IN(buf);
400         args.len = IN(len);
401         if (openfirmware(&args) == -1)
402                 return (-1);
403         return (OUT(args.size));
404 }
405
406 /* Return the fully qualified pathname corresponding to a package. */
407 int
408 OF_package_to_path(phandle_t package, char *buf, int len)
409 {
410         static struct {
411                 cell_t name;
412                 cell_t nargs;
413                 cell_t nreturns;
414                 cell_t package;
415                 cell_t buf;
416                 cell_t len;
417                 cell_t size;
418         } args = {};
419         SETUP(args, "package-to-path", 3, 1);
420
421         args.package = package;
422         args.buf = IN(buf);
423         args.len = IN(len);
424         if (openfirmware(&args) == -1)
425                 return (-1);
426         return (OUT(args.size));
427 }
428
429 /*  Call the method in the scope of a given instance. */
430 int
431 OF_call_method(char *method, ihandle_t instance, int nargs, int nreturns, ...)
432 {
433         va_list ap;
434         static struct {
435                 cell_t name;
436                 cell_t nargs;
437                 cell_t nreturns;
438                 cell_t method;
439                 cell_t instance;
440                 cell_t args_n_results[12];
441         } args = {};
442         SETUP(args, "call-method", nargs + 2, nreturns + 1);
443         cell_t *cp;
444         int n;
445
446         if (nargs > 6)
447                 return (-1);
448         args.method = IN(method);
449         args.instance = instance;
450         va_start(ap, nreturns);
451         for (cp = (cell_t *)(args.args_n_results + (n = nargs)); --n >= 0;)
452                 *--cp = IN(va_arg(ap, cell_t));
453         if (openfirmware(&args) == -1)
454                 return (-1);
455         if (args.args_n_results[nargs])
456                 return (OUT(args.args_n_results[nargs]));
457         /* XXX what if ihandles or phandles are returned */
458         for (cp = (cell_t *)(args.args_n_results + nargs +
459             (n = be32toh(args.nreturns))); --n > 0;)
460                 *va_arg(ap, cell_t *) = OUT(*--cp);
461         va_end(ap);
462         return (0);
463 }
464
465 /*
466  * Device I/O functions
467  */
468
469 /* Open an instance for a device. */
470 ihandle_t
471 OF_open(char *device)
472 {
473         static struct {
474                 cell_t name;
475                 cell_t nargs;
476                 cell_t nreturns;
477                 cell_t device;
478                 cell_t instance;
479         } args = {};
480         SETUP(args, "open", 1, 1);
481
482         args.device = IN(device);
483         if (openfirmware(&args) == -1 || args.instance == 0) {
484                 return (-1);
485         }
486         return (args.instance);
487 }
488
489 /* Close an instance. */
490 void
491 OF_close(ihandle_t instance)
492 {
493         static struct {
494                 cell_t name;
495                 cell_t nargs;
496                 cell_t nreturns;
497                 cell_t instance;
498         } args = {};
499         SETUP(args, "close", 1, 0);
500
501         args.instance = instance;
502         openfirmware(&args);
503 }
504
505 /* Read from an instance. */
506 int
507 OF_read(ihandle_t instance, void *addr, int len)
508 {
509         static struct {
510                 cell_t name;
511                 cell_t nargs;
512                 cell_t nreturns;
513                 cell_t instance;
514                 cell_t addr;
515                 cell_t len;
516                 cell_t actual;
517         } args = {};
518         SETUP(args, "read", 3, 1);
519
520         args.instance = instance;
521         args.addr = IN(addr);
522         args.len = IN(len);
523
524 #if defined(OPENFIRM_DEBUG)
525         printf("OF_read: called with instance=%08x, addr=%p, len=%d\n",
526             instance, addr, len);
527 #endif
528
529         if (openfirmware(&args) == -1)
530                 return (-1);
531
532 #if defined(OPENFIRM_DEBUG)
533         printf("OF_read: returning instance=%d, addr=%p, len=%d, actual=%d\n",
534             args.instance, OUT(args.addr), OUT(args.len), OUT(args.actual));
535 #endif
536
537         return (OUT(args.actual));
538 }
539
540 /* Write to an instance. */
541 int
542 OF_write(ihandle_t instance, void *addr, int len)
543 {
544         static struct {
545                 cell_t name;
546                 cell_t nargs;
547                 cell_t nreturns;
548                 cell_t instance;
549                 cell_t addr;
550                 cell_t len;
551                 cell_t actual;
552         } args = {};
553         SETUP(args, "write", 3, 1);
554
555         args.instance = instance;
556         args.addr = IN(addr);
557         args.len = IN(len);
558         if (openfirmware(&args) == -1)
559                 return (-1);
560         return (OUT(args.actual));
561 }
562
563 /* Seek to a position. */
564 int
565 OF_seek(ihandle_t instance, uint64_t pos)
566 {
567         static struct {
568                 cell_t name;
569                 cell_t nargs;
570                 cell_t nreturns;
571                 cell_t instance;
572                 cell_t poshi;
573                 cell_t poslo;
574                 cell_t status;
575         } args = {};
576         SETUP(args, "seek", 3, 1);
577
578         args.instance = instance;
579         args.poshi = IN(((uint64_t)pos >> 32));
580         args.poslo = IN(pos);
581         if (openfirmware(&args) == -1)
582                 return (-1);
583         return (OUT(args.status));
584 }
585
586 /* Blocks. */
587 unsigned int
588 OF_blocks(ihandle_t instance)
589 {
590         static struct {
591                 cell_t name;
592                 cell_t nargs;
593                 cell_t nreturns;
594                 cell_t instance;
595                 cell_t result;
596                 cell_t blocks;
597         } args = {};
598         SETUP(args, "#blocks", 2, 1);
599
600         args.instance = instance;
601         if (openfirmware(&args) == -1)
602                 return ((unsigned int)-1);
603         return (OUT(args.blocks));
604 }
605
606 /* Block size. */
607 int
608 OF_block_size(ihandle_t instance)
609 {
610         static struct {
611                 cell_t name;
612                 cell_t nargs;
613                 cell_t nreturns;
614                 cell_t instance;
615                 cell_t result;
616                 cell_t size;
617         } args = {};
618         SETUP(args, "block-size", 2, 1);
619
620         args.instance = instance;
621         if (openfirmware(&args) == -1)
622                 return (512);
623         return (OUT(args.size));
624 }
625
626 /* 
627  * Memory functions
628  */
629
630 /* Claim an area of memory. */
631 void *
632 OF_claim(void *virt, u_int size, u_int align)
633 {
634         static struct {
635                 cell_t name;
636                 cell_t nargs;
637                 cell_t nreturns;
638                 cell_t virt;
639                 cell_t size;
640                 cell_t align;
641                 cell_t baseaddr;
642         } args = {};
643         SETUP(args, "claim", 3, 1);
644
645         args.virt = IN(virt);
646         args.size = IN(size);
647         args.align = IN(align);
648         if (openfirmware(&args) == -1)
649                 return ((void *)-1);
650         return ((void *)OUT(args.baseaddr));
651 }
652
653 /* Release an area of memory. */
654 void
655 OF_release(void *virt, u_int size)
656 {
657         static struct {
658                 cell_t name;
659                 cell_t nargs;
660                 cell_t nreturns;
661                 cell_t virt;
662                 cell_t size;
663         } args = {};
664         SETUP(args, "release", 2, 0);
665
666         args.virt = IN(virt);
667         args.size = IN(size);
668         openfirmware(&args);
669 }
670
671 /*
672  * Control transfer functions
673  */
674
675 /* Reset the system and call "boot <bootspec>". */
676 void
677 OF_boot(char *bootspec)
678 {
679         static struct {
680                 cell_t name;
681                 cell_t nargs;
682                 cell_t nreturns;
683                 cell_t bootspec;
684         } args = {};
685         SETUP(args, "boot", 1, 0);
686
687         args.bootspec = IN(bootspec);
688         openfirmware(&args);
689         for (;;)                        /* just in case */
690                 ;
691 }
692
693 /* Suspend and drop back to the Open Firmware interface. */
694 void
695 OF_enter(void)
696 {
697         static struct {
698                 cell_t name;
699                 cell_t nargs;
700                 cell_t nreturns;
701         } args = {};
702         SETUP(args, "enter", 0, 0);
703
704         openfirmware(&args);
705         /* We may come back. */
706 }
707
708 /* Shut down and drop back to the Open Firmware interface. */
709 void
710 OF_exit(void)
711 {
712         static struct {
713                 cell_t name;
714                 cell_t nargs;
715                 cell_t nreturns;
716         } args = {};
717         SETUP(args, "exit", 0, 0);
718
719         openfirmware(&args);
720         for (;;)                        /* just in case */
721                 ;
722 }
723
724 void
725 OF_quiesce(void)
726 {
727         static struct {
728                 cell_t name;
729                 cell_t nargs;
730                 cell_t nreturns;
731         } args = {};
732         SETUP(args, "quiesce", 0, 0);
733
734         openfirmware(&args);
735 }
736
737 /* Free <size> bytes starting at <virt>, then call <entry> with <arg>. */
738 #if 0
739 void
740 OF_chain(void *virt, u_int size, void (*entry)(), void *arg, u_int len)
741 {
742         static struct {
743                 cell_t name;
744                 cell_t nargs;
745                 cell_t nreturns;
746                 cell_t virt;
747                 cell_t size;
748                 cell_t entry;
749                 cell_t arg;
750                 cell_t len;
751         } args = {};
752         SETUP(args, "chain", 5, 0);
753
754         args.virt = IN(virt);
755         args.size = IN(size);
756         args.entry = IN(entry);
757         args.arg = IN(arg);
758         args.len = IN(len);
759         openfirmware(&args);
760 }
761 #else
762 void
763 OF_chain(void *virt, u_int size, void (*entry)(), void *arg, u_int len)
764 {
765         /*
766          * This is a REALLY dirty hack till the firmware gets this going
767          */
768 #if 0
769         if (size > 0)
770                 OF_release(virt, size);
771 #endif
772         ((int (*)(u_long, u_long, u_long, void *, u_long))entry)
773             (0, 0, (u_long)openfirmware, arg, len);
774 }
775 #endif