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