1 /* $OpenBSD: openfirm.c,v 1.22 2022/10/16 01:22:39 jsg Exp $ */
2 /* $NetBSD: openfirm.c,v 1.13 2001/06/21 00:08:02 eeh Exp $ */
3
4 /*
5 * Copyright (C) 1995, 1996 Wolfgang Solfrank.
6 * Copyright (C) 1995, 1996 TooLs GmbH.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by TooLs GmbH.
20 * 4. The name of TooLs GmbH may not be used to endorse or promote products
21 * derived from this software without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
29 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
30 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
31 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
32 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 */
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/stdarg.h>
37 #include <machine/psl.h>
38
39 #include <machine/openfirm.h>
40
41 #define min(x,y) ((x<y)?(x):(y))
42
43 int
OF_peer(int phandle)44 OF_peer(int phandle)
45 {
46 struct {
47 cell_t name;
48 cell_t nargs;
49 cell_t nreturns;
50 cell_t phandle;
51 cell_t sibling;
52 } args;
53
54 args.name = ADR2CELL("peer");
55 args.nargs = 1;
56 args.nreturns = 1;
57 args.phandle = HDL2CELL(phandle);
58 if (openfirmware(&args) == -1)
59 return 0;
60 return args.sibling;
61 }
62
63 int
OF_child(int phandle)64 OF_child(int phandle)
65 {
66 struct {
67 cell_t name;
68 cell_t nargs;
69 cell_t nreturns;
70 cell_t phandle;
71 cell_t child;
72 } args;
73
74 args.name = ADR2CELL("child");
75 args.nargs = 1;
76 args.nreturns = 1;
77 args.phandle = HDL2CELL(phandle);
78 if (openfirmware(&args) == -1)
79 return 0;
80 return args.child;
81 }
82
83 int
OF_parent(int phandle)84 OF_parent(int phandle)
85 {
86 struct {
87 cell_t name;
88 cell_t nargs;
89 cell_t nreturns;
90 cell_t phandle;
91 cell_t parent;
92 } args;
93
94 args.name = ADR2CELL("parent");
95 args.nargs = 1;
96 args.nreturns = 1;
97 args.phandle = HDL2CELL(phandle);
98 if (openfirmware(&args) == -1)
99 return 0;
100 return args.parent;
101 }
102
103 int
OF_instance_to_package(int ihandle)104 OF_instance_to_package(int ihandle)
105 {
106 static struct {
107 cell_t name;
108 cell_t nargs;
109 cell_t nreturns;
110 cell_t ihandle;
111 cell_t phandle;
112 } args;
113
114 args.name = ADR2CELL("instance-to-package");
115 args.nargs = 1;
116 args.nreturns = 1;
117 args.ihandle = HDL2CELL(ihandle);
118 if (openfirmware(&args) == -1)
119 return -1;
120 return args.phandle;
121 }
122
123 /* Should really return a `long' */
124 int
OF_getproplen(int handle,char * prop)125 OF_getproplen(int handle, char *prop)
126 {
127 struct {
128 cell_t name;
129 cell_t nargs;
130 cell_t nreturns;
131 cell_t phandle;
132 cell_t prop;
133 cell_t size;
134 } args;
135
136 args.name = ADR2CELL("getproplen");
137 args.nargs = 2;
138 args.nreturns = 1;
139 args.phandle = HDL2CELL(handle);
140 args.prop = ADR2CELL(prop);
141 if (openfirmware(&args) == -1)
142 return -1;
143 return args.size;
144 }
145
146 int
OF_getprop(int handle,char * prop,void * buf,int buflen)147 OF_getprop(int handle, char *prop, void *buf, int buflen)
148 {
149 struct {
150 cell_t name;
151 cell_t nargs;
152 cell_t nreturns;
153 cell_t phandle;
154 cell_t prop;
155 cell_t buf;
156 cell_t buflen;
157 cell_t size;
158 } args;
159
160 if (buflen > NBPG)
161 return -1;
162 args.name = ADR2CELL("getprop");
163 args.nargs = 4;
164 args.nreturns = 1;
165 args.phandle = HDL2CELL(handle);
166 args.prop = ADR2CELL(prop);
167 args.buf = ADR2CELL(buf);
168 args.buflen = buflen;
169 if (openfirmware(&args) == -1)
170 return -1;
171 return args.size;
172 }
173
174 int
OF_setprop(int handle,char * prop,const void * buf,int buflen)175 OF_setprop(int handle, char *prop, const void *buf, int buflen)
176 {
177 struct {
178 cell_t name;
179 cell_t nargs;
180 cell_t nreturns;
181 cell_t phandle;
182 cell_t prop;
183 cell_t buf;
184 cell_t buflen;
185 cell_t size;
186 } args;
187
188 if (buflen > NBPG)
189 return -1;
190 args.name = ADR2CELL("setprop");
191 args.nargs = 4;
192 args.nreturns = 1;
193 args.phandle = HDL2CELL(handle);
194 args.prop = ADR2CELL(prop);
195 args.buf = ADR2CELL(buf);
196 args.buflen = buflen;
197 if (openfirmware(&args) == -1)
198 return -1;
199 return args.size;
200 }
201
202 int
OF_nextprop(int handle,char * prop,void * buf)203 OF_nextprop(int handle, char *prop, void *buf)
204 {
205 struct {
206 cell_t name;
207 cell_t nargs;
208 cell_t nreturns;
209 cell_t phandle;
210 cell_t prev;
211 cell_t buf;
212 cell_t next;
213 } args;
214
215 args.name = ADR2CELL("nextprop");
216 args.nargs = 3;
217 args.nreturns = 1;
218 args.phandle = HDL2CELL(handle);
219 args.prev = ADR2CELL(prop);
220 args.buf = ADR2CELL(buf);
221 if (openfirmware(&args) == -1)
222 return -1;
223 return args.next;
224 }
225
226 int
OF_finddevice(char * name)227 OF_finddevice(char *name)
228 {
229 struct {
230 cell_t name;
231 cell_t nargs;
232 cell_t nreturns;
233 cell_t device;
234 cell_t phandle;
235 } args;
236
237 args.name = ADR2CELL("finddevice");
238 args.nargs = 1;
239 args.nreturns = 1;
240 args.device = ADR2CELL(name);
241 if (openfirmware(&args) == -1)
242 return -1;
243 return args.phandle;
244 }
245
246 int
OF_instance_to_path(int ihandle,char * buf,int buflen)247 OF_instance_to_path(int ihandle, char *buf, int buflen)
248 {
249 struct {
250 cell_t name;
251 cell_t nargs;
252 cell_t nreturns;
253 cell_t ihandle;
254 cell_t buf;
255 cell_t buflen;
256 cell_t length;
257 } args;
258
259 if (buflen > NBPG)
260 return -1;
261 args.name = ADR2CELL("instance-to-path");
262 args.nargs = 3;
263 args.nreturns = 1;
264 args.ihandle = HDL2CELL(ihandle);
265 args.buf = ADR2CELL(buf);
266 args.buflen = buflen;
267 if (openfirmware(&args) < 0)
268 return -1;
269 return args.length;
270 }
271
272 int
OF_package_to_path(int phandle,char * buf,int buflen)273 OF_package_to_path(int phandle, char *buf, int buflen)
274 {
275 struct {
276 cell_t name;
277 cell_t nargs;
278 cell_t nreturns;
279 cell_t phandle;
280 cell_t buf;
281 cell_t buflen;
282 cell_t length;
283 } args;
284
285 if (buflen > NBPG)
286 return -1;
287 args.name = ADR2CELL("package-to-path");
288 args.nargs = 3;
289 args.nreturns = 1;
290 args.phandle = HDL2CELL(phandle);
291 args.buf = ADR2CELL(buf);
292 args.buflen = buflen;
293 if (openfirmware(&args) < 0)
294 return -1;
295 return args.length;
296 }
297
298 /*
299 * The following two functions may need to be re-worked to be 64-bit clean.
300 */
301 int
OF_call_method(char * method,int ihandle,int nargs,int nreturns,...)302 OF_call_method(char *method, int ihandle, int nargs, int nreturns, ...)
303 {
304 va_list ap;
305 struct {
306 cell_t name;
307 cell_t nargs;
308 cell_t nreturns;
309 cell_t method;
310 cell_t ihandle;
311 cell_t args_n_results[12];
312 } args;
313 long *ip, n;
314
315 if (nargs > 6)
316 return -1;
317 args.name = ADR2CELL("call-method");
318 args.nargs = nargs + 2;
319 args.nreturns = nreturns + 1;
320 args.method = ADR2CELL(method);
321 args.ihandle = HDL2CELL(ihandle);
322 va_start(ap, nreturns);
323 for (ip = (long *)(args.args_n_results + (n = nargs)); --n >= 0;)
324 *--ip = va_arg(ap, unsigned long);
325 if (openfirmware(&args) == -1) {
326 va_end(ap);
327 return -1;
328 }
329 if (args.args_n_results[nargs]) {
330 va_end(ap);
331 return args.args_n_results[nargs];
332 }
333 for (ip = (long *)(args.args_n_results + nargs + (n = args.nreturns)); --n > 0;)
334 *va_arg(ap, unsigned long *) = *--ip;
335 va_end(ap);
336 return 0;
337 }
338
339 int
OF_call_method_1(char * method,int ihandle,int nargs,...)340 OF_call_method_1(char *method, int ihandle, int nargs, ...)
341 {
342 va_list ap;
343 struct {
344 cell_t name;
345 cell_t nargs;
346 cell_t nreturns;
347 cell_t method;
348 cell_t ihandle;
349 cell_t args_n_results[16];
350 } args;
351 long *ip, n;
352
353 if (nargs > 6)
354 return -1;
355 args.name = ADR2CELL("call-method");
356 args.nargs = nargs + 2;
357 args.nreturns = 1;
358 args.method = ADR2CELL(method);
359 args.ihandle = HDL2CELL(ihandle);
360 va_start(ap, nargs);
361 for (ip = (long *)(args.args_n_results + (n = nargs)); --n >= 0;)
362 *--ip = va_arg(ap, unsigned long);
363 va_end(ap);
364 if (openfirmware(&args) == -1)
365 return -1;
366 if (args.args_n_results[nargs])
367 return -1;
368 return args.args_n_results[nargs + 1];
369 }
370
371 int
OF_open(char * dname)372 OF_open(char *dname)
373 {
374 struct {
375 cell_t name;
376 cell_t nargs;
377 cell_t nreturns;
378 cell_t dname;
379 cell_t handle;
380 } args;
381 int l;
382
383 if ((l = strlen(dname)) >= NBPG)
384 return -1;
385 args.name = ADR2CELL("open");
386 args.nargs = 1;
387 args.nreturns = 1;
388 args.dname = ADR2CELL(dname);
389 if (openfirmware(&args) == -1)
390 return -1;
391 return args.handle;
392 }
393
394 void
OF_close(int handle)395 OF_close(int handle)
396 {
397 struct {
398 cell_t name;
399 cell_t nargs;
400 cell_t nreturns;
401 cell_t handle;
402 } args;
403
404 args.name = ADR2CELL("close");
405 args.nargs = 1;
406 args.nreturns = 0;
407 args.handle = HDL2CELL(handle);
408 openfirmware(&args);
409 }
410
411 int
OF_test(char * service)412 OF_test(char *service)
413 {
414 struct {
415 cell_t name;
416 cell_t nargs;
417 cell_t nreturns;
418 cell_t service;
419 cell_t status;
420 } args;
421
422 args.name = ADR2CELL("test");
423 args.nargs = 1;
424 args.nreturns = 1;
425 args.service = ADR2CELL(service);
426 if (openfirmware(&args) == -1)
427 return -1;
428 return args.status;
429 }
430
431 int
OF_test_method(int service,char * method)432 OF_test_method(int service, char *method)
433 {
434 struct {
435 cell_t name;
436 cell_t nargs;
437 cell_t nreturns;
438 cell_t service;
439 cell_t method;
440 cell_t status;
441 } args;
442
443 args.name = ADR2CELL("test-method");
444 args.nargs = 2;
445 args.nreturns = 1;
446 args.service = HDL2CELL(service);
447 args.method = ADR2CELL(method);
448 if (openfirmware(&args) == -1)
449 return -1;
450 return args.status;
451 }
452
453
454 /*
455 * This assumes that character devices don't read in multiples of NBPG.
456 */
457 int
OF_read(int handle,void * addr,int len)458 OF_read(int handle, void *addr, int len)
459 {
460 struct {
461 cell_t name;
462 cell_t nargs;
463 cell_t nreturns;
464 cell_t ihandle;
465 cell_t addr;
466 cell_t len;
467 cell_t actual;
468 } args;
469 int l, act = 0;
470
471 args.name = ADR2CELL("read");
472 args.nargs = 3;
473 args.nreturns = 1;
474 args.ihandle = HDL2CELL(handle);
475 args.addr = ADR2CELL(addr);
476 for (; len > 0; len -= l) {
477 l = min(NBPG, len);
478 args.len = l;
479 if (openfirmware(&args) == -1)
480 return -1;
481 if (args.actual > 0) {
482 act += args.actual;
483 }
484 if (args.actual < l) {
485 if (act)
486 return act;
487 else
488 return args.actual;
489 }
490 }
491 return act;
492 }
493
494 void prom_printf(const char *fmt, ...); /* XXX for below */
495
496 int
OF_write(int handle,void * addr,int len)497 OF_write(int handle, void *addr, int len)
498 {
499 struct {
500 cell_t name;
501 cell_t nargs;
502 cell_t nreturns;
503 cell_t ihandle;
504 cell_t addr;
505 cell_t len;
506 cell_t actual;
507 } args;
508 int l, act = 0;
509
510 if (len > 1024) {
511 panic("OF_write(len=%d)", len);
512 }
513 args.name = ADR2CELL("write");
514 args.nargs = 3;
515 args.nreturns = 1;
516 args.ihandle = HDL2CELL(handle);
517 args.addr = ADR2CELL(addr);
518 for (; len > 0; len -= l) {
519 l = min(NBPG, len);
520 args.len = l;
521 if (openfirmware(&args) == -1)
522 return -1;
523 l = args.actual;
524 act += l;
525 }
526 return act;
527 }
528
529
530 int
OF_seek(int handle,u_quad_t pos)531 OF_seek(int handle, u_quad_t pos)
532 {
533 struct {
534 cell_t name;
535 cell_t nargs;
536 cell_t nreturns;
537 cell_t handle;
538 cell_t poshi;
539 cell_t poslo;
540 cell_t status;
541 } args;
542
543 args.name = ADR2CELL("seek");
544 args.nargs = 3;
545 args.nreturns = 1;
546 args.handle = HDL2CELL(handle);
547 args.poshi = HDQ2CELL_HI(pos);
548 args.poslo = HDQ2CELL_LO(pos);
549 if (openfirmware(&args) == -1)
550 return -1;
551 return args.status;
552 }
553
554 void
OF_boot(char * bootspec)555 OF_boot(char *bootspec)
556 {
557 struct {
558 cell_t name;
559 cell_t nargs;
560 cell_t nreturns;
561 cell_t bootspec;
562 } args;
563 int l;
564
565 if ((l = strlen(bootspec)) >= NBPG)
566 panic("OF_boot");
567 args.name = ADR2CELL("boot");
568 args.nargs = 1;
569 args.nreturns = 0;
570 args.bootspec = ADR2CELL(bootspec);
571 openfirmware(&args);
572 panic("OF_boot failed");
573 }
574
575 void
OF_enter(void)576 OF_enter(void)
577 {
578 struct {
579 cell_t name;
580 cell_t nargs;
581 cell_t nreturns;
582 } args;
583
584 args.name = ADR2CELL("enter");
585 args.nargs = 0;
586 args.nreturns = 0;
587 openfirmware(&args);
588 }
589
590 void
OF_exit(void)591 OF_exit(void)
592 {
593 struct {
594 cell_t name;
595 cell_t nargs;
596 cell_t nreturns;
597 } args;
598
599 args.name = ADR2CELL("exit");
600 args.nargs = 0;
601 args.nreturns = 0;
602 openfirmware(&args);
603 panic("OF_exit failed");
604 }
605
606 void
OF_poweroff(void)607 OF_poweroff(void)
608 {
609 struct {
610 cell_t name;
611 cell_t nargs;
612 cell_t nreturns;
613 } args;
614
615 args.name = ADR2CELL("SUNW,power-off");
616 args.nargs = 0;
617 args.nreturns = 0;
618 openfirmware(&args);
619 }
620
621 void
OF_set_callback(void (* newfunc)(void *))622 (*OF_set_callback(void (*newfunc)(void *)))(void *)
623 {
624 struct {
625 cell_t name;
626 cell_t nargs;
627 cell_t nreturns;
628 cell_t newfunc;
629 cell_t oldfunc;
630 } args;
631
632 args.name = ADR2CELL("set-callback");
633 args.nargs = 1;
634 args.nreturns = 1;
635 args.newfunc = ADR2CELL(newfunc);
636 if (openfirmware(&args) == -1)
637 return (void *)(long)-1;
638 return (void *)(long)args.oldfunc;
639 }
640
641 void
OF_set_symbol_lookup(void (* s2v)(void *),void (* v2s)(void *))642 OF_set_symbol_lookup(void (*s2v)(void *), void (*v2s)(void *))
643 {
644 struct {
645 cell_t name;
646 cell_t nargs;
647 cell_t nreturns;
648 cell_t sym2val;
649 cell_t val2sym;
650 } args;
651
652 args.name = ADR2CELL("set-symbol-lookup");
653 args.nargs = 2;
654 args.nreturns = 0;
655 args.sym2val = ADR2CELL(s2v);
656 args.val2sym = ADR2CELL(v2s);
657
658 (void)openfirmware(&args);
659 }
660
661 int
OF_interpret(char * cmd,int nreturns,...)662 OF_interpret(char *cmd, int nreturns, ...)
663 {
664 va_list ap;
665 struct {
666 cell_t name;
667 cell_t nargs;
668 cell_t nreturns;
669 cell_t slot[16];
670 } args;
671 cell_t status;
672 int i = 0;
673
674 args.name = ADR2CELL("interpret");
675 args.nargs = 1;
676 args.nreturns = ++nreturns;
677 args.slot[i++] = ADR2CELL(cmd);
678 va_start(ap, nreturns);
679 while (i < 1)
680 args.slot[i++] = va_arg(ap, cell_t);
681 if (openfirmware(&args) == -1) {
682 va_end(ap);
683 return (-1);
684 }
685 status = args.slot[i++];
686 while (i < 1 + nreturns)
687 *va_arg(ap, cell_t *) = args.slot[i++];
688 va_end(ap);
689 return (status);
690 }
691
692 int
OF_milliseconds(void)693 OF_milliseconds(void)
694 {
695 struct {
696 cell_t name;
697 cell_t nargs;
698 cell_t nreturns;
699 cell_t nticks;
700 } args;
701
702 args.name = ADR2CELL("milliseconds");
703 args.nargs = 0;
704 args.nreturns = 1;
705 if (openfirmware(&args) == -1)
706 return -1;
707 return (args.nticks);
708 }
709
710 #ifdef DDB
711 #include <machine/db_machdep.h>
712 #include <ddb/db_sym.h>
713 #include <ddb/db_extern.h>
714
715 int obp_symbol_debug = 0;
716
717 void
OF_sym2val(void * cells)718 OF_sym2val(void *cells)
719 {
720 struct args {
721 cell_t service;
722 cell_t nargs;
723 cell_t nreturns;
724 cell_t symbol;
725 cell_t result;
726 cell_t value;
727 } *args = (struct args*)cells;
728 char *symbol;
729 db_expr_t value;
730
731 /* Set data segment pointer */
732 __asm volatile("clr %%g4" : :);
733
734 /* No args? Nothing to do. */
735 if (!args->nargs ||
736 !args->nreturns) return;
737
738 /* Do we have a place for the value? */
739 if (args->nreturns != 2) {
740 args->nreturns = 1;
741 args->result = -1;
742 return;
743 }
744 symbol = (char *)(u_long)args->symbol;
745 if (obp_symbol_debug)
746 prom_printf("looking up symbol %s\r\n", symbol);
747 args->result = (db_symbol_by_name(symbol, &value) != NULL) ? 0 : -1;
748 if (obp_symbol_debug)
749 prom_printf("%s is %lx\r\n", symbol, value);
750 args->value = ADR2CELL(value);
751 }
752
753 void
OF_val2sym(void * cells)754 OF_val2sym(void *cells)
755 {
756 struct args {
757 cell_t service;
758 cell_t nargs;
759 cell_t nreturns;
760 cell_t value;
761 cell_t offset;
762 cell_t symbol;
763 } *args = (struct args*)cells;
764 Elf_Sym *symbol;
765 db_expr_t value;
766 db_expr_t offset;
767
768 /* Set data segment pointer */
769 __asm volatile("clr %%g4" : :);
770
771 if (obp_symbol_debug)
772 prom_printf("OF_val2sym: nargs %lx nreturns %lx\r\n",
773 args->nargs, args->nreturns);
774 /* No args? Nothing to do. */
775 if (!args->nargs ||
776 !args->nreturns) return;
777
778 /* Do we have a place for the value? */
779 if (args->nreturns != 2) {
780 args->nreturns = 1;
781 args->offset = -1;
782 return;
783 }
784
785 value = args->value;
786 if (obp_symbol_debug)
787 prom_printf("looking up value %ld\r\n", value);
788 symbol = db_search_symbol(value, 0, &offset);
789 if (symbol == NULL) {
790 if (obp_symbol_debug)
791 prom_printf("OF_val2sym: not found\r\n");
792 args->nreturns = 1;
793 args->offset = -1;
794 return;
795 }
796 args->offset = offset;
797 args->symbol = ADR2CELL(symbol);
798
799 }
800 #endif
801
802 int
OF_is_compatible(int handle,const char * name)803 OF_is_compatible(int handle, const char *name)
804 {
805 char compat[256];
806 char *str;
807 int len;
808
809 len = OF_getprop(handle, "compatible", &compat, sizeof(compat));
810 if (len <= 0)
811 return 0;
812
813 /* Guarantee that the buffer is null-terminated. */
814 compat[sizeof(compat) - 1] = 0;
815
816 str = compat;
817 while (len > 0) {
818 if (strcmp(str, name) == 0)
819 return 1;
820 len -= strlen(str) + 1;
821 str += strlen(str) + 1;
822 }
823
824 return 0;
825 }
826