openfirm.c revision 139738
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 139738 2005-01-05 22:16:58Z imp $");
60
61#include <machine/stdarg.h>
62
63#include <stand.h>
64
65#include "openfirm.h"
66
67int (*openfirmware)(void *);
68
69static ihandle_t stdin;
70static ihandle_t stdout;
71
72ihandle_t mmu;
73ihandle_t memory;
74
75/* Initialiaser */
76
77void
78OF_init(int (*openfirm)(void *))
79{
80	phandle_t	chosen;
81
82	openfirmware = openfirm;
83
84	chosen = OF_finddevice("/chosen");
85	OF_getprop(chosen, "memory", &memory, sizeof(memory));
86	if (memory == 0)
87		panic("failed to get memory ihandle");
88	OF_getprop(chosen, "mmu", &mmu, sizeof(mmu));
89	if (mmu == 0)
90		panic("failed to get mmu ihandle");
91}
92
93/*
94 * Generic functions
95 */
96
97/* Test to see if a service exists. */
98int
99OF_test(char *name)
100{
101	static struct {
102		cell_t	name;
103		cell_t	nargs;
104		cell_t	nreturns;
105		cell_t	service;
106		cell_t	missing;
107	} args = {
108		(cell_t)"test",
109		1,
110		1,
111		0,
112		0
113	};
114
115	args.service = (cell_t)name;
116	if (openfirmware(&args) == -1)
117		return -1;
118	return (int)args.missing;
119}
120
121/* Return firmware millisecond count. */
122int
123OF_milliseconds()
124{
125	static struct {
126		cell_t	name;
127		cell_t	nargs;
128		cell_t	nreturns;
129		cell_t	ms;
130	} args = {
131		(cell_t)"milliseconds",
132		0,
133		1,
134		0
135	};
136
137	openfirmware(&args);
138	return (int)args.ms;
139}
140
141/*
142 * Device tree functions
143 */
144
145/* Return the next sibling of this node or 0. */
146phandle_t
147OF_peer(phandle_t node)
148{
149	static struct {
150		cell_t		name;
151		cell_t		nargs;
152		cell_t		nreturns;
153		cell_t		node;
154		cell_t		next;
155	} args = {
156		(cell_t)"peer",
157		1,
158		1,
159		0,
160		0
161	};
162
163	args.node = (u_int)node;
164	if (openfirmware(&args) == -1)
165		return -1;
166	return (phandle_t)args.next;
167}
168
169/* Return the first child of this node or 0. */
170phandle_t
171OF_child(phandle_t node)
172{
173	static struct {
174		cell_t		name;
175		cell_t		nargs;
176		cell_t		nreturns;
177		cell_t		node;
178		cell_t		child;
179	} args = {
180		(cell_t)"child",
181		1,
182		1,
183		0,
184		0
185	};
186
187	args.node = (u_int)node;
188	if (openfirmware(&args) == -1)
189		return -1;
190	return (phandle_t)args.child;
191}
192
193/* Return the parent of this node or 0. */
194phandle_t
195OF_parent(phandle_t node)
196{
197	static struct {
198		cell_t		name;
199		cell_t		nargs;
200		cell_t		nreturns;
201		cell_t		node;
202		cell_t		parent;
203	} args = {
204		(cell_t)"parent",
205		1,
206		1,
207		0,
208		0
209	};
210
211	args.node = (u_int)node;
212	if (openfirmware(&args) == -1)
213		return -1;
214	return (phandle_t)args.parent;
215}
216
217/* Return the package handle that corresponds to an instance handle. */
218phandle_t
219OF_instance_to_package(ihandle_t instance)
220{
221	static struct {
222		cell_t	name;
223		cell_t	nargs;
224		cell_t	nreturns;
225		cell_t	instance;
226		cell_t	package;
227	} args = {
228		(cell_t)"instance-to-package",
229		1,
230		1,
231		0,
232		0
233	};
234
235	args.instance = (u_int)instance;
236	if (openfirmware(&args) == -1)
237		return -1;
238	return (phandle_t)args.package;
239}
240
241/* Get the length of a property of a package. */
242int
243OF_getproplen(phandle_t package, char *propname)
244{
245	static struct {
246		cell_t	name;
247		cell_t	nargs;
248		cell_t	nreturns;
249		cell_t	package;
250		cell_t	propname;
251		cell_t	proplen;
252	} args = {
253		(cell_t)"getproplen",
254		2,
255		1,
256		0,
257		0,
258		0
259	};
260
261	args.package = (u_int)package;
262	args.propname = (cell_t)propname;
263	if (openfirmware(&args) == -1)
264		return -1;
265	return (int)args.proplen;
266}
267
268/* Get the value of a property of a package. */
269int
270OF_getprop(phandle_t package, char *propname, void *buf, int buflen)
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		buf;
279		cell_t		buflen;
280		cell_t		size;
281	} args = {
282		(cell_t)"getprop",
283		4,
284		1,
285		0,
286		0,
287		0,
288		0,
289		0
290	};
291
292	args.package = (u_int)package;
293	args.propname = (cell_t)propname;
294	args.buf = (cell_t)buf;
295	args.buflen = (u_int)buflen;
296	if (openfirmware(&args) == -1)
297		return -1;
298	return (int)args.size;
299}
300
301/* Get the next property of a package. */
302int
303OF_nextprop(phandle_t package, char *previous, char *buf)
304{
305	static struct {
306		cell_t		name;
307		cell_t		nargs;
308		cell_t		nreturns;
309		cell_t		package;
310		cell_t		previous;
311		cell_t		buf;
312		cell_t		flag;
313	} args = {
314		(cell_t)"nextprop",
315		3,
316		1,
317		0,
318		0,
319		0,
320		0
321	};
322
323	args.package = (u_int)package;
324	args.previous = (cell_t)previous;
325	args.buf = (cell_t)buf;
326	if (openfirmware(&args) == -1)
327		return -1;
328	return (int)args.flag;
329}
330
331/* Set the value of a property of a package. */
332/* XXX Has a bug on FirePower */
333int
334OF_setprop(phandle_t package, char *propname, void *buf, int len)
335{
336	static struct {
337		cell_t		name;
338		cell_t		nargs;
339		cell_t		nreturns;
340		cell_t		package;
341		cell_t		propname;
342		cell_t		buf;
343		cell_t		len;
344		cell_t		size;
345	} args = {
346		(cell_t)"setprop",
347		4,
348		1,
349		0,
350		0,
351		0,
352		0,
353		0
354	};
355
356	args.package = (u_int)package;
357	args.propname = (cell_t)propname;
358	args.buf = (cell_t)buf;
359	args.len = (u_int)len;
360	if (openfirmware(&args) == -1)
361		return -1;
362	return (int)args.size;
363}
364
365/* Convert a device specifier to a fully qualified pathname. */
366int
367OF_canon(const char *device, char *buf, int len)
368{
369	static struct {
370		cell_t	name;
371		cell_t	nargs;
372		cell_t	nreturns;
373		cell_t	device;
374		cell_t	buf;
375		cell_t	len;
376		cell_t	size;
377	} args = {
378		(cell_t)"canon",
379		3,
380		1,
381		0,
382		0,
383		0,
384		0
385	};
386
387	args.device = (cell_t)device;
388	args.buf = (cell_t)buf;
389	args.len = (cell_t)len;
390	if (openfirmware(&args) == -1)
391		return -1;
392	return (int)args.size;
393}
394
395/* Return a package handle for the specified device. */
396phandle_t
397OF_finddevice(const char *device)
398{
399	int i;
400	static struct {
401		cell_t		name;
402		cell_t		nargs;
403		cell_t		nreturns;
404		cell_t		device;
405		cell_t		package;
406	} args = {
407		(cell_t)"finddevice",
408		1,
409		1,
410		0,
411		0
412	};
413
414	args.device = (cell_t)device;
415	if (openfirmware(&args) == -1)
416		return -1;
417
418	return (phandle_t)args.package;
419}
420
421/* Return the fully qualified pathname corresponding to an instance. */
422int
423OF_instance_to_path(ihandle_t instance, char *buf, int len)
424{
425	static struct {
426		cell_t		name;
427		cell_t		nargs;
428		cell_t		nreturns;
429		cell_t		instance;
430		cell_t		buf;
431		cell_t		len;
432		cell_t		size;
433	} args = {
434		(cell_t)"instance-to-path",
435		3,
436		1,
437		0,
438		0,
439		0,
440		0
441	};
442
443	args.instance = (u_int)instance;
444	args.buf = (cell_t)buf;
445	args.len = (u_int)len;
446	if (openfirmware(&args) == -1)
447		return -1;
448	return (int)args.size;
449}
450
451/* Return the fully qualified pathname corresponding to a package. */
452int
453OF_package_to_path(phandle_t package, char *buf, int len)
454{
455	static struct {
456		cell_t		name;
457		cell_t		nargs;
458		cell_t		nreturns;
459		cell_t		package;
460		cell_t		buf;
461		cell_t		len;
462		cell_t		size;
463	} args = {
464		(cell_t)"package-to-path",
465		3,
466		1,
467		0,
468		0,
469		0,
470		0
471	};
472
473	args.package = (u_int)package;
474	args.buf = (cell_t)buf;
475	args.len = (u_int)len;
476	if (openfirmware(&args) == -1)
477		return -1;
478	return (int)args.size;
479}
480
481/*  Call the method in the scope of a given instance. */
482int
483OF_call_method(char *method, ihandle_t instance, int nargs, int nreturns, ...)
484{
485	va_list ap;
486	static struct {
487		cell_t		name;
488		cell_t		nargs;
489		cell_t		nreturns;
490		cell_t		method;
491		cell_t		instance;
492		cell_t		args_n_results[12];
493	} args = {
494		(cell_t)"call-method",
495		2,
496		1,
497		0,
498		0,
499		{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
500	};
501	int *ip, n;
502
503	if (nargs > 6)
504		return -1;
505	args.nargs = nargs + 2;
506	args.nreturns = nreturns + 1;
507	args.method = (cell_t)method;
508	args.instance = (u_int)instance;
509	va_start(ap, nreturns);
510	for (ip = (int *)(args.args_n_results + (n = nargs)); --n >= 0;)
511		*--ip = va_arg(ap, int);
512
513	if (openfirmware(&args) == -1)
514		return -1;
515	if (args.args_n_results[nargs])
516		return (int)args.args_n_results[nargs];
517	for (ip = (int *)(args.args_n_results + nargs + (n = args.nreturns));
518	    --n > 0;)
519		*va_arg(ap, int *) = *--ip;
520	va_end(ap);
521	return 0;
522}
523
524/*
525 * Device I/O functions.
526 */
527
528/* Open an instance for a device. */
529ihandle_t
530OF_open(char *device)
531{
532	static struct {
533		cell_t		name;
534		cell_t		nargs;
535		cell_t		nreturns;
536		cell_t		device;
537		cell_t		instance;
538	} args = {
539		(cell_t)"open",
540		1,
541		1,
542		0,
543		0
544	};
545
546	args.device = (cell_t)device;
547	if (openfirmware(&args) == -1 || args.instance == 0) {
548		return -1;
549	}
550	return (ihandle_t)args.instance;
551}
552
553/* Close an instance. */
554void
555OF_close(ihandle_t instance)
556{
557	static struct {
558		cell_t		name;
559		cell_t		nargs;
560		cell_t		nreturns;
561		cell_t		instance;
562	} args = {
563		(cell_t)"close",
564		1,
565		0,
566		0
567	};
568
569	args.instance = (u_int)instance;
570	openfirmware(&args);
571}
572
573/* Read from an instance. */
574int
575OF_read(ihandle_t instance, void *addr, int len)
576{
577	static struct {
578		cell_t		name;
579		cell_t		nargs;
580		cell_t		nreturns;
581		cell_t		instance;
582		cell_t		addr;
583		cell_t		len;
584		cell_t		actual;
585	} args = {
586		(cell_t)"read",
587		3,
588		1,
589		0,
590		0,
591		0,
592		0
593	};
594
595	args.instance = (u_int)instance;
596	args.addr = (cell_t)addr;
597	args.len = (u_int)len;
598
599#if defined(OPENFIRM_DEBUG)
600	printf("OF_read: called with instance=%08x, addr=%p, len=%d\n",
601	    args.instance, args.addr, args.len);
602#endif
603
604	if (openfirmware(&args) == -1)
605		return -1;
606
607#if defined(OPENFIRM_DEBUG)
608	printf("OF_read: returning instance=%d, addr=%p, len=%d, actual=%d\n",
609	    args.instance, args.addr, args.len, args.actual);
610#endif
611
612	return (int)args.actual;
613}
614
615/* Write to an instance. */
616int
617OF_write(ihandle_t instance, void *addr, int len)
618{
619	static struct {
620		cell_t		name;
621		cell_t		nargs;
622		cell_t		nreturns;
623		cell_t		instance;
624		cell_t		addr;
625		cell_t		len;
626		cell_t		actual;
627	} args = {
628		(cell_t)"write",
629		3,
630		1,
631		0,
632		0,
633		0,
634		0
635	};
636
637	args.instance = (u_int)instance;
638	args.addr = (cell_t)addr;
639	args.len = (u_int)len;
640	if (openfirmware(&args) == -1)
641		return -1;
642	return (int)args.actual;
643}
644
645/* Seek to a position. */
646int
647OF_seek(ihandle_t instance, u_int64_t pos)
648{
649	static struct {
650		cell_t		name;
651		cell_t		nargs;
652		cell_t		nreturns;
653		cell_t		instance;
654		cell_t		poshi;
655		cell_t		poslo;
656		cell_t		status;
657	} args = {
658		(cell_t)"seek",
659		3,
660		1,
661		0,
662		0,
663		0,
664		0
665	};
666
667	args.instance = (u_int)instance;
668	args.poshi = pos >> 32;
669	args.poslo = pos;
670	if (openfirmware(&args) == -1)
671		return -1;
672	return (int)args.status;
673}
674
675/*
676 * Memory functions.
677 */
678
679/* Claim an area of memory. */
680void *
681OF_claim(void *virt, u_int size, u_int align)
682{
683	static struct {
684		cell_t	name;
685		cell_t	nargs;
686		cell_t	nreturns;
687		cell_t	virt;
688		cell_t	size;
689		cell_t	align;
690		cell_t	baseaddr;
691	} args = {
692		(cell_t)"claim",
693		3,
694		1,
695		0,
696		0,
697		0,
698		0
699	};
700
701	args.virt = (cell_t)virt;
702	args.size = size;
703	args.align = align;
704	if (openfirmware(&args) == -1)
705		return (void *)-1;
706	return (void *)args.baseaddr;
707}
708
709/* Allocate an area of physical memory */
710vm_offset_t
711OF_claim_virt(vm_offset_t virt, size_t size, int align)
712{
713	static struct {
714		cell_t	name;
715		cell_t	nargs;
716		cell_t	nret;
717		cell_t	method;
718		cell_t	ihandle;
719		cell_t	align;
720		cell_t	size;
721		cell_t	virt;
722		cell_t	status;
723		cell_t	ret;
724	} args = {
725		(cell_t)"call-method",
726		5,
727		2,
728		(cell_t)"claim",
729		0,
730		0,
731		0,
732		0,
733		0,	/* ret */
734		0,
735	};
736
737	args.ihandle = mmu;
738	args.align = align;
739	args.size = size;
740	args.virt = virt;
741
742	if (openfirmware(&args) == -1)
743		return (vm_offset_t)-1;
744
745	return (vm_offset_t)args.ret;
746}
747
748/* Allocate an area of physical memory */
749void *
750OF_alloc_phys(size_t size, int align)
751{
752	static struct {
753		cell_t	name;
754		cell_t	nargs;
755		cell_t	nret;
756		cell_t	method;
757		cell_t	ihandle;
758		cell_t	align;
759		cell_t	size;
760		cell_t	status;
761		cell_t	phys_hi;
762		cell_t	phys_low;
763	} args = {
764		(cell_t)"call-method",
765		4,
766		3,
767		(cell_t)"claim",
768		0,
769		0,
770		0,
771		0,	/* ret */
772		0,
773		0,
774	};
775
776	args.ihandle = memory;
777	args.size = size;
778	args.align = align;
779
780	if (openfirmware(&args) == -1)
781		return (void *)-1;
782
783	return (void *)(args.phys_hi << 32 | args.phys_low);
784}
785
786/* Release an area of memory. */
787void
788OF_release(void *virt, u_int size)
789{
790	static struct {
791		cell_t	name;
792		cell_t	nargs;
793		cell_t	nreturns;
794		cell_t	virt;
795		cell_t	size;
796	} args = {
797		(cell_t)"release",
798		2,
799		0,
800		0,
801		0
802	};
803
804	args.virt = (cell_t)virt;
805	args.size = size;
806	openfirmware(&args);
807}
808
809/* Release an area of physical memory. */
810void
811OF_release_phys(vm_offset_t phys, u_int size)
812{
813	static struct {
814		cell_t	name;
815		cell_t	nargs;
816		cell_t	nret;
817		cell_t	method;
818		cell_t	ihandle;
819		cell_t	size;
820		cell_t	phys_hi;
821		cell_t	phys_lo;
822	} args = {
823		(cell_t)"call-method",
824		5,
825		0,
826		(cell_t)"release",
827		0,
828		0,
829		0,
830		0
831	};
832
833	args.ihandle = memory;
834	args.phys_hi = (u_int32_t)(phys >> 32);
835	args.phys_lo = (u_int32_t)phys;
836	args.size = size;
837	openfirmware(&args);
838}
839
840/*
841 * Control transfer functions.
842 */
843
844/* Reset the system and call "boot <bootspec>". */
845void
846OF_boot(char *bootspec)
847{
848	static struct {
849		cell_t	name;
850		cell_t	nargs;
851		cell_t	nreturns;
852		cell_t	bootspec;
853	} args = {
854		(cell_t)"boot",
855		1,
856		0,
857		0
858	};
859
860	args.bootspec = (cell_t)bootspec;
861	openfirmware(&args);
862	for (;;);			/* just in case */
863}
864
865/* Suspend and drop back to the Open Firmware interface. */
866void
867OF_enter()
868{
869	static struct {
870		cell_t	name;
871		cell_t	nargs;
872		cell_t	nreturns;
873	} args = {
874		(cell_t)"enter",
875		0,
876		0
877	};
878
879	openfirmware(&args);
880}
881
882/* Shut down and drop back to the Open Firmware interface. */
883void
884OF_exit()
885{
886	static struct {
887		cell_t	name;
888		cell_t	nargs;
889		cell_t	nreturns;
890	} args = {
891		(cell_t)"exit",
892		0,
893		0
894	};
895
896	openfirmware(&args);
897	for (;;);			/* just in case */
898}
899
900/* Free <size> bytes starting at <virt>, then call <entry> with <arg>. */
901#if 0
902void
903OF_chain(void *virt, u_int size, void (*entry)(), void *arg, u_int len)
904{
905	static struct {
906		cell_t	name;
907		cell_t	nargs;
908		cell_t	nreturns;
909		cell_t	virt;
910		cell_t	size;
911		cell_t	entry;
912		cell_t	arg;
913		cell_t	len;
914	} args = {
915		(cell_t)"chain",
916		5,
917		0,
918		0,
919		0,
920		0,
921		0,
922		0
923	};
924
925	args.virt = (cell_t)virt;
926	args.size = size;
927	args.entry = (cell_t)entry;
928	args.arg = (cell_t)arg;
929	args.len = len;
930	openfirmware(&args);
931}
932#else
933void
934OF_chain(void *virt, u_int size, void (*entry)(), void *arg, u_int len)
935{
936	/*
937	 * This is a REALLY dirty hack till the firmware gets this going
938	 */
939#if 0
940	if (size > 0)
941		OF_release(virt, size);
942#endif
943
944	entry(0, 0, openfirmware, arg, len);
945}
946#endif
947