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