1/*	$NetBSD: start.S,v 1.6 2024/02/09 17:39:33 andvar Exp $	*/
2
3/*
4 * Copyright (c) 2002 Reinoud Zandijk
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote products
16 *    derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#include <machine/asm.h>
31#include <arm/armreg.h>
32#include <riscoscalls.h>
33
34
35/* ----------------------------------------------------------------------- */
36ENTRY(relocate_code)
37	/*
38		- r0 pointer to configuration structure
39		- r1 pointer to physical restart point
40		- r3 pointer to physical new L1 page address (P)
41		- r4 kernel entry point
42	*/
43
44	/* save registers / move args up in register bank later */
45	/* r8-r12 becomes r0-r4 */
46	stmfd	sp!, {r0-r4}
47	ldmfd	sp!, {r8-r12}
48
49	/*
50	 * determine processor architecture version. This is necessary for the
51	 * correct coprocessor instruction.
52	 */
53	mrc	p15, 0, r0, c0, c0, 0					/* read CPU id in r0			*/
54	mov	r3, r0							/* store in r3				*/
55
56	/* assume its ARMv4 instruction set									*/
57	mov	r14, #1
58
59	/* check ARM6. It needs a special mask									*/
60	mov	r0, #0x0000ff00
61	mov	r1, #0x00000600						/* check for 0xxxxx06xx => ARM6		*/
62	and	r2, r3, r0
63	cmp	r2, r1
64	moveq	r14, #0							/* mark v3				*/
65
66	/* newer ARM's need a different mask									*/
67	mov	r0, #0x0000f000
68
69	/* check for ARM7 and derivatives like the ARM 7500 and ARM 7500FE					*/
70	mov	r1, #0x00007000						/* check for 0xxxxx7xxx => ARM 7	*/
71	and	r2, r3, r0
72	cmp	r2, r1
73	moveq	r14, #0							/* mark v3				*/
74
75	/* flush everything out before we turn off the MMU */
76
77	/* flush ID cache											*/
78	mov	r0, #0
79	cmp	r14, #0
80	mcreq	p15, 0, r0, c7, c0, 0					/* flush v3 ID cache			*/
81	mcrne	p15, 0, r0, c7, c7, 0					/* flush v4 ID cache			*/
82	mcrne	p15, 0, r0, c7, c10, 4					/* drain WB (v4)			*/
83
84	/* flush TLB												*/
85	mcr	p15, 0, r0, c5, c0, 0					/* flush TLB for v3 and v4		*/
86
87	/* switch off MMU, IDcache and WB and branch to physical code space					*/
88	cmp	r14, #0
89	mrcne	p15, 0, r0, c1, c0, 0					/* read processor control register if v4*/
90	bic	r0, r0, #0x3f						/* clear only known bits		*/
91	moveq	r0, #0							/* for v3 just set to zero		*/
92	orr	r0, r0, #CPU_CONTROL_LABT_ENABLE | CPU_CONTROL_32BD_ENABLE | CPU_CONTROL_32BP_ENABLE
93	mov	r13, r0							/* save this control value in r13	*/
94	cmp	r14, #0
95	mcr	p15, 0, r0, c1, c0, 0					/* write control register!		*/
96/*1*/	mcrne	p15, 0, r1, c7, c5, 0					/* write zero in ARMv4 MMU disable	*/
97/*2*/	mov	pc, r9							/* branch to physical address		*/
98
99relocate_code_physical_restart:
100	/* we are running in physical flat 1:1 space now */
101
102	/* make the screen border red */
103	mov	r4, #0x03400000
104	mov	r0, #0x40000000
105	orr	r0, r0, #0xff
106	str	r0, [r4]
107
108	adr	r5, relocate_table_start
109	ldr	r6, [r5], #4						/* r6 = number of relocated pages	*/
110
111loop_relocate_pages:
112	ldr	r2, [r5], #4						/* r2 = from address			*/
113	ldr	r3, [r5], #4						/* r3 = to address			*/
114	ldr	r7, [r5], #4						/* r7 = number of bytes to travel	*/
115	/* its slow ... we dont know anything about alignment here 						*/
116loop_one_page:
117	ldr	r0, [r2], #4
118	str	r0, [r3], #4
119	subs	r7, r7, #4
120	bgt	loop_one_page
121
122	subs	r6, r6, #1
123	bne	loop_relocate_pages
124
125	/* make the screen border go green */
126	mov	r0, #0x40000000
127	orr	r0, r0, #0xff00
128	str	r0, [r4]
129
130	/* OK! all is relocated... now switch over to the new L1 pages						*/
131
132	/* flush ID cache											*/
133	mov	r0, #0
134	cmp	r14, #0
135	mcreq	p15, 0, r0, c7, c0, 0					/* flush v3 ID cache			*/
136	mcrne	p15, 0, r0, c7, c7, 0					/* flush v4 ID cache			*/
137
138	/* drain write buffer (v4)										*/
139	mov	r0, #0
140	cmp	r14, #0
141	mcrne	p15, 0, r0, c7, c10, 4					/* drain WB (v4)			*/
142
143	/* flush TLB												*/
144	mcr	p15, 0, r0, c5, c0, 0					/* flush TLB for v3 and v4		*/
145
146	/* set new TLB address											*/
147	mov	r0, r11
148	mcr	p15, 0, r0, c2, c0, 0					/* write TLB address			*/
149
150	/* Switch on MMU, IDCache and WB and keep on running on flat translated memory				*/
151	orr	r0, r13, #CPU_CONTROL_LABT_ENABLE | CPU_CONTROL_32BD_ENABLE | CPU_CONTROL_32BP_ENABLE
152	orr	r0, r0,  #CPU_CONTROL_WBUF_ENABLE | CPU_CONTROL_DC_ENABLE   | CPU_CONTROL_MMU_ENABLE
153	mcr	p15, 0, r0, c1, c0, 0					/* write register !!!			*/
154	mov	r0, r0							/* flat					*/
155	mov	r0, r0							/* flat					*/
156	/* not flat anymore but we just continue								*/
157
158	/* make the screen border go blue */
159	mov	r0, #0x40000000
160	orr	r0, r0, #0xff0000
161	str	r0, [r4]
162
163	/* call the kernel!											*/
164	mov	r0, r8							/* saved configuration structure	*/
165	mov	pc, r12							/* entry point ..... bye bye!		*/
166
167relocate_code_end:
168	b	relocate_code_end
169
170relocate_table_start:
171	/* relocation table is copied here, so it must be kept small */
172
173
174/* ----------------------------------------------------------------------- */
175
176
177/* we are not expected to ever return from here */
178ENTRY(start_kernel)
179	/*
180	entry conditions :
181		- on RISC OS page tables in usr26 mode on virtual space
182		- r0 relocation code page (V)
183		- r1 relocation pv offset
184		- r2 configuration structure
185		- r3 relocation table (V)
186		- r4 L1 page descriptor (P)
187		- r5 kernel entry point
188	*/
189	mov	ip, sp
190	stmfd	sp!, {r4-r9, fp, ip, lr, pc}
191	sub	fp, ip, #4
192
193	/* get stuff out of the calling frame */
194	ldr	r4, [ip, #0]
195	ldr	r5, [ip, #4]
196
197	/* relocate the relocation routine to the given page */
198	adr	r6, relocate_code
199	ldr	r7, =relocate_table_start - relocate_code	/* get length to copy */
200	mov	r8, r0
201relocate_code_loop:
202	ldr	r9, [r6], #4
203	str	r9, [r8], #4
204	subs	r7, r7, #4
205	bne	relocate_code_loop
206
207	/* now relocate the relocate table onto the same page */
208
209	/* next we need to copy the table over */
210	ldr	r6, [r3], #4					/* r6 has number of threes to copy */
211	str	r6, [r8], #4
212
213relocate_table_loop:
214	ldr	r9, [r3], #4
215	str	r9, [r8], #4
216	ldr	r9, [r3], #4
217	str	r9, [r8], #4
218	ldr	r9, [r3], #4
219	str	r9, [r8], #4
220	subs	r6, r6, #1
221	bne	relocate_table_loop
222
223	/* we messed up the data cache : lets read a 64 or 128 kb <-- GROSS */
224	mov	r7, #128*1024
225	mov	r6, #0x8000						/* start of RISCOS application area	*/
226flush_ID_cache_try:
227	ldr	r9, [r6], #4
228	subs	r7, r7, #4
229	bne	flush_ID_cache_try
230
231	/* enter sub26 mode */
232	swi	OS_EnterOS
233
234	/* go to sup32 mode with ICQ and FIQ disabled */
235	mrs	r6, cpsr
236	bic	r6, r6, #PSR_MODE					/* clear processor mode			*/
237	orr	r6, r6, #(I32_bit | F32_bit)				/* disable ICQ + FIQ			*/
238	orr	r6, r6, #PSR_SVC32_MODE					/* go to 32 bit supervisor mode		*/
239	msr	cpsr, r6
240	mov	r0, r0							/* nops ... just in case		*/
241	mov	r0, r0
242
243	/* set up info */
244	mov	r9, r0							/* save relocated page address		*/
245	ldr	r7, =relocate_code_physical_restart - relocate_code	/* get offset			*/
246	add	r1, r0, r1						/* get physical address			*/
247	add	r1, r1, r7						/* add offset				*/
248	mov	r0, r2							/* put configuration structure in r0	*/
249	mov	r2, r3
250	mov	r3, r4							/* L1 page descriptor			*/
251	mov	r4, r5							/* kernel entry point			*/
252
253	mov	pc, r9							/* jump to page addr == relocate_code	*/
254
255emergency_exit:
256	ldmdb	fp, {r4-r9, fp, sp, pc}
257
258