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