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