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
66 int (*openfirmware)(void *);
67
68 phandle_t chosen;
69 ihandle_t mmu;
70 ihandle_t memory;
71 int 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
82 void
OF_init(int (* openfirm)(void *))83 OF_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. */
117 int
OF_test(char * name)118 OF_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. */
136 int
OF_milliseconds(void)137 OF_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. */
156 phandle_t
OF_peer(phandle_t node)157 OF_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. */
175 phandle_t
OF_child(phandle_t node)176 OF_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. */
194 phandle_t
OF_parent(phandle_t node)195 OF_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. */
213 phandle_t
OF_instance_to_package(ihandle_t instance)214 OF_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. */
232 int
OF_getproplen(phandle_t package,const char * propname)233 OF_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. */
253 int
OF_getprop(phandle_t package,const char * propname,void * buf,int buflen)254 OF_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. */
278 int
OF_getencprop(phandle_t package,const char * propname,cell_t * buf,int buflen)279 OF_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. */
293 int
OF_nextprop(phandle_t package,const char * previous,char * buf)294 OF_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 */
317 int
OF_setprop(phandle_t package,const char * propname,void * buf,int len)318 OF_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. */
342 int
OF_canon(const char * device,char * buf,int len)343 OF_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. */
365 phandle_t
OF_finddevice(const char * device)366 OF_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. */
384 int
OF_instance_to_path(ihandle_t instance,char * buf,int len)385 OF_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. */
407 int
OF_package_to_path(phandle_t package,char * buf,int len)408 OF_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. */
430 int
OF_call_method(char * method,ihandle_t instance,int nargs,int nreturns,...)431 OF_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. */
470 ihandle_t
OF_open(char * device)471 OF_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. */
490 void
OF_close(ihandle_t instance)491 OF_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. */
506 int
OF_read(ihandle_t instance,void * addr,int len)507 OF_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. */
541 int
OF_write(ihandle_t instance,void * addr,int len)542 OF_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. */
564 int
OF_seek(ihandle_t instance,uint64_t pos)565 OF_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. */
587 unsigned int
OF_blocks(ihandle_t instance)588 OF_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. */
607 int
OF_block_size(ihandle_t instance)608 OF_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. */
631 void *
OF_claim(void * virt,u_int size,u_int align)632 OF_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. */
654 void
OF_release(void * virt,u_int size)655 OF_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>". */
676 void
OF_boot(char * bootspec)677 OF_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. */
694 void
OF_enter(void)695 OF_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. */
709 void
OF_exit(void)710 OF_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
724 void
OF_quiesce(void)725 OF_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
739 void
740 OF_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
762 void
OF_chain(void * virt,u_int size,void (* entry)(),void * arg,u_int len)763 OF_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