]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - sys/arm/arm/locore.S
MFC r269390: Fix unwind info in hand-written asm (avoid nested functions).
[FreeBSD/stable/10.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 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/pte.h>
41
42 __FBSDID("$FreeBSD$");
43
44 /* What size should this really be ? It is only used by initarm() */
45 #define INIT_ARM_STACK_SIZE     (2048 * 4)
46
47 #define CPWAIT_BRANCH                                                    \
48         sub     pc, pc, #4
49
50 #define CPWAIT(tmp)                                                      \
51         mrc     p15, 0, tmp, c2, c0, 0  /* arbitrary read of CP15 */    ;\
52         mov     tmp, tmp                /* wait for it to complete */   ;\
53         CPWAIT_BRANCH                   /* branch to next insn */
54
55 /*
56  * This is for kvm_mkdb, and should be the address of the beginning
57  * of the kernel text segment (not necessarily the same as kernbase).
58  */
59         .text
60         .align  0
61 .globl kernbase
62 .set kernbase,KERNBASE
63 .globl physaddr
64 .set physaddr,PHYSADDR
65
66 /*
67  * On entry for FreeBSD boot ABI:
68  *      r0 - metadata pointer or 0 (boothowto on AT91's boot2)
69  *      r1 - if (r0 == 0) then metadata pointer
70  * On entry for Linux boot ABI:
71  *      r0 - 0
72  *      r1 - machine type (passed as arg2 to initarm)
73  *      r2 - Pointer to a tagged list or dtb image (phys addr) (passed as arg1 initarm)
74  *
75  * For both types of boot we gather up the args, put them in a struct arm_boot_params
76  * structure and pass that to initarm.
77  */
78         .globl  btext
79 btext:
80 ASENTRY_NP(_start)
81         STOP_UNWINDING          /* Can't unwind into the bootloader! */
82
83         mov     r9, r0          /* 0 or boot mode from boot2 */
84         mov     r8, r1          /* Save Machine type */
85         mov     ip, r2          /* Save meta data */
86         mov     fp, r3          /* Future expantion */
87
88         /* Make sure interrupts are disabled. */
89         mrs     r7, cpsr
90         orr     r7, r7, #(I32_bit|F32_bit)
91         msr     cpsr_c, r7
92
93 #if defined (FLASHADDR) && defined(LOADERRAMADDR)
94         /* Check if we're running from flash. */
95         ldr     r7, =FLASHADDR
96         /*
97          * If we're running with MMU disabled, test against the
98          * physical address instead.
99          */
100         mrc     p15, 0, r2, c1, c0, 0
101         ands    r2, r2, #CPU_CONTROL_MMU_ENABLE
102         ldreq   r6, =PHYSADDR
103         ldrne   r6, =LOADERRAMADDR
104         cmp     r7, r6
105         bls     flash_lower
106         cmp     r7, pc
107         bhi     from_ram
108         b       do_copy
109         
110 flash_lower:
111         cmp     r6, pc
112         bls     from_ram
113 do_copy:
114         ldr     r7, =KERNBASE
115         adr     r1, _start
116         ldr     r0, Lreal_start
117         ldr     r2, Lend
118         sub     r2, r2, r0
119         sub     r0, r0, r7
120         add     r0, r0, r6
121         mov     r4, r0
122         bl      memcpy
123         ldr     r0, Lram_offset
124         add     pc, r4, r0
125 Lram_offset:    .word from_ram-_C_LABEL(_start)
126 from_ram:
127         nop
128 #endif
129         adr     r7, Lunmapped
130         bic     r7, r7, #0xf0000000
131         orr     r7, r7, #PHYSADDR
132
133
134 disable_mmu:
135         /* Disable MMU for a while */
136         mrc     p15, 0, r2, c1, c0, 0
137         bic     r2, r2, #(CPU_CONTROL_MMU_ENABLE | CPU_CONTROL_DC_ENABLE |\
138             CPU_CONTROL_WBUF_ENABLE)
139         bic     r2, r2, #(CPU_CONTROL_IC_ENABLE)
140         bic     r2, r2, #(CPU_CONTROL_BPRD_ENABLE)
141         mcr     p15, 0, r2, c1, c0, 0
142
143         nop
144         nop
145         nop
146         mov     pc, r7
147 Lunmapped:
148         /*
149          * Build page table from scratch.
150          */
151
152         /* Find the delta between VA and PA */
153         adr     r0, Lpagetable
154         ldr     r1, [r0]
155         sub     r2, r1, r0
156         /* At this point: r2 = VA - PA */
157
158         /*
159          * Find the physical address of the table. After these two
160          * instructions:
161          * r1 = va(pagetable)
162          *
163          * r0 = va(pagetable) - (VA - PA)
164          *    = va(pagetable) - VA + PA
165          *    = pa(pagetable)
166          */
167         ldr     r1, [r0, #4]
168         sub     r0, r1, r2
169
170         /*
171          * Map PA == VA
172          */
173         /* Find the start kernels load address */
174         adr     r5, _start
175         ldr     r2, =(L1_S_OFFSET)
176         bic     r5, r2
177         mov     r1, r5
178         mov     r2, r5
179         /* Map 64MiB, preserved over calls to build_pagetables */
180         mov     r3, #64
181         bl      build_pagetables
182
183         /* Create the kernel map to jump to */
184         mov     r1, r5
185         ldr     r2, =(KERNVIRTADDR)
186         bl      build_pagetables
187         
188 #if defined(SOCDEV_PA) && defined(SOCDEV_VA)
189         /* Create the custom map */
190         ldr     r1, =SOCDEV_PA
191         ldr     r2, =SOCDEV_VA
192         bl      build_pagetables
193 #endif
194
195 #if defined(SMP)
196         orr     r0, r0, #2              /* Set TTB shared memory flag */
197 #endif
198         mcr     p15, 0, r0, c2, c0, 0   /* Set TTB */
199         mcr     p15, 0, r0, c8, c7, 0   /* Flush TLB */
200
201 #if defined(CPU_ARM1136) || defined(CPU_ARM1176) || defined(CPU_CORTEXA) || defined(CPU_MV_PJ4B) || defined(CPU_KRAIT)
202         mov     r0, #0
203         mcr     p15, 0, r0, c13, c0, 1  /* Set ASID to 0 */
204 #endif
205
206         /* Set the Domain Access register.  Very important! */
207         mov     r0, #((DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)) | DOMAIN_CLIENT)
208         mcr     p15, 0, r0, c3, c0, 0
209         /* 
210          * Enable MMU.
211          * On armv6 enable extended page tables, and set alignment checking
212          * to modulo-4 (CPU_CONTROL_UNAL_ENABLE) for the ldrd/strd
213          * instructions emitted by clang.
214          */
215         mrc     p15, 0, r0, c1, c0, 0
216 #ifdef _ARM_ARCH_6
217         orr     r0, r0, #(CPU_CONTROL_V6_EXTPAGE | CPU_CONTROL_UNAL_ENABLE)
218         orr     r0, r0, #(CPU_CONTROL_AFLT_ENABLE)
219         orr     r0, r0, #(CPU_CONTROL_AF_ENABLE)
220 #endif
221         orr     r0, r0, #(CPU_CONTROL_MMU_ENABLE)
222         mcr     p15, 0, r0, c1, c0, 0
223         nop
224         nop
225         nop
226         CPWAIT(r0)
227
228 mmu_done:
229         nop
230         adr     r1, .Lstart
231         ldmia   r1, {r1, r2, sp}        /* Set initial stack and */
232         sub     r2, r2, r1              /* get zero init data */
233         mov     r3, #0
234 .L1:
235         str     r3, [r1], #0x0004       /* get zero init data */
236         subs    r2, r2, #4
237         bgt     .L1
238         ldr     pc, .Lvirt_done
239
240 virt_done:
241         mov     r1, #28                 /* loader info size is 28 bytes also second arg */
242         subs    sp, sp, r1              /* allocate arm_boot_params struct on stack */
243         mov     r0, sp                  /* loader info pointer is first arg */
244         bic     sp, sp, #7              /* align stack to 8 bytes */
245         str     r1, [r0]                /* Store length of loader info */
246         str     r9, [r0, #4]            /* Store r0 from boot loader */
247         str     r8, [r0, #8]            /* Store r1 from boot loader */
248         str     ip, [r0, #12]           /* store r2 from boot loader */
249         str     fp, [r0, #16]           /* store r3 from boot loader */
250         str     r5, [r0, #20]           /* store the physical address */
251         adr     r4, Lpagetable          /* load the pagetable address */
252         ldr     r5, [r4, #4]
253         str     r5, [r0, #24]           /* store the pagetable address */
254         mov     fp, #0                  /* trace back starts here */
255         bl      _C_LABEL(initarm)       /* Off we go */
256
257         /* init arm will return the new stack pointer. */
258         mov     sp, r0
259
260         bl      _C_LABEL(mi_startup)            /* call mi_startup()! */
261
262         adr     r0, .Lmainreturned
263         b       _C_LABEL(panic)
264         /* NOTREACHED */
265 END(_start)
266
267 /*
268  * Builds the page table
269  * r0 - The table base address
270  * r1 - The physical address (trashed)
271  * r2 - The virtual address (trashed)
272  * r3 - The number of 1MiB sections
273  * r4 - Trashed
274  *
275  * Addresses must be 1MiB aligned
276  */
277 build_pagetables:
278         /* Set the required page attributed */
279         ldr     r4, =(L1_TYPE_S|L1_S_C|L1_S_AP(AP_KRW))
280 #if defined(SMP)
281         orr     r4, #(L1_SHARED)
282 #endif
283         orr     r1, r4
284
285         /* Move the virtual address to the correct bit location */
286         lsr     r2, #(L1_S_SHIFT - 2)
287
288         mov     r4, r3
289 1:
290         str     r1, [r0, r2]
291         add     r2, r2, #4
292         add     r1, r1, #(L1_S_SIZE)
293         adds    r4, r4, #-1
294         bhi     1b
295
296         RET
297
298 Lpagetable:
299         .word   .
300         .word   pagetable
301
302 Lvirtaddr:
303         .word   KERNVIRTADDR
304 Lphysaddr:
305         .word   KERNPHYSADDR
306 Lreal_start:
307         .word   _start
308 Lend:
309         .word   _edata
310
311 .Lstart:
312         .word   _edata
313         .word   _ebss
314         .word   svcstk + INIT_ARM_STACK_SIZE
315
316 .Lvirt_done:
317         .word   virt_done
318
319 .Lmainreturned:
320         .asciz  "main() returned"
321         .align  0
322
323         .bss
324 svcstk:
325         .space  INIT_ARM_STACK_SIZE
326
327 /*
328  * Memory for the initial pagetable. We are unable to place this in
329  * the bss as this will be cleared after the table is loaded.
330  */
331         .section ".init_pagetable"
332         .align  14 /* 16KiB aligned */
333 pagetable:
334         .space  L1_TABLE_SIZE
335
336         .text
337         .align  0
338
339 .Lcpufuncs:
340         .word   _C_LABEL(cpufuncs)
341
342 #if defined(SMP)
343
344 .Lmpvirt_done:
345         .word   mpvirt_done
346 Lstartup_pagetable_secondary:
347         .word   temp_pagetable
348
349 ASENTRY_NP(mpentry)
350
351         /* Make sure interrupts are disabled. */
352         mrs     r7, cpsr
353         orr     r7, r7, #(I32_bit|F32_bit)
354         msr     cpsr_c, r7
355
356         /* Disable MMU.  It should be disabled already, but make sure. */
357         mrc     p15, 0, r2, c1, c0, 0
358         bic     r2, r2, #(CPU_CONTROL_MMU_ENABLE | CPU_CONTROL_DC_ENABLE |\
359             CPU_CONTROL_WBUF_ENABLE)
360         bic     r2, r2, #(CPU_CONTROL_IC_ENABLE)
361         bic     r2, r2, #(CPU_CONTROL_BPRD_ENABLE)
362         mcr     p15, 0, r2, c1, c0, 0
363         nop
364         nop
365         nop
366         CPWAIT(r0)
367
368 #if defined(ARM_MMU_V6)
369         bl      armv6_idcache_inv_all   /* Modifies r0 only */
370 #elif defined(ARM_MMU_V7)
371         bl      armv7_idcache_inv_all   /* Modifies r0-r3, ip */
372 #endif
373
374         ldr     r0, Lstartup_pagetable_secondary
375         bic     r0, r0, #0xf0000000
376         orr     r0, r0, #PHYSADDR
377         ldr     r0, [r0]
378         orr     r0, r0, #2              /* Set TTB shared memory flag */
379         mcr     p15, 0, r0, c2, c0, 0   /* Set TTB */
380         mcr     p15, 0, r0, c8, c7, 0   /* Flush TLB */
381
382         mov     r0, #0
383         mcr     p15, 0, r0, c13, c0, 1  /* Set ASID to 0 */
384
385         /* Set the Domain Access register.  Very important! */
386         mov     r0, #((DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)) | DOMAIN_CLIENT)
387         mcr     p15, 0, r0, c3, c0, 0
388         /* Enable MMU */
389         mrc     p15, 0, r0, c1, c0, 0
390         orr     r0, r0, #CPU_CONTROL_V6_EXTPAGE
391         orr     r0, r0, #CPU_CONTROL_AF_ENABLE
392         orr     r0, r0, #(CPU_CONTROL_MMU_ENABLE | CPU_CONTROL_DC_ENABLE |\
393             CPU_CONTROL_WBUF_ENABLE)
394         orr     r0, r0, #(CPU_CONTROL_IC_ENABLE)
395         orr     r0, r0, #(CPU_CONTROL_BPRD_ENABLE)
396         mcr     p15, 0, r0, c1, c0, 0
397         nop
398         nop
399         nop
400         CPWAIT(r0)
401
402         adr     r1, .Lstart
403         ldmia   r1, {r1, r2, sp}        /* Set initial stack and */
404         mrc     p15, 0, r0, c0, c0, 5
405         and     r0, r0, #15
406         mov     r1, #2048
407         mul     r2, r1, r0
408         sub     sp, sp, r2
409         str     r1, [sp]
410         ldr     pc, .Lmpvirt_done
411
412 mpvirt_done:
413
414         mov     fp, #0                  /* trace back starts here */
415         bl      _C_LABEL(init_secondary)        /* Off we go */
416
417         adr     r0, .Lmpreturned
418         b       _C_LABEL(panic)
419         /* NOTREACHED */
420
421 .Lmpreturned:
422         .asciz  "init_secondary() returned"
423         .align  0
424 END(mpentry)
425 #endif
426
427 ENTRY_NP(cpu_halt)
428         mrs     r2, cpsr
429         bic     r2, r2, #(PSR_MODE)
430         orr     r2, r2, #(PSR_SVC32_MODE)
431         orr     r2, r2, #(I32_bit | F32_bit)
432         msr     cpsr_fsxc, r2
433
434         ldr     r4, .Lcpu_reset_address
435         ldr     r4, [r4]
436
437         ldr     r0, .Lcpufuncs
438         mov     lr, pc
439         ldr     pc, [r0, #CF_IDCACHE_WBINV_ALL]
440         mov     lr, pc
441         ldr     pc, [r0, #CF_L2CACHE_WBINV_ALL]
442
443         /*
444          * Load the cpu_reset_needs_v4_MMU_disable flag to determine if it's
445          * necessary.
446          */
447
448         ldr     r1, .Lcpu_reset_needs_v4_MMU_disable
449         ldr     r1, [r1]
450         cmp     r1, #0
451         mov     r2, #0
452
453         /*
454          * MMU & IDC off, 32 bit program & data space
455          * Hurl ourselves into the ROM
456          */
457         mov     r0, #(CPU_CONTROL_32BP_ENABLE | CPU_CONTROL_32BD_ENABLE)
458         mcr     15, 0, r0, c1, c0, 0
459         mcrne   15, 0, r2, c8, c7, 0    /* nail I+D TLB on ARMv4 and greater */
460         mov     pc, r4
461
462         /*
463          * _cpu_reset_address contains the address to branch to, to complete
464          * the cpu reset after turning the MMU off
465          * This variable is provided by the hardware specific code
466          */
467 .Lcpu_reset_address:
468         .word   _C_LABEL(cpu_reset_address)
469
470         /*
471          * cpu_reset_needs_v4_MMU_disable contains a flag that signals if the
472          * v4 MMU disable instruction needs executing... it is an illegal instruction
473          * on f.e. ARM6/7 that locks up the computer in an endless illegal
474          * instruction / data-abort / reset loop.
475          */
476 .Lcpu_reset_needs_v4_MMU_disable:
477         .word   _C_LABEL(cpu_reset_needs_v4_MMU_disable)
478 END(cpu_halt)
479
480
481 /*
482  * setjump + longjmp
483  */
484 ENTRY(setjmp)
485         stmia   r0, {r4-r14}
486         mov     r0, #0x00000000
487         RET
488 END(setjmp)
489
490 ENTRY(longjmp)
491         ldmia   r0, {r4-r14}
492         mov     r0, #0x00000001
493         RET
494 END(longjmp)
495
496         .data
497         .global _C_LABEL(esym)
498 _C_LABEL(esym): .word   _C_LABEL(end)
499
500 ENTRY_NP(abort)
501         b       _C_LABEL(abort)
502 END(abort)
503
504 ENTRY_NP(sigcode)
505         mov     r0, sp
506         add     r0, r0, #SIGF_UC
507
508         /*
509          * Call the sigreturn system call.
510          * 
511          * We have to load r7 manually rather than using
512          * "ldr r7, =SYS_sigreturn" to ensure the value of szsigcode is
513          * correct. Using the alternative places esigcode at the address
514          * of the data rather than the address one past the data.
515          */
516
517         ldr     r7, [pc, #12]   /* Load SYS_sigreturn */
518         swi     SYS_sigreturn
519
520         /* Well if that failed we better exit quick ! */
521
522         ldr     r7, [pc, #8]    /* Load SYS_exit */
523         swi     SYS_exit
524
525         /* Branch back to retry SYS_sigreturn */
526         b       . - 16
527 END(sigcode)
528         .word   SYS_sigreturn
529         .word   SYS_exit
530
531         .align  0
532         .global _C_LABEL(esigcode)
533                 _C_LABEL(esigcode):
534
535         .data
536         .global szsigcode
537 szsigcode:
538         .long esigcode-sigcode
539
540 /* End of locore.S */