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