]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - sys/arm/arm/locore.S
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / 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 */