1 /* $NetBSD: openfirm.c,v 1.33 2021/02/13 01:48:33 thorpej 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 #include <sys/cdefs.h>
35 __KERNEL_RCSID(0, "$NetBSD: openfirm.c,v 1.33 2021/02/13 01:48:33 thorpej Exp $");
36
37 #ifdef _KERNEL_OPT
38 #include "opt_multiprocessor.h"
39 #endif
40
41 #include <sys/param.h>
42 #include <sys/systm.h>
43
44 #include <uvm/uvm_extern.h>
45
46 #include <machine/psl.h>
47 #include <machine/autoconf.h>
48
49 #include <dev/ofw/openfirm.h>
50
51 char *OF_buf;
52
53 static void ofbcopy(const void *, void *, size_t);
54
55 #ifdef MULTIPROCESSOR
56 void OF_start_cpu(int, u_int, int);
57
58
59 static __cpu_simple_lock_t ofw_mutex = __SIMPLELOCK_UNLOCKED;
60 #endif /* MULTIPROCESSOR */
61
62 static inline register_t
ofw_lock(void)63 ofw_lock(void)
64 {
65 const register_t s = mfmsr();
66
67 mtmsr(s & ~(PSL_EE|PSL_RI)); /* disable interrupts */
68
69 #ifdef MULTIPROCESSOR
70 __cpu_simple_lock(&ofw_mutex);
71 #endif /* MULTIPROCESSOR */
72
73 return s;
74 }
75
76 static inline void
ofw_unlock(register_t s)77 ofw_unlock(register_t s)
78 {
79 #ifdef MULTIPROCESSOR
80 __cpu_simple_unlock(&ofw_mutex);
81 #endif /* MULTIPROCESSOR */
82 mtmsr(s);
83 }
84
85 int
OF_peer(int phandle)86 OF_peer(int phandle)
87 {
88 static struct {
89 const char *name;
90 int nargs;
91 int nreturns;
92 int phandle;
93 int sibling;
94 } args = {
95 "peer",
96 1,
97 1,
98 };
99
100 const register_t s = ofw_lock();
101 int rv;
102
103 args.phandle = phandle;
104 if (openfirmware(&args) == -1)
105 rv = 0;
106 else
107 rv = args.sibling;
108
109 ofw_unlock(s);
110 return rv;
111 }
112
113 int
OF_child(int phandle)114 OF_child(int phandle)
115 {
116 static struct {
117 const char *name;
118 int nargs;
119 int nreturns;
120 int phandle;
121 int child;
122 } args = {
123 "child",
124 1,
125 1,
126 };
127
128 const register_t s = ofw_lock();
129 int rv;
130
131 args.phandle = phandle;
132 if (openfirmware(&args) == -1)
133 rv = 0;
134 else
135 rv = args.child;
136
137 ofw_unlock(s);
138 return rv;
139 }
140
141 int
OF_parent(int phandle)142 OF_parent(int phandle)
143 {
144 static struct {
145 const char *name;
146 int nargs;
147 int nreturns;
148 int phandle;
149 int parent;
150 } args = {
151 "parent",
152 1,
153 1,
154 };
155
156 const register_t s = ofw_lock();
157 int rv;
158
159 args.phandle = phandle;
160 if (openfirmware(&args) == -1)
161 rv = 0;
162 else
163 rv = args.parent;
164
165 ofw_unlock(s);
166 return rv;
167 }
168
169 int
OF_instance_to_package(int ihandle)170 OF_instance_to_package(int ihandle)
171 {
172 static struct {
173 const char *name;
174 int nargs;
175 int nreturns;
176 int ihandle;
177 int phandle;
178 } args = {
179 "instance-to-package",
180 1,
181 1,
182 };
183
184 const register_t s = ofw_lock();
185 int rv;
186
187 args.ihandle = ihandle;
188 if (openfirmware(&args) == -1)
189 rv = -1;
190 else
191 rv = args.phandle;
192
193 ofw_unlock(s);
194 return rv;
195 }
196
197 int
OF_getproplen(int handle,const char * prop)198 OF_getproplen(int handle, const char *prop)
199 {
200 static struct {
201 const char *name;
202 int nargs;
203 int nreturns;
204 int phandle;
205 const char *prop;
206 int proplen;
207 } args = {
208 "getproplen",
209 2,
210 1,
211 };
212
213 const register_t s = ofw_lock();
214 int rv;
215
216 strncpy(OF_buf, prop, 32);
217 args.phandle = handle;
218 args.prop = OF_buf;
219 if (openfirmware(&args) == -1)
220 rv = -1;
221 else
222 rv = args.proplen;
223
224 ofw_unlock(s);
225 return rv;
226 }
227
228 int
OF_getprop(int handle,const char * prop,void * buf,int buflen)229 OF_getprop(int handle, const char *prop, void *buf, int buflen)
230 {
231 static struct {
232 const char *name;
233 int nargs;
234 int nreturns;
235 int phandle;
236 const char *prop;
237 void *buf;
238 int buflen;
239 int size;
240 } args = {
241 "getprop",
242 4,
243 1,
244 };
245
246 if (buflen > PAGE_SIZE)
247 return -1;
248
249 const register_t s = ofw_lock();
250 int rv;
251
252 strncpy(OF_buf, prop, 32);
253 args.phandle = handle;
254 args.prop = OF_buf;
255 args.buf = &OF_buf[33];
256 args.buflen = buflen;
257 if (openfirmware(&args) == -1)
258 rv = -1;
259 else {
260 if (args.size > buflen)
261 args.size = buflen;
262 if (args.size > 0)
263 ofbcopy(&OF_buf[33], buf, args.size);
264 rv = args.size;
265 }
266
267 ofw_unlock(s);
268 return rv;
269 }
270
271 int
OF_setprop(int handle,const char * prop,const void * buf,int buflen)272 OF_setprop(int handle, const char *prop, const void *buf, int buflen)
273 {
274 struct {
275 const char *name;
276 int nargs;
277 int nreturns;
278 int phandle;
279 const char *prop;
280 const void *buf;
281 int buflen;
282 int size;
283 } args = {
284 "setprop",
285 4,
286 1
287 };
288
289 if (buflen > PAGE_SIZE)
290 return -1;
291
292 const register_t s = ofw_lock();
293 int rv;
294
295 ofbcopy(buf, OF_buf, buflen);
296 args.phandle = handle;
297 args.prop = prop;
298 args.buf = OF_buf;
299 args.buflen = buflen;
300 if (openfirmware(&args) == -1)
301 rv = -1;
302 else
303 rv = args.size;
304
305 ofw_unlock(s);
306 return rv;
307 }
308
309 int
OF_nextprop(int handle,const char * prop,void * nextprop)310 OF_nextprop(int handle, const char *prop, void *nextprop)
311 {
312 static struct {
313 const char *name;
314 int nargs;
315 int nreturns;
316 int phandle;
317 const char *prop;
318 char *buf;
319 int flag;
320 } args = {
321 "nextprop",
322 3,
323 1,
324 };
325
326 const register_t s = ofw_lock();
327 int rv;
328
329 strncpy(OF_buf, prop, 32);
330 args.phandle = handle;
331 args.prop = OF_buf;
332 args.buf = &OF_buf[33];
333 if (openfirmware(&args) == -1)
334 rv = -1;
335 else {
336 strncpy(nextprop, &OF_buf[33], 32);
337 rv = args.flag;
338 }
339
340 ofw_unlock(s);
341 return rv;
342 }
343
344 int
OF_finddevice(const char * name)345 OF_finddevice(const char *name)
346 {
347 static struct {
348 const char *name;
349 int nargs;
350 int nreturns;
351 const char *device;
352 int phandle;
353 } args = {
354 "finddevice",
355 1,
356 1,
357 };
358
359 const register_t s = ofw_lock();
360 int rv;
361
362 strncpy(OF_buf, name, NBPG);
363 args.device = OF_buf;
364 if (openfirmware(&args) == -1)
365 rv = -1;
366 else
367 rv = args.phandle;
368
369 ofw_unlock(s);
370 return rv;
371 }
372
373 int
OF_instance_to_path(int ihandle,char * buf,int buflen)374 OF_instance_to_path(int ihandle, char *buf, int buflen)
375 {
376 static struct {
377 const char *name;
378 int nargs;
379 int nreturns;
380 int ihandle;
381 char *buf;
382 int buflen;
383 int length;
384 } args = {
385 "instance-to-path",
386 3,
387 1,
388 };
389
390 if (buflen > PAGE_SIZE)
391 return -1;
392
393 const register_t s = ofw_lock();
394 int rv;
395
396 args.ihandle = ihandle;
397 args.buf = OF_buf;
398 args.buflen = buflen;
399 if (openfirmware(&args) < 0)
400 rv = -1;
401 else {
402 if (args.length > buflen)
403 args.length = buflen;
404 if (args.length > 0)
405 ofbcopy(OF_buf, buf, args.length);
406 rv = args.length;
407 }
408
409 ofw_unlock(s);
410 return rv;
411 }
412
413 int
OF_package_to_path(int phandle,char * buf,int buflen)414 OF_package_to_path(int phandle, char *buf, int buflen)
415 {
416 static struct {
417 const char *name;
418 int nargs;
419 int nreturns;
420 int phandle;
421 char *buf;
422 int buflen;
423 int length;
424 } args = {
425 "package-to-path",
426 3,
427 1,
428 };
429
430 if (buflen > PAGE_SIZE)
431 return -1;
432
433 const register_t s = ofw_lock();
434 int rv;
435
436 args.phandle = phandle;
437 args.buf = OF_buf;
438 args.buflen = buflen;
439 if (openfirmware(&args) < 0)
440 rv = -1;
441 else {
442 if (args.length > buflen)
443 args.length = buflen;
444 if (args.length > 0)
445 ofbcopy(OF_buf, buf, args.length);
446 rv = args.length;
447 }
448
449 ofw_unlock(s);
450 return rv;
451 }
452
453 int
OF_call_method(const char * method,int ihandle,int nargs,int nreturns,...)454 OF_call_method(const char *method, int ihandle, int nargs, int nreturns, ...)
455 {
456 static struct {
457 const char *name;
458 int nargs;
459 int nreturns;
460 const char *method;
461 int ihandle;
462 int args_n_results[12];
463 } args = {
464 "call-method",
465 2,
466 1,
467 };
468
469 if (nargs > 6)
470 return -1;
471
472 va_list ap;
473 int *ip, n;
474 int rv;
475
476 const register_t s = ofw_lock();
477
478 args.nargs = nargs + 2;
479 args.nreturns = nreturns + 1;
480 args.method = method;
481 args.ihandle = ihandle;
482
483 va_start(ap, nreturns);
484
485 for (ip = args.args_n_results + (n = nargs); --n >= 0;) {
486 *--ip = va_arg(ap, int);
487 }
488
489 if (openfirmware(&args) == -1) {
490 rv = -1;
491 } else if (args.args_n_results[nargs]) {
492 rv = args.args_n_results[nargs];
493 } else {
494 for (ip = args.args_n_results + nargs + (n = args.nreturns);
495 --n > 0;) {
496 *va_arg(ap, int *) = *--ip;
497 }
498 rv = 0;
499 }
500
501 va_end(ap);
502
503 ofw_unlock(s);
504 return rv;
505 }
506
507 int
OF_call_method_1(const char * method,int ihandle,int nargs,...)508 OF_call_method_1(const char *method, int ihandle, int nargs, ...)
509 {
510 static struct {
511 const char *name;
512 int nargs;
513 int nreturns;
514 const char *method;
515 int ihandle;
516 int args_n_results[8];
517 } args = {
518 "call-method",
519 2,
520 2,
521 };
522
523 if (nargs > 6)
524 return -1;
525
526 va_list ap;
527 int *ip, n;
528 int rv;
529
530 const register_t s = ofw_lock();
531
532 args.nargs = nargs + 2;
533 args.method = method;
534 args.ihandle = ihandle;
535
536 va_start(ap, nargs);
537 for (ip = args.args_n_results + (n = nargs); --n >= 0;) {
538 *--ip = va_arg(ap, int);
539 }
540 va_end(ap);
541
542 if (openfirmware(&args) == -1)
543 rv = -1;
544 else if (args.args_n_results[nargs])
545 rv = -1;
546 else
547 rv = args.args_n_results[nargs + 1];
548
549 ofw_unlock(s);
550 return rv;
551 }
552
553 int
OF_open(const char * dname)554 OF_open(const char *dname)
555 {
556 static struct {
557 const char *name;
558 int nargs;
559 int nreturns;
560 const char *dname;
561 int handle;
562 } args = {
563 "open",
564 1,
565 1,
566 };
567 int l;
568
569 if ((l = strlen(dname)) >= PAGE_SIZE)
570 return -1;
571
572 const register_t s = ofw_lock();
573 int rv;
574
575 ofbcopy(dname, OF_buf, l + 1);
576 args.dname = OF_buf;
577 if (openfirmware(&args) == -1)
578 rv = -1;
579 else
580 rv = args.handle;
581
582 ofw_unlock(s);
583 return rv;
584 }
585
586 void
OF_close(int handle)587 OF_close(int handle)
588 {
589 static struct {
590 const char *name;
591 int nargs;
592 int nreturns;
593 int handle;
594 } args = {
595 "close",
596 1,
597 0,
598 };
599
600 const register_t s = ofw_lock();
601
602 args.handle = handle;
603 openfirmware(&args);
604
605 ofw_unlock(s);
606 }
607
608 /*
609 * This assumes that character devices don't read in multiples of PAGE_SIZE.
610 */
611 int
OF_read(int handle,void * addr,int len)612 OF_read(int handle, void *addr, int len)
613 {
614 static struct {
615 const char *name;
616 int nargs;
617 int nreturns;
618 int ihandle;
619 void *addr;
620 int len;
621 int actual;
622 } args = {
623 "read",
624 3,
625 1,
626 };
627 int l, act = 0;
628 char *p = addr;
629
630 const register_t s = ofw_lock();
631
632 args.ihandle = handle;
633 args.addr = OF_buf;
634 for (; len > 0; len -= l, p += l) {
635 l = uimin(PAGE_SIZE, len);
636 args.len = l;
637 if (openfirmware(&args) == -1) {
638 act = -1;
639 goto out;
640 }
641 if (args.actual > 0) {
642 ofbcopy(OF_buf, p, args.actual);
643 act += args.actual;
644 }
645 if (args.actual < l) {
646 if (act == 0) {
647 act = args.actual;
648 }
649 goto out;
650 }
651 }
652
653 out:
654 ofw_unlock(s);
655 return act;
656 }
657
658 int
OF_write(int handle,const void * addr,int len)659 OF_write(int handle, const void *addr, int len)
660 {
661 static struct {
662 const char *name;
663 int nargs;
664 int nreturns;
665 int ihandle;
666 void *addr;
667 int len;
668 int actual;
669 } args = {
670 "write",
671 3,
672 1,
673 };
674 int l, act = 0;
675 const char *p = addr;
676
677 const register_t s = ofw_lock();
678
679 args.ihandle = handle;
680 args.addr = OF_buf;
681 for (; len > 0; len -= l, p += l) {
682 l = uimin(PAGE_SIZE, len);
683 ofbcopy(p, OF_buf, l);
684 args.len = l;
685 args.actual = l; /* work around a PIBS bug */
686 if (openfirmware(&args) == -1) {
687 act = -1;
688 goto out;
689 }
690 l = args.actual;
691 act += l;
692 }
693
694 out:
695 ofw_unlock(s);
696 return act;
697 }
698
699 int
OF_seek(int handle,u_quad_t pos)700 OF_seek(int handle, u_quad_t pos)
701 {
702 static struct {
703 const char *name;
704 int nargs;
705 int nreturns;
706 int handle;
707 int poshi;
708 int poslo;
709 int status;
710 } args = {
711 "seek",
712 3,
713 1,
714 };
715
716 const register_t s = ofw_lock();
717 int rv;
718
719 args.handle = handle;
720 args.poshi = (int)(pos >> 32);
721 args.poslo = (int)pos;
722 if (openfirmware(&args) == -1)
723 rv = -1;
724 else
725 rv = args.status;
726
727 ofw_unlock(s);
728 return rv;
729 }
730
731 #ifdef MULTIPROCESSOR
732 void
OF_start_cpu(int phandle,u_int pc,int arg)733 OF_start_cpu(int phandle, u_int pc, int arg)
734 {
735 static struct {
736 const char *name;
737 int nargs;
738 int nreturns;
739 int phandle;
740 u_int pc;
741 int arg;
742 } args = {
743 "start-cpu",
744 3,
745 0,
746 };
747
748 const register_t s = ofw_lock();
749 bool failed = false;
750
751 args.phandle = phandle;
752 args.pc = pc;
753 args.arg = arg;
754 if (openfirmware(&args) == -1)
755 failed = true;
756
757 ofw_unlock(s);
758 if (failed) {
759 panic("WTF?");
760 }
761 }
762 #endif
763
764 void
OF_boot(const char * bstr)765 OF_boot(const char *bstr)
766 {
767 static struct {
768 const char *name;
769 int nargs;
770 int nreturns;
771 char *bootspec;
772 } args = {
773 "boot",
774 1,
775 0,
776 };
777 int l;
778
779 if ((l = strlen(bstr)) >= PAGE_SIZE)
780 panic("OF_boot");
781
782 const register_t s = ofw_lock();
783
784 ofbcopy(bstr, OF_buf, l + 1);
785 args.bootspec = OF_buf;
786 openfirmware(&args);
787
788 ofw_unlock(s);
789 panic("OF_boot didn't");
790 }
791
792 void
OF_enter(void)793 OF_enter(void)
794 {
795 static struct {
796 const char *name;
797 int nargs;
798 int nreturns;
799 } args = {
800 "enter",
801 0,
802 0,
803 };
804
805 const register_t s = ofw_lock();
806
807 openfirmware(&args);
808
809 ofw_unlock(s);
810 }
811
812 void
OF_exit(void)813 OF_exit(void)
814 {
815 static struct {
816 const char *name;
817 int nargs;
818 int nreturns;
819 } args = {
820 "exit",
821 0,
822 0,
823 };
824
825 const register_t s = ofw_lock();
826
827 openfirmware(&args);
828
829 ofw_unlock(s);
830 while (1); /* just in case */
831 }
832
833 void
OF_set_callback(void (* newfunc)(void *))834 (*OF_set_callback (void (*newfunc)(void *))) (void *)
835 {
836 static struct {
837 const char *name;
838 int nargs;
839 int nreturns;
840 void (*newfunc)(void *);
841 void (*oldfunc)(void *);
842 } args = {
843 "set-callback",
844 1,
845 1,
846 };
847
848 const register_t s = ofw_lock();
849 void (*rv)(void *);
850
851 args.newfunc = newfunc;
852 if (openfirmware(&args) == -1)
853 rv = NULL;
854 else
855 rv = args.oldfunc;
856
857 ofw_unlock(s);
858 return rv;
859 }
860
861 int
OF_interpret(const char * cmd,int nargs,int nreturns,...)862 OF_interpret(const char *cmd, int nargs, int nreturns, ...)
863 {
864 static struct {
865 const char *name;
866 uint32_t nargs;
867 uint32_t nreturns;
868 uint32_t slots[16];
869 } args = {
870 "interpret",
871 1,
872 2,
873 };
874
875 va_list ap;
876 int i, len;
877 int rv;
878
879 if (nreturns > 8)
880 return -1;
881 if ((len = strlen(cmd)) >= PAGE_SIZE)
882 return -1;
883
884 const register_t s = ofw_lock();
885
886 ofbcopy(cmd, OF_buf, len + 1);
887 i = 0;
888 args.slots[i] = (uintptr_t)OF_buf;
889 args.nargs = nargs + 1;
890 args.nreturns = nreturns + 1;
891 va_start(ap, nreturns);
892 i++;
893 while (i < args.nargs) {
894 args.slots[i] = (uintptr_t)va_arg(ap, uint32_t *);
895 i++;
896 }
897
898 if (openfirmware(&args) == -1)
899 rv = -1;
900 else {
901 rv = args.slots[i];
902 i++;
903
904 while (i < args.nargs + args.nreturns) {
905 *va_arg(ap, uint32_t *) = args.slots[i];
906 i++;
907 }
908 }
909 va_end(ap);
910
911 ofw_unlock(s);
912 return rv;
913 }
914
915 void
OF_quiesce(void)916 OF_quiesce(void)
917 {
918 static struct {
919 const char *name;
920 int nargs;
921 int nreturns;
922 } args = {
923 "quiesce",
924 0,
925 0,
926 };
927
928 const register_t s = ofw_lock();
929
930 openfirmware(&args);
931
932 ofw_unlock(s);
933 }
934
935 /*
936 * This version of bcopy doesn't work for overlapping regions!
937 */
938 static void
ofbcopy(const void * src,void * dst,size_t len)939 ofbcopy(const void *src, void *dst, size_t len)
940 {
941 const char *sp = src;
942 char *dp = dst;
943
944 if (src == dst)
945 return;
946
947 while (len-- > 0)
948 *dp++ = *sp++;
949 }
950