xref: /netbsd/sys/arch/powerpc/powerpc/openfirm.c (revision 6550d01e)
1 /*	$NetBSD: openfirm.c,v 1.20 2008/04/08 02:33:03 garbled 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 "opt_multiprocessor.h"
35 
36 #include <sys/cdefs.h>
37 __KERNEL_RCSID(0, "$NetBSD: openfirm.c,v 1.20 2008/04/08 02:33:03 garbled Exp $");
38 
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 
42 #include <uvm/uvm_extern.h>
43 
44 #include <machine/psl.h>
45 #include <machine/stdarg.h>
46 
47 #include <dev/ofw/openfirm.h>
48 
49 char *OF_buf;
50 
51 void ofw_stack(void);
52 void ofbcopy(const void *, void *, size_t);
53 #ifdef MULTIPROCESSOR
54 void OF_start_cpu(int, u_int, int);
55 #endif
56 
57 int
58 OF_peer(int phandle)
59 {
60 	static struct {
61 		const char *name;
62 		int nargs;
63 		int nreturns;
64 		int phandle;
65 		int sibling;
66 	} args = {
67 		"peer",
68 		1,
69 		1,
70 	};
71 
72 	ofw_stack();
73 	args.phandle = phandle;
74 	if (openfirmware(&args) == -1)
75 		return 0;
76 	return args.sibling;
77 }
78 
79 int
80 OF_child(int phandle)
81 {
82 	static struct {
83 		const char *name;
84 		int nargs;
85 		int nreturns;
86 		int phandle;
87 		int child;
88 	} args = {
89 		"child",
90 		1,
91 		1,
92 	};
93 
94 	ofw_stack();
95 	args.phandle = phandle;
96 	if (openfirmware(&args) == -1)
97 		return 0;
98 	return args.child;
99 }
100 
101 int
102 OF_parent(int phandle)
103 {
104 	static struct {
105 		const char *name;
106 		int nargs;
107 		int nreturns;
108 		int phandle;
109 		int parent;
110 	} args = {
111 		"parent",
112 		1,
113 		1,
114 	};
115 
116 	ofw_stack();
117 	args.phandle = phandle;
118 	if (openfirmware(&args) == -1)
119 		return 0;
120 	return args.parent;
121 }
122 
123 int
124 OF_instance_to_package(int ihandle)
125 {
126 	static struct {
127 		const char *name;
128 		int nargs;
129 		int nreturns;
130 		int ihandle;
131 		int phandle;
132 	} args = {
133 		"instance-to-package",
134 		1,
135 		1,
136 	};
137 
138 	ofw_stack();
139 	args.ihandle = ihandle;
140 	if (openfirmware(&args) == -1)
141 		return -1;
142 	return args.phandle;
143 }
144 
145 int
146 OF_getproplen(int handle, const char *prop)
147 {
148 	static struct {
149 		const char *name;
150 		int nargs;
151 		int nreturns;
152 		int phandle;
153 		const char *prop;
154 		int proplen;
155 	} args = {
156 		"getproplen",
157 		2,
158 		1,
159 	};
160 
161 	ofw_stack();
162 	args.phandle = handle;
163 	args.prop = prop;
164 	if (openfirmware(&args) == -1)
165 		return -1;
166 	return args.proplen;
167 }
168 
169 int
170 OF_getprop(int handle, const char *prop, void *buf, int buflen)
171 {
172 	static struct {
173 		const char *name;
174 		int nargs;
175 		int nreturns;
176 		int phandle;
177 		const char *prop;
178 		void *buf;
179 		int buflen;
180 		int size;
181 	} args = {
182 		"getprop",
183 		4,
184 		1,
185 	};
186 
187 	ofw_stack();
188 	if (buflen > PAGE_SIZE)
189 		return -1;
190 	args.phandle = handle;
191 	args.prop = prop;
192 	args.buf = OF_buf;
193 	args.buflen = buflen;
194 	if (openfirmware(&args) == -1)
195 		return -1;
196 	if (args.size > buflen)
197 		args.size = buflen;
198 	if (args.size > 0)
199 		ofbcopy(OF_buf, buf, args.size);
200 	return args.size;
201 }
202 
203 int
204 OF_setprop(int handle, const char *prop, const void *buf, int buflen)
205 {
206 	struct {
207 		const char *name;
208 		int nargs;
209 		int nreturns;
210 		int phandle;
211 		const char *prop;
212 		const void *buf;
213 		int buflen;
214 		int size;
215 	} args = {
216 		"setprop",
217 		4,
218 		1
219 	};
220 	ofw_stack();
221 
222 	if (buflen > NBPG)
223 		return -1;
224 
225 	ofbcopy(buf, OF_buf, buflen);
226 	args.phandle = handle;
227 	args.prop = prop;
228 	args.buf = OF_buf;
229 	args.buflen = buflen;
230 	if (openfirmware(&args) == -1)
231 		return -1;
232 	return args.size;
233 }
234 
235 int
236 OF_nextprop(int handle, const char *prop, void *nextprop)
237 {
238 	static struct {
239 		const char *name;
240 		int nargs;
241 		int nreturns;
242 		int phandle;
243 		const char *prop;
244 		char *buf;
245 		int flag;
246 	} args = {
247 		"nextprop",
248 		3,
249 		1,
250 	};
251 
252 	ofw_stack();
253 	args.phandle = handle;
254 	args.prop = prop;
255 	args.buf = OF_buf;
256 	if (openfirmware(&args) == -1)
257 		return -1;
258 	strncpy(nextprop, OF_buf, 32);
259 	return args.flag;
260 }
261 
262 int
263 OF_finddevice(const char *name)
264 {
265 	static struct {
266 		const char *name;
267 		int nargs;
268 		int nreturns;
269 		const char *device;
270 		int phandle;
271 	} args = {
272 		"finddevice",
273 		1,
274 		1,
275 	};
276 
277 	ofw_stack();
278 	args.device = name;
279 	if (openfirmware(&args) == -1)
280 		return -1;
281 	return args.phandle;
282 }
283 
284 int
285 OF_instance_to_path(int ihandle, char *buf, int buflen)
286 {
287 	static struct {
288 		const char *name;
289 		int nargs;
290 		int nreturns;
291 		int ihandle;
292 		char *buf;
293 		int buflen;
294 		int length;
295 	} args = {
296 		"instance-to-path",
297 		3,
298 		1,
299 	};
300 
301 	if (buflen > PAGE_SIZE)
302 		return -1;
303 	args.ihandle = ihandle;
304 	args.buf = OF_buf;
305 	args.buflen = buflen;
306 	if (openfirmware(&args) < 0)
307 		return -1;
308 	if (args.length > buflen)
309 		args.length = buflen;
310 	if (args.length > 0)
311 		ofbcopy(OF_buf, buf, args.length);
312 	return args.length;
313 }
314 
315 int
316 OF_package_to_path(int phandle, char *buf, int buflen)
317 {
318 	static struct {
319 		const char *name;
320 		int nargs;
321 		int nreturns;
322 		int phandle;
323 		char *buf;
324 		int buflen;
325 		int length;
326 	} args = {
327 		"package-to-path",
328 		3,
329 		1,
330 	};
331 
332 	ofw_stack();
333 	if (buflen > PAGE_SIZE)
334 		return -1;
335 	args.phandle = phandle;
336 	args.buf = OF_buf;
337 	args.buflen = buflen;
338 	if (openfirmware(&args) < 0)
339 		return -1;
340 	if (args.length > buflen)
341 		args.length = buflen;
342 	if (args.length > 0)
343 		ofbcopy(OF_buf, buf, args.length);
344 	return args.length;
345 }
346 
347 int
348 OF_call_method(const char *method, int ihandle, int nargs, int nreturns, ...)
349 {
350 	va_list ap;
351 	static struct {
352 		const char *name;
353 		int nargs;
354 		int nreturns;
355 		const char *method;
356 		int ihandle;
357 		int args_n_results[12];
358 	} args = {
359 		"call-method",
360 		2,
361 		1,
362 	};
363 	int *ip, n;
364 
365 	if (nargs > 6)
366 		return -1;
367 	args.nargs = nargs + 2;
368 	args.nreturns = nreturns + 1;
369 	args.method = method;
370 	args.ihandle = ihandle;
371 	va_start(ap, nreturns);
372 	for (ip = args.args_n_results + (n = nargs); --n >= 0;)
373 		*--ip = va_arg(ap, int);
374 	ofw_stack();
375 	if (openfirmware(&args) == -1) {
376 		va_end(ap);
377 		return -1;
378 	}
379 	if (args.args_n_results[nargs]) {
380 		va_end(ap);
381 		return args.args_n_results[nargs];
382 	}
383 	for (ip = args.args_n_results + nargs + (n = args.nreturns); --n > 0;)
384 		*va_arg(ap, int *) = *--ip;
385 	va_end(ap);
386 	return 0;
387 }
388 
389 int
390 OF_call_method_1(const char *method, int ihandle, int nargs, ...)
391 {
392 	va_list ap;
393 	static struct {
394 		const char *name;
395 		int nargs;
396 		int nreturns;
397 		const char *method;
398 		int ihandle;
399 		int args_n_results[8];
400 	} args = {
401 		"call-method",
402 		2,
403 		2,
404 	};
405 	int *ip, n;
406 
407 	if (nargs > 6)
408 		return -1;
409 	args.nargs = nargs + 2;
410 	args.method = method;
411 	args.ihandle = ihandle;
412 	va_start(ap, nargs);
413 	for (ip = args.args_n_results + (n = nargs); --n >= 0;)
414 		*--ip = va_arg(ap, int);
415 	va_end(ap);
416 	ofw_stack();
417 	if (openfirmware(&args) == -1)
418 		return -1;
419 	if (args.args_n_results[nargs])
420 		return -1;
421 	return args.args_n_results[nargs + 1];
422 }
423 
424 int
425 OF_open(const char *dname)
426 {
427 	static struct {
428 		const char *name;
429 		int nargs;
430 		int nreturns;
431 		const char *dname;
432 		int handle;
433 	} args = {
434 		"open",
435 		1,
436 		1,
437 	};
438 	int l;
439 
440 	ofw_stack();
441 	if ((l = strlen(dname)) >= PAGE_SIZE)
442 		return -1;
443 	ofbcopy(dname, OF_buf, l + 1);
444 	args.dname = OF_buf;
445 	if (openfirmware(&args) == -1)
446 		return -1;
447 	return args.handle;
448 }
449 
450 void
451 OF_close(int handle)
452 {
453 	static struct {
454 		const char *name;
455 		int nargs;
456 		int nreturns;
457 		int handle;
458 	} args = {
459 		"close",
460 		1,
461 		0,
462 	};
463 
464 	ofw_stack();
465 	args.handle = handle;
466 	openfirmware(&args);
467 }
468 
469 /*
470  * This assumes that character devices don't read in multiples of PAGE_SIZE.
471  */
472 int
473 OF_read(int handle, void *addr, int len)
474 {
475 	static struct {
476 		const char *name;
477 		int nargs;
478 		int nreturns;
479 		int ihandle;
480 		void *addr;
481 		int len;
482 		int actual;
483 	} args = {
484 		"read",
485 		3,
486 		1,
487 	};
488 	int l, act = 0;
489 	char *p = addr;
490 
491 	ofw_stack();
492 	args.ihandle = handle;
493 	args.addr = OF_buf;
494 	for (; len > 0; len -= l, p += l) {
495 		l = min(PAGE_SIZE, len);
496 		args.len = l;
497 		if (openfirmware(&args) == -1)
498 			return -1;
499 		if (args.actual > 0) {
500 			ofbcopy(OF_buf, p, args.actual);
501 			act += args.actual;
502 		}
503 		if (args.actual < l) {
504 			if (act)
505 				return act;
506 			else
507 				return args.actual;
508 		}
509 	}
510 	return act;
511 }
512 
513 int
514 OF_write(int handle, const void *addr, int len)
515 {
516 	static struct {
517 		const char *name;
518 		int nargs;
519 		int nreturns;
520 		int ihandle;
521 		void *addr;
522 		int len;
523 		int actual;
524 	} args = {
525 		"write",
526 		3,
527 		1,
528 	};
529 	int l, act = 0;
530 	const char *p = addr;
531 
532 	ofw_stack();
533 	args.ihandle = handle;
534 	args.addr = OF_buf;
535 	for (; len > 0; len -= l, p += l) {
536 		l = min(PAGE_SIZE, len);
537 		ofbcopy(p, OF_buf, l);
538 		args.len = l;
539 		args.actual = l;	/* work around a PIBS bug */
540 		if (openfirmware(&args) == -1)
541 			return -1;
542 		l = args.actual;
543 		act += l;
544 	}
545 	return act;
546 }
547 
548 int
549 OF_seek(int handle, u_quad_t pos)
550 {
551 	static struct {
552 		const char *name;
553 		int nargs;
554 		int nreturns;
555 		int handle;
556 		int poshi;
557 		int poslo;
558 		int status;
559 	} args = {
560 		"seek",
561 		3,
562 		1,
563 	};
564 
565 	ofw_stack();
566 	args.handle = handle;
567 	args.poshi = (int)(pos >> 32);
568 	args.poslo = (int)pos;
569 	if (openfirmware(&args) == -1)
570 		return -1;
571 	return args.status;
572 }
573 
574 #ifdef MULTIPROCESSOR
575 void
576 OF_start_cpu(int phandle, u_int pc, int arg)
577 {
578 	static struct {
579 		const char *name;
580 		int nargs;
581 		int nreturns;
582 		int phandle;
583 		u_int pc;
584 		int arg;
585 	} args = {
586 		"start-cpu",
587 		3,
588 		0,
589 	};
590 	ofw_stack();
591 	args.phandle = phandle;
592 	args.pc = pc;
593 	args.arg = arg;
594 	if (openfirmware(&args) == -1)
595 		panic("WTF?");
596 }
597 #endif
598 
599 void
600 OF_boot(const char *bootspec)
601 {
602 	static struct {
603 		const char *name;
604 		int nargs;
605 		int nreturns;
606 		char *bootspec;
607 	} args = {
608 		"boot",
609 		1,
610 		0,
611 	};
612 	int l;
613 
614 	if ((l = strlen(bootspec)) >= PAGE_SIZE)
615 		panic("OF_boot");
616 	ofw_stack();
617 	ofbcopy(bootspec, OF_buf, l + 1);
618 	args.bootspec = OF_buf;
619 	openfirmware(&args);
620 	while (1);			/* just in case */
621 }
622 
623 void
624 OF_enter(void)
625 {
626 	static struct {
627 		const char *name;
628 		int nargs;
629 		int nreturns;
630 	} args = {
631 		"enter",
632 		0,
633 		0,
634 	};
635 
636 	ofw_stack();
637 	openfirmware(&args);
638 }
639 
640 void
641 OF_exit(void)
642 {
643 	static struct {
644 		const char *name;
645 		int nargs;
646 		int nreturns;
647 	} args = {
648 		"exit",
649 		0,
650 		0,
651 	};
652 
653 	ofw_stack();
654 	openfirmware(&args);
655 	while (1);			/* just in case */
656 }
657 
658 void
659 (*OF_set_callback (void (*newfunc)(void *))) (void *)
660 {
661 	static struct {
662 		const char *name;
663 		int nargs;
664 		int nreturns;
665 		void (*newfunc)(void *);
666 		void (*oldfunc)(void *);
667 	} args = {
668 		"set-callback",
669 		1,
670 		1,
671 	};
672 
673 	ofw_stack();
674 	args.newfunc = newfunc;
675 	if (openfirmware(&args) == -1)
676 		return 0;
677 	return args.oldfunc;
678 }
679 
680 int
681 OF_interpret(const char *cmd, int nargs, int nreturns, ...)
682 {
683 	va_list ap;
684 	int i, len, status;
685 	static struct {
686 		const char *name;
687 		uint32_t nargs;
688 		uint32_t nreturns;
689 		uint32_t slots[16];
690 	} args = {
691 		"interpret",
692 		1,
693 		2,
694 	};
695 
696 	ofw_stack();
697 	if (nreturns > 8)
698 		return -1;
699 	if ((len = strlen(cmd)) >= PAGE_SIZE)
700 		return -1;
701 	ofbcopy(cmd, OF_buf, len + 1);
702 	i = 0;
703 	args.slots[i] = (uint32_t)OF_buf;
704 	args.nargs = nargs + 1;
705 	args.nreturns = nreturns + 1;
706 	va_start(ap, nreturns);
707 	i++;
708 	while (i < args.nargs) {
709 		args.slots[i] = (uint32_t)va_arg(ap, uint32_t *);
710 		i++;
711 	}
712 
713 	if (openfirmware(&args) == -1)
714 		return -1;
715 	status = args.slots[i];
716 	i++;
717 
718 	while (i < args.nargs + args.nreturns) {
719 		*va_arg(ap, uint32_t *) = args.slots[i];
720 		i++;
721 	}
722 	va_end(ap);
723 	return status;
724 }
725 
726 /*
727  * This version of bcopy doesn't work for overlapping regions!
728  */
729 void
730 ofbcopy(const void *src, void *dst, size_t len)
731 {
732 	const char *sp = src;
733 	char *dp = dst;
734 
735 	if (src == dst)
736 		return;
737 
738 	/*
739 	 * Do some optimization?						XXX
740 	 */
741 	while (len-- > 0)
742 		*dp++ = *sp++;
743 }
744