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