FreeBSD/Linux Kernel Cross Reference
sys/arm/arm/locore.S
1 /* $NetBSD: locore.S,v 1.14 2003/04/20 16:21:40 thorpej Exp $ */
2
3 /*-
4 * Copyright (C) 1994-1997 Mark Brinicombe
5 * Copyright (C) 1994 Brini
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 Brini.
19 * 4. The name of Brini 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 BRINI ``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 BRINI 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
35 #include "assym.s"
36 #include <sys/syscall.h>
37 #include <machine/asm.h>
38 #include <machine/armreg.h>
39 #include <machine/pte.h>
40 __FBSDID("$FreeBSD$");
41
42 /* What size should this really be ? It is only used by initarm() */
43 #define INIT_ARM_STACK_SIZE 2048
44
45 /*
46 * This is for kvm_mkdb, and should be the address of the beginning
47 * of the kernel text segment (not necessarily the same as kernbase).
48 */
49
50
51 #define CPWAIT_BRANCH \
52 sub pc, pc, #4
53
54 #define CPWAIT(tmp) \
55 mrc p15, 0, tmp, c2, c0, 0 /* arbitrary read of CP15 */ ;\
56 mov tmp, tmp /* wait for it to complete */ ;\
57 CPWAIT_BRANCH /* branch to next insn */
58
59 .text
60 .align 0
61 .globl kernbase
62 .set kernbase,KERNBASE
63 .globl physaddr
64 .set physaddr,PHYSADDR
65
66 ENTRY_NP(btext)
67
68 /*
69 * On entry:
70 * r0 - metadata pointer or 0
71 * r1 - if (r0 == 0) then metadata pointer
72 */
73 ASENTRY_NP(_start)
74
75 /* Move metadata ptr to r12 (ip) */
76 mov ip, r0
77 ldr r0, =0
78 cmp ip, r0
79 bne 1f
80 mov ip, r1
81 1:
82 /* Make sure interrupts are disabled. */
83 mrs r7, cpsr
84 orr r7, r7, #(I32_bit|F32_bit)
85 msr cpsr_c, r7
86
87 #if defined (FLASHADDR) && defined(LOADERRAMADDR)
88 /* Check if we're running from flash. */
89 ldr r7, =FLASHADDR
90 /*
91 * If we're running with MMU disabled, test against the
92 * physical address instead.
93 */
94 mrc p15, 0, r2, c1, c0, 0
95 ands r2, r2, #CPU_CONTROL_MMU_ENABLE
96 ldreq r8, =PHYSADDR
97 ldrne r8, =LOADERRAMADDR
98 cmp r7, r8
99 bls flash_lower
100 cmp r7, pc
101 bhi from_ram
102 b do_copy
103
104 flash_lower:
105 cmp r8, pc
106 bls from_ram
107 do_copy:
108 ldr r9, =KERNBASE
109 adr r1, _start
110 ldr r0, Lreal_start
111 ldr r2, Lend
112 sub r2, r2, r0
113 sub r0, r0, r9
114 add r0, r0, r8
115 mov r4, r0
116 bl memcpy
117 ldr r0, Lram_offset
118 add pc, r4, r0
119 Lram_offset: .word from_ram-_C_LABEL(_start)
120 from_ram:
121 nop
122 #endif
123 adr r7, Lunmapped
124 bic r7, r7, #0xf0000000
125 orr r7, r7, #PHYSADDR
126
127
128 disable_mmu:
129 /* Disable MMU for a while */
130 mrc p15, 0, r2, c1, c0, 0
131 bic r2, r2, #(CPU_CONTROL_MMU_ENABLE | CPU_CONTROL_DC_ENABLE |\
132 CPU_CONTROL_WBUF_ENABLE)
133 bic r2, r2, #(CPU_CONTROL_IC_ENABLE)
134 bic r2, r2, #(CPU_CONTROL_BPRD_ENABLE)
135 mcr p15, 0, r2, c1, c0, 0
136
137 nop
138 nop
139 nop
140 mov pc, r7
141 Lunmapped:
142 #ifdef STARTUP_PAGETABLE_ADDR
143 /* build page table from scratch */
144 ldr r0, Lstartup_pagetable
145 adr r4, mmu_init_table
146 b 3f
147
148 2:
149 str r3, [r0, r2]
150 add r2, r2, #4
151 add r3, r3, #(L1_S_SIZE)
152 adds r1, r1, #-1
153 bhi 2b
154 3:
155 ldmia r4!, {r1,r2,r3} /* # of sections, VA, PA|attr */
156 cmp r1, #0
157 adrne r5, 2b
158 bicne r5, r5, #0xf0000000
159 orrne r5, r5, #PHYSADDR
160 movne pc, r5
161
162 mcr p15, 0, r0, c2, c0, 0 /* Set TTB */
163 mcr p15, 0, r0, c8, c7, 0 /* Flush TLB */
164
165 /* Set the Domain Access register. Very important! */
166 mov r0, #((DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)) | DOMAIN_CLIENT)
167 mcr p15, 0, r0, c3, c0, 0
168 /* Enable MMU */
169 mrc p15, 0, r0, c1, c0, 0
170 orr r0, r0, #CPU_CONTROL_MMU_ENABLE
171 mcr p15, 0, r0, c1, c0, 0
172 nop
173 nop
174 nop
175 CPWAIT(r0)
176
177 #endif
178 mmu_done:
179 nop
180 adr r1, .Lstart
181 ldmia r1, {r1, r2, sp} /* Set initial stack and */
182 sub r2, r2, r1 /* get zero init data */
183 mov r3, #0
184 .L1:
185 str r3, [r1], #0x0004 /* get zero init data */
186 subs r2, r2, #4
187 bgt .L1
188 ldr pc, .Lvirt_done
189
190 virt_done:
191 mov r0, ip /* Load argument: metadata ptr */
192
193 mov fp, #0 /* trace back starts here */
194 bl _C_LABEL(initarm) /* Off we go */
195
196 /* init arm will return the new stack pointer. */
197 mov sp, r0
198
199 bl _C_LABEL(mi_startup) /* call mi_startup()! */
200
201 adr r0, .Lmainreturned
202 b _C_LABEL(panic)
203 /* NOTREACHED */
204 #ifdef STARTUP_PAGETABLE_ADDR
205 #define MMU_INIT(va,pa,n_sec,attr) \
206 .word n_sec ; \
207 .word 4*((va)>>L1_S_SHIFT) ; \
208 .word (pa)|(attr) ;
209
210 Lvirtaddr:
211 .word KERNVIRTADDR
212 Lphysaddr:
213 .word KERNPHYSADDR
214 Lreal_start:
215 .word _start
216 Lend:
217 .word _edata
218 Lstartup_pagetable:
219 .word STARTUP_PAGETABLE_ADDR
220 mmu_init_table:
221 /* fill all table VA==PA */
222 /* map SDRAM VA==PA, WT cacheable */
223 MMU_INIT(PHYSADDR, PHYSADDR , 64, L1_TYPE_S|L1_S_C|L1_S_AP(AP_KRW))
224 /* map VA 0xc0000000..0xc3ffffff to PA */
225 MMU_INIT(KERNBASE, PHYSADDR, 64, L1_TYPE_S|L1_S_C|L1_S_AP(AP_KRW))
226
227 .word 0 /* end of table */
228 #endif
229 .Lstart:
230 .word _edata
231 .word _end
232 .word svcstk + INIT_ARM_STACK_SIZE
233
234 #if defined(FLASHADDR) && defined(LOADERRAMADDR)
235 .L_arm_memcpy:
236 .word _C_LABEL(_arm_memcpy)
237 #endif
238
239 .Lvirt_done:
240 .word virt_done
241 .Lmainreturned:
242 .asciz "main() returned"
243 .align 0
244
245 .bss
246 svcstk:
247 .space INIT_ARM_STACK_SIZE
248
249 .text
250 .align 0
251
252 .Lcpufuncs:
253 .word _C_LABEL(cpufuncs)
254
255 ENTRY_NP(cpu_halt)
256 mrs r2, cpsr
257 bic r2, r2, #(PSR_MODE)
258 orr r2, r2, #(PSR_SVC32_MODE)
259 orr r2, r2, #(I32_bit | F32_bit)
260 msr cpsr_all, r2
261
262 ldr r4, .Lcpu_reset_address
263 ldr r4, [r4]
264
265 ldr r0, .Lcpufuncs
266 mov lr, pc
267 ldr pc, [r0, #CF_IDCACHE_WBINV_ALL]
268 mov lr, pc
269 ldr pc, [r0, #CF_L2CACHE_WBINV_ALL]
270
271 /*
272 * Load the cpu_reset_needs_v4_MMU_disable flag to determine if it's
273 * necessary.
274 */
275
276 ldr r1, .Lcpu_reset_needs_v4_MMU_disable
277 ldr r1, [r1]
278 cmp r1, #0
279 mov r2, #0
280
281 /*
282 * MMU & IDC off, 32 bit program & data space
283 * Hurl ourselves into the ROM
284 */
285 mov r0, #(CPU_CONTROL_32BP_ENABLE | CPU_CONTROL_32BD_ENABLE)
286 mcr 15, 0, r0, c1, c0, 0
287 mcrne 15, 0, r2, c8, c7, 0 /* nail I+D TLB on ARMv4 and greater */
288 mov pc, r4
289
290 /*
291 * _cpu_reset_address contains the address to branch to, to complete
292 * the cpu reset after turning the MMU off
293 * This variable is provided by the hardware specific code
294 */
295 .Lcpu_reset_address:
296 .word _C_LABEL(cpu_reset_address)
297
298 /*
299 * cpu_reset_needs_v4_MMU_disable contains a flag that signals if the
300 * v4 MMU disable instruction needs executing... it is an illegal instruction
301 * on f.e. ARM6/7 that locks up the computer in an endless illegal
302 * instruction / data-abort / reset loop.
303 */
304 .Lcpu_reset_needs_v4_MMU_disable:
305 .word _C_LABEL(cpu_reset_needs_v4_MMU_disable)
306
307
308 /*
309 * setjump + longjmp
310 */
311 ENTRY(setjmp)
312 stmia r0, {r4-r14}
313 mov r0, #0x00000000
314 RET
315
316 ENTRY(longjmp)
317 ldmia r0, {r4-r14}
318 mov r0, #0x00000001
319 RET
320
321 .data
322 .global _C_LABEL(esym)
323 _C_LABEL(esym): .word _C_LABEL(end)
324
325 ENTRY_NP(abort)
326 b _C_LABEL(abort)
327
328 ENTRY_NP(sigcode)
329 mov r0, sp
330 swi SYS_sigreturn
331
332 /* Well if that failed we better exit quick ! */
333
334 swi SYS_exit
335 b . - 8
336
337 .align 0
338 .global _C_LABEL(esigcode)
339 _C_LABEL(esigcode):
340
341 .data
342 .global szsigcode
343 szsigcode:
344 .long esigcode-sigcode
345 /* End of locore.S */
Cache object: bd3b60721c93bbba4fd6e273fa00fb34
|