xref: /netbsd/sys/arch/macppc/stand/ofwboot/Locore.c (revision 3e99b94d)
1 /*	$NetBSD: Locore.c,v 1.33 2018/11/12 20:00:46 scole 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 <sys/param.h>
35 #include <lib/libsa/stand.h>
36 
37 #include <machine/cpu.h>
38 #include <powerpc/oea/spr.h>
39 
40 #include "openfirm.h"
41 
42 static int (*openfirmware)(void *);
43 
44 static void startup(void *, int, int (*)(void *), char *, int)
45 		__attribute__((__used__));
46 static void setup(void);
47 
48 #ifdef HEAP_VARIABLE
49 #ifndef HEAP_SIZE
50 #define HEAP_SIZE 0x20000
51 #endif
52 char *heapspace;
53 #endif
54 
55 static int stack[8192/4 + 4] __attribute__((__used__));
56 
57 #ifdef XCOFF_GLUE
58 __asm(
59 "	.text			\n"
60 "	.globl	_entry		\n"
61 "_entry:			\n"
62 "	.long	_start,0,0	\n"
63 );
64 #endif /* XCOFF_GLUE */
65 
66 __asm(
67 "	.text			\n"
68 "	.globl	_start		\n"
69 "_start:			\n"
70 "	sync			\n"
71 "	isync			\n"
72 "	lis	%r1,stack@ha	\n"
73 "	addi	%r1,%r1,stack@l	\n"
74 "	addi	%r1,%r1,8192	\n"
75 "				\n"
76 "	mfmsr	%r8		\n"
77 "	li	%r0,0		\n"
78 "	mtmsr	%r0		\n"
79 "	isync			\n"
80 "				\n"
81 "				\n" /* test for 601 */
82 "	mfspr	%r0,287		\n" /* mfpvbr %r0 PVR = 287 */
83 "	srwi	%r0,%r0,0x10	\n"
84 "	cmplwi	%r0,0x02	\n" /* 601 CPU = 0x0001 */
85 "	blt	2f		\n" /* skip over non-601 BAT setup */
86 "	cmplwi	%r0,0x39	\n" /* PPC970 */
87 "	blt	0f		\n"
88 "	cmplwi	%r0,0x45	\n" /* PPC970GX */
89 "	ble	1f		\n"
90 	/* non PPC 601 BATs */
91 "0:	li	%r0,0		\n"
92 "	mtibatu	0,%r0		\n"
93 "	mtibatu	1,%r0		\n"
94 "	mtibatu	2,%r0		\n"
95 "	mtibatu	3,%r0		\n"
96 "	mtdbatu	0,%r0		\n"
97 "	mtdbatu	1,%r0		\n"
98 "	mtdbatu	2,%r0		\n"
99 "	mtdbatu	3,%r0		\n"
100 "				\n"
101 "	li	%r9,0x12	\n"	/* BATL(0, BAT_M, BAT_PP_RW) */
102 "	mtibatl	0,%r9		\n"
103 "	mtdbatl	0,%r9		\n"
104 "	li	%r9,0x1ffe	\n"	/* BATU(0, BAT_BL_256M, BAT_Vs) */
105 "	mtibatu	0,%r9		\n"
106 "	mtdbatu	0,%r9		\n"
107 "	b	3f		\n"
108 	/* 970 initialization stuff */
109 "1:				\n"
110 	/* make sure we're in bridge mode */
111 "	clrldi	%r8,%r8,3	\n"
112 "	mtmsrd	%r8		\n"
113 "	isync			\n"
114 	 /* clear HID5 DCBZ bits (56/57), need to do this early */
115 "	mfspr	%r9,0x3f6	\n"
116 "	rldimi	%r9,0,6,56	\n"
117 "	sync			\n"
118 "	mtspr	0x3f6,%r9	\n"
119 "	isync			\n"
120 "	sync			\n"
121 	/* Setup HID1 features, prefetch + i-cacheability controlled by PTE */
122 "	mfspr	%r9,0x3f1	\n"
123 "	li	%r11,0x1200	\n"
124 "	sldi	%r11,%r11,44	\n"
125 "	or	%r9,%r9,%r11	\n"
126 "	mtspr	0x3f1,%r9	\n"
127 "	isync			\n"
128 "	sync			\n"
129 "	b	3f		\n"
130 	/* PPC 601 BATs */
131 "2:	li	%r0,0		\n"
132 "	mtibatu	0,%r0		\n"
133 "	mtibatu	1,%r0		\n"
134 "	mtibatu	2,%r0		\n"
135 "	mtibatu	3,%r0		\n"
136 "				\n"
137 "	li	%r9,0x7f	\n"
138 "	mtibatl	0,%r9		\n"
139 "	li	%r9,0x1a	\n"
140 "	mtibatu	0,%r9		\n"
141 "				\n"
142 "	lis	%r9,0x80	\n"
143 "	addi	%r9,%r9,0x7f	\n"
144 "	mtibatl	1,%r9		\n"
145 "	lis	%r9,0x80	\n"
146 "	addi	%r9,%r9,0x1a	\n"
147 "	mtibatu	1,%r9		\n"
148 "				\n"
149 "	lis	%r9,0x100	\n"
150 "	addi	%r9,%r9,0x7f	\n"
151 "	mtibatl	2,%r9		\n"
152 "	lis	%r9,0x100	\n"
153 "	addi	%r9,%r9,0x1a	\n"
154 "	mtibatu	2,%r9		\n"
155 "				\n"
156 "	lis	%r9,0x180	\n"
157 "	addi	%r9,%r9,0x7f	\n"
158 "	mtibatl	3,%r9		\n"
159 "	lis	%r9,0x180	\n"
160 "	addi	%r9,%r9,0x1a	\n"
161 "	mtibatu	3,%r9		\n"
162 "				\n"
163 "3:	isync			\n"
164 "				\n"
165 "	mtmsr	%r8		\n"
166 "	isync			\n"
167 "				\n"
168 	/*
169 	 * Make sure that .bss is zeroed
170 	 */
171 "				\n"
172 "	li	%r0,0		\n"
173 "	lis	%r8,_edata@ha	\n"
174 "	addi	%r8,%r8,_edata@l\n"
175 "	lis	%r9,_end@ha	\n"
176 "	addi	%r9,%r9,_end@l	\n"
177 "				\n"
178 "5:	cmpw	0,%r8,%r9	\n"
179 "	bge	6f		\n"
180 	/*
181 	 * clear by bytes to avoid ppc601 alignment exceptions
182 	 */
183 "	stb	%r0,0(%r8)	\n"
184 "	stb	%r0,1(%r8)	\n"
185 "	stb	%r0,2(%r8)	\n"
186 "	stb	%r0,3(%r8)	\n"
187 "	addi	%r8,%r8,4	\n"
188 "	b	5b		\n"
189 "				\n"
190 "6:	b	startup		\n"
191 );
192 
193 #if 0
194 static int
195 openfirmware(void *arg)
196 {
197 
198 	__asm volatile ("sync; isync");
199 	openfirmware_entry(arg);
200 	__asm volatile ("sync; isync");
201 }
202 #endif
203 
204 static void
205 startup(void *vpd, int res, int (*openfirm)(void *), char *arg, int argl)
206 {
207 
208 	openfirmware = openfirm;
209 	setup();
210 	main();
211 	OF_exit();
212 }
213 
214 #if 0
215 void
216 OF_enter(void)
217 {
218 	static struct {
219 		const char *name;
220 		int nargs;
221 		int nreturns;
222 	} args = {
223 		"enter",
224 		0,
225 		0
226 	};
227 
228 	openfirmware(&args);
229 }
230 #endif	/* OF_enter */
231 
232 __dead void
233 OF_exit(void)
234 {
235 	static struct {
236 		const char *name;
237 		int nargs;
238 		int nreturns;
239 	} args = {
240 		"exit",
241 		0,
242 		0
243 	};
244 
245 	openfirmware(&args);
246 	for (;;);			/* just in case */
247 }
248 
249 int
250 OF_finddevice(const char *name)
251 {
252 	static struct {
253 		const char *name;
254 		int nargs;
255 		int nreturns;
256 		const char *device;
257 		int phandle;
258 	} args = {
259 		"finddevice",
260 		1,
261 		1,
262 	};
263 
264 	args.device = name;
265 	if (openfirmware(&args) == -1)
266 		return -1;
267 	return args.phandle;
268 }
269 
270 int
271 OF_instance_to_package(int ihandle)
272 {
273 	static struct {
274 		const char *name;
275 		int nargs;
276 		int nreturns;
277 		int ihandle;
278 		int phandle;
279 	} args = {
280 		"instance-to-package",
281 		1,
282 		1,
283 	};
284 
285 	args.ihandle = ihandle;
286 	if (openfirmware(&args) == -1)
287 		return -1;
288 	return args.phandle;
289 }
290 
291 int
292 OF_getprop(int handle, const char *prop, void *buf, int buflen)
293 {
294 	static struct {
295 		const char *name;
296 		int nargs;
297 		int nreturns;
298 		int phandle;
299 		const char *prop;
300 		void *buf;
301 		int buflen;
302 		int size;
303 	} args = {
304 		"getprop",
305 		4,
306 		1,
307 	};
308 
309 	args.phandle = handle;
310 	args.prop = prop;
311 	args.buf = buf;
312 	args.buflen = buflen;
313 	if (openfirmware(&args) == -1)
314 		return -1;
315 	return args.size;
316 }
317 
318 #ifdef	__notyet__	/* Has a bug on FirePower */
319 int
320 OF_setprop(int handle, const char *prop, void *buf, int len)
321 {
322 	static struct {
323 		const char *name;
324 		int nargs;
325 		int nreturns;
326 		int phandle;
327 		const char *prop;
328 		void *buf;
329 		int len;
330 		int size;
331 	} args = {
332 		"setprop",
333 		4,
334 		1,
335 	};
336 
337 	args.phandle = handle;
338 	args.prop = prop;
339 	args.buf = buf;
340 	args.len = len;
341 	if (openfirmware(&args) == -1)
342 		return -1;
343 	return args.size;
344 }
345 #endif
346 
347 int
348 OF_open(const char *dname)
349 {
350 	static struct {
351 		const char *name;
352 		int nargs;
353 		int nreturns;
354 		const char *dname;
355 		int handle;
356 	} args = {
357 		"open",
358 		1,
359 		1,
360 	};
361 
362 #ifdef OFW_DEBUG
363 	printf("OF_open(%s) -> ", dname);
364 #endif
365 	args.dname = dname;
366 	if (openfirmware(&args) == -1 ||
367 	    args.handle == 0) {
368 #ifdef OFW_DEBUG
369 		printf("lose\n");
370 #endif
371 		return -1;
372 	}
373 #ifdef OFW_DEBUG
374 	printf("%d\n", args.handle);
375 #endif
376 	return args.handle;
377 }
378 
379 void
380 OF_close(int handle)
381 {
382 	static struct {
383 		const char *name;
384 		int nargs;
385 		int nreturns;
386 		int handle;
387 	} args = {
388 		"close",
389 		1,
390 		0,
391 	};
392 
393 #ifdef OFW_DEBUG
394 	printf("OF_close(%d)\n", handle);
395 #endif
396 	args.handle = handle;
397 	openfirmware(&args);
398 }
399 
400 int
401 OF_write(int handle, void *addr, int len)
402 {
403 	static struct {
404 		const char *name;
405 		int nargs;
406 		int nreturns;
407 		int ihandle;
408 		void *addr;
409 		int len;
410 		int actual;
411 	} args = {
412 		"write",
413 		3,
414 		1,
415 	};
416 
417 #ifdef OFW_DEBUG
418 	if (len != 1)
419 		printf("OF_write(%d, %p, %x) -> ", handle, addr, len);
420 #endif
421 	args.ihandle = handle;
422 	args.addr = addr;
423 	args.len = len;
424 	if (openfirmware(&args) == -1) {
425 #ifdef OFW_DEBUG
426 		printf("lose\n");
427 #endif
428 		return -1;
429 	}
430 #ifdef OFW_DEBUG
431 	if (len != 1)
432 		printf("%x\n", args.actual);
433 #endif
434 	return args.actual;
435 }
436 
437 int
438 OF_read(int handle, void *addr, int len)
439 {
440 	static struct {
441 		const char *name;
442 		int nargs;
443 		int nreturns;
444 		int ihandle;
445 		void *addr;
446 		int len;
447 		int actual;
448 	} args = {
449 		"read",
450 		3,
451 		1,
452 	};
453 
454 #ifdef OFW_DEBUG
455 	if (len != 1)
456 		printf("OF_read(%d, %p, %x) -> ", handle, addr, len);
457 #endif
458 	args.ihandle = handle;
459 	args.addr = addr;
460 	args.len = len;
461 	if (openfirmware(&args) == -1) {
462 #ifdef OFW_DEBUG
463 		printf("lose\n");
464 #endif
465 		return -1;
466 	}
467 #ifdef OFW_DEBUG
468 	if (len != 1)
469 		printf("%x\n", args.actual);
470 #endif
471 	return args.actual;
472 }
473 
474 int
475 OF_seek(int handle, u_quad_t pos)
476 {
477 	static struct {
478 		const char *name;
479 		int nargs;
480 		int nreturns;
481 		int handle;
482 		int poshi;
483 		int poslo;
484 		int status;
485 	} args = {
486 		"seek",
487 		3,
488 		1,
489 	};
490 
491 #ifdef OFW_DEBUG
492 	printf("OF_seek(%d, %x, %x) -> ", handle, (int)(pos >> 32), (int)pos);
493 #endif
494 	args.handle = handle;
495 	args.poshi = (int)(pos >> 32);
496 	args.poslo = (int)pos;
497 	if (openfirmware(&args) == -1) {
498 #ifdef OFW_DEBUG
499 		printf("lose\n");
500 #endif
501 		return -1;
502 	}
503 #ifdef OFW_DEBUG
504 	printf("%d\n", args.status);
505 #endif
506 	return args.status;
507 }
508 
509 void *
510 OF_claim(void *virt, u_int size, u_int align)
511 {
512 	static struct {
513 		const char *name;
514 		int nargs;
515 		int nreturns;
516 		void *virt;
517 		u_int size;
518 		u_int align;
519 		void *baseaddr;
520 	} args = {
521 		"claim",
522 		3,
523 		1,
524 	};
525 
526 #ifdef OFW_DEBUG
527 	printf("OF_claim(%p, %x, %x) -> ", virt, size, align);
528 #endif
529 	args.virt = virt;
530 	args.size = size;
531 	args.align = align;
532 	if (openfirmware(&args) == -1) {
533 #ifdef OFW_DEBUG
534 		printf("lose\n");
535 #endif
536 		return (void *)-1;
537 	}
538 #ifdef OFW_DEBUG
539 	printf("%p\n", args.baseaddr);
540 #endif
541 	return args.baseaddr;
542 }
543 
544 void
545 OF_release(void *virt, u_int size)
546 {
547 	static struct {
548 		const char *name;
549 		int nargs;
550 		int nreturns;
551 		void *virt;
552 		u_int size;
553 	} args = {
554 		"release",
555 		2,
556 		0,
557 	};
558 
559 #ifdef OFW_DEBUG
560 	printf("OF_release(%p, %x)\n", virt, size);
561 #endif
562 	args.virt = virt;
563 	args.size = size;
564 	openfirmware(&args);
565 }
566 
567 int
568 OF_milliseconds(void)
569 {
570 	static struct {
571 		const char *name;
572 		int nargs;
573 		int nreturns;
574 		int ms;
575 	} args = {
576 		"milliseconds",
577 		0,
578 		1,
579 	};
580 
581 	openfirmware(&args);
582 	return args.ms;
583 }
584 
585 #ifdef	__notyet__
586 void
587 OF_chain(void *virt, u_int size, void (*entry)(), void *arg, u_int len)
588 {
589 	static struct {
590 		const char *name;
591 		int nargs;
592 		int nreturns;
593 		void *virt;
594 		u_int size;
595 		void (*entry)();
596 		void *arg;
597 		u_int len;
598 	} args = {
599 		"chain",
600 		5,
601 		0,
602 	};
603 
604 	args.virt = virt;
605 	args.size = size;
606 	args.entry = entry;
607 	args.arg = arg;
608 	args.len = len;
609 	openfirmware(&args);
610 }
611 #else
612 void
613 OF_chain(void *virt, u_int size, boot_entry_t entry, void *arg, u_int len)
614 {
615 	/*
616 	 * This is a REALLY dirty hack till the firmware gets this going
617 	 */
618 #if 0
619 	OF_release(virt, size);
620 #endif
621 	entry(0, 0, openfirmware, arg, len);
622 }
623 #endif
624 
625 int
626 OF_call_method(const char *method, int ihandle, int nargs, int nreturns, ...)
627 {
628 	va_list ap;
629 	static struct {
630 		const char *name;
631 		int nargs;
632 		int nreturns;
633 		const char *method;
634 		int ihandle;
635 		int args_n_results[12];
636 	} args = {
637 		"call-method",
638 		2,
639 		1,
640 	};
641 	int *ip, n;
642 
643 	if (nargs > 6)
644 		return -1;
645 	args.nargs = nargs + 2;
646 	args.nreturns = nreturns + 1;
647 	args.method = method;
648 	args.ihandle = ihandle;
649 	va_start(ap, nreturns);
650 	for (ip = args.args_n_results + (n = nargs); --n >= 0;)
651 		*--ip = va_arg(ap, int);
652 
653 	if (openfirmware(&args) == -1) {
654 		va_end(ap);
655 		return -1;
656 	}
657 	if (args.args_n_results[nargs]) {
658 		va_end(ap);
659 		return args.args_n_results[nargs];
660 	}
661 	for (ip = args.args_n_results + nargs + (n = args.nreturns); --n > 0;)
662 		*va_arg(ap, int *) = *--ip;
663 	va_end(ap);
664 	return 0;
665 }
666 
667 static int stdin;
668 static int stdout;
669 
670 static void
671 setup(void)
672 {
673 	int chosen;
674 
675 	if ((chosen = OF_finddevice("/chosen")) == -1)
676 		OF_exit();
677 	if (OF_getprop(chosen, "stdin", &stdin, sizeof(stdin)) !=
678 	    sizeof(stdin) ||
679 	    OF_getprop(chosen, "stdout", &stdout, sizeof(stdout)) !=
680 	    sizeof(stdout))
681 		OF_exit();
682 
683 #ifdef HEAP_VARIABLE
684 	uint32_t pvr, vers, hsize = HEAP_SIZE;
685 
686 	__asm volatile ("mfpvr %0" : "=r"(pvr));
687 	vers = pvr >> 16;
688 	if (vers >= IBM970 && vers <= IBM970GX) hsize = 0x800000;
689 
690 	heapspace = OF_claim(0, hsize, NBPG);
691 	if (heapspace == (char *)-1) {
692 		panic("Failed to allocate heap");
693 	}
694 
695 	setheap(heapspace, heapspace + HEAP_SIZE);
696 #endif	/* HEAP_VARIABLE */
697 }
698 
699 void
700 putchar(int c)
701 {
702 	char ch = c;
703 
704 	if (c == '\n')
705 		putchar('\r');
706 	OF_write(stdout, &ch, 1);
707 }
708 
709 int
710 getchar(void)
711 {
712 	unsigned char ch = '\0';
713 	int l;
714 
715 	while ((l = OF_read(stdin, &ch, 1)) != 1)
716 		if (l != -2 && l != 0)
717 			return -1;
718 	return ch;
719 }
720