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