]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - sys/arm/arm/locore.S
MFC r261423, r261424, r261516, r261513, r261562, r261563, r261564, r261565,
[FreeBSD/stable/10.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/pte.h>
41
42 __FBSDID("$FreeBSD$");
43
44 /* What size should this really be ? It is only used by initarm() */
45 #define INIT_ARM_STACK_SIZE     (2048 * 4)
46
47 #define CPWAIT_BRANCH                                                    \
48         sub     pc, pc, #4
49
50 #define CPWAIT(tmp)                                                      \
51         mrc     p15, 0, tmp, c2, c0, 0  /* arbitrary read of CP15 */    ;\
52         mov     tmp, tmp                /* wait for it to complete */   ;\
53         CPWAIT_BRANCH                   /* branch to next insn */
54
55 /*
56  * This is for kvm_mkdb, and should be the address of the beginning
57  * of the kernel text segment (not necessarily the same as kernbase).
58  */
59         .text
60         .align  0
61 .globl kernbase
62 .set kernbase,KERNBASE
63 .globl physaddr
64 .set physaddr,PHYSADDR
65
66 /*
67  * On entry for FreeBSD boot ABI:
68  *      r0 - metadata pointer or 0 (boothowto on AT91's boot2)
69  *      r1 - if (r0 == 0) then metadata pointer
70  * On entry for Linux boot ABI:
71  *      r0 - 0
72  *      r1 - machine type (passed as arg2 to initarm)
73  *      r2 - Pointer to a tagged list or dtb image (phys addr) (passed as arg1 initarm)
74  *
75  * For both types of boot we gather up the args, put them in a struct arm_boot_params
76  * structure and pass that to initarm.
77  */
78 ENTRY_NP(btext)
79 ASENTRY_NP(_start)
80         STOP_UNWINDING          /* Can't unwind into the bootloader! */
81
82         mov     r9, r0          /* 0 or boot mode from boot2 */
83         mov     r8, r1          /* Save Machine type */
84         mov     ip, r2          /* Save meta data */
85         mov     fp, r3          /* Future expantion */
86
87         /* Make sure interrupts are disabled. */
88         mrs     r7, cpsr
89         orr     r7, r7, #(I32_bit|F32_bit)
90         msr     cpsr_c, r7
91
92 #if defined (FLASHADDR) && defined(LOADERRAMADDR)
93         /* Check if we're running from flash. */
94         ldr     r7, =FLASHADDR
95         /*
96          * If we're running with MMU disabled, test against the
97          * physical address instead.
98          */
99         mrc     p15, 0, r2, c1, c0, 0
100         ands    r2, r2, #CPU_CONTROL_MMU_ENABLE
101         ldreq   r6, =PHYSADDR
102         ldrne   r6, =LOADERRAMADDR
103         cmp     r7, r6
104         bls     flash_lower
105         cmp     r7, pc
106         bhi     from_ram
107         b       do_copy
108         
109 flash_lower:
110         cmp     r6, pc
111         bls     from_ram
112 do_copy:
113         ldr     r7, =KERNBASE
114         adr     r1, _start
115         ldr     r0, Lreal_start
116         ldr     r2, Lend
117         sub     r2, r2, r0
118         sub     r0, r0, r7
119         add     r0, r0, r6
120         mov     r4, r0
121         bl      memcpy
122         ldr     r0, Lram_offset
123         add     pc, r4, r0
124 Lram_offset:    .word from_ram-_C_LABEL(_start)
125 from_ram:
126         nop
127 #endif
128         adr     r7, Lunmapped
129         bic     r7, r7, #0xf0000000
130         orr     r7, r7, #PHYSADDR
131
132
133 disable_mmu:
134         /* Disable MMU for a while */
135         mrc     p15, 0, r2, c1, c0, 0
136         bic     r2, r2, #(CPU_CONTROL_MMU_ENABLE | CPU_CONTROL_DC_ENABLE |\
137             CPU_CONTROL_WBUF_ENABLE)
138         bic     r2, r2, #(CPU_CONTROL_IC_ENABLE)
139         bic     r2, r2, #(CPU_CONTROL_BPRD_ENABLE)
140         mcr     p15, 0, r2, c1, c0, 0
141
142         nop
143         nop
144         nop
145         mov     pc, r7
146 Lunmapped:
147         /*
148          * Build page table from scratch.
149          */
150
151         /* Load the page tables physical address */
152         ldr     r1, Lstartup_pagetable
153         ldr     r2, =(KERNVIRTADDR - KERNPHYSADDR)
154         sub     r0, r1, r2
155
156         /*
157          * Map PA == VA
158          */
159         ldr     r5, =(PHYSADDR)
160         mov     r1, r5
161         mov     r2, r5
162         /* Map 64MiB, preserved over calls to build_pagetables */
163         mov     r3, #64
164         bl      build_pagetables
165
166         /* Create the kernel map to jump to */
167         mov     r1, r5
168         ldr     r2, =(KERNBASE)
169         bl      build_pagetables
170         
171 #if defined(SOCDEV_PA) && defined(SOCDEV_VA)
172         /* Create the custom map */
173         ldr     r1, =SOCDEV_VA
174         ldr     r2, =SOCDEV_PA
175         bl      build_pagetables
176 #endif
177
178 #if defined(SMP)
179         orr     r0, r0, #2              /* Set TTB shared memory flag */
180 #endif
181         mcr     p15, 0, r0, c2, c0, 0   /* Set TTB */
182         mcr     p15, 0, r0, c8, c7, 0   /* Flush TLB */
183
184 #if defined(CPU_ARM1136) || defined(CPU_ARM1176) || defined(CPU_CORTEXA) || defined(CPU_MV_PJ4B) || defined(CPU_KRAIT)
185         mov     r0, #0
186         mcr     p15, 0, r0, c13, c0, 1  /* Set ASID to 0 */
187 #endif
188
189         /* Set the Domain Access register.  Very important! */
190         mov     r0, #((DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)) | DOMAIN_CLIENT)
191         mcr     p15, 0, r0, c3, c0, 0
192         /* 
193          * Enable MMU.
194          * On armv6 enable extended page tables, and set alignment checking
195          * to modulo-4 (CPU_CONTROL_UNAL_ENABLE) for the ldrd/strd
196          * instructions emitted by clang.
197          */
198         mrc     p15, 0, r0, c1, c0, 0
199 #ifdef _ARM_ARCH_6
200         orr     r0, r0, #(CPU_CONTROL_V6_EXTPAGE | CPU_CONTROL_UNAL_ENABLE)
201         orr     r0, r0, #(CPU_CONTROL_AFLT_ENABLE)
202         orr     r0, r0, #(CPU_CONTROL_AF_ENABLE)
203 #endif
204         orr     r0, r0, #(CPU_CONTROL_MMU_ENABLE)
205         mcr     p15, 0, r0, c1, c0, 0
206         nop
207         nop
208         nop
209         CPWAIT(r0)
210
211 mmu_done:
212         nop
213         adr     r1, .Lstart
214         ldmia   r1, {r1, r2, sp}        /* Set initial stack and */
215         sub     r2, r2, r1              /* get zero init data */
216         mov     r3, #0
217 .L1:
218         str     r3, [r1], #0x0004       /* get zero init data */
219         subs    r2, r2, #4
220         bgt     .L1
221         ldr     pc, .Lvirt_done
222
223 virt_done:
224         mov     r1, #24                 /* loader info size is 24 bytes also second arg */
225         subs    sp, sp, r1              /* allocate arm_boot_params struct on stack */
226         bic     sp, sp, #7              /* align stack to 8 bytes */
227         mov     r0, sp                  /* loader info pointer is first arg */
228         str     r1, [r0]                /* Store length of loader info */
229         str     r9, [r0, #4]            /* Store r0 from boot loader */
230         str     r8, [r0, #8]            /* Store r1 from boot loader */
231         str     ip, [r0, #12]           /* store r2 from boot loader */
232         str     fp, [r0, #16]           /* store r3 from boot loader */
233         ldr     r5, =KERNPHYSADDR       /* load KERNPHYSADDR as the physical address */
234         str     r5, [r0, #20]           /* store the physical address */
235         mov     fp, #0                  /* trace back starts here */
236         bl      _C_LABEL(initarm)       /* Off we go */
237
238         /* init arm will return the new stack pointer. */
239         mov     sp, r0
240
241         bl      _C_LABEL(mi_startup)            /* call mi_startup()! */
242
243         adr     r0, .Lmainreturned
244         b       _C_LABEL(panic)
245         /* NOTREACHED */
246 END(btext)
247 END(_start)
248
249 /*
250  * Builds the page table
251  * r0 - The table base address
252  * r1 - The physical address (trashed)
253  * r2 - The virtual address (trashed)
254  * r3 - The number of 1MiB sections
255  * r4 - Trashed
256  *
257  * Addresses must be 1MiB aligned
258  */
259 build_pagetables:
260         /* Set the required page attributed */
261         ldr     r4, =(L1_TYPE_S|L1_S_C|L1_S_AP(AP_KRW))
262 #if defined(SMP)
263         orr     r4, #(L1_SHARED)
264 #endif
265         orr     r1, r4
266
267         /* Move the virtual address to the correct bit location */
268         lsr     r2, #(L1_S_SHIFT - 2)
269
270         mov     r4, r3
271 1:
272         str     r1, [r0, r2]
273         add     r2, r2, #4
274         add     r1, r1, #(L1_S_SIZE)
275         adds    r4, r4, #-1
276         bhi     1b
277
278         RET
279
280 #define MMU_INIT(va,pa,n_sec,attr) \
281         .word   n_sec                                       ; \
282         .word   4*((va)>>L1_S_SHIFT)                        ; \
283         .word   (pa)|(attr)                                 ;
284
285 Lvirtaddr:
286         .word   KERNVIRTADDR
287 Lphysaddr:
288         .word   KERNPHYSADDR
289 Lreal_start:
290         .word   _start
291 Lend:   
292         .word   _edata
293 Lstartup_pagetable:
294         .word   pagetable
295 #ifdef SMP
296 Lstartup_pagetable_secondary:
297         .word   temp_pagetable
298 #endif
299
300 .Lstart:
301         .word   _edata
302         .word   _ebss
303         .word   svcstk + INIT_ARM_STACK_SIZE
304
305 .Lvirt_done:
306         .word   virt_done
307 #if defined(SMP)
308 .Lmpvirt_done:
309         .word   mpvirt_done
310 #endif
311
312 .Lmainreturned:
313         .asciz  "main() returned"
314         .align  0
315
316         .bss
317 svcstk:
318         .space  INIT_ARM_STACK_SIZE
319
320 /*
321  * Memory for the initial pagetable. We are unable to place this in
322  * the bss as this will be cleared after the table is loaded.
323  */
324         .section ".init_pagetable"
325         .align  14 /* 16KiB aligned */
326 pagetable:
327         .space  L1_TABLE_SIZE
328
329         .text
330         .align  0
331
332 .Lcpufuncs:
333         .word   _C_LABEL(cpufuncs)
334
335 #if defined(SMP)
336 Lsramaddr:
337         .word   0xffff0080
338
339 #if 0
340 #define AP_DEBUG(tmp)                   \
341         mrc     p15, 0, r1, c0, c0, 5;  \
342         ldr     r0, Lsramaddr;          \
343         add     r0, r1, lsl #2;         \
344         mov     r1, tmp;                \
345         str     r1, [r0], #0x0000;
346 #else
347 #define AP_DEBUG(tmp)
348 #endif
349
350
351 ASENTRY_NP(mptramp)
352         mov     r0, #0
353         mcr     p15, 0, r0, c7, c7, 0
354
355         AP_DEBUG(#1)
356
357         mrs     r3, cpsr
358         bic     r3, r3, #(PSR_MODE)
359         orr     r3, r3, #(PSR_SVC32_MODE)
360         msr     cpsr_fsxc, r3
361
362         mrc     p15, 0, r0, c0, c0, 5
363         and     r0, #0x0f               /* Get CPU ID */
364
365         /* Read boot address for CPU */
366         mov     r1, #0x100
367         mul     r2, r0, r1
368         ldr     r1, Lpmureg
369         add     r0, r2, r1
370         ldr     r1, [r0], #0x00
371
372         mov pc, r1
373
374 Lpmureg:
375         .word   0xd0022124
376 END(mptramp)
377
378 ASENTRY_NP(mpentry)
379
380         AP_DEBUG(#2)
381
382         /* Make sure interrupts are disabled. */
383         mrs     r7, cpsr
384         orr     r7, r7, #(I32_bit|F32_bit)
385         msr     cpsr_c, r7
386
387
388         adr     r7, Ltag
389         bic     r7, r7, #0xf0000000
390         orr     r7, r7, #PHYSADDR
391                         
392         /* Disable MMU for a while */
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
400         nop
401         nop
402         nop
403
404         AP_DEBUG(#3)
405
406 Ltag:
407         ldr     r0, Lstartup_pagetable_secondary
408         bic     r0, r0, #0xf0000000
409         orr     r0, r0, #PHYSADDR
410         ldr     r0, [r0]
411 #if defined(SMP)
412         orr     r0, r0, #0              /* Set TTB shared memory flag */
413 #endif
414         mcr     p15, 0, r0, c2, c0, 0   /* Set TTB */
415         mcr     p15, 0, r0, c8, c7, 0   /* Flush TLB */
416
417 #if defined(CPU_ARM1136) || defined(CPU_ARM1176) || defined(CPU_MV_PJ4B) || defined(CPU_CORTEXA) || defined(CPU_KRAIT)
418         mov     r0, #0
419         mcr     p15, 0, r0, c13, c0, 1  /* Set ASID to 0 */
420 #endif
421
422         AP_DEBUG(#4)
423
424         /* Set the Domain Access register.  Very important! */
425         mov     r0, #((DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)) | DOMAIN_CLIENT)
426         mcr     p15, 0, r0, c3, c0, 0
427         /* Enable MMU */
428         mrc     p15, 0, r0, c1, c0, 0
429 #if defined(CPU_ARM1136) || defined(CPU_ARM1176) || defined(CPU_MV_PJ4B) || defined(CPU_CORTEXA) || defined(CPU_KRAIT)
430         orr     r0, r0, #CPU_CONTROL_V6_EXTPAGE
431         orr     r0, r0, #CPU_CONTROL_AF_ENABLE
432 #endif
433         orr     r0, r0, #(CPU_CONTROL_MMU_ENABLE | CPU_CONTROL_DC_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  "main() 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, #(I32_bit | F32_bit)
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
545         /*
546          * Call the sigreturn system call.
547          * 
548          * We have to load r7 manually rather than using
549          * "ldr r7, =SYS_sigreturn" to ensure the value of szsigcode is
550          * correct. Using the alternative places esigcode at the address
551          * of the data rather than the address one past the data.
552          */
553
554         ldr     r7, [pc, #12]   /* Load SYS_sigreturn */
555         swi     SYS_sigreturn
556
557         /* Well if that failed we better exit quick ! */
558
559         ldr     r7, [pc, #8]    /* Load SYS_exit */
560         swi     SYS_exit
561
562         /* Branch back to retry SYS_sigreturn */
563         b       . - 16
564
565         .word   SYS_sigreturn
566         .word   SYS_exit
567
568         .align  0
569         .global _C_LABEL(esigcode)
570                 _C_LABEL(esigcode):
571
572         .data
573         .global szsigcode
574 szsigcode:
575         .long esigcode-sigcode
576 END(sigcode)
577 /* End of locore.S */