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