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