]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/arm/arm/locore.S
Reimport dts files from vendor repo now that it has been properly
[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, #(I32_bit|F32_bit)
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         adr     r7, Lunmapped
131         bic     r7, r7, #0xf0000000
132         orr     r7, r7, #PHYSADDR
133
134
135 disable_mmu:
136         /* Disable MMU for a while */
137         mrc     p15, 0, r2, c1, c0, 0
138         bic     r2, r2, #(CPU_CONTROL_MMU_ENABLE | CPU_CONTROL_DC_ENABLE |\
139             CPU_CONTROL_WBUF_ENABLE)
140         bic     r2, r2, #(CPU_CONTROL_IC_ENABLE)
141         bic     r2, r2, #(CPU_CONTROL_BPRD_ENABLE)
142         mcr     p15, 0, r2, c1, c0, 0
143
144         nop
145         nop
146         nop
147         mov     pc, r7
148 Lunmapped:
149         /*
150          * Build page table from scratch.
151          */
152
153         /* Find the delta between VA and PA */
154         adr     r0, Lpagetable
155         ldr     r1, [r0]
156         sub     r2, r1, r0
157         /* At this point: r2 = VA - PA */
158
159         /*
160          * Find the physical address of the table. After these two
161          * instructions:
162          * r1 = va(pagetable)
163          *
164          * r0 = va(pagetable) - (VA - PA)
165          *    = va(pagetable) - VA + PA
166          *    = pa(pagetable)
167          */
168         ldr     r1, [r0, #4]
169         sub     r0, r1, r2
170
171 #ifndef _ARM_ARCH_6
172         /*
173          * Some of the older ports (the various XScale, mostly) assume
174          * that the memory before the kernel is mapped, and use it for
175          * the various stacks, page tables, etc. For those CPUs, map the 
176          * 64 first MB of RAM, as it used to be. 
177          */
178         /*
179          * Map PA == VA
180          */    
181         ldr     r5, =PHYSADDR
182         mov     r1, r5
183         mov     r2, r5
184         /* Map 64MiB, preserved over calls to build_pagetables */
185         mov     r3, #64
186         bl      build_pagetables
187         
188         /* Create the kernel map to jump to */
189         mov     r1, r5
190         ldr     r2, =(KERNBASE)
191         bl      build_pagetables
192         ldr     r5, =(KERNPHYSADDR)
193 #else
194         /*
195          * Map PA == VA
196          */    
197         /* Find the start kernels load address */
198         adr     r5, _start
199         ldr     r2, =(L1_S_OFFSET)
200         bic     r5, r2
201         mov     r1, r5
202         mov     r2, r5
203         /* Map 64MiB, preserved over calls to build_pagetables */
204         mov     r3, #64
205         bl      build_pagetables
206
207         /* Create the kernel map to jump to */
208         mov     r1, r5
209         ldr     r2, =(KERNVIRTADDR)
210         bl      build_pagetables
211 #endif
212         
213 #if defined(SOCDEV_PA) && defined(SOCDEV_VA)
214         /* Create the custom map */
215         ldr     r1, =SOCDEV_PA
216         ldr     r2, =SOCDEV_VA
217         bl      build_pagetables
218 #endif
219
220 #if defined(SMP)
221         orr     r0, r0, #2              /* Set TTB shared memory flag */
222 #endif
223         mcr     p15, 0, r0, c2, c0, 0   /* Set TTB */
224         mcr     p15, 0, r0, c8, c7, 0   /* Flush TLB */
225
226 #if defined(CPU_ARM1136) || defined(CPU_ARM1176) || defined(CPU_CORTEXA) || defined(CPU_MV_PJ4B) || defined(CPU_KRAIT)
227         mov     r0, #0
228         mcr     p15, 0, r0, c13, c0, 1  /* Set ASID to 0 */
229 #endif
230
231         /* Set the Domain Access register.  Very important! */
232         mov     r0, #((DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)) | DOMAIN_CLIENT)
233         mcr     p15, 0, r0, c3, c0, 0
234         /* 
235          * Enable MMU.
236          * On armv6 enable extended page tables, and set alignment checking
237          * to modulo-4 (CPU_CONTROL_UNAL_ENABLE) for the ldrd/strd
238          * instructions emitted by clang.
239          */
240         mrc     p15, 0, r0, c1, c0, 0
241 #ifdef _ARM_ARCH_6
242         orr     r0, r0, #(CPU_CONTROL_V6_EXTPAGE | CPU_CONTROL_UNAL_ENABLE)
243         orr     r0, r0, #(CPU_CONTROL_AFLT_ENABLE)
244         orr     r0, r0, #(CPU_CONTROL_AF_ENABLE)
245 #endif
246         orr     r0, r0, #(CPU_CONTROL_MMU_ENABLE)
247         mcr     p15, 0, r0, c1, c0, 0
248         nop
249         nop
250         nop
251         CPWAIT(r0)
252
253 mmu_done:
254         nop
255         adr     r1, .Lstart
256         ldmia   r1, {r1, r2, sp}        /* Set initial stack and */
257         sub     r2, r2, r1              /* get zero init data */
258         mov     r3, #0
259 .L1:
260         str     r3, [r1], #0x0004       /* get zero init data */
261         subs    r2, r2, #4
262         bgt     .L1
263         ldr     pc, .Lvirt_done
264
265 virt_done:
266         mov     r1, #28                 /* loader info size is 28 bytes also second arg */
267         subs    sp, sp, r1              /* allocate arm_boot_params struct on stack */
268         mov     r0, sp                  /* loader info pointer is first arg */
269         bic     sp, sp, #7              /* align stack to 8 bytes */
270         str     r1, [r0]                /* Store length of loader info */
271         str     r9, [r0, #4]            /* Store r0 from boot loader */
272         str     r8, [r0, #8]            /* Store r1 from boot loader */
273         str     ip, [r0, #12]           /* store r2 from boot loader */
274         str     fp, [r0, #16]           /* store r3 from boot loader */
275         str     r5, [r0, #20]           /* store the physical address */
276         adr     r4, Lpagetable          /* load the pagetable address */
277         ldr     r5, [r4, #4]
278         str     r5, [r0, #24]           /* store the pagetable address */
279         mov     fp, #0                  /* trace back starts here */
280         bl      _C_LABEL(initarm)       /* Off we go */
281
282         /* init arm will return the new stack pointer. */
283         mov     sp, r0
284
285         bl      _C_LABEL(mi_startup)            /* call mi_startup()! */
286
287         adr     r0, .Lmainreturned
288         b       _C_LABEL(panic)
289         /* NOTREACHED */
290 END(_start)
291
292 /*
293  * Builds the page table
294  * r0 - The table base address
295  * r1 - The physical address (trashed)
296  * r2 - The virtual address (trashed)
297  * r3 - The number of 1MiB sections
298  * r4 - Trashed
299  *
300  * Addresses must be 1MiB aligned
301  */
302 build_pagetables:
303         /* Set the required page attributed */
304         ldr     r4, =(L1_TYPE_S|L1_S_C|L1_S_AP(AP_KRW))
305 #if defined(SMP)
306         orr     r4, #(L1_SHARED)
307 #endif
308         orr     r1, r4
309
310         /* Move the virtual address to the correct bit location */
311         lsr     r2, #(L1_S_SHIFT - 2)
312
313         mov     r4, r3
314 1:
315         str     r1, [r0, r2]
316         add     r2, r2, #4
317         add     r1, r1, #(L1_S_SIZE)
318         adds    r4, r4, #-1
319         bhi     1b
320
321         RET
322
323 Lpagetable:
324         .word   .
325         .word   pagetable
326
327 Lvirtaddr:
328         .word   KERNVIRTADDR
329 Lphysaddr:
330         .word   KERNPHYSADDR
331 Lreal_start:
332         .word   _start
333 Lend:
334         .word   _edata
335
336 .Lstart:
337         .word   _edata
338         .word   _ebss
339         .word   svcstk + INIT_ARM_STACK_SIZE
340
341 .Lvirt_done:
342         .word   virt_done
343
344 .Lmainreturned:
345         .asciz  "main() returned"
346         .align  0
347
348         .bss
349 svcstk:
350         .space  INIT_ARM_STACK_SIZE
351
352 /*
353  * Memory for the initial pagetable. We are unable to place this in
354  * the bss as this will be cleared after the table is loaded.
355  */
356         .section ".init_pagetable"
357         .align  14 /* 16KiB aligned */
358 pagetable:
359         .space  L1_TABLE_SIZE
360
361         .text
362         .align  0
363
364 .Lcpufuncs:
365         .word   _C_LABEL(cpufuncs)
366
367 #if defined(SMP)
368
369 .Lmpvirt_done:
370         .word   mpvirt_done
371 Lstartup_pagetable_secondary:
372         .word   temp_pagetable
373
374 ASENTRY_NP(mpentry)
375
376         /* Make sure interrupts are disabled. */
377         mrs     r7, cpsr
378         orr     r7, r7, #(I32_bit|F32_bit)
379         msr     cpsr_c, r7
380
381         /* Disable MMU.  It should be disabled already, but make sure. */
382         mrc     p15, 0, r2, c1, c0, 0
383         bic     r2, r2, #(CPU_CONTROL_MMU_ENABLE | CPU_CONTROL_DC_ENABLE |\
384             CPU_CONTROL_WBUF_ENABLE)
385         bic     r2, r2, #(CPU_CONTROL_IC_ENABLE)
386         bic     r2, r2, #(CPU_CONTROL_BPRD_ENABLE)
387         mcr     p15, 0, r2, c1, c0, 0
388         nop
389         nop
390         nop
391         CPWAIT(r0)
392
393 #if ARM_MMU_V6
394         bl      armv6_idcache_inv_all   /* Modifies r0 only */
395 #elif ARM_MMU_V7
396         bl      armv7_idcache_inv_all   /* Modifies r0-r3, ip */
397 #endif
398
399         ldr     r0, Lstartup_pagetable_secondary
400         bic     r0, r0, #0xf0000000
401         orr     r0, r0, #PHYSADDR
402         ldr     r0, [r0]
403         orr     r0, r0, #2              /* Set TTB shared memory flag */
404         mcr     p15, 0, r0, c2, c0, 0   /* Set TTB */
405         mcr     p15, 0, r0, c8, c7, 0   /* Flush TLB */
406
407         mov     r0, #0
408         mcr     p15, 0, r0, c13, c0, 1  /* Set ASID to 0 */
409
410         /* Set the Domain Access register.  Very important! */
411         mov     r0, #((DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)) | DOMAIN_CLIENT)
412         mcr     p15, 0, r0, c3, c0, 0
413         /* Enable MMU */
414         mrc     p15, 0, r0, c1, c0, 0
415         orr     r0, r0, #CPU_CONTROL_V6_EXTPAGE
416         orr     r0, r0, #CPU_CONTROL_AF_ENABLE
417         orr     r0, r0, #(CPU_CONTROL_MMU_ENABLE | CPU_CONTROL_DC_ENABLE |\
418             CPU_CONTROL_WBUF_ENABLE)
419         orr     r0, r0, #(CPU_CONTROL_IC_ENABLE)
420         orr     r0, r0, #(CPU_CONTROL_BPRD_ENABLE)
421         mcr     p15, 0, r0, c1, c0, 0
422         nop
423         nop
424         nop
425         CPWAIT(r0)
426
427         adr     r1, .Lstart
428         ldmia   r1, {r1, r2, sp}        /* Set initial stack and */
429         mrc     p15, 0, r0, c0, c0, 5
430         and     r0, r0, #15
431         mov     r1, #2048
432         mul     r2, r1, r0
433         sub     sp, sp, r2
434         str     r1, [sp]
435         ldr     pc, .Lmpvirt_done
436
437 mpvirt_done:
438
439         mov     fp, #0                  /* trace back starts here */
440         bl      _C_LABEL(init_secondary)        /* Off we go */
441
442         adr     r0, .Lmpreturned
443         b       _C_LABEL(panic)
444         /* NOTREACHED */
445
446 .Lmpreturned:
447         .asciz  "init_secondary() returned"
448         .align  0
449 END(mpentry)
450 #endif
451
452 ENTRY_NP(cpu_halt)
453         mrs     r2, cpsr
454         bic     r2, r2, #(PSR_MODE)
455         orr     r2, r2, #(PSR_SVC32_MODE)
456         orr     r2, r2, #(I32_bit | F32_bit)
457         msr     cpsr_fsxc, r2
458
459         ldr     r4, .Lcpu_reset_address
460         ldr     r4, [r4]
461
462         ldr     r0, .Lcpufuncs
463         mov     lr, pc
464         ldr     pc, [r0, #CF_IDCACHE_WBINV_ALL]
465         mov     lr, pc
466         ldr     pc, [r0, #CF_L2CACHE_WBINV_ALL]
467
468         /*
469          * Load the cpu_reset_needs_v4_MMU_disable flag to determine if it's
470          * necessary.
471          */
472
473         ldr     r1, .Lcpu_reset_needs_v4_MMU_disable
474         ldr     r1, [r1]
475         cmp     r1, #0
476         mov     r2, #0
477
478         /*
479          * MMU & IDC off, 32 bit program & data space
480          * Hurl ourselves into the ROM
481          */
482         mov     r0, #(CPU_CONTROL_32BP_ENABLE | CPU_CONTROL_32BD_ENABLE)
483         mcr     15, 0, r0, c1, c0, 0
484         mcrne   15, 0, r2, c8, c7, 0    /* nail I+D TLB on ARMv4 and greater */
485         mov     pc, r4
486
487         /*
488          * _cpu_reset_address contains the address to branch to, to complete
489          * the cpu reset after turning the MMU off
490          * This variable is provided by the hardware specific code
491          */
492 .Lcpu_reset_address:
493         .word   _C_LABEL(cpu_reset_address)
494
495         /*
496          * cpu_reset_needs_v4_MMU_disable contains a flag that signals if the
497          * v4 MMU disable instruction needs executing... it is an illegal instruction
498          * on f.e. ARM6/7 that locks up the computer in an endless illegal
499          * instruction / data-abort / reset loop.
500          */
501 .Lcpu_reset_needs_v4_MMU_disable:
502         .word   _C_LABEL(cpu_reset_needs_v4_MMU_disable)
503 END(cpu_halt)
504
505
506 /*
507  * setjump + longjmp
508  */
509 ENTRY(setjmp)
510         stmia   r0, {r4-r14}
511         mov     r0, #0x00000000
512         RET
513 END(setjmp)
514
515 ENTRY(longjmp)
516         ldmia   r0, {r4-r14}
517         mov     r0, #0x00000001
518         RET
519 END(longjmp)
520
521         .data
522         .global _C_LABEL(esym)
523 _C_LABEL(esym): .word   _C_LABEL(end)
524
525 ENTRY_NP(abort)
526         b       _C_LABEL(abort)
527 END(abort)
528
529 ENTRY_NP(sigcode)
530         mov     r0, sp
531         add     r0, r0, #SIGF_UC
532
533         /*
534          * Call the sigreturn system call.
535          * 
536          * We have to load r7 manually rather than using
537          * "ldr r7, =SYS_sigreturn" to ensure the value of szsigcode is
538          * correct. Using the alternative places esigcode at the address
539          * of the data rather than the address one past the data.
540          */
541
542         ldr     r7, [pc, #12]   /* Load SYS_sigreturn */
543         swi     SYS_sigreturn
544
545         /* Well if that failed we better exit quick ! */
546
547         ldr     r7, [pc, #8]    /* Load SYS_exit */
548         swi     SYS_exit
549
550         /* Branch back to retry SYS_sigreturn */
551         b       . - 16
552 END(sigcode)
553         .word   SYS_sigreturn
554         .word   SYS_exit
555
556         .align  0
557         .global _C_LABEL(esigcode)
558                 _C_LABEL(esigcode):
559
560         .data
561         .global szsigcode
562 szsigcode:
563         .long esigcode-sigcode
564
565 /* End of locore.S */