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