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