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