xref: /netbsd-src/sys/arch/sparc/stand/ofwboot/Locore.c (revision 413d532bcc3f62d122e56d92e13ac64825a40baf)
1 /*	$NetBSD: Locore.c,v 1.13 2013/12/18 10:09:56 martin 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 #include <lib/libsa/stand.h>
35 #include "openfirm.h"
36 
37 #include <machine/cpu.h>
38 
39 extern int openfirmware(void *);
40 
41 
42 __dead void
43 _rtt(void)
44 {
45 
46 	OF_exit();
47 }
48 
49 void __attribute__((__noreturn__))
50 OF_exit(void)
51 {
52 	struct {
53 		cell_t name;
54 		cell_t nargs;
55 		cell_t nreturns;
56 	} args;
57 
58 	args.name = ADR2CELL("exit");
59 	args.nargs = 0;
60 	args.nreturns = 0;
61 	openfirmware(&args);
62 
63 	printf("OF_exit failed");
64 	for (;;)
65 		continue;
66 }
67 
68 void
69 OF_enter(void)
70 {
71 	struct {
72 		cell_t name;
73 		cell_t nargs;
74 		cell_t nreturns;
75 	} args;
76 
77 	args.name = ADR2CELL("enter");
78 	args.nargs = 0;
79 	args.nreturns = 0;
80 	openfirmware(&args);
81 }
82 
83 int
84 OF_finddevice(const char *name)
85 {
86 	struct {
87 		cell_t name;
88 		cell_t nargs;
89 		cell_t nreturns;
90 		cell_t device;
91 		cell_t phandle;
92 	} args;
93 
94 	args.name = ADR2CELL("finddevice");
95 	args.nargs = 1;
96 	args.nreturns = 1;
97 	args.device = ADR2CELL(name);
98 	if (openfirmware(&args) == -1)
99 		return -1;
100 	return args.phandle;
101 }
102 
103 int
104 OF_instance_to_package(int ihandle)
105 {
106 	struct {
107 		cell_t name;
108 		cell_t nargs;
109 		cell_t nreturns;
110 		cell_t ihandle;
111 		cell_t phandle;
112 	} args;
113 
114 	args.name = ADR2CELL("instance-to-package");
115 	args.nargs = 1;
116 	args.nreturns = 1;
117 	args.ihandle = HDL2CELL(ihandle);
118 	if (openfirmware(&args) == -1)
119 		return -1;
120 	return args.phandle;
121 }
122 
123 int
124 OF_instance_to_path(int ihandle, char *buf, int buflen)
125 {
126 	struct {
127 		cell_t name;
128 		cell_t nargs;
129 		cell_t nreturns;
130 		cell_t ihandle;
131 		cell_t buf;
132 		cell_t buflen;
133 		cell_t length;
134 	} args;
135 
136 	args.name = ADR2CELL("instance-to-path");
137 	args.nargs = 3;
138 	args.nreturns = 1;
139 	args.ihandle = HDL2CELL(ihandle);
140 	args.buf = ADR2CELL(buf);
141 	args.buflen = buflen;
142 	if (openfirmware(&args) < 0)
143 		return -1;
144 	return args.length;
145 }
146 
147 int
148 OF_getprop(int handle, const char *prop, void *buf, int buflen)
149 {
150 	struct {
151 		cell_t name;
152 		cell_t nargs;
153 		cell_t nreturns;
154 		cell_t phandle;
155 		cell_t prop;
156 		cell_t buf;
157 		cell_t buflen;
158 		cell_t size;
159 	} args;
160 
161 	args.name = ADR2CELL("getprop");
162 	args.nargs = 4;
163 	args.nreturns = 1;
164 	args.phandle = HDL2CELL(handle);
165 	args.prop = ADR2CELL(prop);
166 	args.buf = ADR2CELL(buf);
167 	args.buflen = buflen;
168 	if (openfirmware(&args) == -1)
169 		return -1;
170 	return args.size;
171 }
172 
173 #ifdef	__notyet__	/* Has a bug on FirePower */
174 int
175 OF_setprop(u_int handle, char *prop, void *buf, int len)
176 {
177 	struct {
178 		cell_t name;
179 		cell_t nargs;
180 		cell_t nreturns;
181 		cell_t phandle;
182 		cell_t prop;
183 		cell_t buf;
184 		cell_t len;
185 		cell_t size;
186 	} args;
187 
188 	args.name = ADR2CELL("setprop");
189 	args.nargs = 4;
190 	args.nreturns = 1;
191 	args.phandle = HDL2CELL(handle);
192 	args.prop = ADR2CELL(prop);
193 	args.buf = ADR2CELL(buf);
194 	args.len = len;
195 	if (openfirmware(&args) == -1)
196 		return -1;
197 	return args.size;
198 }
199 #endif
200 
201 int
202 OF_open(const char *dname)
203 {
204 	struct {
205 		cell_t name;
206 		cell_t nargs;
207 		cell_t nreturns;
208 		cell_t dname;
209 		cell_t handle;
210 	} args;
211 
212 	args.name = ADR2CELL("open");
213 	args.nargs = 1;
214 	args.nreturns = 1;
215 	args.dname = ADR2CELL(dname);
216 	if (openfirmware(&args) == -1 ||
217 	    args.handle == 0)
218 		return -1;
219 	return args.handle;
220 }
221 
222 void
223 OF_close(int handle)
224 {
225 	struct {
226 		cell_t name;
227 		cell_t nargs;
228 		cell_t nreturns;
229 		cell_t handle;
230 	} args;
231 
232 	args.name = ADR2CELL("close");
233 	args.nargs = 1;
234 	args.nreturns = 0;
235 	args.handle = HDL2CELL(handle);
236 	openfirmware(&args);
237 }
238 
239 int
240 OF_write(int handle, const void *addr, int len)
241 {
242 	struct {
243 		cell_t name;
244 		cell_t nargs;
245 		cell_t nreturns;
246 		cell_t ihandle;
247 		cell_t addr;
248 		cell_t len;
249 		cell_t actual;
250 	} args;
251 
252 	args.name = ADR2CELL("write");
253 	args.nargs = 3;
254 	args.nreturns = 1;
255 	args.ihandle = HDL2CELL(handle);
256 	args.addr = ADR2CELL(addr);
257 	args.len = len;
258 	if (openfirmware(&args) == -1)
259 		return -1;
260 	return args.actual;
261 }
262 
263 int
264 OF_read(int handle, void *addr, int len)
265 {
266 	struct {
267 		cell_t name;
268 		cell_t nargs;
269 		cell_t nreturns;
270 		cell_t ihandle;
271 		cell_t addr;
272 		cell_t len;
273 		cell_t actual;
274 	} args;
275 
276 	args.name = ADR2CELL("read");
277 	args.nargs = 3;
278 	args.nreturns = 1;
279 	args.ihandle = HDL2CELL(handle);
280 	args.addr = ADR2CELL(addr);
281 	args.len = len;
282 	if (openfirmware(&args) == -1) {
283 		return -1;
284 	}
285 	return args.actual;
286 }
287 
288 int
289 OF_seek(int handle, u_quad_t pos)
290 {
291 	struct {
292 		cell_t name;
293 		cell_t nargs;
294 		cell_t nreturns;
295 		cell_t handle;
296 		cell_t poshi;
297 		cell_t poslo;
298 		cell_t status;
299 	} args;
300 
301 	args.name = ADR2CELL("seek");
302 	args.nargs = 3;
303 	args.nreturns = 1;
304 	args.handle = HDL2CELL(handle);
305 	args.poshi = HDL2CELL(pos >> 32);
306 	args.poslo = HDL2CELL(pos);
307 	if (openfirmware(&args) == -1) {
308 		return -1;
309 	}
310 	return args.status;
311 }
312 
313 void
314 OF_release(void *virt, u_int size)
315 {
316 	struct {
317 		cell_t name;
318 		cell_t nargs;
319 		cell_t nreturns;
320 		cell_t virt;
321 		cell_t size;
322 	} args;
323 
324 	args.name = ADR2CELL("release");
325 	args.nargs = 2;
326 	args.nreturns = 0;
327 	args.virt = ADR2CELL(virt);
328 	args.size = size;
329 	openfirmware(&args);
330 }
331 
332 int
333 OF_milliseconds(void)
334 {
335 	struct {
336 		cell_t name;
337 		cell_t nargs;
338 		cell_t nreturns;
339 		cell_t ms;
340 	} args;
341 
342 	args.name = ADR2CELL("milliseconds");
343 	args.nargs = 0;
344 	args.nreturns = 1;
345 	openfirmware(&args);
346 	return args.ms;
347 }
348 
349 int
350 OF_peer(int phandle)
351 {
352 	struct {
353 		cell_t name;
354 		cell_t nargs;
355 		cell_t nreturns;
356 		cell_t phandle;
357 		cell_t sibling;
358 	} args;
359 
360 	args.name = ADR2CELL("peer");
361 	args.nargs = 1;
362 	args.nreturns = 1;
363 	args.phandle = HDL2CELL(phandle);
364 	if (openfirmware(&args) == -1)
365 		return 0;
366 	return args.sibling;
367 }
368 
369 int
370 OF_child(int phandle)
371 {
372 	struct {
373 		cell_t name;
374 		cell_t nargs;
375 		cell_t nreturns;
376 		cell_t phandle;
377 		cell_t child;
378 	} args;
379 
380 	args.name = ADR2CELL("child");
381 	args.nargs = 1;
382 	args.nreturns = 1;
383 	args.phandle = HDL2CELL(phandle);
384 	if (openfirmware(&args) == -1)
385 		return 0;
386 	return args.child;
387 }
388 
389 static u_int mmuh = -1;
390 static u_int memh = -1;
391 
392 void
393 OF_initialize(void)
394 {
395 	u_int chosen;
396 
397 	if ( (chosen = OF_finddevice("/chosen")) == -1) {
398 		OF_exit();
399 	}
400 	if (OF_getprop(chosen, "mmu", &mmuh, sizeof(mmuh)) != sizeof(mmuh)
401 	    || OF_getprop(chosen, "memory", &memh, sizeof(memh)) != sizeof(memh))
402 		OF_exit();
403 }
404 
405 /*
406  * The following need either the handle to memory or the handle to the MMU.
407  */
408 
409 /*
410  * Grab some address space from the prom
411  *
412  * Only works while the prom is actively mapping us.
413  */
414 vaddr_t
415 OF_claim_virt(vaddr_t vaddr, int len)
416 {
417 	struct {
418 		cell_t name;
419 		cell_t nargs;
420 		cell_t nreturns;
421 		cell_t method;
422 		cell_t ihandle;
423 		cell_t align;
424 		cell_t len;
425 		cell_t vaddr;
426 		cell_t status;
427 		cell_t retaddr;
428 	} args;
429 
430 #ifdef	__notyet
431 	if (mmuh == -1 && ((mmuh = get_mmu_handle()) == -1)) {
432 		OF_printf("OF_claim_virt: cannot get mmuh\r\n");
433 		return -1LL;
434 	}
435 #endif
436 	args.name = ADR2CELL("call-method");
437 	args.nargs = 5;
438 	args.nreturns = 2;
439 	args.method = ADR2CELL("claim");
440 	args.ihandle = HDL2CELL(mmuh);
441 	args.align = 0;
442 	args.len = len;
443 	args.vaddr = ADR2CELL(vaddr);
444 	if (openfirmware(&args) != 0)
445 		return -1LL;
446 	return (vaddr_t)args.retaddr;
447 }
448 
449 /*
450  * Request some address space from the prom
451  *
452  * Only works while the prom is actively mapping us.
453  */
454 vaddr_t
455 OF_alloc_virt(int len, int align)
456 {
457 	int retaddr=-1;
458 	struct {
459 		cell_t name;
460 		cell_t nargs;
461 		cell_t nreturns;
462 		cell_t method;
463 		cell_t ihandle;
464 		cell_t align;
465 		cell_t len;
466 		cell_t status;
467 		cell_t retaddr;
468 	} args;
469 
470 #ifdef	__notyet
471 	if (mmuh == -1 && ((mmuh = get_mmu_handle()) == -1)) {
472 		OF_printf("OF_alloc_virt: cannot get mmuh\r\n");
473 		return -1LL;
474 	}
475 #endif
476 	args.name = ADR2CELL("call-method");
477 	args.nargs = 4;
478 	args.nreturns = 2;
479 	args.method = ADR2CELL("claim");
480 	args.ihandle = HDL2CELL(mmuh);
481 	args.align = align;
482 	args.len = len;
483 	args.retaddr = ADR2CELL(&retaddr);
484 	if (openfirmware(&args) != 0)
485 		return -1LL;
486 	return (vaddr_t)args.retaddr;
487 }
488 
489 /*
490  * Release some address space to the prom
491  *
492  * Only works while the prom is actively mapping us.
493  */
494 int
495 OF_free_virt(vaddr_t vaddr, int len)
496 {
497 	struct {
498 		cell_t name;
499 		cell_t nargs;
500 		cell_t nreturns;
501 		cell_t method;
502 		cell_t ihandle;
503 		cell_t len;
504 		cell_t vaddr;
505 	} args;
506 
507 #ifdef	__notyet
508 	if (mmuh == -1 && ((mmuh = get_mmu_handle()) == -1)) {
509 		OF_printf("OF_claim_virt: cannot get mmuh\r\n");
510 		return -1;
511 	}
512 #endif
513 	args.name = ADR2CELL("call-method");
514 	args.nargs = 4;
515 	args.nreturns = 0;
516 	args.method = ADR2CELL("release");
517 	args.ihandle = HDL2CELL(mmuh);
518 	args.vaddr = ADR2CELL(vaddr);
519 	args.len = len;
520 	return openfirmware(&args);
521 }
522 
523 
524 /*
525  * Unmap some address space
526  *
527  * Only works while the prom is actively mapping us.
528  */
529 int
530 OF_unmap_virt(vaddr_t vaddr, int len)
531 {
532 	struct {
533 		cell_t name;
534 		cell_t nargs;
535 		cell_t nreturns;
536 		cell_t method;
537 		cell_t ihandle;
538 		cell_t len;
539 		cell_t vaddr;
540 	} args;
541 
542 #ifdef	__notyet
543 	if (mmuh == -1 && ((mmuh = get_mmu_handle()) == -1)) {
544 		OF_printf("OF_claim_virt: cannot get mmuh\r\n");
545 		return -1;
546 	}
547 #endif
548 	args.name = ADR2CELL("call-method");
549 	args.nargs = 4;
550 	args.nreturns = 0;
551 	args.method = ADR2CELL("unmap");
552 	args.ihandle = HDL2CELL(mmuh);
553 	args.vaddr = ADR2CELL(vaddr);
554 	args.len = len;
555 	return openfirmware(&args);
556 }
557 
558 /*
559  * Have prom map in some memory
560  *
561  * Only works while the prom is actively mapping us.
562  */
563 vaddr_t
564 OF_map_phys(paddr_t paddr, off_t size, vaddr_t vaddr, int mode)
565 {
566 	struct {
567 		cell_t name;
568 		cell_t nargs;
569 		cell_t nreturns;
570 		cell_t method;
571 		cell_t ihandle;
572 		cell_t mode;
573 		cell_t size;
574 		cell_t vaddr;
575 		cell_t paddr_hi;
576 		cell_t paddr_lo;
577 		cell_t status;
578 		cell_t retaddr;
579 	} args;
580 
581 #ifdef	__notyet
582 	if (mmuh == -1 && ((mmuh = get_mmu_handle()) == -1)) {
583 		OF_printf("OF_map_phys: cannot get mmuh\r\n");
584 		return 0LL;
585 	}
586 #endif
587 	args.name = ADR2CELL("call-method");
588 	args.nargs = 7;
589 	args.nreturns = 1;
590 	args.method = ADR2CELL("map");
591 	args.ihandle = HDL2CELL(mmuh);
592 	args.mode = mode;
593 	args.size = size;
594 	args.vaddr = ADR2CELL(vaddr);
595 	args.paddr_hi = HDQ2CELL_HI(paddr);
596 	args.paddr_lo = HDQ2CELL_LO(paddr);
597 
598 	if (openfirmware(&args) == -1)
599 		return -1;
600 	if (args.status)
601 		return -1;
602 	return (vaddr_t)args.retaddr;
603 }
604 
605 
606 /*
607  * Request some RAM from the prom
608  *
609  * Only works while the prom is actively mapping us.
610  */
611 paddr_t
612 OF_alloc_phys(int len, int align)
613 {
614 	struct {
615 		cell_t name;
616 		cell_t nargs;
617 		cell_t nreturns;
618 		cell_t method;
619 		cell_t ihandle;
620 		cell_t align;
621 		cell_t len;
622 		cell_t status;
623 		cell_t phys_hi;
624 		cell_t phys_lo;
625 	} args;
626 
627 #ifdef	__notyet
628 	if (memh == -1 && ((memh = get_memory_handle()) == -1)) {
629 		OF_printf("OF_alloc_phys: cannot get memh\r\n");
630 		return -1LL;
631 	}
632 #endif
633 	args.name = ADR2CELL("call-method");
634 	args.nargs = 4;
635 	args.nreturns = 3;
636 	args.method = ADR2CELL("claim");
637 	args.ihandle = HDL2CELL(memh);
638 	args.align = align;
639 	args.len = len;
640 	if (openfirmware(&args) != 0)
641 		return -1LL;
642 	return (paddr_t)CELL2HDQ(args.phys_hi, args.phys_lo);
643 }
644 
645 /*
646  * Request some specific RAM from the prom
647  *
648  * Only works while the prom is actively mapping us.
649  */
650 paddr_t
651 OF_claim_phys(paddr_t phys, int len)
652 {
653 	struct {
654 		cell_t name;
655 		cell_t nargs;
656 		cell_t nreturns;
657 		cell_t method;
658 		cell_t ihandle;
659 		cell_t align;
660 		cell_t len;
661 		cell_t phys_hi;
662 		cell_t phys_lo;
663 		cell_t status;
664 		cell_t res;
665 		cell_t rphys_hi;
666 		cell_t rphys_lo;
667 	} args;
668 
669 #ifdef	__notyet
670 	if (memh == -1 && ((memh = get_memory_handle()) == -1)) {
671 		OF_printf("OF_alloc_phys: cannot get memh\r\n");
672 		return 0LL;
673 	}
674 #endif
675 	args.name = ADR2CELL("call-method");
676 	args.nargs = 6;
677 	args.nreturns = 4;
678 	args.method = ADR2CELL("claim");
679 	args.ihandle = HDL2CELL(memh);
680 	args.align = 0;
681 	args.len = len;
682 	args.phys_hi = HDQ2CELL_HI(phys);
683 	args.phys_lo = HDQ2CELL_LO(phys);
684 	if (openfirmware(&args) != 0)
685 		return 0LL;
686 	return (paddr_t)CELL2HDQ(args.rphys_hi, args.rphys_lo);
687 }
688 
689 /*
690  * Free some RAM to prom
691  *
692  * Only works while the prom is actively mapping us.
693  */
694 int
695 OF_free_phys(paddr_t phys, int len)
696 {
697 	struct {
698 		cell_t name;
699 		cell_t nargs;
700 		cell_t nreturns;
701 		cell_t method;
702 		cell_t ihandle;
703 		cell_t len;
704 		cell_t phys_hi;
705 		cell_t phys_lo;
706 	} args;
707 
708 #ifdef	__notyet
709 	if (memh == -1 && ((memh = get_memory_handle()) == -1)) {
710 		OF_printf("OF_free_phys: cannot get memh\r\n");
711 		return -1;
712 	}
713 #endif
714 	args.name = ADR2CELL("call-method");
715 	args.nargs = 5;
716 	args.nreturns = 0;
717 	args.method = ADR2CELL("release");
718 	args.ihandle = HDL2CELL(memh);
719 	args.len = len;
720 	args.phys_hi = HDQ2CELL_HI(phys);
721 	args.phys_lo = HDQ2CELL_LO(phys);
722 	return openfirmware(&args);
723 }
724 
725 
726 /*
727  * Claim virtual memory -- does not map it in.
728  */
729 
730 void *
731 OF_claim(void *virt, u_int size, u_int align)
732 {
733 #define SUNVMOF
734 #ifndef SUNVMOF
735 	struct {
736 		cell_t name;
737 		cell_t nargs;
738 		cell_t nreturns;
739 		cell_t virt;
740 		cell_t size;
741 		cell_t align;
742 		cell_t baseaddr;
743 	} args;
744 
745 
746 	args.name = ADR2CELL("claim");
747 	args.nargs = 3;
748 	args.nreturns = 1;
749 	args.virt = virt;
750 	args.size = size;
751 	args.align = align;
752 	if (openfirmware(&args) == -1)
753 		return (void *)-1;
754 	return args.baseaddr;
755 #else
756 /*
757  * Sun Ultra machines run the firmware with VM enabled,
758  * so you need to handle allocating and mapping both
759  * virtual and physical memory.  Ugh.
760  */
761 
762 	paddr_t paddr;
763 	void* newvirt = NULL;
764 
765 	if (virt == NULL) {
766 		if ((virt = (void*)OF_alloc_virt(size, align)) == (void*)-1) {
767 			printf("OF_alloc_virt(%d,%d) failed w/%p\n", size, align, virt);
768 			return (void *)-1;
769 		}
770 	} else {
771 		if ((newvirt = (void*)OF_claim_virt((vaddr_t)virt, size)) == (void*)-1) {
772 			printf("OF_claim_virt(%p,%d) failed w/%p\n", virt, size, newvirt);
773 			return (void *)-1;
774 		}
775 	}
776 	if ((paddr = OF_alloc_phys(size, align)) == (paddr_t)-1) {
777 		printf("OF_alloc_phys(%d,%d) failed\n", size, align);
778 		OF_free_virt((vaddr_t)virt, size);
779 		return (void *)-1;
780 	}
781 	if (OF_map_phys(paddr, size, (vaddr_t)virt, -1) == -1) {
782 		printf("OF_map_phys(0x%lx,%d,%p,%d) failed\n",
783 		    (u_long)paddr, size, virt, -1);
784 		OF_free_phys((paddr_t)paddr, size);
785 		OF_free_virt((vaddr_t)virt, size);
786 		return (void *)-1;
787 	}
788 	return (void *)virt;
789 #endif
790 }
791