1 /* $NetBSD: Locore.c,v 1.7 2000/08/20 07:04:59 tsubai Exp $ */
2
3 /*-
4 * SPDX-License-Identifier:BSD-4-Clause AND BSD-2-Clause
5 *
6 * Copyright (C) 1995, 1996 Wolfgang Solfrank.
7 * Copyright (C) 1995, 1996 TooLs GmbH.
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by TooLs GmbH.
21 * 4. The name of TooLs GmbH may not be used to endorse or promote products
22 * derived from this software without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
25 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
29 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
30 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
31 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
32 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
33 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 */
35 /*-
36 * Copyright (C) 2000 Benno Rice.
37 * All rights reserved.
38 *
39 * Redistribution and use in source and binary forms, with or without
40 * modification, are permitted provided that the following conditions
41 * are met:
42 * 1. Redistributions of source code must retain the above copyright
43 * notice, this list of conditions and the following disclaimer.
44 * 2. Redistributions in binary form must reproduce the above copyright
45 * notice, this list of conditions and the following disclaimer in the
46 * documentation and/or other materials provided with the distribution.
47 *
48 * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR
49 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
50 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
51 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
52 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
53 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
54 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
55 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
56 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
57 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
58 */
59
60 #include <sys/cdefs.h>
61 #include <sys/endian.h>
62 #include <sys/param.h>
63 #include <sys/kernel.h>
64 #include <sys/lock.h>
65 #include <sys/mutex.h>
66 #include <sys/systm.h>
67
68 #include <vm/vm.h>
69 #include <vm/vm_page.h>
70 #include <vm/pmap.h>
71
72 #include <machine/bus.h>
73 #include <machine/md_var.h>
74 #include <machine/ofw_machdep.h>
75 #include <machine/stdarg.h>
76
77 #include <dev/ofw/openfirm.h>
78 #include <dev/ofw/ofwvar.h>
79 #include "ofw_if.h"
80
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,
92 char *buf, size_t);
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,
98 size_t len);
99 static ssize_t ofw_real_package_to_path(ofw_t, phandle_t package, char *buf,
100 size_t len);
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,
104 cell_t *returns);
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,
109 size_t len);
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);
115
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),
130
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),
143 { 0, 0 }
144 };
145
146 static ofw_def_t ofw_real = {
147 OFW_STD_REAL,
148 ofw_real_methods,
149 0
150 };
151 OFW_DEF(ofw_real);
152
153 static ofw_def_t ofw_32bit = {
154 OFW_STD_32BIT,
155 ofw_real_methods,
156 0
157 };
158 OFW_DEF(ofw_32bit);
159
160 static MALLOC_DEFINE(M_OFWREAL, "ofwreal",
161 "Open Firmware Real Mode Bounce Page");
162
163 static int (*openfirmware)(void *);
164
165 static vm_offset_t of_bounce_phys;
166 static caddr_t of_bounce_virt;
167 static off_t of_bounce_offset;
168 static size_t of_bounce_size;
169
170 #define IN(x) htobe32(x)
171 #define OUT(x) be32toh(x)
172
173 /*
174 * To be able to use OFW console on PPC, that requires real mode OFW,
175 * the mutex that guards the mapping/unmapping of virtual to physical
176 * buffers (of_real_mtx) must be of SPIN type. This is needed because
177 * kernel console first locks a SPIN mutex before calling OFW real.
178 * By default, of_real_mtx is a sleepable mutex. To make it of SPIN
179 * type, use the following tunnable:
180 * machdep.ofw.mtx_spin=1
181 *
182 * Besides that, a few more tunables are needed to select and use the
183 * OFW console with real mode OFW.
184 *
185 * In order to disable the use of OFW FrameBuffer and fallback to the
186 * OFW console, use:
187 * hw.ofwfb.disable=1
188 *
189 * To disable the use of FDT (that doesn't support OFW read/write methods)
190 * and use real OFW instead, unset the following loader variable:
191 * unset usefdt
192 *
193 * OFW is put in quiesce state in early kernel boot, which usually disables
194 * OFW read/write capabilities (in QEMU write continue to work, but
195 * read doesn't). To avoid OFW quiesce, use:
196 * debug.quiesce_ofw=0
197 *
198 * Note that disabling OFW quiesce can cause conflicts between kernel and
199 * OFW trying to control the same hardware. Thus, it must be used with care.
200 * Some conflicts can be avoided by disabling kernel drivers with hints.
201 * For instance, to disable a xhci controller and an USB keyboard connected
202 * to it, that may be already being used for input by OFW, use:
203 * hint.xhci.0.disabled=1
204 */
205
206 static struct mtx of_bounce_mtx;
207 static struct mtx of_spin_mtx;
208 static struct mtx *of_real_mtx;
209 static void (*of_mtx_lock)(void);
210 static void (*of_mtx_unlock)(void);
211
212 extern int ofw_real_mode;
213
214 /*
215 * After the VM is up, allocate a wired, low memory bounce page.
216 */
217
218 static void ofw_real_bounce_alloc(void *);
219
220 SYSINIT(ofw_real_bounce_alloc, SI_SUB_KMEM, SI_ORDER_ANY,
221 ofw_real_bounce_alloc, NULL);
222
223 static void
ofw_real_mtx_lock_spin(void)224 ofw_real_mtx_lock_spin(void)
225 {
226 mtx_lock_spin(of_real_mtx);
227 }
228
229 static void
ofw_real_mtx_lock(void)230 ofw_real_mtx_lock(void)
231 {
232 mtx_lock(of_real_mtx);
233 }
234
235 static void
ofw_real_mtx_unlock_spin(void)236 ofw_real_mtx_unlock_spin(void)
237 {
238 mtx_unlock_spin(of_real_mtx);
239 }
240
241 static void
ofw_real_mtx_unlock(void)242 ofw_real_mtx_unlock(void)
243 {
244 mtx_unlock(of_real_mtx);
245 }
246
247 static void
ofw_real_start(void)248 ofw_real_start(void)
249 {
250 (*of_mtx_lock)();
251 of_bounce_offset = 0;
252 }
253
254 static void
ofw_real_stop(void)255 ofw_real_stop(void)
256 {
257 (*of_mtx_unlock)();
258 }
259
260 static void
ofw_real_bounce_alloc(void * junk)261 ofw_real_bounce_alloc(void *junk)
262 {
263 caddr_t temp;
264
265 /*
266 * Check that ofw_real is actually in use before allocating wads
267 * of memory. Do this by checking if our mutex has been set up.
268 */
269 if (!mtx_initialized(&of_bounce_mtx))
270 return;
271
272 /*
273 * Allocate a page of contiguous, wired physical memory that can
274 * fit into a 32-bit address space and accessed from real mode.
275 */
276 temp = contigmalloc(4 * PAGE_SIZE, M_OFWREAL, 0, 0,
277 ulmin(platform_real_maxaddr(), BUS_SPACE_MAXADDR_32BIT), PAGE_SIZE,
278 4 * PAGE_SIZE);
279 if (temp == NULL)
280 panic("%s: Not able to allocated contiguous memory\n", __func__);
281
282 mtx_lock(&of_bounce_mtx);
283
284 of_bounce_virt = temp;
285
286 of_bounce_phys = vtophys(of_bounce_virt);
287 of_bounce_size = 4 * PAGE_SIZE;
288
289 /*
290 * For virtual-mode OF, direct map this physical address so that
291 * we have a 32-bit virtual address to give OF.
292 */
293
294 if (!ofw_real_mode && (!hw_direct_map || DMAP_BASE_ADDRESS != 0))
295 pmap_kenter(of_bounce_phys, of_bounce_phys);
296
297 mtx_unlock(&of_bounce_mtx);
298 }
299
300 static cell_t
ofw_real_map(const void * buf,size_t len)301 ofw_real_map(const void *buf, size_t len)
302 {
303 static char emergency_buffer[255];
304 cell_t phys;
305
306 mtx_assert(of_real_mtx, MA_OWNED);
307
308 if (of_bounce_virt == NULL) {
309 /*
310 * If we haven't set up the MMU, then buf is guaranteed
311 * to be accessible to OF, because the only memory we
312 * can use right now is memory mapped by firmware.
313 */
314 if (!pmap_bootstrapped)
315 return (cell_t)((uintptr_t)buf & ~DMAP_BASE_ADDRESS);
316
317 /*
318 * XXX: It is possible for us to get called before the VM has
319 * come online, but after the MMU is up. We don't have the
320 * bounce buffer yet, but can no longer presume a 1:1 mapping.
321 * Copy into the emergency buffer, and reset at the end.
322 */
323 of_bounce_virt = emergency_buffer;
324 of_bounce_phys = (vm_offset_t)of_bounce_virt &
325 ~DMAP_BASE_ADDRESS;
326 of_bounce_size = sizeof(emergency_buffer);
327 }
328
329 /*
330 * Make sure the bounce page offset satisfies any reasonable
331 * alignment constraint.
332 */
333 of_bounce_offset += sizeof(register_t) -
334 (of_bounce_offset % sizeof(register_t));
335
336 if (of_bounce_offset + len > of_bounce_size) {
337 panic("Oversize Open Firmware call!");
338 return 0;
339 }
340
341 if (buf != NULL)
342 memcpy(of_bounce_virt + of_bounce_offset, buf, len);
343 else
344 return (0);
345
346 phys = of_bounce_phys + of_bounce_offset;
347
348 of_bounce_offset += len;
349
350 return (phys);
351 }
352
353 static void
ofw_real_unmap(cell_t physaddr,void * buf,size_t len)354 ofw_real_unmap(cell_t physaddr, void *buf, size_t len)
355 {
356 mtx_assert(of_real_mtx, MA_OWNED);
357
358 if (of_bounce_virt == NULL)
359 return;
360
361 if (physaddr == 0)
362 return;
363
364 memcpy(buf,of_bounce_virt + (physaddr - of_bounce_phys),len);
365 }
366
367 /* Initialiser */
368
369 static int
ofw_real_init(ofw_t ofw,void * openfirm)370 ofw_real_init(ofw_t ofw, void *openfirm)
371 {
372 int mtx_spin;
373
374 openfirmware = (int (*)(void *))openfirm;
375 mtx_init(&of_bounce_mtx, "OF Bounce Page", NULL, MTX_DEF);
376
377 mtx_spin = 0;
378 TUNABLE_INT_FETCH("machdep.ofw.mtx_spin", &mtx_spin);
379 if (mtx_spin) {
380 mtx_init(&of_spin_mtx, "OF Real", NULL, MTX_SPIN);
381 of_real_mtx = &of_spin_mtx;
382 of_mtx_lock = ofw_real_mtx_lock_spin;
383 of_mtx_unlock = ofw_real_mtx_unlock_spin;
384 } else {
385 of_real_mtx = &of_bounce_mtx;
386 of_mtx_lock = ofw_real_mtx_lock;
387 of_mtx_unlock = ofw_real_mtx_unlock;
388 }
389
390 of_bounce_virt = NULL;
391 return (0);
392 }
393
394 /*
395 * Generic functions
396 */
397
398 /* Test to see if a service exists. */
399 static int
ofw_real_test(ofw_t ofw,const char * name)400 ofw_real_test(ofw_t ofw, const char *name)
401 {
402 vm_offset_t argsptr;
403 struct {
404 cell_t name;
405 cell_t nargs;
406 cell_t nreturns;
407 cell_t service;
408 cell_t missing;
409 } args;
410
411 args.name = IN((cell_t)(uintptr_t)"test");
412 args.nargs = IN(1);
413 args.nreturns = IN(1);
414
415 ofw_real_start();
416
417 args.service = IN(ofw_real_map(name, strlen(name) + 1));
418 argsptr = ofw_real_map(&args, sizeof(args));
419 if (args.service == 0 || openfirmware((void *)argsptr) == -1) {
420 ofw_real_stop();
421 return (-1);
422 }
423 ofw_real_unmap(argsptr, &args, sizeof(args));
424 ofw_real_stop();
425 return (OUT(args.missing));
426 }
427
428 /*
429 * Device tree functions
430 */
431
432 /* Return the next sibling of this node or 0. */
433 static phandle_t
ofw_real_peer(ofw_t ofw,phandle_t node)434 ofw_real_peer(ofw_t ofw, phandle_t node)
435 {
436 vm_offset_t argsptr;
437 struct {
438 cell_t name;
439 cell_t nargs;
440 cell_t nreturns;
441 cell_t node;
442 cell_t next;
443 } args;
444
445 args.name = IN((cell_t)(uintptr_t)"peer");
446 args.nargs = IN(1);
447 args.nreturns = IN(1);
448
449 args.node = IN(node);
450 ofw_real_start();
451 argsptr = ofw_real_map(&args, sizeof(args));
452 if (openfirmware((void *)argsptr) == -1) {
453 ofw_real_stop();
454 return (0);
455 }
456 ofw_real_unmap(argsptr, &args, sizeof(args));
457 ofw_real_stop();
458 return (OUT(args.next));
459 }
460
461 /* Return the first child of this node or 0. */
462 static phandle_t
ofw_real_child(ofw_t ofw,phandle_t node)463 ofw_real_child(ofw_t ofw, phandle_t node)
464 {
465 vm_offset_t argsptr;
466 struct {
467 cell_t name;
468 cell_t nargs;
469 cell_t nreturns;
470 cell_t node;
471 cell_t child;
472 } args;
473
474 args.name = IN((cell_t)(uintptr_t)"child");
475 args.nargs = IN(1);
476 args.nreturns = IN(1);
477
478 args.node = IN(node);
479 ofw_real_start();
480 argsptr = ofw_real_map(&args, sizeof(args));
481 if (openfirmware((void *)argsptr) == -1) {
482 ofw_real_stop();
483 return (0);
484 }
485 ofw_real_unmap(argsptr, &args, sizeof(args));
486 ofw_real_stop();
487 return (OUT(args.child));
488 }
489
490 /* Return the parent of this node or 0. */
491 static phandle_t
ofw_real_parent(ofw_t ofw,phandle_t node)492 ofw_real_parent(ofw_t ofw, phandle_t node)
493 {
494 vm_offset_t argsptr;
495 struct {
496 cell_t name;
497 cell_t nargs;
498 cell_t nreturns;
499 cell_t node;
500 cell_t parent;
501 } args;
502
503 args.name = IN((cell_t)(uintptr_t)"parent");
504 args.nargs = IN(1);
505 args.nreturns = IN(1);
506
507 args.node = IN(node);
508 ofw_real_start();
509 argsptr = ofw_real_map(&args, sizeof(args));
510 if (openfirmware((void *)argsptr) == -1) {
511 ofw_real_stop();
512 return (0);
513 }
514 ofw_real_unmap(argsptr, &args, sizeof(args));
515 ofw_real_stop();
516 return (OUT(args.parent));
517 }
518
519 /* Return the package handle that corresponds to an instance handle. */
520 static phandle_t
ofw_real_instance_to_package(ofw_t ofw,ihandle_t instance)521 ofw_real_instance_to_package(ofw_t ofw, ihandle_t instance)
522 {
523 vm_offset_t argsptr;
524 struct {
525 cell_t name;
526 cell_t nargs;
527 cell_t nreturns;
528 cell_t instance;
529 cell_t package;
530 } args;
531
532 args.name = IN((cell_t)(uintptr_t)"instance-to-package");
533 args.nargs = IN(1);
534 args.nreturns = IN(1);
535
536 args.instance = IN(instance);
537 ofw_real_start();
538 argsptr = ofw_real_map(&args, sizeof(args));
539 if (openfirmware((void *)argsptr) == -1) {
540 ofw_real_stop();
541 return (-1);
542 }
543 ofw_real_unmap(argsptr, &args, sizeof(args));
544 ofw_real_stop();
545 return (OUT(args.package));
546 }
547
548 /* Get the length of a property of a package. */
549 static ssize_t
ofw_real_getproplen(ofw_t ofw,phandle_t package,const char * propname)550 ofw_real_getproplen(ofw_t ofw, phandle_t package, const char *propname)
551 {
552 vm_offset_t argsptr;
553 struct {
554 cell_t name;
555 cell_t nargs;
556 cell_t nreturns;
557 cell_t package;
558 cell_t propname;
559 int32_t proplen;
560 } args;
561
562 args.name = IN((cell_t)(uintptr_t)"getproplen");
563 args.nargs = IN(2);
564 args.nreturns = IN(1);
565
566 ofw_real_start();
567
568 args.package = IN(package);
569 args.propname = IN(ofw_real_map(propname, strlen(propname) + 1));
570 argsptr = ofw_real_map(&args, sizeof(args));
571 if (args.propname == 0 || openfirmware((void *)argsptr) == -1) {
572 ofw_real_stop();
573 return (-1);
574 }
575 ofw_real_unmap(argsptr, &args, sizeof(args));
576 ofw_real_stop();
577 return ((ssize_t)(int32_t)OUT(args.proplen));
578 }
579
580 /* Get the value of a property of a package. */
581 static ssize_t
ofw_real_getprop(ofw_t ofw,phandle_t package,const char * propname,void * buf,size_t buflen)582 ofw_real_getprop(ofw_t ofw, phandle_t package, const char *propname, void *buf,
583 size_t buflen)
584 {
585 vm_offset_t argsptr;
586 struct {
587 cell_t name;
588 cell_t nargs;
589 cell_t nreturns;
590 cell_t package;
591 cell_t propname;
592 cell_t buf;
593 cell_t buflen;
594 int32_t size;
595 } args;
596
597 args.name = IN((cell_t)(uintptr_t)"getprop");
598 args.nargs = IN(4);
599 args.nreturns = IN(1);
600
601 ofw_real_start();
602
603 args.package = IN(package);
604 args.propname = IN(ofw_real_map(propname, strlen(propname) + 1));
605 args.buf = IN(ofw_real_map(buf, buflen));
606 args.buflen = IN(buflen);
607 argsptr = ofw_real_map(&args, sizeof(args));
608 if (args.propname == 0 || args.buf == 0 ||
609 openfirmware((void *)argsptr) == -1) {
610 ofw_real_stop();
611 return (-1);
612 }
613 ofw_real_unmap(argsptr, &args, sizeof(args));
614 ofw_real_unmap(OUT(args.buf), buf, buflen);
615
616 ofw_real_stop();
617 return ((ssize_t)(int32_t)OUT(args.size));
618 }
619
620 /* Get the next property of a package. */
621 static int
ofw_real_nextprop(ofw_t ofw,phandle_t package,const char * previous,char * buf,size_t size)622 ofw_real_nextprop(ofw_t ofw, phandle_t package, const char *previous,
623 char *buf, size_t size)
624 {
625 vm_offset_t argsptr;
626 struct {
627 cell_t name;
628 cell_t nargs;
629 cell_t nreturns;
630 cell_t package;
631 cell_t previous;
632 cell_t buf;
633 cell_t flag;
634 } args;
635
636 args.name = IN((cell_t)(uintptr_t)"nextprop");
637 args.nargs = IN(3);
638 args.nreturns = IN(1);
639
640 ofw_real_start();
641
642 args.package = IN(package);
643 args.previous = IN(ofw_real_map(previous, (previous != NULL) ? (strlen(previous) + 1) : 0));
644 args.buf = IN(ofw_real_map(buf, size));
645 argsptr = ofw_real_map(&args, sizeof(args));
646 if (args.buf == 0 || openfirmware((void *)argsptr) == -1) {
647 ofw_real_stop();
648 return (-1);
649 }
650 ofw_real_unmap(argsptr, &args, sizeof(args));
651 ofw_real_unmap(OUT(args.buf), buf, size);
652
653 ofw_real_stop();
654 return (OUT(args.flag));
655 }
656
657 /* Set the value of a property of a package. */
658 /* XXX Has a bug on FirePower */
659 static int
ofw_real_setprop(ofw_t ofw,phandle_t package,const char * propname,const void * buf,size_t len)660 ofw_real_setprop(ofw_t ofw, phandle_t package, const char *propname,
661 const void *buf, size_t len)
662 {
663 vm_offset_t argsptr;
664 struct {
665 cell_t name;
666 cell_t nargs;
667 cell_t nreturns;
668 cell_t package;
669 cell_t propname;
670 cell_t buf;
671 cell_t len;
672 cell_t size;
673 } args;
674
675 args.name = IN((cell_t)(uintptr_t)"setprop");
676 args.nargs = IN(4);
677 args.nreturns = IN(1);
678
679 ofw_real_start();
680
681 args.package = IN(package);
682 args.propname = IN(ofw_real_map(propname, strlen(propname) + 1));
683 args.buf = IN(ofw_real_map(buf, len));
684 args.len = IN(len);
685 argsptr = ofw_real_map(&args, sizeof(args));
686 if (args.propname == 0 || args.buf == 0 ||
687 openfirmware((void *)argsptr) == -1) {
688 ofw_real_stop();
689 return (-1);
690 }
691 ofw_real_unmap(argsptr, &args, sizeof(args));
692 ofw_real_stop();
693 return (OUT(args.size));
694 }
695
696 /* Convert a device specifier to a fully qualified pathname. */
697 static ssize_t
ofw_real_canon(ofw_t ofw,const char * device,char * buf,size_t len)698 ofw_real_canon(ofw_t ofw, const char *device, char *buf, size_t len)
699 {
700 vm_offset_t argsptr;
701 struct {
702 cell_t name;
703 cell_t nargs;
704 cell_t nreturns;
705 cell_t device;
706 cell_t buf;
707 cell_t len;
708 int32_t size;
709 } args;
710
711 args.name = IN((cell_t)(uintptr_t)"canon");
712 args.nargs = IN(3);
713 args.nreturns = IN(1);
714
715 ofw_real_start();
716
717 args.device = IN(ofw_real_map(device, strlen(device) + 1));
718 args.buf = IN(ofw_real_map(buf, len));
719 args.len = IN(len);
720 argsptr = ofw_real_map(&args, sizeof(args));
721 if (args.device == 0 || args.buf == 0 ||
722 openfirmware((void *)argsptr) == -1) {
723 ofw_real_stop();
724 return (-1);
725 }
726 ofw_real_unmap(argsptr, &args, sizeof(args));
727 ofw_real_unmap(OUT(args.buf), buf, len);
728
729 ofw_real_stop();
730 return ((ssize_t)(int32_t)OUT(args.size));
731 }
732
733 /* Return a package handle for the specified device. */
734 static phandle_t
ofw_real_finddevice(ofw_t ofw,const char * device)735 ofw_real_finddevice(ofw_t ofw, const char *device)
736 {
737 vm_offset_t argsptr;
738 struct {
739 cell_t name;
740 cell_t nargs;
741 cell_t nreturns;
742 cell_t device;
743 cell_t package;
744 } args;
745
746 args.name = IN((cell_t)(uintptr_t)"finddevice");
747 args.nargs = IN(1);
748 args.nreturns = IN(1);
749
750 ofw_real_start();
751
752 args.device = IN(ofw_real_map(device, strlen(device) + 1));
753 argsptr = ofw_real_map(&args, sizeof(args));
754 if (args.device == 0 ||
755 openfirmware((void *)argsptr) == -1) {
756 ofw_real_stop();
757 return (-1);
758 }
759 ofw_real_unmap(argsptr, &args, sizeof(args));
760 ofw_real_stop();
761 return (OUT(args.package));
762 }
763
764 /* Return the fully qualified pathname corresponding to an instance. */
765 static ssize_t
ofw_real_instance_to_path(ofw_t ofw,ihandle_t instance,char * buf,size_t len)766 ofw_real_instance_to_path(ofw_t ofw, ihandle_t instance, char *buf, size_t len)
767 {
768 vm_offset_t argsptr;
769 struct {
770 cell_t name;
771 cell_t nargs;
772 cell_t nreturns;
773 cell_t instance;
774 cell_t buf;
775 cell_t len;
776 int32_t size;
777 } args;
778
779 args.name = IN((cell_t)(uintptr_t)"instance-to-path");
780 args.nargs = IN(3);
781 args.nreturns = IN(1);
782
783 ofw_real_start();
784
785 args.instance = IN(instance);
786 args.buf = IN(ofw_real_map(buf, len));
787 args.len = IN(len);
788 argsptr = ofw_real_map(&args, sizeof(args));
789 if (args.buf == 0 ||
790 openfirmware((void *)argsptr) == -1) {
791 ofw_real_stop();
792 return (-1);
793 }
794 ofw_real_unmap(argsptr, &args, sizeof(args));
795 ofw_real_unmap(OUT(args.buf), buf, len);
796
797 ofw_real_stop();
798 return ((ssize_t)(int32_t)OUT(args.size));
799 }
800
801 /* Return the fully qualified pathname corresponding to a package. */
802 static ssize_t
ofw_real_package_to_path(ofw_t ofw,phandle_t package,char * buf,size_t len)803 ofw_real_package_to_path(ofw_t ofw, phandle_t package, char *buf, size_t len)
804 {
805 vm_offset_t argsptr;
806 struct {
807 cell_t name;
808 cell_t nargs;
809 cell_t nreturns;
810 cell_t package;
811 cell_t buf;
812 cell_t len;
813 int32_t size;
814 } args;
815
816 args.name = IN((cell_t)(uintptr_t)"package-to-path");
817 args.nargs = IN(3);
818 args.nreturns = IN(1);
819
820 ofw_real_start();
821
822 args.package = IN(package);
823 args.buf = IN(ofw_real_map(buf, len));
824 args.len = IN(len);
825 argsptr = ofw_real_map(&args, sizeof(args));
826 if (args.buf == 0 ||
827 openfirmware((void *)argsptr) == -1) {
828 ofw_real_stop();
829 return (-1);
830 }
831 ofw_real_unmap(argsptr, &args, sizeof(args));
832 ofw_real_unmap(OUT(args.buf), buf, len);
833
834 ofw_real_stop();
835 return ((ssize_t)(int32_t)OUT(args.size));
836 }
837
838 /* Call the method in the scope of a given instance. */
839 static int
ofw_real_call_method(ofw_t ofw,ihandle_t instance,const char * method,int nargs,int nreturns,cell_t * args_and_returns)840 ofw_real_call_method(ofw_t ofw, ihandle_t instance, const char *method,
841 int nargs, int nreturns, cell_t *args_and_returns)
842 {
843 vm_offset_t argsptr;
844 struct {
845 cell_t name;
846 cell_t nargs;
847 cell_t nreturns;
848 cell_t method;
849 cell_t instance;
850 cell_t args_n_results[12];
851 } args;
852 cell_t *ap, *cp;
853 int n;
854
855 args.name = IN((cell_t)(uintptr_t)"call-method");
856 args.nargs = IN(2);
857 args.nreturns = IN(1);
858
859 if (nargs > 6)
860 return (-1);
861
862 ofw_real_start();
863 args.nargs = IN(nargs + 2);
864 args.nreturns = IN(nreturns + 1);
865 args.method = IN(ofw_real_map(method, strlen(method) + 1));
866 args.instance = IN(instance);
867
868 ap = args_and_returns;
869 for (cp = args.args_n_results + (n = nargs); --n >= 0;)
870 *--cp = IN(*(ap++));
871 argsptr = ofw_real_map(&args, sizeof(args));
872 if (args.method == 0 ||
873 openfirmware((void *)argsptr) == -1) {
874 ofw_real_stop();
875 return (-1);
876 }
877 ofw_real_unmap(argsptr, &args, sizeof(args));
878 ofw_real_stop();
879 if (OUT(args.args_n_results[nargs]))
880 return (OUT(args.args_n_results[nargs]));
881 for (cp = args.args_n_results + nargs + (n = OUT(args.nreturns)); --n > 0;)
882 *(ap++) = OUT(*--cp);
883 return (0);
884 }
885
886 static int
ofw_real_interpret(ofw_t ofw,const char * cmd,int nreturns,cell_t * returns)887 ofw_real_interpret(ofw_t ofw, const char *cmd, int nreturns, cell_t *returns)
888 {
889 vm_offset_t argsptr;
890 struct {
891 cell_t name;
892 cell_t nargs;
893 cell_t nreturns;
894 cell_t slot[16];
895 } args;
896 cell_t status;
897 int i = 0, j = 0;
898
899 args.name = IN((cell_t)(uintptr_t)"interpret");
900 args.nargs = IN(1);
901
902 ofw_real_start();
903 args.nreturns = IN(++nreturns);
904 args.slot[i++] = IN(ofw_real_map(cmd, strlen(cmd) + 1));
905 argsptr = ofw_real_map(&args, sizeof(args));
906 if (openfirmware((void *)argsptr) == -1) {
907 ofw_real_stop();
908 return (-1);
909 }
910 ofw_real_unmap(argsptr, &args, sizeof(args));
911 ofw_real_stop();
912 status = OUT(args.slot[i++]);
913 while (i < 1 + nreturns)
914 returns[j++] = OUT(args.slot[i++]);
915 return (status);
916 }
917
918 /*
919 * Device I/O functions
920 */
921
922 /* Open an instance for a device. */
923 static ihandle_t
ofw_real_open(ofw_t ofw,const char * device)924 ofw_real_open(ofw_t ofw, const char *device)
925 {
926 vm_offset_t argsptr;
927 struct {
928 cell_t name;
929 cell_t nargs;
930 cell_t nreturns;
931 cell_t device;
932 cell_t instance;
933 } args;
934
935 args.name = IN((cell_t)(uintptr_t)"open");
936 args.nargs = IN(1);
937 args.nreturns = IN(1);
938
939 ofw_real_start();
940
941 args.device = IN(ofw_real_map(device, strlen(device) + 1));
942 argsptr = ofw_real_map(&args, sizeof(args));
943 if (args.device == 0 || openfirmware((void *)argsptr) == -1
944 || args.instance == 0) {
945 ofw_real_stop();
946 return (-1);
947 }
948 ofw_real_unmap(argsptr, &args, sizeof(args));
949 ofw_real_stop();
950 return (OUT(args.instance));
951 }
952
953 /* Close an instance. */
954 static void
ofw_real_close(ofw_t ofw,ihandle_t instance)955 ofw_real_close(ofw_t ofw, ihandle_t instance)
956 {
957 vm_offset_t argsptr;
958 struct {
959 cell_t name;
960 cell_t nargs;
961 cell_t nreturns;
962 cell_t instance;
963 } args;
964
965 args.name = IN((cell_t)(uintptr_t)"close");
966 args.nargs = IN(1);
967 args.nreturns = IN(0);
968 args.instance = IN(instance);
969 ofw_real_start();
970 argsptr = ofw_real_map(&args, sizeof(args));
971 openfirmware((void *)argsptr);
972 ofw_real_stop();
973 }
974
975 /* Read from an instance. */
976 static ssize_t
ofw_real_read(ofw_t ofw,ihandle_t instance,void * addr,size_t len)977 ofw_real_read(ofw_t ofw, ihandle_t instance, void *addr, size_t len)
978 {
979 vm_offset_t argsptr;
980 struct {
981 cell_t name;
982 cell_t nargs;
983 cell_t nreturns;
984 cell_t instance;
985 cell_t addr;
986 cell_t len;
987 int32_t actual;
988 } args;
989
990 args.name = IN((cell_t)(uintptr_t)"read");
991 args.nargs = IN(3);
992 args.nreturns = IN(1);
993
994 ofw_real_start();
995
996 args.instance = IN(instance);
997 args.addr = IN(ofw_real_map(addr, len));
998 args.len = IN(len);
999 argsptr = ofw_real_map(&args, sizeof(args));
1000 if (args.addr == 0 || openfirmware((void *)argsptr) == -1) {
1001 ofw_real_stop();
1002 return (-1);
1003 }
1004 ofw_real_unmap(argsptr, &args, sizeof(args));
1005 ofw_real_unmap(OUT(args.addr), addr, len);
1006
1007 ofw_real_stop();
1008 return ((ssize_t)(int32_t)OUT(args.actual));
1009 }
1010
1011 /* Write to an instance. */
1012 static ssize_t
ofw_real_write(ofw_t ofw,ihandle_t instance,const void * addr,size_t len)1013 ofw_real_write(ofw_t ofw, ihandle_t instance, const void *addr, size_t len)
1014 {
1015 vm_offset_t argsptr;
1016 struct {
1017 cell_t name;
1018 cell_t nargs;
1019 cell_t nreturns;
1020 cell_t instance;
1021 cell_t addr;
1022 cell_t len;
1023 int32_t actual;
1024 } args;
1025
1026 args.name = IN((cell_t)(uintptr_t)"write");
1027 args.nargs = IN(3);
1028 args.nreturns = IN(1);
1029
1030 ofw_real_start();
1031
1032 args.instance = IN(instance);
1033 args.addr = IN(ofw_real_map(addr, len));
1034 args.len = IN(len);
1035 argsptr = ofw_real_map(&args, sizeof(args));
1036 if (args.addr == 0 || openfirmware((void *)argsptr) == -1) {
1037 ofw_real_stop();
1038 return (-1);
1039 }
1040 ofw_real_unmap(argsptr, &args, sizeof(args));
1041 ofw_real_stop();
1042 return ((ssize_t)(int32_t)OUT(args.actual));
1043 }
1044
1045 /* Seek to a position. */
1046 static int
ofw_real_seek(ofw_t ofw,ihandle_t instance,u_int64_t pos)1047 ofw_real_seek(ofw_t ofw, ihandle_t instance, u_int64_t pos)
1048 {
1049 vm_offset_t argsptr;
1050 struct {
1051 cell_t name;
1052 cell_t nargs;
1053 cell_t nreturns;
1054 cell_t instance;
1055 cell_t poshi;
1056 cell_t poslo;
1057 cell_t status;
1058 } args;
1059
1060 args.name = IN((cell_t)(uintptr_t)"seek");
1061 args.nargs = IN(3);
1062 args.nreturns = IN(1);
1063
1064 args.instance = IN(instance);
1065 args.poshi = IN(pos >> 32);
1066 args.poslo = IN(pos);
1067 ofw_real_start();
1068 argsptr = ofw_real_map(&args, sizeof(args));
1069 if (openfirmware((void *)argsptr) == -1) {
1070 ofw_real_stop();
1071 return (-1);
1072 }
1073 ofw_real_unmap(argsptr, &args, sizeof(args));
1074 ofw_real_stop();
1075 return (OUT(args.status));
1076 }
1077
1078 /*
1079 * Memory functions
1080 */
1081
1082 /* Claim an area of memory. */
1083 static caddr_t
ofw_real_claim(ofw_t ofw,void * virt,size_t size,u_int align)1084 ofw_real_claim(ofw_t ofw, void *virt, size_t size, u_int align)
1085 {
1086 vm_offset_t argsptr;
1087 struct {
1088 cell_t name;
1089 cell_t nargs;
1090 cell_t nreturns;
1091 cell_t virt;
1092 cell_t size;
1093 cell_t align;
1094 cell_t baseaddr;
1095 } args;
1096
1097 args.name = IN((cell_t)(uintptr_t)"claim");
1098 args.nargs = IN(3);
1099 args.nreturns = IN(1);
1100
1101 args.virt = IN((cell_t)(uintptr_t)virt);
1102 args.size = IN(size);
1103 args.align = IN(align);
1104 ofw_real_start();
1105 argsptr = ofw_real_map(&args, sizeof(args));
1106 if (openfirmware((void *)argsptr) == -1) {
1107 ofw_real_stop();
1108 return ((void *)-1);
1109 }
1110 ofw_real_unmap(argsptr, &args, sizeof(args));
1111 ofw_real_stop();
1112 return ((void *)(uintptr_t)(OUT(args.baseaddr)));
1113 }
1114
1115 /* Release an area of memory. */
1116 static void
ofw_real_release(ofw_t ofw,void * virt,size_t size)1117 ofw_real_release(ofw_t ofw, void *virt, size_t size)
1118 {
1119 vm_offset_t argsptr;
1120 struct {
1121 cell_t name;
1122 cell_t nargs;
1123 cell_t nreturns;
1124 cell_t virt;
1125 cell_t size;
1126 } args;
1127
1128 args.name = IN((cell_t)(uintptr_t)"release");
1129 args.nargs = IN(2);
1130 args.nreturns = IN(0);
1131
1132 args.virt = IN((cell_t)(uintptr_t)virt);
1133 args.size = IN(size);
1134 ofw_real_start();
1135 argsptr = ofw_real_map(&args, sizeof(args));
1136 openfirmware((void *)argsptr);
1137 ofw_real_stop();
1138 }
1139
1140 /*
1141 * Control transfer functions
1142 */
1143
1144 /* Suspend and drop back to the Open Firmware interface. */
1145 static void
ofw_real_enter(ofw_t ofw)1146 ofw_real_enter(ofw_t ofw)
1147 {
1148 vm_offset_t argsptr;
1149 struct {
1150 cell_t name;
1151 cell_t nargs;
1152 cell_t nreturns;
1153 } args;
1154
1155 args.name = IN((cell_t)(uintptr_t)"enter");
1156 args.nargs = IN(0);
1157 args.nreturns = IN(0);
1158
1159 ofw_real_start();
1160 argsptr = ofw_real_map(&args, sizeof(args));
1161 openfirmware((void *)argsptr);
1162 /* We may come back. */
1163 ofw_real_stop();
1164 }
1165
1166 /* Shut down and drop back to the Open Firmware interface. */
1167 static void
ofw_real_exit(ofw_t ofw)1168 ofw_real_exit(ofw_t ofw)
1169 {
1170 vm_offset_t argsptr;
1171 struct {
1172 cell_t name;
1173 cell_t nargs;
1174 cell_t nreturns;
1175 } args;
1176
1177 args.name = IN((cell_t)(uintptr_t)"exit");
1178 args.nargs = IN(0);
1179 args.nreturns = IN(0);
1180
1181 ofw_real_start();
1182 argsptr = ofw_real_map(&args, sizeof(args));
1183 openfirmware((void *)argsptr);
1184 for (;;) /* just in case */
1185 ;
1186 ofw_real_stop();
1187 }
1188