]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/arm/arm/locore-v6.S
Update llvm to trunk r256945.
[FreeBSD/FreeBSD.git] / sys / arm / arm / locore-v6.S
1 /*-
2  * Copyright 2004-2014 Olivier Houchard <cognet@FreeBSD.org>
3  * Copyright 2012-2014 Ian Lepore <ian@FreeBSD.org>
4  * Copyright 2013-2014 Andrew Turner <andrew@FreeBSD.org>
5  * Copyright 2014 Svatopluk Kraus <onwahe@gmail.com>
6  * Copyright 2014 Michal Meloun <meloun@miracle.cz>
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  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  */
30
31 #include "assym.s"
32 #include <sys/syscall.h>
33 #include <machine/asm.h>
34 #include <machine/asmacros.h>
35 #include <machine/armreg.h>
36 #include <machine/sysreg.h>
37 #include <machine/cpuconf.h>
38 #include <machine/pte.h>
39
40 __FBSDID("$FreeBSD$");
41
42 #ifndef ARM_NEW_PMAP
43 #define PTE1_OFFSET     L1_S_OFFSET
44 #define PTE1_SHIFT      L1_S_SHIFT
45 #define PTE1_SIZE       L1_S_SIZE
46 #endif
47
48 #if __ARM_ARCH >= 7
49 #if defined(__ARM_ARCH_7VE__) || defined(__clang__)
50 /*
51  * HYP support is in bintuils >= 2.21 and gcc >= 4.9 defines __ARM_ARCH_7VE__
52  * when enabled. llvm >= 3.6 supports it too.
53  */
54 .arch_extension virt
55 #define MSR_ELR_HYP(regnum)     msr     elr_hyp, lr
56 #define ERET    eret
57 #else
58 #define MSR_ELR_HYP(regnum) .word (0xe12ef300 | regnum)
59 #define ERET .word 0xe160006e
60 #endif
61 #endif /* __ARM_ARCH >= 7 */
62
63 /* A small statically-allocated stack used only during initarm() and AP startup. */
64 #define INIT_ARM_STACK_SIZE     2048
65
66         .text
67         .align  2
68
69 #if __ARM_ARCH >= 7
70 #define LEAVE_HYP                                                       \
71         /* Leave HYP mode */                                            ;\
72         mrs     r0, cpsr                                                ;\
73         and     r0, r0, #(PSR_MODE)   /* Mode is in the low 5 bits of CPSR */ ;\
74         teq     r0, #(PSR_HYP32_MODE) /* Hyp Mode? */                   ;\
75         bne     1f                                                      ;\
76         /* Ensure that IRQ, FIQ and Aborts will be disabled after eret */ ;\
77         mrs     r0, cpsr                                                ;\
78         bic     r0, r0, #(PSR_MODE)                                     ;\
79         orr     r0, r0, #(PSR_SVC32_MODE)                               ;\
80         orr     r0, r0, #(PSR_I | PSR_F | PSR_A)                        ;\
81         msr     spsr_cxsf, r0                                           ;\
82         /* Exit hypervisor mode */                                      ;\
83         adr     lr, 1f                                                  ;\
84         MSR_ELR_HYP(14)                                                 ;\
85         ERET                                                            ;\
86 1:
87 #else
88 #define LEAVE_HYP
89 #endif /* __ARM_ARCH >= 7 */
90
91 /*
92  * On entry for FreeBSD boot ABI:
93  *      r0 - metadata pointer or 0 (boothowto on AT91's boot2)
94  *      r1 - if (r0 == 0) then metadata pointer
95  * On entry for Linux boot ABI:
96  *      r0 - 0
97  *      r1 - machine type (passed as arg2 to initarm)
98  *      r2 - Pointer to a tagged list or dtb image (phys addr) (passed as arg1 initarm)
99  *
100  * For both types of boot we gather up the args, put them in a struct arm_boot_params
101  * structure and pass that to initarm.
102  */
103         .globl  btext
104 btext:
105 ASENTRY_NP(_start)
106         STOP_UNWINDING          /* Can't unwind into the bootloader! */
107
108         /* Make sure interrupts are disabled. */
109         cpsid   ifa
110
111         mov     r8, r0          /* 0 or boot mode from boot2 */
112         mov     r9, r1          /* Save Machine type */
113         mov     r10, r2         /* Save meta data */
114         mov     r11, r3         /* Future expansion */
115
116         LEAVE_HYP
117
118         /*
119          * Check whether data cache is enabled.  If it is, then we know
120          * current tags are valid (not power-on garbage values) and there
121          * might be dirty lines that need cleaning.  Disable cache to prevent
122          * new lines being allocated, then call wbinv_poc_all to clean it.
123          */
124         mrc     CP15_SCTLR(r7)
125         tst     r7, #CPU_CONTROL_DC_ENABLE
126         blne    dcache_wbinv_poc_all
127
128         /* ! Do not write to memory between wbinv and disabling cache ! */
129
130         /*
131          * Now there are no dirty lines, but there may still be lines marked
132          * valid.  Disable all caches and the MMU, and invalidate everything
133          * before setting up new page tables and re-enabling the mmu.
134          */
135 1:
136         bic     r7, #CPU_CONTROL_DC_ENABLE
137         bic     r7, #CPU_CONTROL_MMU_ENABLE
138         bic     r7, #CPU_CONTROL_IC_ENABLE
139         bic     r7, #CPU_CONTROL_UNAL_ENABLE
140         bic     r7, #CPU_CONTROL_BPRD_ENABLE
141         bic     r7, #CPU_CONTROL_SW_ENABLE
142         orr     r7, #CPU_CONTROL_AFLT_ENABLE
143         orr     r7, #CPU_CONTROL_VECRELOC
144         mcr     CP15_SCTLR(r7)
145         DSB
146         ISB
147         bl      dcache_inv_poc_all
148         mcr     CP15_ICIALLU
149         DSB
150         ISB
151
152         /*
153          * Build page table from scratch.
154          */
155
156         /* 
157          * Figure out the physical address we're loaded at by assuming this
158          * entry point code is in the first L1 section and so if we clear the
159          * offset bits of the pc that will give us the section-aligned load
160          * address, which remains in r5 throughout all the following code.
161          */
162         ldr     r2, =(L1_S_OFFSET)
163         bic     r5, pc, r2
164
165         /* Find the delta between VA and PA, result stays in r0 throughout. */
166         adr     r0, Lpagetable
167         bl      translate_va_to_pa
168
169         /* 
170          * First map the entire 4GB address space as VA=PA.  It's mapped as
171          * normal (cached) memory because it's for things like accessing the
172          * parameters passed in from the bootloader, which might be at any
173          * physical address, different for every platform.
174          */
175         mov     r1, #0
176         mov     r2, #0
177         mov     r3, #4096
178         bl      build_pagetables
179
180         /* 
181          * Next we do 64MiB starting at the physical load address, mapped to
182          * the VA the kernel is linked for.
183          */
184         mov     r1, r5
185         ldr     r2, =(KERNVIRTADDR)
186         mov     r3, #64
187         bl      build_pagetables
188
189         /* Create a device mapping for early_printf if specified. */
190 #if defined(SOCDEV_PA) && defined(SOCDEV_VA)
191         ldr     r1, =SOCDEV_PA
192         ldr     r2, =SOCDEV_VA
193         mov     r3, #1
194         bl      build_device_pagetables
195 #endif
196         bl      init_mmu
197
198         /* Transition the PC from physical to virtual addressing. */
199         ldr     pc, =1f
200 1:
201
202         /* Setup stack, clear BSS */
203         ldr     r1, =.Lstart
204         ldmia   r1, {r1, r2, sp}        /* Set initial stack and */
205         add     sp, sp, #INIT_ARM_STACK_SIZE
206         sub     r2, r2, r1              /* get zero init data */
207         mov     r3, #0
208 2:
209         str     r3, [r1], #0x0004       /* get zero init data */
210         subs    r2, r2, #4
211         bgt     2b
212
213         mov     r1, #28                 /* loader info size is 28 bytes also second arg */
214         subs    sp, sp, r1              /* allocate arm_boot_params struct on stack */
215         mov     r0, sp                  /* loader info pointer is first arg */
216         bic     sp, sp, #7              /* align stack to 8 bytes */
217         str     r1, [r0]                /* Store length of loader info */
218         str     r8, [r0, #4]            /* Store r0 from boot loader */
219         str     r9, [r0, #8]            /* Store r1 from boot loader */
220         str     r10, [r0, #12]          /* store r2 from boot loader */
221         str     r11, [r0, #16]          /* store r3 from boot loader */
222         str     r5, [r0, #20]           /* store the physical address */
223         adr     r4, Lpagetable          /* load the pagetable address */
224         ldr     r5, [r4, #4]
225         str     r5, [r0, #24]           /* store the pagetable address */
226         mov     fp, #0                  /* trace back starts here */
227         bl      _C_LABEL(initarm)       /* Off we go */
228
229         /* init arm will return the new stack pointer. */
230         mov     sp, r0
231
232         bl      _C_LABEL(mi_startup)    /* call mi_startup()! */
233
234         ldr     r0, =.Lmainreturned
235         b       _C_LABEL(panic)
236         /* NOTREACHED */
237 END(_start)
238
239 #define VA_TO_PA_POINTER(name, table)    \
240 name:                                   ;\
241         .word   .                       ;\
242         .word   table
243
244 /*
245  * Returns the physical address of a magic va to pa pointer.
246  * r0     - The pagetable data pointer. This must be built using the
247  *          VA_TO_PA_POINTER macro.
248  *          e.g.
249  *            VA_TO_PA_POINTER(Lpagetable, pagetable)
250  *            ...
251  *            adr  r0, Lpagetable
252  *            bl   translate_va_to_pa
253  *            r0 will now contain the physical address of pagetable
254  * r1, r2 - Trashed
255  */
256 translate_va_to_pa:
257         ldr     r1, [r0]
258         sub     r2, r1, r0
259         /* At this point: r2 = VA - PA */
260
261         /*
262          * Find the physical address of the table. After these two
263          * instructions:
264          * r1 = va(pagetable)
265          *
266          * r0 = va(pagetable) - (VA - PA)
267          *    = va(pagetable) - VA + PA
268          *    = pa(pagetable)
269          */
270         ldr     r1, [r0, #4]
271         sub     r0, r1, r2
272         mov     pc, lr
273
274 /*
275  * Init MMU
276  * r0 - the table base address
277  */
278
279 ASENTRY_NP(init_mmu)
280
281         /* Setup TLB and MMU registers */
282         mcr     CP15_TTBR0(r0)          /* Set TTB */
283         mov     r0, #0
284         mcr     CP15_CONTEXTIDR(r0)     /* Set ASID to 0 */
285
286         /* Set the Domain Access register */
287         mov     r0, #((DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)) | DOMAIN_CLIENT)
288         mcr     CP15_DACR(r0)
289
290 #ifdef ARM_NEW_PMAP
291         /*
292          * Set TEX remap registers
293          *  - All is set to uncacheable memory
294          */
295         ldr     r0, =0xAAAAA
296         mcr     CP15_PRRR(r0)
297         mov     r0, #0
298         mcr     CP15_NMRR(r0)
299 #endif
300         mcr     CP15_TLBIALL            /* Flush TLB */
301         DSB
302         ISB
303
304         /* Enable MMU */
305         mrc     CP15_SCTLR(r0)
306         orr     r0, r0, #CPU_CONTROL_MMU_ENABLE
307         orr     r0, r0, #CPU_CONTROL_V6_EXTPAGE
308 #ifdef ARM_NEW_PMAP
309         orr     r0, r0, #CPU_CONTROL_TR_ENABLE
310 #endif
311         orr     r0, r0, #CPU_CONTROL_AF_ENABLE
312         mcr     CP15_SCTLR(r0)
313         DSB
314         ISB
315         mcr     CP15_TLBIALL            /* Flush TLB */
316         mcr     CP15_BPIALL             /* Flush Branch predictor */
317         DSB
318         ISB
319
320         mov     pc, lr
321 END(init_mmu)
322
323
324 /*
325  * Init SMP coherent mode, enable caching and switch to final MMU table.
326  * Called with disabled caches
327  * r0 - The table base address
328  * r1 - clear bits for aux register
329  * r2 - set bits for aux register
330  */
331 ASENTRY_NP(reinit_mmu)
332         push    {r4-r11, lr}
333         mov     r4, r0
334         mov     r5, r1
335         mov     r6, r2
336
337         /* !! Be very paranoid here !! */
338         /* !! We cannot write single bit here !! */
339
340 #if 0   /* XXX writeback shouldn't be necessary */
341         /* Write back and invalidate all integrated caches */
342         bl      dcache_wbinv_poc_all
343 #else
344         bl      dcache_inv_pou_all
345 #endif
346         mcr     CP15_ICIALLU
347         DSB
348         ISB
349
350         /* Set auxiliary register */
351         mrc     CP15_ACTLR(r7)
352         bic     r8, r7, r5              /* Mask bits */
353         eor     r8, r8, r6              /* Set bits */
354         teq     r7, r8
355         mcrne   CP15_ACTLR(r8)
356         DSB
357         ISB
358
359         /* Enable caches. */
360         mrc     CP15_SCTLR(r7)
361         orr     r7, #CPU_CONTROL_DC_ENABLE
362         orr     r7, #CPU_CONTROL_IC_ENABLE
363         orr     r7, #CPU_CONTROL_BPRD_ENABLE
364         mcr     CP15_SCTLR(r7)
365         DSB
366
367         mcr     CP15_TTBR0(r4)          /* Set new TTB */
368         DSB
369         ISB
370
371         mcr     CP15_TLBIALL            /* Flush TLB */
372         mcr     CP15_BPIALL             /* Flush Branch predictor */
373         DSB
374         ISB
375
376 #if 0 /* XXX writeback shouldn't be necessary */
377         /* Write back and invalidate all integrated caches */
378         bl      dcache_wbinv_poc_all
379 #else
380         bl      dcache_inv_pou_all
381 #endif
382         mcr     CP15_ICIALLU
383         DSB
384         ISB
385
386         pop     {r4-r11, pc}
387 END(reinit_mmu)
388
389
390 /*
391  * Builds the page table
392  * r0 - The table base address
393  * r1 - The physical address (trashed)
394  * r2 - The virtual address (trashed)
395  * r3 - The number of 1MiB sections
396  * r4 - Trashed
397  *
398  * Addresses must be 1MiB aligned
399  */
400 build_device_pagetables:
401 #if defined(ARM_NEW_PMAP)
402         ldr     r4, =PTE1_V|PTE1_A|PTE1_AP_KRW|TEX1_CLASS_0
403 #elif defined(SMP)
404         ldr     r4, =(L1_TYPE_S|L1_S_AP(AP_KRW)|L1_SHARED)
405 #else
406         ldr     r4, =(L1_TYPE_S|L1_S_AP(AP_KRW))
407 #endif
408         b       1f
409 build_pagetables:
410         /* Set the required page attributed */
411 #if defined(ARM_NEW_PMAP)
412         ldr     r4, =PTE1_V|PTE1_A|PTE1_AP_KRW|TEX1_CLASS_0
413 #elif defined(SMP)
414         ldr     r4, =(L1_TYPE_S|L1_S_C|L1_S_AP(AP_KRW)|L1_SHARED)
415 #else
416         ldr     r4, =(L1_TYPE_S|L1_S_C|L1_S_AP(AP_KRW))
417 #endif
418 1:
419         orr     r1, r4
420
421         /* Move the virtual address to the correct bit location */
422         lsr     r2, #(PTE1_SHIFT - 2)
423
424         mov     r4, r3
425 2:
426         str     r1, [r0, r2]
427         add     r2, r2, #4
428         add     r1, r1, #(PTE1_SIZE)
429         adds    r4, r4, #-1
430         bhi     2b
431
432         mov     pc, lr
433
434 VA_TO_PA_POINTER(Lpagetable, boot_pt1)
435
436
437 .Lstart:
438         .word   _edata                  /* Note that these three items are */
439         .word   _ebss                   /* loaded with a single ldmia and */
440         .word   svcstk                  /* must remain in order together. */
441
442 .Lmainreturned:
443         .asciz  "main() returned"
444         .align  2
445
446         .bss
447 svcstk:
448         .space  INIT_ARM_STACK_SIZE * MAXCPU
449
450 /*
451  * Memory for the initial pagetable. We are unable to place this in
452  * the bss as this will be cleared after the table is loaded.
453  */
454         .section ".init_pagetable"
455         .align  14 /* 16KiB aligned */
456         .globl  boot_pt1
457 boot_pt1:
458         .space  L1_TABLE_SIZE
459
460         .text
461         .align  2
462
463 .Lcpufuncs:
464         .word   _C_LABEL(cpufuncs)
465
466 #if defined(SMP)
467
468 ASENTRY_NP(mpentry)
469         /* Make sure interrupts are disabled. */
470         cpsid   ifa
471
472         LEAVE_HYP
473
474         /* Setup core, disable all caches. */
475         mrc     CP15_SCTLR(r0)
476         bic     r0, #CPU_CONTROL_MMU_ENABLE
477         bic     r0, #CPU_CONTROL_DC_ENABLE
478         bic     r0, #CPU_CONTROL_IC_ENABLE
479         bic     r0, #CPU_CONTROL_UNAL_ENABLE
480         bic     r0, #CPU_CONTROL_BPRD_ENABLE
481         bic     r0, #CPU_CONTROL_SW_ENABLE
482         orr     r0, #CPU_CONTROL_AFLT_ENABLE
483         orr     r0, #CPU_CONTROL_VECRELOC
484         mcr     CP15_SCTLR(r0)
485         DSB
486         ISB
487
488         /* Invalidate L1 cache I+D cache */
489         bl      dcache_inv_pou_all
490         mcr     CP15_ICIALLU
491         DSB
492         ISB
493
494         /* Find the delta between VA and PA */
495         adr     r0, Lpagetable
496         bl      translate_va_to_pa
497
498         bl      init_mmu
499
500         adr     r1, .Lstart+8           /* Get initstack pointer from */
501         ldr     sp, [r1]                /* startup data. */
502         mrc     CP15_MPIDR(r0)          /* Get processor id number. */
503         and     r0, r0, #0x0f
504         mov     r1, #INIT_ARM_STACK_SIZE
505         mul     r2, r1, r0              /* Point sp to initstack */
506         add     sp, sp, r2              /* area for this processor. */
507
508         /* Switch to virtual addresses. */
509         ldr     pc, =1f
510 1:
511         mov     fp, #0                  /* trace back starts here */
512         bl      _C_LABEL(init_secondary)/* Off we go, cpu id in r0. */
513
514         adr     r0, .Lmpreturned
515         b       _C_LABEL(panic)
516         /* NOTREACHED */
517 END(mpentry)
518
519 .Lmpreturned:
520         .asciz  "init_secondary() returned"
521         .align  2
522 #endif
523
524 ENTRY_NP(cpu_halt)
525
526         /* XXX re-implement !!! */
527         cpsid   ifa
528         bl      dcache_wbinv_poc_all
529
530         ldr     r4, .Lcpu_reset_address
531         ldr     r4, [r4]
532         teq     r4, #0
533         movne   pc, r4
534 1:
535         WFI
536         b       1b
537
538         /*
539          * _cpu_reset_address contains the address to branch to, to complete
540          * the cpu reset after turning the MMU off
541          * This variable is provided by the hardware specific code
542          */
543 .Lcpu_reset_address:
544         .word   _C_LABEL(cpu_reset_address)
545 END(cpu_halt)
546
547
548 /*
549  * setjump + longjmp
550  */
551 ENTRY(setjmp)
552         stmia   r0, {r4-r14}
553         mov     r0, #0x00000000
554         RET
555 END(setjmp)
556
557 ENTRY(longjmp)
558         ldmia   r0, {r4-r14}
559         mov     r0, #0x00000001
560         RET
561 END(longjmp)
562
563         .data
564         .global _C_LABEL(esym)
565 _C_LABEL(esym): .word   _C_LABEL(end)
566
567 ENTRY_NP(abort)
568         b       _C_LABEL(abort)
569 END(abort)
570
571 ENTRY_NP(sigcode)
572         mov     r0, sp
573         add     r0, r0, #SIGF_UC
574
575         /*
576          * Call the sigreturn system call.
577          *
578          * We have to load r7 manually rather than using
579          * "ldr r7, =SYS_sigreturn" to ensure the value of szsigcode is
580          * correct. Using the alternative places esigcode at the address
581          * of the data rather than the address one past the data.
582          */
583
584         ldr     r7, [pc, #12]   /* Load SYS_sigreturn */
585         swi     SYS_sigreturn
586
587         /* Well if that failed we better exit quick ! */
588
589         ldr     r7, [pc, #8]    /* Load SYS_exit */
590         swi     SYS_exit
591
592         /* Branch back to retry SYS_sigreturn */
593         b       . - 16
594 END(sigcode)
595         .word   SYS_sigreturn
596         .word   SYS_exit
597
598         .align  2
599         .global _C_LABEL(esigcode)
600                 _C_LABEL(esigcode):
601
602         .data
603         .global szsigcode
604 szsigcode:
605         .long esigcode-sigcode
606
607 /* End of locore.S */