xref: /freebsd/sys/dev/ofw/openfirm.c (revision 7660b554bc59a07be0431c17e0e33815818baa69)
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 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
36 /*
37  * Copyright (C) 2000 Benno Rice.
38  * All rights reserved.
39  *
40  * Redistribution and use in source and binary forms, with or without
41  * modification, are permitted provided that the following conditions
42  * are met:
43  * 1. Redistributions of source code must retain the above copyright
44  *    notice, this list of conditions and the following disclaimer.
45  * 2. Redistributions in binary form must reproduce the above copyright
46  *    notice, this list of conditions and the following disclaimer in the
47  *    documentation and/or other materials provided with the distribution.
48  *
49  * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR
50  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
51  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
52  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
53  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
54  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
55  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
56  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
57  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
58  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
59  *
60  */
61 
62 #include <sys/param.h>
63 #include <sys/kernel.h>
64 #include <sys/malloc.h>
65 #include <sys/systm.h>
66 
67 #include <machine/stdarg.h>
68 
69 #include <dev/ofw/openfirm.h>
70 
71 MALLOC_DEFINE(M_OFWPROP, "openfirm", "OpenFirmware properties");
72 
73 static ihandle_t stdin;
74 static ihandle_t stdout;
75 
76 char	*OF_buf;
77 
78 void	ofbcopy(const void *, void *, size_t);
79 
80 /* Initialiaser */
81 
82 void
83 OF_init(int (*openfirm)(void *))
84 {
85 	phandle_t	chosen;
86 
87 	set_openfirm_callback(openfirm);
88 	if ((chosen = OF_finddevice("/chosen")) == -1)
89 		OF_exit();
90 	OF_getprop(chosen, "stdin", &stdin, sizeof(stdin));
91 	OF_getprop(chosen, "stdout", &stdout, sizeof(stdout));
92 }
93 
94 void
95 OF_printf(const char *fmt, ...)
96 {
97 	va_list	va;
98 	char	buf[1024];
99 
100 	va_start(va, fmt);
101 	vsprintf(buf, fmt, va);
102 	OF_write(stdout, buf, strlen(buf));
103 	va_end(va);
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 int
133 OF_interpret(char *cmd, int nreturns, ...)
134 {
135 	va_list ap;
136 	static struct {
137 		cell_t name;
138 		cell_t nargs;
139 		cell_t nreturns;
140 		cell_t slot[16];
141 	} args = {
142 		(cell_t)"interpret",
143 		1
144 	};
145 	cell_t status;
146 	int i = 0;
147 
148 	args.nreturns = ++nreturns;
149 	args.slot[i++] = (cell_t)cmd;
150 	va_start(ap, nreturns);
151 	while (i < 1)
152 		args.slot[i++] = va_arg(ap, cell_t);
153 	if (openfirmware(&args) == -1) {
154 		va_end(ap);
155 		return (-1);
156 	}
157 	status = args.slot[i++];
158 	while (i < 1 + nreturns)
159 		*va_arg(ap, cell_t *) = args.slot[i++];
160 	va_end(ap);
161 	return (status);
162 }
163 
164 /* Return firmware millisecond count. */
165 int
166 OF_milliseconds()
167 {
168 	static struct {
169 		cell_t	name;
170 		cell_t	nargs;
171 		cell_t	nreturns;
172 		cell_t	ms;
173 	} args = {
174 		(cell_t)"milliseconds",
175 		0,
176 		1,
177 	};
178 
179 	openfirmware(&args);
180 	return args.ms;
181 }
182 
183 /*
184  * Device tree functions
185  */
186 
187 /* Return the next sibling of this node or 0. */
188 phandle_t
189 OF_peer(phandle_t node)
190 {
191 	static struct {
192 		cell_t		name;
193 		cell_t		nargs;
194 		cell_t		nreturns;
195 		cell_t		node;
196 		cell_t		next;
197 	} args = {
198 		(cell_t)"peer",
199 		1,
200 		1,
201 	};
202 
203 	args.node = (cell_t)node;
204 	if (openfirmware(&args) == -1)
205 		return -1;
206 	return args.next;
207 }
208 
209 /* Return the first child of this node or 0. */
210 phandle_t
211 OF_child(phandle_t node)
212 {
213 	static struct {
214 		cell_t		name;
215 		cell_t		nargs;
216 		cell_t		nreturns;
217 		cell_t		node;
218 		cell_t		child;
219 	} args = {
220 		(cell_t)"child",
221 		1,
222 		1,
223 	};
224 
225 	args.node = (cell_t)node;
226 	if (openfirmware(&args) == -1)
227 		return -1;
228 	return args.child;
229 }
230 
231 /* Return the parent of this node or 0. */
232 phandle_t
233 OF_parent(phandle_t node)
234 {
235 	static struct {
236 		cell_t		name;
237 		cell_t		nargs;
238 		cell_t		nreturns;
239 		cell_t		node;
240 		cell_t		parent;
241 	} args = {
242 		(cell_t)"parent",
243 		1,
244 		1,
245 	};
246 
247 	args.node = (cell_t)node;
248 	if (openfirmware(&args) == -1)
249 		return -1;
250 	return args.parent;
251 }
252 
253 /* Return the package handle that corresponds to an instance handle. */
254 phandle_t
255 OF_instance_to_package(ihandle_t instance)
256 {
257 	static struct {
258 		cell_t		name;
259 		cell_t		nargs;
260 		cell_t		nreturns;
261 		cell_t		instance;
262 		cell_t		package;
263 	} args = {
264 		(cell_t)"instance-to-package",
265 		1,
266 		1,
267 	};
268 
269 	args.instance = (cell_t)instance;
270 	if (openfirmware(&args) == -1)
271 		return -1;
272 	return args.package;
273 }
274 
275 /* Get the length of a property of a package. */
276 int
277 OF_getproplen(phandle_t package, char *propname)
278 {
279 	static struct {
280 		cell_t		name;
281 		cell_t		nargs;
282 		cell_t		nreturns;
283 		cell_t		package;
284 		cell_t 		propname;
285 		cell_t		proplen;
286 	} args = {
287 		(cell_t)"getproplen",
288 		2,
289 		1,
290 	};
291 
292 	args.package = (cell_t)package;
293 	args.propname = (cell_t)propname;
294 	if (openfirmware(&args) == -1)
295 		return -1;
296 	return args.proplen;
297 }
298 
299 /* Get the value of a property of a package. */
300 int
301 OF_getprop(phandle_t package, char *propname, void *buf, int buflen)
302 {
303 	static struct {
304 		cell_t		name;
305 		cell_t		nargs;
306 		cell_t		nreturns;
307 		cell_t		package;
308 		cell_t		propname;
309 		cell_t		buf;
310 		cell_t		buflen;
311 		cell_t		size;
312 	} args = {
313 		(cell_t)"getprop",
314 		4,
315 		1,
316 	};
317 
318 	args.package = (cell_t)package;
319 	args.propname = (cell_t)propname;
320 	args.buf = (cell_t)buf;
321 	args.buflen = (cell_t)buflen;
322 	if (openfirmware(&args) == -1)
323 		return -1;
324 	return args.size;
325 }
326 
327 /*
328  * Store the value of a property of a package into newly allocated memory (using
329  * the M_OFWPROP malloc pool and M_WAITOK). elsz is the size of a single element,
330  * the number of elements is return in number.
331  */
332 int
333 OF_getprop_alloc(phandle_t package, char *propname, int elsz, void **buf)
334 {
335 	int len;
336 
337 	*buf = NULL;
338 	if ((len = OF_getproplen(package, propname)) == -1 ||
339 	    len % elsz != 0)
340 		return (-1);
341 
342 	*buf = malloc(len, M_OFWPROP, M_WAITOK);
343 	if (OF_getprop(package, propname, *buf, len) == -1) {
344 		free(*buf, M_OFWPROP);
345 		*buf = NULL;
346 		return (-1);
347 	}
348 	return (len / elsz);
349 }
350 
351 /* Get the next property of a package. */
352 int
353 OF_nextprop(phandle_t package, char *previous, char *buf)
354 {
355 	static struct {
356 		cell_t		name;
357 		cell_t		nargs;
358 		cell_t		nreturns;
359 		cell_t		package;
360 		cell_t 		previous;
361 		cell_t		buf;
362 		cell_t		flag;
363 	} args = {
364 		(cell_t)"nextprop",
365 		3,
366 		1,
367 	};
368 
369 	args.package = (cell_t)package;
370 	args.previous = (cell_t)previous;
371 	args.buf = (cell_t)buf;
372 	if (openfirmware(&args) == -1)
373 		return -1;
374 	return args.flag;
375 }
376 
377 /* Set the value of a property of a package. */
378 /* XXX Has a bug on FirePower */
379 int
380 OF_setprop(phandle_t package, char *propname, void *buf, int len)
381 {
382 	static struct {
383 		cell_t		name;
384 		cell_t		nargs;
385 		cell_t		nreturns;
386 		cell_t		package;
387 		cell_t		propname;
388 		cell_t		buf;;
389 		cell_t		len;
390 		cell_t		size;
391 	} args = {
392 		(cell_t)"setprop",
393 		4,
394 		1,
395 	};
396 
397 	args.package = (cell_t)package;
398 	args.propname = (cell_t)propname;
399 	args.buf = (cell_t)buf;
400 	args.len = (cell_t)len;
401 	if (openfirmware(&args) == -1)
402 		return -1;
403 	return args.size;
404 }
405 
406 /* Convert a device specifier to a fully qualified pathname. */
407 int
408 OF_canon(const char *device, char *buf, int len)
409 {
410 	static struct {
411 		cell_t	name;
412 		cell_t	nargs;
413 		cell_t	nreturns;
414 		cell_t	device;
415 		cell_t	buf;
416 		cell_t	len;
417 		cell_t	size;
418 	} args = {
419 		(cell_t)"canon",
420 		3,
421 		1,
422 	};
423 
424 	args.device = (cell_t)device;
425 	args.buf = (cell_t)buf;
426 	args.len = (cell_t)len;
427 	if (openfirmware(&args) == -1)
428 		return -1;
429 	return args.size;
430 }
431 
432 /* Return a package handle for the specified device. */
433 phandle_t
434 OF_finddevice(const char *device)
435 {
436 	static struct {
437 		cell_t		name;
438 		cell_t		nargs;
439 		cell_t		nreturns;
440 		cell_t		device;
441 		cell_t		package;
442 	} args = {
443 		(cell_t)"finddevice",
444 		1,
445 		1,
446 	};
447 
448 	args.device = (cell_t)device;
449 	if (openfirmware(&args) == -1)
450 		return -1;
451 	return args.package;
452 }
453 
454 /* Return the fully qualified pathname corresponding to an instance. */
455 int
456 OF_instance_to_path(ihandle_t instance, char *buf, int len)
457 {
458 	static struct {
459 		cell_t		name;
460 		cell_t		nargs;
461 		cell_t		nreturns;
462 		cell_t		instance;
463 		cell_t		buf;
464 		cell_t		len;
465 		cell_t		size;
466 	} args = {
467 		(cell_t)"instance-to-path",
468 		3,
469 		1,
470 	};
471 
472 	args.instance = (cell_t)instance;
473 	args.buf = (cell_t)buf;
474 	args.len = (cell_t)len;
475 	if (openfirmware(&args) == -1)
476 		return -1;
477 	return(args.size);
478 }
479 
480 /* Return the fully qualified pathname corresponding to a package. */
481 int
482 OF_package_to_path(phandle_t package, char *buf, int len)
483 {
484 	static struct {
485 		cell_t		name;
486 		cell_t		nargs;
487 		cell_t		nreturns;
488 		cell_t		package;
489 		cell_t		buf;
490 		cell_t		len;
491 		cell_t		size;
492 	} args = {
493 		(cell_t)"package-to-path",
494 		3,
495 		1,
496 	};
497 
498 	args.package = (cell_t)package;
499 	args.buf = (cell_t)buf;
500 	args.len = (cell_t)len;
501 	if (openfirmware(&args) == -1)
502 		return -1;
503 	return(args.size);
504 }
505 
506 /*  Call the method in the scope of a given instance. */
507 int
508 OF_call_method(char *method, ihandle_t instance, int nargs, int nreturns, ...)
509 {
510 	va_list ap;
511 	static struct {
512 		cell_t		name;
513 		cell_t		nargs;
514 		cell_t		nreturns;
515 		cell_t		method;
516 		cell_t		instance;
517 		cell_t		args_n_results[12];
518 	} args = {
519 		(cell_t)"call-method",
520 		2,
521 		1,
522 	};
523 	cell_t *ip;
524 	int n;
525 
526 	if (nargs > 6)
527 		return -1;
528 	args.nargs = (cell_t)nargs + 2;
529 	args.nreturns = (cell_t)nreturns + 1;
530 	args.method = (cell_t)method;
531 	args.instance = (cell_t)instance;
532 	va_start(ap, nreturns);
533 	for (ip = args.args_n_results + (n = (cell_t)nargs); --n >= 0;)
534 		*--ip = va_arg(ap, cell_t);
535 
536 	if (openfirmware(&args) == -1)
537 		return -1;
538 	if (args.args_n_results[nargs])
539 		return args.args_n_results[nargs];
540 	for (ip = args.args_n_results + nargs + (n = args.nreturns); --n > 0;)
541 		*va_arg(ap, cell_t *) = *--ip;
542 	va_end(ap);
543 	return 0;
544 }
545 
546 /*
547  * Device I/O functions.
548  */
549 
550 /* Open an instance for a device. */
551 ihandle_t
552 OF_open(char *device)
553 {
554 	static struct {
555 		cell_t		name;
556 		cell_t		nargs;
557 		cell_t		nreturns;
558 		cell_t		device;
559 		cell_t		instance;
560 	} args = {
561 		(cell_t)"open",
562 		1,
563 		1,
564 	};
565 
566 	args.device = (cell_t)device;
567 	if (openfirmware(&args) == -1 || args.instance == 0) {
568 		return -1;
569 	}
570 	return args.instance;
571 }
572 
573 /* Close an instance. */
574 void
575 OF_close(ihandle_t instance)
576 {
577 	static struct {
578 		cell_t		name;
579 		cell_t		nargs;
580 		cell_t		nreturns;
581 		cell_t		instance;
582 	} args = {
583 		(cell_t)"close",
584 		1,
585 		0,
586 	};
587 
588 	args.instance = (cell_t)instance;
589 	openfirmware(&args);
590 }
591 
592 /* Read from an instance. */
593 int
594 OF_read(ihandle_t instance, void *addr, int len)
595 {
596 	static struct {
597 		cell_t		name;
598 		cell_t		nargs;
599 		cell_t		nreturns;
600 		cell_t		instance;
601 		cell_t		addr;
602 		cell_t		len;
603 		cell_t		actual;
604 	} args = {
605 		(cell_t)"read",
606 		3,
607 		1,
608 	};
609 
610 	args.instance = (cell_t)instance;
611 	args.addr = (cell_t)addr;
612 	args.len = (cell_t)len;
613 	if (openfirmware(&args) == -1)
614 		return -1;
615 
616 	return args.actual;
617 }
618 
619 /* Write to an instance. */
620 int
621 OF_write(ihandle_t instance, void *addr, int len)
622 {
623 	static struct {
624 		cell_t		name;
625 		cell_t		nargs;
626 		cell_t		nreturns;
627 		cell_t		instance;
628 		cell_t		addr;
629 		cell_t		len;
630 		cell_t		actual;
631 	} args = {
632 		(cell_t)"write",
633 		3,
634 		1,
635 	};
636 
637 	args.instance = (cell_t)instance;
638 	args.addr = (cell_t)addr;
639 	args.len = (cell_t)len;
640 	if (openfirmware(&args) == -1)
641 		return -1;
642 	return args.actual;
643 }
644 
645 /* Seek to a position. */
646 int
647 OF_seek(ihandle_t instance, u_int64_t pos)
648 {
649 	static struct {
650 		cell_t		name;
651 		cell_t		nargs;
652 		cell_t		nreturns;
653 		cell_t		instance;
654 		cell_t		poshi;
655 		cell_t		poslo;
656 		cell_t		status;
657 	} args = {
658 		(cell_t)"seek",
659 		3,
660 		1,
661 	};
662 
663 	args.instance = (cell_t)instance;
664 	args.poshi = (cell_t)(pos >> 32);
665 	args.poslo = (cell_t)pos;
666 	if (openfirmware(&args) == -1)
667 		return -1;
668 	return args.status;
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 = (cell_t)size;
695 	args.align = (cell_t)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 		0,
715 	};
716 
717 	args.virt = (cell_t)virt;
718 	args.size = (cell_t)size;
719 	openfirmware(&args);
720 }
721 
722 /*
723  * Control transfer functions.
724  */
725 
726 /* Reset the system and call "boot <bootspec>". */
727 void
728 OF_boot(char *bootspec)
729 {
730 	static struct {
731 		cell_t	name;
732 		cell_t	nargs;
733 		cell_t	nreturns;
734 		cell_t	bootspec;
735 	} args = {
736 		(cell_t)"boot",
737 		1,
738 		0,
739 	};
740 
741 	args.bootspec = (cell_t)bootspec;
742 	openfirmware(&args);
743 	for (;;);			/* just in case */
744 }
745 
746 /* Suspend and drop back to the OpenFirmware interface. */
747 void
748 OF_enter()
749 {
750 	static struct {
751 		cell_t name;
752 		cell_t nargs;
753 		cell_t nreturns;
754 	} args = {
755 		(cell_t)"enter",
756 		0,
757 		0
758 	};
759 
760 	openfirmware(&args);
761 	return;				/* We may come back. */
762 }
763 
764 /* Shut down and drop back to the OpenFirmware interface. */
765 void
766 OF_exit()
767 {
768 	static struct {
769 		cell_t name;
770 		cell_t nargs;
771 		cell_t nreturns;
772 	} args = {
773 		(cell_t)"exit",
774 		0,
775 		0
776 	};
777 
778 	openfirmware(&args);
779 	for (;;);			/* just in case */
780 }
781 
782 /* Free <size> bytes starting at <virt>, then call <entry> with <arg>. */
783 #ifdef	__notyet__
784 void
785 OF_chain(void *virt, u_int size, void (*entry)(), void *arg, u_int len)
786 {
787 	static struct {
788 		cell_t	name;
789 		cell_t	nargs;
790 		cell_t	nreturns;
791 		cell_t	virt;
792 		cell_t	size;
793 		call_t	entry;
794 		cell_t	arg;
795 		cell_t	len;
796 	} args = {
797 		(cell_t)"chain",
798 		5,
799 		0,
800 	};
801 
802 	args.virt = (cell_t)virt;
803 	args.size = (cell_t)size;
804 	args.entry = (cell_t)entry;
805 	args.arg = (cell_t)arg;
806 	args.len = (cell_t)len;
807 	openfirmware(&args);
808 }
809 #else
810 void
811 OF_chain(void *virt, u_int size,
812     void (*entry)(void *, u_int, void *, void *, u_int), void *arg, u_int len)
813 {
814 	/*
815 	 * This is a REALLY dirty hack till the firmware gets this going
816 	 */
817 #if 0
818 	OF_release(virt, size);
819 #endif
820 	entry(0, 0, openfirmware, arg, len);
821 }
822 #endif
823 
824 void
825 ofbcopy(const void *src, void *dst, size_t len)
826 {
827 	const char *sp = src;
828 	char *dp = dst;
829 
830 	if (src == dst)
831 		return;
832 
833 	while (len-- > 0)
834 		*dp++ = *sp++;
835 }
836