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