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>
68 #include <vm/vm_page.h>
71 #include <machine/bus.h>
72 #include <machine/md_var.h>
73 #include <machine/ofw_machdep.h>
74 #include <machine/pmap.h>
75 #include <machine/stdarg.h>
77 #include <dev/ofw/openfirm.h>
78 #include <dev/ofw/ofwvar.h>
81 static int ofw_real_init(ofw_t, void *openfirm);
82 static int ofw_real_test(ofw_t, const char *name);
83 static phandle_t ofw_real_peer(ofw_t, phandle_t node);
84 static phandle_t ofw_real_child(ofw_t, phandle_t node);
85 static phandle_t ofw_real_parent(ofw_t, phandle_t node);
86 static phandle_t ofw_real_instance_to_package(ofw_t, ihandle_t instance);
87 static ssize_t ofw_real_getproplen(ofw_t, phandle_t package,
88 const char *propname);
89 static ssize_t ofw_real_getprop(ofw_t, phandle_t package, const char *propname,
90 void *buf, size_t buflen);
91 static int ofw_real_nextprop(ofw_t, phandle_t package, const char *previous,
93 static int ofw_real_setprop(ofw_t, phandle_t package, const char *propname,
94 const void *buf, size_t len);
95 static ssize_t ofw_real_canon(ofw_t, const char *device, char *buf, size_t len);
96 static phandle_t ofw_real_finddevice(ofw_t, const char *device);
97 static ssize_t ofw_real_instance_to_path(ofw_t, ihandle_t instance, char *buf,
99 static ssize_t ofw_real_package_to_path(ofw_t, phandle_t package, char *buf,
101 static int ofw_real_call_method(ofw_t, ihandle_t instance, const char *method,
102 int nargs, int nreturns, cell_t *args_and_returns);
103 static int ofw_real_interpret(ofw_t ofw, const char *cmd, int nreturns,
105 static ihandle_t ofw_real_open(ofw_t, const char *device);
106 static void ofw_real_close(ofw_t, ihandle_t instance);
107 static ssize_t ofw_real_read(ofw_t, ihandle_t instance, void *addr, size_t len);
108 static ssize_t ofw_real_write(ofw_t, ihandle_t instance, const void *addr,
110 static int ofw_real_seek(ofw_t, ihandle_t instance, u_int64_t pos);
111 static caddr_t ofw_real_claim(ofw_t, void *virt, size_t size, u_int align);
112 static void ofw_real_release(ofw_t, void *virt, size_t size);
113 static void ofw_real_enter(ofw_t);
114 static void ofw_real_exit(ofw_t);
116 static ofw_method_t ofw_real_methods[] = {
117 OFWMETHOD(ofw_init, ofw_real_init),
118 OFWMETHOD(ofw_peer, ofw_real_peer),
119 OFWMETHOD(ofw_child, ofw_real_child),
120 OFWMETHOD(ofw_parent, ofw_real_parent),
121 OFWMETHOD(ofw_instance_to_package, ofw_real_instance_to_package),
122 OFWMETHOD(ofw_getproplen, ofw_real_getproplen),
123 OFWMETHOD(ofw_getprop, ofw_real_getprop),
124 OFWMETHOD(ofw_nextprop, ofw_real_nextprop),
125 OFWMETHOD(ofw_setprop, ofw_real_setprop),
126 OFWMETHOD(ofw_canon, ofw_real_canon),
127 OFWMETHOD(ofw_finddevice, ofw_real_finddevice),
128 OFWMETHOD(ofw_instance_to_path, ofw_real_instance_to_path),
129 OFWMETHOD(ofw_package_to_path, ofw_real_package_to_path),
131 OFWMETHOD(ofw_test, ofw_real_test),
132 OFWMETHOD(ofw_call_method, ofw_real_call_method),
133 OFWMETHOD(ofw_interpret, ofw_real_interpret),
134 OFWMETHOD(ofw_open, ofw_real_open),
135 OFWMETHOD(ofw_close, ofw_real_close),
136 OFWMETHOD(ofw_read, ofw_real_read),
137 OFWMETHOD(ofw_write, ofw_real_write),
138 OFWMETHOD(ofw_seek, ofw_real_seek),
139 OFWMETHOD(ofw_claim, ofw_real_claim),
140 OFWMETHOD(ofw_release, ofw_real_release),
141 OFWMETHOD(ofw_enter, ofw_real_enter),
142 OFWMETHOD(ofw_exit, ofw_real_exit),
147 static ofw_def_t ofw_real = {
154 static ofw_def_t ofw_32bit = {
161 static MALLOC_DEFINE(M_OFWREAL, "ofwreal",
162 "Open Firmware Real Mode Bounce Page");
164 static int (*openfirmware)(void *);
166 static vm_offset_t of_bounce_phys;
167 static caddr_t of_bounce_virt;
168 static off_t of_bounce_offset;
169 static size_t of_bounce_size;
170 static struct mtx of_bounce_mtx;
172 extern int ofw_real_mode;
175 * After the VM is up, allocate a wired, low memory bounce page.
178 static void ofw_real_bounce_alloc(void *);
180 SYSINIT(ofw_real_bounce_alloc, SI_SUB_KMEM, SI_ORDER_ANY,
181 ofw_real_bounce_alloc, NULL);
186 mtx_lock(&of_bounce_mtx);
187 of_bounce_offset = 0;
193 mtx_unlock(&of_bounce_mtx);
197 ofw_real_bounce_alloc(void *junk)
200 * Check that ofw_real is actually in use before allocating wads
201 * of memory. Do this by checking if our mutex has been set up.
203 if (!mtx_initialized(&of_bounce_mtx))
207 * Allocate a page of contiguous, wired physical memory that can
208 * fit into a 32-bit address space and accessed from real mode.
211 mtx_lock(&of_bounce_mtx);
213 of_bounce_virt = contigmalloc(4 * PAGE_SIZE, M_OFWREAL, 0, 0,
214 ulmin(platform_real_maxaddr(), BUS_SPACE_MAXADDR_32BIT), PAGE_SIZE,
217 of_bounce_phys = vtophys(of_bounce_virt);
218 of_bounce_size = 4 * PAGE_SIZE;
221 * For virtual-mode OF, direct map this physical address so that
222 * we have a 32-bit virtual address to give OF.
225 if (!ofw_real_mode && !hw_direct_map)
226 pmap_kenter(of_bounce_phys, of_bounce_phys);
228 mtx_unlock(&of_bounce_mtx);
232 ofw_real_map(const void *buf, size_t len)
234 static char emergency_buffer[255];
237 mtx_assert(&of_bounce_mtx, MA_OWNED);
239 if (of_bounce_virt == NULL) {
241 * If we haven't set up the MMU, then buf is guaranteed
242 * to be accessible to OF, because the only memory we
243 * can use right now is memory mapped by firmware.
245 if (!pmap_bootstrapped)
246 return (cell_t)(uintptr_t)buf;
249 * XXX: It is possible for us to get called before the VM has
250 * come online, but after the MMU is up. We don't have the
251 * bounce buffer yet, but can no longer presume a 1:1 mapping.
252 * Copy into the emergency buffer, and reset at the end.
254 of_bounce_virt = emergency_buffer;
255 of_bounce_phys = (vm_offset_t)of_bounce_virt;
256 of_bounce_size = sizeof(emergency_buffer);
260 * Make sure the bounce page offset satisfies any reasonable
261 * alignment constraint.
263 of_bounce_offset += sizeof(register_t) - (of_bounce_offset % sizeof(register_t));
265 if (of_bounce_offset + len > of_bounce_size) {
266 panic("Oversize Open Firmware call!");
271 memcpy(of_bounce_virt + of_bounce_offset, buf, len);
275 phys = of_bounce_phys + of_bounce_offset;
277 of_bounce_offset += len;
283 ofw_real_unmap(cell_t physaddr, void *buf, size_t len)
285 mtx_assert(&of_bounce_mtx, MA_OWNED);
287 if (of_bounce_virt == NULL)
293 memcpy(buf,of_bounce_virt + (physaddr - of_bounce_phys),len);
299 ofw_real_init(ofw_t ofw, void *openfirm)
301 openfirmware = (int (*)(void *))openfirm;
303 mtx_init(&of_bounce_mtx, "OF Bounce Page", NULL, MTX_DEF);
304 of_bounce_virt = NULL;
312 /* Test to see if a service exists. */
314 ofw_real_test(ofw_t ofw, const char *name)
325 args.name = (cell_t)(uintptr_t)"test";
331 args.service = ofw_real_map(name, strlen(name) + 1);
332 argsptr = ofw_real_map(&args, sizeof(args));
333 if (args.service == 0 || openfirmware((void *)argsptr) == -1) {
337 ofw_real_unmap(argsptr, &args, sizeof(args));
339 return (args.missing);
343 * Device tree functions
346 /* Return the next sibling of this node or 0. */
348 ofw_real_peer(ofw_t ofw, phandle_t node)
359 args.name = (cell_t)(uintptr_t)"peer";
365 argsptr = ofw_real_map(&args, sizeof(args));
366 if (openfirmware((void *)argsptr) == -1) {
370 ofw_real_unmap(argsptr, &args, sizeof(args));
375 /* Return the first child of this node or 0. */
377 ofw_real_child(ofw_t ofw, phandle_t node)
388 args.name = (cell_t)(uintptr_t)"child";
394 argsptr = ofw_real_map(&args, sizeof(args));
395 if (openfirmware((void *)argsptr) == -1) {
399 ofw_real_unmap(argsptr, &args, sizeof(args));
404 /* Return the parent of this node or 0. */
406 ofw_real_parent(ofw_t ofw, phandle_t node)
417 args.name = (cell_t)(uintptr_t)"parent";
423 argsptr = ofw_real_map(&args, sizeof(args));
424 if (openfirmware((void *)argsptr) == -1) {
428 ofw_real_unmap(argsptr, &args, sizeof(args));
430 return (args.parent);
433 /* Return the package handle that corresponds to an instance handle. */
435 ofw_real_instance_to_package(ofw_t ofw, ihandle_t instance)
446 args.name = (cell_t)(uintptr_t)"instance-to-package";
450 args.instance = instance;
452 argsptr = ofw_real_map(&args, sizeof(args));
453 if (openfirmware((void *)argsptr) == -1) {
457 ofw_real_unmap(argsptr, &args, sizeof(args));
459 return (args.package);
462 /* Get the length of a property of a package. */
464 ofw_real_getproplen(ofw_t ofw, phandle_t package, const char *propname)
476 args.name = (cell_t)(uintptr_t)"getproplen";
482 args.package = package;
483 args.propname = ofw_real_map(propname, strlen(propname) + 1);
484 argsptr = ofw_real_map(&args, sizeof(args));
485 if (args.propname == 0 || openfirmware((void *)argsptr) == -1) {
489 ofw_real_unmap(argsptr, &args, sizeof(args));
491 return (args.proplen);
494 /* Get the value of a property of a package. */
496 ofw_real_getprop(ofw_t ofw, phandle_t package, const char *propname, void *buf,
511 args.name = (cell_t)(uintptr_t)"getprop";
517 args.package = package;
518 args.propname = ofw_real_map(propname, strlen(propname) + 1);
519 args.buf = ofw_real_map(buf, buflen);
520 args.buflen = buflen;
521 argsptr = ofw_real_map(&args, sizeof(args));
522 if (args.propname == 0 || args.buf == 0 ||
523 openfirmware((void *)argsptr) == -1) {
527 ofw_real_unmap(argsptr, &args, sizeof(args));
528 ofw_real_unmap(args.buf, buf, buflen);
534 /* Get the next property of a package. */
536 ofw_real_nextprop(ofw_t ofw, phandle_t package, const char *previous,
537 char *buf, size_t size)
550 args.name = (cell_t)(uintptr_t)"nextprop";
556 args.package = package;
557 args.previous = ofw_real_map(previous, (previous != NULL) ? (strlen(previous) + 1) : 0);
558 args.buf = ofw_real_map(buf, size);
559 argsptr = ofw_real_map(&args, sizeof(args));
560 if (args.buf == 0 || openfirmware((void *)argsptr) == -1) {
564 ofw_real_unmap(argsptr, &args, sizeof(args));
565 ofw_real_unmap(args.buf, buf, size);
571 /* Set the value of a property of a package. */
572 /* XXX Has a bug on FirePower */
574 ofw_real_setprop(ofw_t ofw, phandle_t package, const char *propname,
575 const void *buf, size_t len)
589 args.name = (cell_t)(uintptr_t)"setprop";
595 args.package = package;
596 args.propname = ofw_real_map(propname, strlen(propname) + 1);
597 args.buf = ofw_real_map(buf, len);
599 argsptr = ofw_real_map(&args, sizeof(args));
600 if (args.propname == 0 || args.buf == 0 ||
601 openfirmware((void *)argsptr) == -1) {
605 ofw_real_unmap(argsptr, &args, sizeof(args));
610 /* Convert a device specifier to a fully qualified pathname. */
612 ofw_real_canon(ofw_t ofw, const char *device, char *buf, size_t len)
625 args.name = (cell_t)(uintptr_t)"canon";
631 args.device = ofw_real_map(device, strlen(device) + 1);
632 args.buf = ofw_real_map(buf, len);
634 argsptr = ofw_real_map(&args, sizeof(args));
635 if (args.device == 0 || args.buf == 0 ||
636 openfirmware((void *)argsptr) == -1) {
640 ofw_real_unmap(argsptr, &args, sizeof(args));
641 ofw_real_unmap(args.buf, buf, len);
647 /* Return a package handle for the specified device. */
649 ofw_real_finddevice(ofw_t ofw, const char *device)
660 args.name = (cell_t)(uintptr_t)"finddevice";
666 args.device = ofw_real_map(device, strlen(device) + 1);
667 argsptr = ofw_real_map(&args, sizeof(args));
668 if (args.device == 0 ||
669 openfirmware((void *)argsptr) == -1) {
673 ofw_real_unmap(argsptr, &args, sizeof(args));
675 return (args.package);
678 /* Return the fully qualified pathname corresponding to an instance. */
680 ofw_real_instance_to_path(ofw_t ofw, ihandle_t instance, char *buf, size_t len)
693 args.name = (cell_t)(uintptr_t)"instance-to-path";
699 args.instance = instance;
700 args.buf = ofw_real_map(buf, len);
702 argsptr = ofw_real_map(&args, sizeof(args));
704 openfirmware((void *)argsptr) == -1) {
708 ofw_real_unmap(argsptr, &args, sizeof(args));
709 ofw_real_unmap(args.buf, buf, len);
715 /* Return the fully qualified pathname corresponding to a package. */
717 ofw_real_package_to_path(ofw_t ofw, phandle_t package, char *buf, size_t len)
730 args.name = (cell_t)(uintptr_t)"package-to-path";
736 args.package = package;
737 args.buf = ofw_real_map(buf, len);
739 argsptr = ofw_real_map(&args, sizeof(args));
741 openfirmware((void *)argsptr) == -1) {
745 ofw_real_unmap(argsptr, &args, sizeof(args));
746 ofw_real_unmap(args.buf, buf, len);
752 /* Call the method in the scope of a given instance. */
754 ofw_real_call_method(ofw_t ofw, ihandle_t instance, const char *method,
755 int nargs, int nreturns, cell_t *args_and_returns)
764 cell_t args_n_results[12];
769 args.name = (cell_t)(uintptr_t)"call-method";
777 args.nargs = nargs + 2;
778 args.nreturns = nreturns + 1;
779 args.method = ofw_real_map(method, strlen(method) + 1);
780 args.instance = instance;
782 ap = args_and_returns;
783 for (cp = args.args_n_results + (n = nargs); --n >= 0;)
785 argsptr = ofw_real_map(&args, sizeof(args));
786 if (args.method == 0 ||
787 openfirmware((void *)argsptr) == -1) {
791 ofw_real_unmap(argsptr, &args, sizeof(args));
793 if (args.args_n_results[nargs])
794 return (args.args_n_results[nargs]);
795 for (cp = args.args_n_results + nargs + (n = args.nreturns); --n > 0;)
801 ofw_real_interpret(ofw_t ofw, const char *cmd, int nreturns, cell_t *returns)
813 args.name = (cell_t)(uintptr_t)"interpret";
817 args.nreturns = ++nreturns;
818 args.slot[i++] = ofw_real_map(cmd, strlen(cmd) + 1);
819 argsptr = ofw_real_map(&args, sizeof(args));
820 if (openfirmware((void *)argsptr) == -1) {
824 ofw_real_unmap(argsptr, &args, sizeof(args));
826 status = args.slot[i++];
827 while (i < 1 + nreturns)
828 returns[j++] = args.slot[i++];
833 * Device I/O functions
836 /* Open an instance for a device. */
838 ofw_real_open(ofw_t ofw, const char *device)
849 args.name = (cell_t)(uintptr_t)"open";
855 args.device = ofw_real_map(device, strlen(device) + 1);
856 argsptr = ofw_real_map(&args, sizeof(args));
857 if (args.device == 0 || openfirmware((void *)argsptr) == -1
858 || args.instance == 0) {
862 ofw_real_unmap(argsptr, &args, sizeof(args));
864 return (args.instance);
867 /* Close an instance. */
869 ofw_real_close(ofw_t ofw, ihandle_t instance)
879 args.name = (cell_t)(uintptr_t)"close";
882 args.instance = instance;
884 argsptr = ofw_real_map(&args, sizeof(args));
885 openfirmware((void *)argsptr);
889 /* Read from an instance. */
891 ofw_real_read(ofw_t ofw, ihandle_t instance, void *addr, size_t len)
904 args.name = (cell_t)(uintptr_t)"read";
910 args.instance = instance;
911 args.addr = ofw_real_map(addr, len);
913 argsptr = ofw_real_map(&args, sizeof(args));
914 if (args.addr == 0 || openfirmware((void *)argsptr) == -1) {
918 ofw_real_unmap(argsptr, &args, sizeof(args));
919 ofw_real_unmap(args.addr, addr, len);
922 return (args.actual);
925 /* Write to an instance. */
927 ofw_real_write(ofw_t ofw, ihandle_t instance, const void *addr, size_t len)
940 args.name = (cell_t)(uintptr_t)"write";
946 args.instance = instance;
947 args.addr = ofw_real_map(addr, len);
949 argsptr = ofw_real_map(&args, sizeof(args));
950 if (args.addr == 0 || openfirmware((void *)argsptr) == -1) {
954 ofw_real_unmap(argsptr, &args, sizeof(args));
956 return (args.actual);
959 /* Seek to a position. */
961 ofw_real_seek(ofw_t ofw, ihandle_t instance, u_int64_t pos)
974 args.name = (cell_t)(uintptr_t)"seek";
978 args.instance = instance;
979 args.poshi = pos >> 32;
982 argsptr = ofw_real_map(&args, sizeof(args));
983 if (openfirmware((void *)argsptr) == -1) {
987 ofw_real_unmap(argsptr, &args, sizeof(args));
989 return (args.status);
996 /* Claim an area of memory. */
998 ofw_real_claim(ofw_t ofw, void *virt, size_t size, u_int align)
1000 vm_offset_t argsptr;
1011 args.name = (cell_t)(uintptr_t)"claim";
1015 args.virt = (cell_t)(uintptr_t)virt;
1019 argsptr = ofw_real_map(&args, sizeof(args));
1020 if (openfirmware((void *)argsptr) == -1) {
1022 return ((void *)-1);
1024 ofw_real_unmap(argsptr, &args, sizeof(args));
1026 return ((void *)(uintptr_t)args.baseaddr);
1029 /* Release an area of memory. */
1031 ofw_real_release(ofw_t ofw, void *virt, size_t size)
1033 vm_offset_t argsptr;
1042 args.name = (cell_t)(uintptr_t)"release";
1046 args.virt = (cell_t)(uintptr_t)virt;
1049 argsptr = ofw_real_map(&args, sizeof(args));
1050 openfirmware((void *)argsptr);
1055 * Control transfer functions
1058 /* Suspend and drop back to the Open Firmware interface. */
1060 ofw_real_enter(ofw_t ofw)
1062 vm_offset_t argsptr;
1069 args.name = (cell_t)(uintptr_t)"enter";
1074 argsptr = ofw_real_map(&args, sizeof(args));
1075 openfirmware((void *)argsptr);
1076 /* We may come back. */
1080 /* Shut down and drop back to the Open Firmware interface. */
1082 ofw_real_exit(ofw_t ofw)
1084 vm_offset_t argsptr;
1091 args.name = (cell_t)(uintptr_t)"exit";
1096 argsptr = ofw_real_map(&args, sizeof(args));
1097 openfirmware((void *)argsptr);
1098 for (;;) /* just in case */