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