openfirm.c revision 163221
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#include <sys/cdefs.h>
35__FBSDID("$FreeBSD: head/sys/dev/ofw/openfirm.c 163221 2006-10-11 02:52:46Z kmacy $");
36/*-
37 * Copyright (C) 2000 Benno Rice.
38 * All rights reserved.
39 *
40 * Redistribution and use in source and binary forms, with or without
41 * modification, are permitted provided that the following conditions
42 * are met:
43 * 1. Redistributions of source code must retain the above copyright
44 *    notice, this list of conditions and the following disclaimer.
45 * 2. Redistributions in binary form must reproduce the above copyright
46 *    notice, this list of conditions and the following disclaimer in the
47 *    documentation and/or other materials provided with the distribution.
48 *
49 * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR
50 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
51 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
52 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
53 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
54 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
55 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
56 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
57 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
58 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
59 *
60 */
61
62#include <sys/param.h>
63#include <sys/kernel.h>
64#include <sys/malloc.h>
65#include <sys/systm.h>
66
67#include <machine/stdarg.h>
68
69#include <dev/ofw/openfirm.h>
70
71MALLOC_DEFINE(M_OFWPROP, "openfirm", "Open Firmware properties");
72
73static ihandle_t stdout;
74
75/* Initialiaser */
76
77void
78OF_init(int (*openfirm)(void *))
79{
80	phandle_t	chosen;
81
82	set_openfirm_callback(openfirm);
83	if ((chosen = OF_finddevice("/chosen")) == -1)
84		OF_exit();
85	OF_getprop(chosen, "stdout", &stdout, sizeof(stdout));
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	args.nreturns = ++nreturns;
143	args.slot[i++] = (cell_t)cmd;
144	va_start(ap, nreturns);
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 = (cell_t)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 = (cell_t)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 = (cell_t)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 = (cell_t)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 = (cell_t)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 = (cell_t)package;
313	args.propname = (cell_t)propname;
314	args.buf = (cell_t)buf;
315	args.buflen = (cell_t)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 = (cell_t)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 = (cell_t)package;
392	args.propname = (cell_t)propname;
393	args.buf = (cell_t)buf;
394	args.len = (cell_t)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 = (cell_t)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 = (cell_t)instance;
467	args.buf = (cell_t)buf;
468	args.len = (cell_t)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 = (cell_t)package;
493	args.buf = (cell_t)buf;
494	args.len = (cell_t)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 *ip;
518	int n;
519
520	if (nargs > 6)
521		return -1;
522	args.nargs = (cell_t)nargs + 2;
523	args.nreturns = (cell_t)nreturns + 1;
524	args.method = (cell_t)method;
525	args.instance = (cell_t)instance;
526	va_start(ap, nreturns);
527	for (ip = args.args_n_results + (n = (cell_t)nargs); --n >= 0;)
528		*--ip = va_arg(ap, cell_t);
529
530	if (openfirmware(&args) == -1)
531		return -1;
532	if (args.args_n_results[nargs])
533		return args.args_n_results[nargs];
534	for (ip = args.args_n_results + nargs + (n = args.nreturns); --n > 0;)
535		*va_arg(ap, cell_t *) = *--ip;
536	va_end(ap);
537	return 0;
538}
539
540/*
541 * Device I/O functions.
542 */
543
544/* Open an instance for a device. */
545ihandle_t
546OF_open(char *device)
547{
548	static struct {
549		cell_t		name;
550		cell_t		nargs;
551		cell_t		nreturns;
552		cell_t		device;
553		cell_t		instance;
554	} args = {
555		(cell_t)"open",
556		1,
557		1,
558	};
559
560	args.device = (cell_t)device;
561	if (openfirmware(&args) == -1 || args.instance == 0) {
562		return -1;
563	}
564	return args.instance;
565}
566
567/* Close an instance. */
568void
569OF_close(ihandle_t instance)
570{
571	static struct {
572		cell_t		name;
573		cell_t		nargs;
574		cell_t		nreturns;
575		cell_t		instance;
576	} args = {
577		(cell_t)"close",
578		1,
579		0,
580	};
581
582	args.instance = (cell_t)instance;
583	openfirmware(&args);
584}
585
586/* Read from an instance. */
587int
588OF_read(ihandle_t instance, void *addr, int len)
589{
590	static struct {
591		cell_t		name;
592		cell_t		nargs;
593		cell_t		nreturns;
594		cell_t		instance;
595		cell_t		addr;
596		cell_t		len;
597		cell_t		actual;
598	} args = {
599		(cell_t)"read",
600		3,
601		1,
602	};
603
604	args.instance = (cell_t)instance;
605	args.addr = (cell_t)addr;
606	args.len = (cell_t)len;
607	if (openfirmware(&args) == -1)
608		return -1;
609
610	return args.actual;
611}
612
613/* Write to an instance. */
614int
615OF_write(ihandle_t instance, void *addr, int len)
616{
617	static struct {
618		cell_t		name;
619		cell_t		nargs;
620		cell_t		nreturns;
621		cell_t		instance;
622		cell_t		addr;
623		cell_t		len;
624		cell_t		actual;
625	} args = {
626		(cell_t)"write",
627		3,
628		1,
629	};
630
631	args.instance = (cell_t)instance;
632	args.addr = (cell_t)addr;
633	args.len = (cell_t)len;
634	if (openfirmware(&args) == -1)
635		return -1;
636	return args.actual;
637}
638
639/* Seek to a position. */
640int
641OF_seek(ihandle_t instance, u_int64_t pos)
642{
643	static struct {
644		cell_t		name;
645		cell_t		nargs;
646		cell_t		nreturns;
647		cell_t		instance;
648		cell_t		poshi;
649		cell_t		poslo;
650		cell_t		status;
651	} args = {
652		(cell_t)"seek",
653		3,
654		1,
655	};
656
657	args.instance = (cell_t)instance;
658	args.poshi = (cell_t)(pos >> 32);
659	args.poslo = (cell_t)pos;
660	if (openfirmware(&args) == -1)
661		return -1;
662	return args.status;
663}
664
665/*
666 * Memory functions.
667 */
668
669/* Claim an area of memory. */
670void *
671OF_claim(void *virt, u_int size, u_int align)
672{
673	static struct {
674		cell_t	 name;
675		cell_t	 nargs;
676		cell_t	 nreturns;
677		cell_t	 virt;
678		cell_t	 size;
679		cell_t	 align;
680		cell_t	 baseaddr;
681	} args = {
682		(cell_t)"claim",
683		3,
684		1,
685	};
686
687	args.virt = (cell_t)virt;
688	args.size = (cell_t)size;
689	args.align = (cell_t)align;
690	if (openfirmware(&args) == -1)
691		return (void *)-1;
692	return (void *)args.baseaddr;
693}
694
695/* Release an area of memory. */
696void
697OF_release(void *virt, u_int size)
698{
699	static struct {
700		cell_t	name;
701		cell_t	nargs;
702		cell_t	nreturns;
703		cell_t	virt;
704		cell_t	size;
705	} args = {
706		(cell_t)"release",
707		2,
708		0,
709	};
710
711	args.virt = (cell_t)virt;
712	args.size = (cell_t)size;
713	openfirmware(&args);
714}
715
716/*
717 * Control transfer functions.
718 */
719
720/* Reset the system and call "boot <bootspec>". */
721void
722OF_boot(char *bootspec)
723{
724	static struct {
725		cell_t	name;
726		cell_t	nargs;
727		cell_t	nreturns;
728		cell_t	bootspec;
729	} args = {
730		(cell_t)"boot",
731		1,
732		0,
733	};
734
735	args.bootspec = (cell_t)bootspec;
736	openfirmware(&args);
737	for (;;);			/* just in case */
738}
739
740/* Suspend and drop back to the Open Firmware interface. */
741void
742OF_enter()
743{
744	static struct {
745		cell_t name;
746		cell_t nargs;
747		cell_t nreturns;
748	} args = {
749		(cell_t)"enter",
750		0,
751		0
752	};
753
754	openfirmware(&args);
755	return;				/* We may come back. */
756}
757
758/* Shut down and drop back to the Open Firmware interface. */
759void
760OF_exit()
761{
762	static struct {
763		cell_t name;
764		cell_t nargs;
765		cell_t nreturns;
766	} args = {
767		(cell_t)"exit",
768		0,
769		0
770	};
771
772	openfirmware(&args);
773	for (;;);			/* just in case */
774}
775
776/* Free <size> bytes starting at <virt>, then call <entry> with <arg>. */
777#ifdef	__notyet__
778void
779OF_chain(void *virt, u_int size, void (*entry)(), void *arg, u_int len)
780{
781	static struct {
782		cell_t	name;
783		cell_t	nargs;
784		cell_t	nreturns;
785		cell_t	virt;
786		cell_t	size;
787		call_t	entry;
788		cell_t	arg;
789		cell_t	len;
790	} args = {
791		(cell_t)"chain",
792		5,
793		0,
794	};
795
796	args.virt = (cell_t)virt;
797	args.size = (cell_t)size;
798	args.entry = (cell_t)entry;
799	args.arg = (cell_t)arg;
800	args.len = (cell_t)len;
801	openfirmware(&args);
802}
803#else
804void
805OF_chain(void *virt, u_int size,
806    void (*entry)(void *, u_int, void *, void *, u_int), void *arg, u_int len)
807{
808	/*
809	 * This is a REALLY dirty hack till the firmware gets this going
810	 */
811#if 0
812	OF_release(virt, size);
813#endif
814	entry(0, 0, openfirmware, arg, len);
815}
816#endif
817
818
819/*
820 * Extensions added for sun4v support
821 *
822 */
823
824/*
825 * This interface allows the client to safely take over the %tba by
826 * the prom's service. The prom will take care of the quiescence of
827 * interrupts and handle any pending soft interrupts.
828 * This call also sets the MMU fault status area for the cpu.
829 */
830void
831OF_set_mmfsa_traptable(void *tba_addr, uint64_t mmfsa_ra)
832{
833        static struct {
834                cell_t   name;
835                cell_t   nargs;
836                cell_t   nreturns;
837                cell_t   tba_addr;
838                cell_t   mmfsa_ra;
839        } args = {
840                (cell_t)"SUNW,set-trap-table",
841                2,
842                0,
843        };
844
845        args.tba_addr = (cell_t)tba_addr;
846        args.mmfsa_ra = (cell_t)mmfsa_ra;
847        openfirmware(&args);
848}
849
850