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