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