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