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