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