1/*	$NetBSD: Locore.c,v 1.35 2021/02/28 20:27:40 thorpej 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
42static int (*openfirmware)(void *);
43
44static void startup(void *, int, int (*)(void *), char *, int)
45		__attribute__((__used__));
46static void setup(void);
47
48#ifdef HEAP_VARIABLE
49#ifndef HEAP_SIZE
50#define HEAP_SIZE 0x20000
51#endif
52char *heapspace;
53#endif
54
55static 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
194static int
195openfirmware(void *arg)
196{
197
198	__asm volatile ("sync; isync");
199	openfirmware_entry(arg);
200	__asm volatile ("sync; isync");
201}
202#endif
203
204int	ofw_real_mode;
205int	ofw_address_cells;
206int	ofw_size_cells;
207
208int	ofw_root;		/* / */
209int	ofw_options;		/* /options */
210int	ofw_openprom;		/* /openprom */
211int	ofw_chosen;		/* /chosen (package) */
212int	ofw_stdin;		/* /chosen/stdin */
213int	ofw_stdout;		/* /chosen/stdout */
214int	ofw_memory_ihandle;	/* /chosen/memory */
215int	ofw_mmu_ihandle;	/* /chosen/mmu */
216
217bool
218ofw_option_truefalse(const char *prop, int proplen)
219{
220	/* These are all supposed to be strings. */
221	switch (prop[0]) {
222	case 'y':
223	case 'Y':
224	case 't':
225	case 'T':
226	case '1':
227		return true;
228	}
229	return false;
230}
231
232static void
233startup(void *vpd, int res, int (*openfirm)(void *), char *arg, int argl)
234{
235
236	openfirmware = openfirm;
237	setup();
238	main();
239	OF_exit();
240}
241
242#if 0
243void
244OF_enter(void)
245{
246	static struct {
247		const char *name;
248		int nargs;
249		int nreturns;
250	} args = {
251		"enter",
252		0,
253		0
254	};
255
256	openfirmware(&args);
257}
258#endif	/* OF_enter */
259
260__dead void
261OF_exit(void)
262{
263	static struct {
264		const char *name;
265		int nargs;
266		int nreturns;
267	} args = {
268		"exit",
269		0,
270		0
271	};
272
273	openfirmware(&args);
274	for (;;);			/* just in case */
275}
276
277int
278OF_finddevice(const char *name)
279{
280	static struct {
281		const char *name;
282		int nargs;
283		int nreturns;
284		const char *device;
285		int phandle;
286	} args = {
287		"finddevice",
288		1,
289		1,
290	};
291
292	args.device = name;
293	if (openfirmware(&args) == -1)
294		return -1;
295	return args.phandle;
296}
297
298int
299OF_instance_to_package(int ihandle)
300{
301	static struct {
302		const char *name;
303		int nargs;
304		int nreturns;
305		int ihandle;
306		int phandle;
307	} args = {
308		"instance-to-package",
309		1,
310		1,
311	};
312
313	args.ihandle = ihandle;
314	if (openfirmware(&args) == -1)
315		return -1;
316	return args.phandle;
317}
318
319int
320OF_getprop(int handle, const char *prop, void *buf, int buflen)
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 buflen;
330		int size;
331	} args = {
332		"getprop",
333		4,
334		1,
335	};
336
337	args.phandle = handle;
338	args.prop = prop;
339	args.buf = buf;
340	args.buflen = buflen;
341	if (openfirmware(&args) == -1)
342		return -1;
343	return args.size;
344}
345
346#ifdef	__notyet__	/* Has a bug on FirePower */
347int
348OF_setprop(int handle, const char *prop, void *buf, int len)
349{
350	static struct {
351		const char *name;
352		int nargs;
353		int nreturns;
354		int phandle;
355		const char *prop;
356		void *buf;
357		int len;
358		int size;
359	} args = {
360		"setprop",
361		4,
362		1,
363	};
364
365	args.phandle = handle;
366	args.prop = prop;
367	args.buf = buf;
368	args.len = len;
369	if (openfirmware(&args) == -1)
370		return -1;
371	return args.size;
372}
373#endif
374
375int
376OF_open(const char *dname)
377{
378	static struct {
379		const char *name;
380		int nargs;
381		int nreturns;
382		const char *dname;
383		int handle;
384	} args = {
385		"open",
386		1,
387		1,
388	};
389
390#ifdef OFW_DEBUG
391	printf("OF_open(%s) -> ", dname);
392#endif
393	args.dname = dname;
394	if (openfirmware(&args) == -1 ||
395	    args.handle == 0) {
396#ifdef OFW_DEBUG
397		printf("lose\n");
398#endif
399		return -1;
400	}
401#ifdef OFW_DEBUG
402	printf("%d\n", args.handle);
403#endif
404	return args.handle;
405}
406
407void
408OF_close(int handle)
409{
410	static struct {
411		const char *name;
412		int nargs;
413		int nreturns;
414		int handle;
415	} args = {
416		"close",
417		1,
418		0,
419	};
420
421#ifdef OFW_DEBUG
422	printf("OF_close(%d)\n", handle);
423#endif
424	args.handle = handle;
425	openfirmware(&args);
426}
427
428int
429OF_write(int handle, void *addr, int len)
430{
431	static struct {
432		const char *name;
433		int nargs;
434		int nreturns;
435		int ihandle;
436		void *addr;
437		int len;
438		int actual;
439	} args = {
440		"write",
441		3,
442		1,
443	};
444
445#ifdef OFW_DEBUG
446	if (len != 1)
447		printf("OF_write(%d, %p, %x) -> ", handle, addr, len);
448#endif
449	args.ihandle = handle;
450	args.addr = addr;
451	args.len = len;
452	if (openfirmware(&args) == -1) {
453#ifdef OFW_DEBUG
454		printf("lose\n");
455#endif
456		return -1;
457	}
458#ifdef OFW_DEBUG
459	if (len != 1)
460		printf("%x\n", args.actual);
461#endif
462	return args.actual;
463}
464
465int
466OF_read(int handle, void *addr, int len)
467{
468	static struct {
469		const char *name;
470		int nargs;
471		int nreturns;
472		int ihandle;
473		void *addr;
474		int len;
475		int actual;
476	} args = {
477		"read",
478		3,
479		1,
480	};
481
482#ifdef OFW_DEBUG
483	if (len != 1)
484		printf("OF_read(%d, %p, %x) -> ", handle, addr, len);
485#endif
486	args.ihandle = handle;
487	args.addr = addr;
488	args.len = len;
489	if (openfirmware(&args) == -1) {
490#ifdef OFW_DEBUG
491		printf("lose\n");
492#endif
493		return -1;
494	}
495#ifdef OFW_DEBUG
496	if (len != 1)
497		printf("%x\n", args.actual);
498#endif
499	return args.actual;
500}
501
502int
503OF_seek(int handle, u_quad_t pos)
504{
505	static struct {
506		const char *name;
507		int nargs;
508		int nreturns;
509		int handle;
510		int poshi;
511		int poslo;
512		int status;
513	} args = {
514		"seek",
515		3,
516		1,
517	};
518
519#ifdef OFW_DEBUG
520	printf("OF_seek(%d, %x, %x) -> ", handle, (int)(pos >> 32), (int)pos);
521#endif
522	args.handle = handle;
523	args.poshi = (int)(pos >> 32);
524	args.poslo = (int)pos;
525	if (openfirmware(&args) == -1) {
526#ifdef OFW_DEBUG
527		printf("lose\n");
528#endif
529		return -1;
530	}
531#ifdef OFW_DEBUG
532	printf("%d\n", args.status);
533#endif
534	return args.status;
535}
536
537void *
538OF_claim(void *virt, u_int size, u_int align)
539{
540	static struct {
541		const char *name;
542		int nargs;
543		int nreturns;
544		void *virt;
545		u_int size;
546		u_int align;
547		void *baseaddr;
548	} args = {
549		"claim",
550		3,
551		1,
552	};
553
554#ifdef OFW_DEBUG
555	printf("OF_claim(%p, %x, %x) -> ", virt, size, align);
556#endif
557	args.virt = virt;
558	args.size = size;
559	args.align = align;
560	if (openfirmware(&args) == -1) {
561#ifdef OFW_DEBUG
562		printf("lose\n");
563#endif
564		return (void *)-1;
565	}
566#ifdef OFW_DEBUG
567	printf("%p\n", args.baseaddr);
568#endif
569	return args.baseaddr;
570}
571
572void
573OF_release(void *virt, u_int size)
574{
575	static struct {
576		const char *name;
577		int nargs;
578		int nreturns;
579		void *virt;
580		u_int size;
581	} args = {
582		"release",
583		2,
584		0,
585	};
586
587#ifdef OFW_DEBUG
588	printf("OF_release(%p, %x)\n", virt, size);
589#endif
590	args.virt = virt;
591	args.size = size;
592	openfirmware(&args);
593}
594
595int
596OF_milliseconds(void)
597{
598	static struct {
599		const char *name;
600		int nargs;
601		int nreturns;
602		int ms;
603	} args = {
604		"milliseconds",
605		0,
606		1,
607	};
608
609	openfirmware(&args);
610	return args.ms;
611}
612
613#ifdef	__notyet__
614void
615OF_chain(void *virt, u_int size, void (*entry)(), void *arg, u_int len)
616{
617	static struct {
618		const char *name;
619		int nargs;
620		int nreturns;
621		void *virt;
622		u_int size;
623		void (*entry)();
624		void *arg;
625		u_int len;
626	} args = {
627		"chain",
628		5,
629		0,
630	};
631
632	args.virt = virt;
633	args.size = size;
634	args.entry = entry;
635	args.arg = arg;
636	args.len = len;
637	openfirmware(&args);
638}
639#else
640void
641OF_chain(void *virt, u_int size, boot_entry_t entry, void *arg, u_int len)
642{
643	/*
644	 * This is a REALLY dirty hack till the firmware gets this going
645	 */
646#if 0
647	OF_release(virt, size);
648#endif
649	entry(0, 0, openfirmware, arg, len);
650}
651#endif
652
653int
654OF_call_method(const char *method, int ihandle, int nargs, int nreturns,
655    int *cells)
656{
657	static struct {
658		const char *name;
659		int nargs;
660		int nreturns;
661		const char *method;
662		int ihandle;
663		int args_n_results[12];
664	} args = {
665		"call-method",
666		2,
667		1,
668	};
669	int *ip, n;
670
671	if (nargs > 6)
672		return -1;
673
674	args.nargs = nargs + 2;
675	args.nreturns = nreturns + 1;
676	args.method = method;
677	args.ihandle = ihandle;
678
679	for (ip = args.args_n_results + (n = nargs); --n >= 0;)
680		*--ip = *cells++;
681
682	if (openfirmware(&args) == -1) {
683		return -1;
684	}
685
686	if (args.args_n_results[nargs]) {
687		return args.args_n_results[nargs];
688	}
689
690	for (ip = args.args_n_results + nargs + (n = args.nreturns); --n > 0;)
691		*cells++ = *--ip;
692
693	return 0;
694}
695
696static void
697setup(void)
698{
699	char prop[32];
700	int proplen;
701	const char *reason = NULL;
702
703	if ((ofw_chosen = OF_finddevice("/chosen")) == -1)
704		OF_exit();
705	if (OF_getprop(ofw_chosen, "stdin", &ofw_stdin, sizeof(ofw_stdin)) !=
706	    sizeof(ofw_stdin) ||
707	    OF_getprop(ofw_chosen, "stdout", &ofw_stdout, sizeof(ofw_stdout)) !=
708	    sizeof(ofw_stdout))
709		OF_exit();
710
711	if (ofw_stdout == 0) {
712		/* screen should be console, but it is not open */
713		ofw_stdout = OF_open("screen");
714	}
715
716#ifdef HEAP_VARIABLE
717	uint32_t pvr, vers, hsize = HEAP_SIZE;
718
719	__asm volatile ("mfpvr %0" : "=r"(pvr));
720	vers = pvr >> 16;
721	if (vers >= IBM970 && vers <= IBM970GX) hsize = 0x800000;
722
723	heapspace = OF_claim(0, hsize, NBPG);
724	if (heapspace == (char *)-1) {
725		panic("Failed to allocate heap");
726	}
727
728	setheap(heapspace, heapspace + HEAP_SIZE);
729#endif	/* HEAP_VARIABLE */
730
731	ofw_root = OF_finddevice("/");
732	ofw_options = OF_finddevice("/options");
733	ofw_openprom = OF_finddevice("/openprom");
734	ofw_chosen = OF_finddevice("/chosen");
735
736	if (ofw_root == -1) {
737		reason = "No root node";
738		goto bad_environment;
739	}
740	if (ofw_chosen == -1) {
741		reason = "No chosen node";
742		goto bad_environment;
743	}
744
745	if (ofw_options != -1) {
746		proplen = OF_getprop(ofw_options, "real-mode?", prop,
747		    sizeof(prop));
748		if (proplen > 0) {
749			ofw_real_mode = ofw_option_truefalse(prop, proplen);
750		}
751	}
752
753	/*
754	 * Get #address-cells and #size-cells.
755	 */
756	ofw_address_cells = 1;
757	ofw_size_cells = 1;
758	OF_getprop(ofw_root, "#address-cells", &ofw_address_cells,
759		   sizeof(ofw_address_cells));
760	OF_getprop(ofw_root, "#size-cells", &ofw_size_cells,
761		   sizeof(ofw_size_cells));
762
763	/* See loadfile_machdep.c */
764	if (ofw_size_cells != 1) {
765		printf("#size-cells = %d not yet supported\n", ofw_size_cells);
766		reason = "unsupported #size-cells";
767		goto bad_environment;
768	}
769
770	/*
771	 * Get the ihandle on /chosen/memory and /chosen/mmu.
772	 */
773	ofw_memory_ihandle = -1;
774	ofw_mmu_ihandle = -1;
775	OF_getprop(ofw_chosen, "memory", &ofw_memory_ihandle,
776		   sizeof(ofw_memory_ihandle));
777	OF_getprop(ofw_chosen, "mmu", &ofw_mmu_ihandle,
778		   sizeof(ofw_mmu_ihandle));
779	if (ofw_memory_ihandle == -1) {
780		reason = "no /chosen/memory";
781		goto bad_environment;
782	}
783	if (ofw_mmu_ihandle == -1) {
784		reason = "no /chosen/mmu";
785		goto bad_environment;
786	}
787
788	return;
789
790 bad_environment:
791	if (reason == NULL) {
792		reason = "unknown reason";
793	}
794	printf("Invalid Openfirmware environment: %s\n", reason);
795	OF_exit();
796}
797
798void
799putchar(int c)
800{
801	char ch = c;
802
803	if (c == '\n')
804		putchar('\r');
805	OF_write(ofw_stdout, &ch, 1);
806}
807
808int
809getchar(void)
810{
811	unsigned char ch = '\0';
812	int l;
813
814	while ((l = OF_read(ofw_stdin, &ch, 1)) != 1)
815		if (l != -2 && l != 0)
816			return -1;
817	return ch;
818}
819