]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/arm/arm/locore-v4.S
Merge llvm, clang, lld and lldb trunk r291476.
[FreeBSD/FreeBSD.git] / sys / arm / arm / locore-v4.S
1 /*      $NetBSD: locore.S,v 1.14 2003/04/20 16:21:40 thorpej Exp $      */
2
3 /*-
4  * Copyright 2011 Semihalf
5  * Copyright (C) 1994-1997 Mark Brinicombe
6  * Copyright (C) 1994 Brini
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. All advertising materials mentioning features or use of this software
18  *    must display the following acknowledgement:
19  *      This product includes software developed by Brini.
20  * 4. The name of Brini may not be used to endorse or promote products
21  *    derived from this software without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR
24  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26  * IN NO EVENT SHALL BRINI BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
29  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
30  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
31  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
32  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  *
34  */
35
36 #include "assym.s"
37 #include <sys/syscall.h>
38 #include <machine/asm.h>
39 #include <machine/armreg.h>
40 #include <machine/cpuconf.h>
41 #include <machine/pte-v4.h>
42
43 __FBSDID("$FreeBSD$");
44
45 /* 2K initial stack is plenty, it is only used by initarm() */
46 #define INIT_ARM_STACK_SIZE     2048
47
48 #define CPWAIT_BRANCH                                                    \
49         sub     pc, pc, #4
50
51 #define CPWAIT(tmp)                                                      \
52         mrc     p15, 0, tmp, c2, c0, 0  /* arbitrary read of CP15 */    ;\
53         mov     tmp, tmp                /* wait for it to complete */   ;\
54         CPWAIT_BRANCH                   /* branch to next insn */
55
56 /*
57  * This is for libkvm, and should be the address of the beginning
58  * of the kernel text segment (not necessarily the same as kernbase).
59  *
60  * These are being phased out. Newer copies of libkvm don't need these
61  * values as the information is added to the core file by inspecting
62  * the running kernel.
63  */
64         .text
65         .align  2
66 #ifdef PHYSADDR
67 .globl kernbase
68 .set kernbase,KERNBASE
69 .globl physaddr
70 .set physaddr,PHYSADDR
71 #endif
72
73 /*
74  * On entry for FreeBSD boot ABI:
75  *      r0 - metadata pointer or 0 (boothowto on AT91's boot2)
76  *      r1 - if (r0 == 0) then metadata pointer
77  * On entry for Linux boot ABI:
78  *      r0 - 0
79  *      r1 - machine type (passed as arg2 to initarm)
80  *      r2 - Pointer to a tagged list or dtb image (phys addr) (passed as arg1 initarm)
81  *
82  * For both types of boot we gather up the args, put them in a struct arm_boot_params
83  * structure and pass that to initarm.
84  */
85         .globl  btext
86 btext:
87 ASENTRY_NP(_start)
88         STOP_UNWINDING          /* Can't unwind into the bootloader! */
89
90         mov     r9, r0          /* 0 or boot mode from boot2 */
91         mov     r8, r1          /* Save Machine type */
92         mov     ip, r2          /* Save meta data */
93         mov     fp, r3          /* Future expansion */
94
95         /* Make sure interrupts are disabled. */
96         mrs     r7, cpsr
97         orr     r7, r7, #(PSR_I | PSR_F)
98         msr     cpsr_c, r7
99
100 #if defined (FLASHADDR) && defined(LOADERRAMADDR)
101 /*
102  * Sanity check the configuration.
103  * FLASHADDR and LOADERRAMADDR depend on PHYSADDR in some cases.
104  * ARMv4 and ARMv5 make assumptions on where they are loaded.
105  * TODO: Fix the ARMv4/v5 case.
106  */
107 #ifndef PHYSADDR
108 #error PHYSADDR must be defined for this configuration
109 #endif
110
111         /* Check if we're running from flash. */
112         ldr     r7, =FLASHADDR
113         /*
114          * If we're running with MMU disabled, test against the
115          * physical address instead.
116          */
117         mrc     CP15_SCTLR(r2)
118         ands    r2, r2, #CPU_CONTROL_MMU_ENABLE
119         ldreq   r6, =PHYSADDR
120         ldrne   r6, =LOADERRAMADDR
121         cmp     r7, r6
122         bls     flash_lower
123         cmp     r7, pc
124         bhi     from_ram
125         b       do_copy
126
127 flash_lower:
128         cmp     r6, pc
129         bls     from_ram
130 do_copy:
131         ldr     r7, =KERNBASE
132         adr     r1, _start
133         ldr     r0, Lreal_start
134         ldr     r2, Lend
135         sub     r2, r2, r0
136         sub     r0, r0, r7
137         add     r0, r0, r6
138         mov     r4, r0
139         bl      memcpy
140         ldr     r0, Lram_offset
141         add     pc, r4, r0
142 Lram_offset:    .word from_ram-_C_LABEL(_start)
143 from_ram:
144         nop
145 #endif
146
147 disable_mmu:
148         /* Disable MMU for a while */
149         mrc     CP15_SCTLR(r2)
150         bic     r2, r2, #(CPU_CONTROL_MMU_ENABLE | CPU_CONTROL_DC_ENABLE |\
151             CPU_CONTROL_WBUF_ENABLE)
152         bic     r2, r2, #(CPU_CONTROL_IC_ENABLE)
153         bic     r2, r2, #(CPU_CONTROL_BPRD_ENABLE)
154         mcr     CP15_SCTLR(r2)
155
156         nop
157         nop
158         nop
159         CPWAIT(r0)
160
161 Lunmapped:
162         /*
163          * Build page table from scratch.
164          */
165
166         /* 
167          * Figure out the physical address we're loaded at by assuming this
168          * entry point code is in the first L1 section and so if we clear the
169          * offset bits of the pc that will give us the section-aligned load
170          * address, which remains in r5 throughout all the following code.
171          */
172         ldr     r2, =(L1_S_OFFSET)
173         bic     r5, pc, r2
174
175         /* Find the delta between VA and PA, result stays in r0 throughout. */
176         adr     r0, Lpagetable
177         bl      translate_va_to_pa
178
179         /* 
180          * First map the entire 4GB address space as VA=PA.  It's mapped as
181          * normal (cached) memory because it's for things like accessing the
182          * parameters passed in from the bootloader, which might be at any
183          * physical address, different for every platform.
184          */
185         mov     r1, #0
186         mov     r2, #0
187         mov     r3, #4096
188         bl      build_pagetables
189
190         /* 
191          * Next we do 64MiB starting at the physical load address, mapped to
192          * the VA the kernel is linked for.
193          */
194         mov     r1, r5
195         ldr     r2, =(KERNVIRTADDR)
196         mov     r3, #64
197         bl      build_pagetables
198 #if defined(PHYSADDR) && (KERNVIRTADDR != KERNBASE)
199 /* 
200  * If the kernel wasn't loaded at the beginning of the ram, map the memory
201  * before the kernel too, as some ports use that for pagetables, stack, etc...
202  */
203         ldr     r1, =PHYSADDR
204         ldr     r2, =KERNBASE
205         ldr     r3, =((KERNVIRTADDR - KERNBASE) / L1_S_SIZE)
206         bl      build_pagetables
207 #endif
208
209         /* Create a device mapping for early_printf if specified. */
210 #if defined(SOCDEV_PA) && defined(SOCDEV_VA)
211         ldr     r1, =SOCDEV_PA
212         ldr     r2, =SOCDEV_VA
213         mov     r3, #1
214         bl      build_device_pagetables
215 #endif
216
217         mcr     p15, 0, r0, c2, c0, 0   /* Set TTB */
218         mcr     p15, 0, r0, c8, c7, 0   /* Flush TLB */
219
220         /* Set the Domain Access register.  Very important! */
221         mov     r0, #((DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)) | DOMAIN_CLIENT)
222         mcr     p15, 0, r0, c3, c0, 0
223         /*
224          * Enable MMU.
225          */
226         mrc     CP15_SCTLR(r0)
227         orr     r0, r0, #(CPU_CONTROL_MMU_ENABLE)
228         mcr     CP15_SCTLR(r0)
229         nop
230         nop
231         nop
232         CPWAIT(r0)
233
234         /* Transition the PC from physical to virtual addressing. */
235         ldr     pc,=mmu_done
236
237 mmu_done:
238         nop
239         adr     r1, .Lstart
240         ldmia   r1, {r1, r2, sp}        /* Set initial stack and */
241         sub     r2, r2, r1              /* get zero init data */
242         mov     r3, #0
243 .L1:
244         str     r3, [r1], #0x0004       /* get zero init data */
245         subs    r2, r2, #4
246         bgt     .L1
247
248 virt_done:
249         mov     r1, #28                 /* loader info size is 28 bytes also second arg */
250         subs    sp, sp, r1              /* allocate arm_boot_params struct on stack */
251         mov     r0, sp                  /* loader info pointer is first arg */
252         bic     sp, sp, #7              /* align stack to 8 bytes */
253         str     r1, [r0]                /* Store length of loader info */
254         str     r9, [r0, #4]            /* Store r0 from boot loader */
255         str     r8, [r0, #8]            /* Store r1 from boot loader */
256         str     ip, [r0, #12]           /* store r2 from boot loader */
257         str     fp, [r0, #16]           /* store r3 from boot loader */
258         str     r5, [r0, #20]           /* store the physical address */
259         adr     r4, Lpagetable          /* load the pagetable address */
260         ldr     r5, [r4, #4]
261         str     r5, [r0, #24]           /* store the pagetable address */
262         mov     fp, #0                  /* trace back starts here */
263         bl      _C_LABEL(initarm)       /* Off we go */
264
265         /* init arm will return the new stack pointer. */
266         mov     sp, r0
267
268         bl      _C_LABEL(mi_startup)    /* call mi_startup()! */
269
270         adr     r0, .Lmainreturned
271         b       _C_LABEL(panic)
272         /* NOTREACHED */
273 END(_start)
274
275 #define VA_TO_PA_POINTER(name, table)    \
276 name:                                   ;\
277         .word   .                       ;\
278         .word   table
279
280 /*
281  * Returns the physical address of a magic va to pa pointer.
282  * r0     - The pagetable data pointer. This must be built using the
283  *          VA_TO_PA_POINTER macro.
284  *          e.g.
285  *            VA_TO_PA_POINTER(Lpagetable, pagetable)
286  *            ...
287  *            adr  r0, Lpagetable
288  *            bl   translate_va_to_pa
289  *            r0 will now contain the physical address of pagetable
290  * r1, r2 - Trashed
291  */
292 translate_va_to_pa:
293         ldr     r1, [r0]
294         sub     r2, r1, r0
295         /* At this point: r2 = VA - PA */
296
297         /*
298          * Find the physical address of the table. After these two
299          * instructions:
300          * r1 = va(pagetable)
301          *
302          * r0 = va(pagetable) - (VA - PA)
303          *    = va(pagetable) - VA + PA
304          *    = pa(pagetable)
305          */
306         ldr     r1, [r0, #4]
307         sub     r0, r1, r2
308         RET
309
310 /*
311  * Builds the page table
312  * r0 - The table base address
313  * r1 - The physical address (trashed)
314  * r2 - The virtual address (trashed)
315  * r3 - The number of 1MiB sections
316  * r4 - Trashed
317  *
318  * Addresses must be 1MiB aligned
319  */
320 build_device_pagetables:
321         ldr     r4, =(L1_TYPE_S|L1_S_AP(AP_KRW))
322         b       1f
323 build_pagetables:
324         /* Set the required page attributed */
325         ldr     r4, =(L1_TYPE_S|L1_S_C|L1_S_AP(AP_KRW))
326 1:
327         orr     r1, r4
328
329         /* Move the virtual address to the correct bit location */
330         lsr     r2, #(L1_S_SHIFT - 2)
331
332         mov     r4, r3
333 2:
334         str     r1, [r0, r2]
335         add     r2, r2, #4
336         add     r1, r1, #(L1_S_SIZE)
337         adds    r4, r4, #-1
338         bhi     2b
339
340         RET
341
342 VA_TO_PA_POINTER(Lpagetable, pagetable)
343
344 Lreal_start:
345         .word   _start
346 Lend:
347         .word   _edata
348
349 .Lstart:
350         .word   _edata
351         .word   _ebss
352         .word   svcstk + INIT_ARM_STACK_SIZE
353
354 .Lvirt_done:
355         .word   virt_done
356
357 .Lmainreturned:
358         .asciz  "main() returned"
359         .align  2
360
361         .bss
362 svcstk:
363         .space  INIT_ARM_STACK_SIZE
364
365 /*
366  * Memory for the initial pagetable. We are unable to place this in
367  * the bss as this will be cleared after the table is loaded.
368  */
369         .section ".init_pagetable"
370         .align  14 /* 16KiB aligned */
371 pagetable:
372         .space  L1_TABLE_SIZE
373
374         .text
375         .align  2
376
377 .Lcpufuncs:
378         .word   _C_LABEL(cpufuncs)
379
380 ENTRY_NP(cpu_halt)
381         mrs     r2, cpsr
382         bic     r2, r2, #(PSR_MODE)
383         orr     r2, r2, #(PSR_SVC32_MODE)
384         orr     r2, r2, #(PSR_I | PSR_F)
385         msr     cpsr_fsxc, r2
386
387         ldr     r4, .Lcpu_reset_address
388         ldr     r4, [r4]
389
390         ldr     r0, .Lcpufuncs
391         mov     lr, pc
392         ldr     pc, [r0, #CF_IDCACHE_WBINV_ALL]
393         mov     lr, pc
394         ldr     pc, [r0, #CF_L2CACHE_WBINV_ALL]
395
396         /*
397          * Load the cpu_reset_needs_v4_MMU_disable flag to determine if it's
398          * necessary.
399          */
400
401         ldr     r1, .Lcpu_reset_needs_v4_MMU_disable
402         ldr     r1, [r1]
403         cmp     r1, #0
404         mov     r2, #0
405
406         /*
407          * MMU & IDC off, 32 bit program & data space
408          * Hurl ourselves into the ROM
409          */
410         mov     r0, #(CPU_CONTROL_32BP_ENABLE | CPU_CONTROL_32BD_ENABLE)
411         mcr     CP15_SCTLR(r0)
412         mcrne   p15, 0, r2, c8, c7, 0   /* nail I+D TLB on ARMv4 and greater */
413         mov     pc, r4
414
415         /*
416          * _cpu_reset_address contains the address to branch to, to complete
417          * the cpu reset after turning the MMU off
418          * This variable is provided by the hardware specific code
419          */
420 .Lcpu_reset_address:
421         .word   _C_LABEL(cpu_reset_address)
422
423         /*
424          * cpu_reset_needs_v4_MMU_disable contains a flag that signals if the
425          * v4 MMU disable instruction needs executing... it is an illegal instruction
426          * on f.e. ARM6/7 that locks up the computer in an endless illegal
427          * instruction / data-abort / reset loop.
428          */
429 .Lcpu_reset_needs_v4_MMU_disable:
430         .word   _C_LABEL(cpu_reset_needs_v4_MMU_disable)
431 END(cpu_halt)
432
433
434 /*
435  * setjump + longjmp
436  */
437 ENTRY(setjmp)
438         stmia   r0, {r4-r14}
439         mov     r0, #0x00000000
440         RET
441 END(setjmp)
442
443 ENTRY(longjmp)
444         ldmia   r0, {r4-r14}
445         mov     r0, #0x00000001
446         RET
447 END(longjmp)
448
449         .data
450         .global _C_LABEL(esym)
451 _C_LABEL(esym): .word   _C_LABEL(end)
452
453 ENTRY_NP(abort)
454         b       _C_LABEL(abort)
455 END(abort)
456
457 ENTRY_NP(sigcode)
458         mov     r0, sp
459         add     r0, r0, #SIGF_UC
460
461         /*
462          * Call the sigreturn system call.
463          *
464          * We have to load r7 manually rather than using
465          * "ldr r7, =SYS_sigreturn" to ensure the value of szsigcode is
466          * correct. Using the alternative places esigcode at the address
467          * of the data rather than the address one past the data.
468          */
469
470         ldr     r7, [pc, #12]   /* Load SYS_sigreturn */
471         swi     SYS_sigreturn
472
473         /* Well if that failed we better exit quick ! */
474
475         ldr     r7, [pc, #8]    /* Load SYS_exit */
476         swi     SYS_exit
477
478         /* Branch back to retry SYS_sigreturn */
479         b       . - 16
480 END(sigcode)
481         .word   SYS_sigreturn
482         .word   SYS_exit
483
484         .align  2
485         .global _C_LABEL(esigcode)
486                 _C_LABEL(esigcode):
487
488         .data
489         .global szsigcode
490 szsigcode:
491         .long esigcode-sigcode
492
493 /* End of locore.S */