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