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