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