1 /* $NetBSD: Locore.c,v 1.7 2000/08/20 07:04:59 tsubai Exp $ */
4 * Copyright (C) 1995, 1996 Wolfgang Solfrank.
5 * Copyright (C) 1995, 1996 TooLs GmbH.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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.
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.
34 * Copyright (C) 2000 Benno Rice.
35 * All rights reserved.
37 * Redistribution and use in source and binary forms, with or without
38 * modification, are permitted provided that the following conditions
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.
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.
58 #include <sys/cdefs.h>
59 __FBSDID("$FreeBSD$");
61 #include <sys/param.h>
62 #include <sys/kernel.h>
64 #include <sys/mutex.h>
65 #include <sys/systm.h>
70 #include <machine/stdarg.h>
71 #include <machine/bus.h>
72 #include <machine/pmap.h>
73 #include <machine/ofw_machdep.h>
75 #include <dev/ofw/openfirm.h>
76 #include <dev/ofw/ofwvar.h>
79 static void ofw_real_init(ofw_t, void *openfirm);
80 static int ofw_real_test(ofw_t, const char *name);
81 static phandle_t ofw_real_peer(ofw_t, phandle_t node);
82 static phandle_t ofw_real_child(ofw_t, phandle_t node);
83 static phandle_t ofw_real_parent(ofw_t, phandle_t node);
84 static phandle_t ofw_real_instance_to_package(ofw_t, ihandle_t instance);
85 static ssize_t ofw_real_getproplen(ofw_t, phandle_t package,
86 const char *propname);
87 static ssize_t ofw_real_getprop(ofw_t, phandle_t package, const char *propname,
88 void *buf, size_t buflen);
89 static int ofw_real_nextprop(ofw_t, phandle_t package, const char *previous,
91 static int ofw_real_setprop(ofw_t, phandle_t package, const char *propname,
92 const void *buf, size_t len);
93 static ssize_t ofw_real_canon(ofw_t, const char *device, char *buf, size_t len);
94 static phandle_t ofw_real_finddevice(ofw_t, const char *device);
95 static ssize_t ofw_real_instance_to_path(ofw_t, ihandle_t instance, char *buf,
97 static ssize_t ofw_real_package_to_path(ofw_t, phandle_t package, char *buf,
99 static int ofw_real_call_method(ofw_t, ihandle_t instance, const char *method,
100 int nargs, int nreturns, unsigned long *args_and_returns);
101 static ihandle_t ofw_real_open(ofw_t, const char *device);
102 static void ofw_real_close(ofw_t, ihandle_t instance);
103 static ssize_t ofw_real_read(ofw_t, ihandle_t instance, void *addr, size_t len);
104 static ssize_t ofw_real_write(ofw_t, ihandle_t instance, const void *addr,
106 static int ofw_real_seek(ofw_t, ihandle_t instance, u_int64_t pos);
107 static caddr_t ofw_real_claim(ofw_t, void *virt, size_t size, u_int align);
108 static void ofw_real_release(ofw_t, void *virt, size_t size);
109 static void ofw_real_enter(ofw_t);
110 static void ofw_real_exit(ofw_t);
112 static ofw_method_t ofw_real_methods[] = {
113 OFWMETHOD(ofw_init, ofw_real_init),
114 OFWMETHOD(ofw_peer, ofw_real_peer),
115 OFWMETHOD(ofw_child, ofw_real_child),
116 OFWMETHOD(ofw_parent, ofw_real_parent),
117 OFWMETHOD(ofw_instance_to_package, ofw_real_instance_to_package),
118 OFWMETHOD(ofw_getproplen, ofw_real_getproplen),
119 OFWMETHOD(ofw_getprop, ofw_real_getprop),
120 OFWMETHOD(ofw_nextprop, ofw_real_nextprop),
121 OFWMETHOD(ofw_setprop, ofw_real_setprop),
122 OFWMETHOD(ofw_canon, ofw_real_canon),
123 OFWMETHOD(ofw_finddevice, ofw_real_finddevice),
124 OFWMETHOD(ofw_instance_to_path, ofw_real_instance_to_path),
125 OFWMETHOD(ofw_package_to_path, ofw_real_package_to_path),
127 OFWMETHOD(ofw_test, ofw_real_test),
128 OFWMETHOD(ofw_call_method, ofw_real_call_method),
129 OFWMETHOD(ofw_open, ofw_real_open),
130 OFWMETHOD(ofw_close, ofw_real_close),
131 OFWMETHOD(ofw_read, ofw_real_read),
132 OFWMETHOD(ofw_write, ofw_real_write),
133 OFWMETHOD(ofw_seek, ofw_real_seek),
134 OFWMETHOD(ofw_claim, ofw_real_claim),
135 OFWMETHOD(ofw_release, ofw_real_release),
136 OFWMETHOD(ofw_enter, ofw_real_enter),
137 OFWMETHOD(ofw_exit, ofw_real_exit),
142 static ofw_def_t ofw_real = {
149 MALLOC_DEFINE(M_OFWREAL, "ofwreal", "Open Firmware Real Mode Bounce Page");
151 static int (*openfirmware)(void *);
153 static vm_offset_t of_bounce_phys;
154 static caddr_t of_bounce_virt;
155 static off_t of_bounce_offset;
156 static size_t of_bounce_size;
157 static struct mtx of_bounce_mtx;
160 * After the VM is up, allocate a wired, low memory bounce page.
163 static void ofw_real_bounce_alloc(void *);
165 SYSINIT(ofw_real_bounce_alloc, SI_SUB_VM, SI_ORDER_ANY,
166 ofw_real_bounce_alloc, NULL);
171 mtx_lock(&of_bounce_mtx);
172 of_bounce_offset = 0;
178 mtx_unlock(&of_bounce_mtx);
182 ofw_real_bounce_alloc(void *junk)
185 * Check that ofw_real is actually in use before allocating wads
186 * of memory. Do this by checking if our mutex has been set up.
188 if (!mtx_initialized(&of_bounce_mtx))
192 * Allocate a page of contiguous, wired physical memory that can
193 * fit into a 32-bit address space.
196 mtx_lock(&of_bounce_mtx);
198 of_bounce_virt = contigmalloc(PAGE_SIZE, M_OFWREAL, 0,
199 0, BUS_SPACE_MAXADDR_32BIT, PAGE_SIZE, PAGE_SIZE);
200 of_bounce_phys = vtophys(of_bounce_virt);
201 of_bounce_size = PAGE_SIZE;
203 mtx_unlock(&of_bounce_mtx);
207 ofw_real_map(const void *buf, size_t len)
211 mtx_assert(&of_bounce_mtx, MA_OWNED);
213 if (of_bounce_virt == NULL) {
214 if (!pmap_bootstrapped)
218 * XXX: It is possible for us to get called before the VM has
219 * come online, but after the MMU is up. We don't have the
220 * bounce buffer yet, but can no longer presume a 1:1 mapping.
221 * Grab the physical address of the buffer, and hope it is
222 * in range if this happens.
224 return (cell_t)vtophys(buf);
228 * Make sure the bounce page offset satisfies any reasonable
229 * alignment constraint.
231 of_bounce_offset += of_bounce_offset % sizeof(register_t);
233 if (of_bounce_offset + len > of_bounce_size) {
234 panic("Oversize Open Firmware call!");
238 memcpy(of_bounce_virt + of_bounce_offset, buf, len);
239 phys = of_bounce_phys + of_bounce_offset;
241 of_bounce_offset += len;
247 ofw_real_unmap(cell_t physaddr, void *buf, size_t len)
249 mtx_assert(&of_bounce_mtx, MA_OWNED);
251 if (of_bounce_virt == NULL)
254 memcpy(buf,of_bounce_virt + (physaddr - of_bounce_phys),len);
260 ofw_real_init(ofw_t ofw, void *openfirm)
262 openfirmware = (int (*)(void *))openfirm;
264 mtx_init(&of_bounce_mtx, "OF Bounce Page", MTX_DEF, 0);
265 of_bounce_virt = NULL;
272 /* Test to see if a service exists. */
274 ofw_real_test(ofw_t ofw, const char *name)
290 args.service = ofw_real_map(name, strlen(name) + 1);
291 if (args.service == 0 || openfirmware(&args) == -1) {
296 return (args.missing);
300 * Device tree functions
303 /* Return the next sibling of this node or 0. */
305 ofw_real_peer(ofw_t ofw, phandle_t node)
320 if (openfirmware(&args) == -1)
325 /* Return the first child of this node or 0. */
327 ofw_real_child(ofw_t ofw, phandle_t node)
342 if (openfirmware(&args) == -1)
347 /* Return the parent of this node or 0. */
349 ofw_real_parent(ofw_t ofw, phandle_t node)
364 if (openfirmware(&args) == -1)
366 return (args.parent);
369 /* Return the package handle that corresponds to an instance handle. */
371 ofw_real_instance_to_package(ofw_t ofw, ihandle_t instance)
380 (cell_t)"instance-to-package",
385 args.instance = instance;
386 if (openfirmware(&args) == -1)
388 return (args.package);
391 /* Get the length of a property of a package. */
393 ofw_real_getproplen(ofw_t ofw, phandle_t package, const char *propname)
403 (cell_t)"getproplen",
410 args.package = package;
411 args.propname = ofw_real_map(propname, strlen(propname) + 1);
412 if (args.propname == 0 || openfirmware(&args) == -1) {
417 return (args.proplen);
420 /* Get the value of a property of a package. */
422 ofw_real_getprop(ofw_t ofw, phandle_t package, const char *propname, void *buf,
442 args.package = package;
443 args.propname = ofw_real_map(propname, strlen(propname) + 1);
444 args.buf = ofw_real_map(buf, buflen);
445 args.buflen = buflen;
446 if (args.propname == 0 || args.buf == 0 || openfirmware(&args) == -1) {
450 ofw_real_unmap(args.buf, buf, buflen);
456 /* Get the next property of a package. */
458 ofw_real_nextprop(ofw_t ofw, phandle_t package, const char *previous,
459 char *buf, size_t size)
477 args.package = package;
478 args.previous = ofw_real_map(previous, strlen(previous) + 1);
479 args.buf = ofw_real_map(buf, size);
480 if (args.previous == 0 || args.buf == 0 || openfirmware(&args) == -1) {
484 ofw_real_unmap(args.buf, buf, size);
490 /* Set the value of a property of a package. */
491 /* XXX Has a bug on FirePower */
493 ofw_real_setprop(ofw_t ofw, phandle_t package, const char *propname,
494 const void *buf, size_t len)
513 args.package = package;
514 args.propname = ofw_real_map(propname, strlen(propname) + 1);
515 args.buf = ofw_real_map(buf, len);
517 if (args.propname == 0 || args.buf == 0 || openfirmware(&args) == -1) {
525 /* Convert a device specifier to a fully qualified pathname. */
527 ofw_real_canon(ofw_t ofw, const char *device, char *buf, size_t len)
545 args.device = ofw_real_map(device, strlen(device) + 1);
546 args.buf = ofw_real_map(buf, len);
548 if (args.device == 0 || args.buf == 0 || openfirmware(&args) == -1) {
552 ofw_real_unmap(args.buf, buf, len);
558 /* Return a package handle for the specified device. */
560 ofw_real_finddevice(ofw_t ofw, const char *device)
569 (cell_t)"finddevice",
576 args.device = ofw_real_map(device, strlen(device) + 1);
577 if (args.device == 0 || openfirmware(&args) == -1) {
582 return (args.package);
585 /* Return the fully qualified pathname corresponding to an instance. */
587 ofw_real_instance_to_path(ofw_t ofw, ihandle_t instance, char *buf, size_t len)
598 (cell_t)"instance-to-path",
605 args.instance = instance;
606 args.buf = ofw_real_map(buf, len);
608 if (args.buf == 0 || openfirmware(&args) == -1) {
612 ofw_real_unmap(args.buf, buf, len);
618 /* Return the fully qualified pathname corresponding to a package. */
620 ofw_real_package_to_path(ofw_t ofw, phandle_t package, char *buf, size_t len)
631 (cell_t)"package-to-path",
638 args.package = package;
639 args.buf = ofw_real_map(buf, len);
641 if (args.buf == 0 || openfirmware(&args) == -1) {
645 ofw_real_unmap(args.buf, buf, len);
651 /* Call the method in the scope of a given instance. */
653 ofw_real_call_method(ofw_t ofw, ihandle_t instance, const char *method,
654 int nargs, int nreturns, unsigned long *args_and_returns)
662 cell_t args_n_results[12];
664 (cell_t)"call-method",
676 args.nargs = nargs + 2;
677 args.nreturns = nreturns + 1;
678 args.method = ofw_real_map(method, strlen(method) + 1);
679 args.instance = instance;
681 ap = args_and_returns;
682 for (cp = args.args_n_results + (n = nargs); --n >= 0;)
684 if (args.method == 0 || openfirmware(&args) == -1) {
689 if (args.args_n_results[nargs])
690 return (args.args_n_results[nargs]);
691 for (cp = args.args_n_results + nargs + (n = args.nreturns); --n > 0;)
697 * Device I/O functions
700 /* Open an instance for a device. */
702 ofw_real_open(ofw_t ofw, const char *device)
718 args.device = ofw_real_map(device, strlen(device) + 1);
719 if (args.device == 0 || openfirmware(&args) == -1
720 || args.instance == 0) {
725 return (args.instance);
728 /* Close an instance. */
730 ofw_real_close(ofw_t ofw, ihandle_t instance)
742 args.instance = instance;
746 /* Read from an instance. */
748 ofw_real_read(ofw_t ofw, ihandle_t instance, void *addr, size_t len)
766 args.instance = instance;
767 args.addr = ofw_real_map(addr, len);
769 if (args.addr == 0 || openfirmware(&args) == -1) {
773 ofw_real_unmap(args.addr, addr, len);
776 return (args.actual);
779 /* Write to an instance. */
781 ofw_real_write(ofw_t ofw, ihandle_t instance, const void *addr, size_t len)
799 args.instance = instance;
800 args.addr = ofw_real_map(addr, len);
802 if (args.addr == 0 || openfirmware(&args) == -1) {
807 return (args.actual);
810 /* Seek to a position. */
812 ofw_real_seek(ofw_t ofw, ihandle_t instance, u_int64_t pos)
828 args.instance = instance;
829 args.poshi = pos >> 32;
831 if (openfirmware(&args) == -1)
833 return (args.status);
840 /* Claim an area of memory. */
842 ofw_real_claim(ofw_t ofw, void *virt, size_t size, u_int align)
858 args.virt = (cell_t)virt;
861 if (openfirmware(&args) == -1)
863 return ((void *)args.baseaddr);
866 /* Release an area of memory. */
868 ofw_real_release(ofw_t ofw, void *virt, size_t size)
881 args.virt = (cell_t)virt;
887 * Control transfer functions
890 /* Suspend and drop back to the Open Firmware interface. */
892 ofw_real_enter(ofw_t ofw)
903 /* We may come back. */
906 /* Shut down and drop back to the Open Firmware interface. */
908 ofw_real_exit(ofw_t ofw)
919 for (;;) /* just in case */