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