]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/arm/arm/locore-v4.S
powerpc/pmap: Minor optimizations to 64-bit booke pmap
[FreeBSD/FreeBSD.git] / sys / arm / arm / locore-v4.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.inc"
37 #include <sys/syscall.h>
38 #include <machine/asm.h>
39 #include <machine/armreg.h>
40 #include <machine/pte-v4.h>
41
42 __FBSDID("$FreeBSD$");
43
44 /* 2K initial stack is plenty, it is only used by initarm() */
45 #define INIT_ARM_STACK_SIZE     2048
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 libkvm, and should be the address of the beginning
57  * of the kernel text segment (not necessarily the same as kernbase).
58  *
59  * These are being phased out. Newer copies of libkvm don't need these
60  * values as the information is added to the core file by inspecting
61  * the running kernel.
62  */
63         .text
64         .align  2
65 #ifdef PHYSADDR
66 .globl kernbase
67 .set kernbase,KERNBASE
68 .globl physaddr
69 .set physaddr,PHYSADDR
70 #endif
71
72 /*
73  * On entry for FreeBSD boot ABI:
74  *      r0 - metadata pointer or 0 (boothowto on AT91's boot2)
75  *      r1 - if (r0 == 0) then metadata pointer
76  * On entry for Linux boot ABI:
77  *      r0 - 0
78  *      r1 - machine type (passed as arg2 to initarm)
79  *      r2 - Pointer to a tagged list or dtb image (phys addr) (passed as arg1 initarm)
80  *
81  * For both types of boot we gather up the args, put them in a struct arm_boot_params
82  * structure and pass that to initarm.
83  */
84         .globl  btext
85 btext:
86 ASENTRY_NP(_start)
87         STOP_UNWINDING          /* Can't unwind into the bootloader! */
88
89         mov     r9, r0          /* 0 or boot mode from boot2 */
90         mov     r8, r1          /* Save Machine type */
91         mov     ip, r2          /* Save meta data */
92         mov     fp, r3          /* Future expansion */
93
94         /* Make sure interrupts are disabled. */
95         mrs     r7, cpsr
96         orr     r7, r7, #(PSR_I | PSR_F)
97         msr     cpsr_c, r7
98
99 #if defined (FLASHADDR) && defined(LOADERRAMADDR)
100 /*
101  * Sanity check the configuration.
102  * FLASHADDR and LOADERRAMADDR depend on PHYSADDR in some cases.
103  * ARMv4 and ARMv5 make assumptions on where they are loaded.
104  * TODO: Fix the ARMv4/v5 case.
105  */
106 #ifndef PHYSADDR
107 #error PHYSADDR must be defined for this configuration
108 #endif
109
110         /* Check if we're running from flash. */
111         ldr     r7, =FLASHADDR
112         /*
113          * If we're running with MMU disabled, test against the
114          * physical address instead.
115          */
116         mrc     CP15_SCTLR(r2)
117         ands    r2, r2, #CPU_CONTROL_MMU_ENABLE
118         ldreq   r6, =PHYSADDR
119         ldrne   r6, =LOADERRAMADDR
120         cmp     r7, r6
121         bls     flash_lower
122         cmp     r7, pc
123         bhi     from_ram
124         b       do_copy
125
126 flash_lower:
127         cmp     r6, pc
128         bls     from_ram
129 do_copy:
130         ldr     r7, =KERNBASE
131         adr     r1, _start
132         ldr     r0, Lreal_start
133         ldr     r2, Lend
134         sub     r2, r2, r0
135         sub     r0, r0, r7
136         add     r0, r0, r6
137         mov     r4, r0
138         bl      memcpy
139         ldr     r0, Lram_offset
140         add     pc, r4, r0
141 Lram_offset:    .word from_ram-_C_LABEL(_start)
142 from_ram:
143         nop
144 #endif
145
146 disable_mmu:
147         /* Disable MMU for a while */
148         mrc     CP15_SCTLR(r2)
149         bic     r2, r2, #(CPU_CONTROL_MMU_ENABLE | CPU_CONTROL_DC_ENABLE |\
150             CPU_CONTROL_WBUF_ENABLE)
151         bic     r2, r2, #(CPU_CONTROL_IC_ENABLE)
152         bic     r2, r2, #(CPU_CONTROL_BPRD_ENABLE)
153         mcr     CP15_SCTLR(r2)
154
155         nop
156         nop
157         nop
158         CPWAIT(r0)
159
160 Lunmapped:
161         /*
162          * Build page table from scratch.
163          */
164
165         /* 
166          * Figure out the physical address we're loaded at by assuming this
167          * entry point code is in the first L1 section and so if we clear the
168          * offset bits of the pc that will give us the section-aligned load
169          * address, which remains in r5 throughout all the following code.
170          */
171         ldr     r2, =(L1_S_OFFSET)
172         bic     r5, pc, r2
173
174         /* Find the delta between VA and PA, result stays in r0 throughout. */
175         adr     r0, Lpagetable
176         bl      translate_va_to_pa
177
178         /* 
179          * First map the entire 4GB address space as VA=PA.  It's mapped as
180          * normal (cached) memory because it's for things like accessing the
181          * parameters passed in from the bootloader, which might be at any
182          * physical address, different for every platform.
183          */
184         mov     r1, #0
185         mov     r2, #0
186         mov     r3, #4096
187         bl      build_pagetables
188
189         /* 
190          * Next we do 64MiB starting at the physical load address, mapped to
191          * the VA the kernel is linked for.
192          */
193         mov     r1, r5
194         ldr     r2, =(KERNVIRTADDR)
195         mov     r3, #64
196         bl      build_pagetables
197 #if defined(PHYSADDR) && (KERNVIRTADDR != KERNBASE)
198 /* 
199  * If the kernel wasn't loaded at the beginning of the ram, map the memory
200  * before the kernel too, as some ports use that for pagetables, stack, etc...
201  */
202         ldr     r1, =PHYSADDR
203         ldr     r2, =KERNBASE
204         ldr     r3, =((KERNVIRTADDR - KERNBASE) / L1_S_SIZE)
205         bl      build_pagetables
206 #endif
207
208         /* Create a device mapping for early_printf if specified. */
209 #if defined(SOCDEV_PA) && defined(SOCDEV_VA)
210         ldr     r1, =SOCDEV_PA
211         ldr     r2, =SOCDEV_VA
212         mov     r3, #1
213         bl      build_device_pagetables
214 #endif
215
216         mcr     p15, 0, r0, c2, c0, 0   /* Set TTB */
217         mcr     p15, 0, r0, c8, c7, 0   /* Flush TLB */
218
219         /* Set the Domain Access register.  Very important! */
220         mov     r0, #((DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)) | DOMAIN_CLIENT)
221         mcr     p15, 0, r0, c3, c0, 0
222         /*
223          * Enable MMU.
224          */
225         mrc     CP15_SCTLR(r0)
226         orr     r0, r0, #(CPU_CONTROL_MMU_ENABLE)
227         mcr     CP15_SCTLR(r0)
228         nop
229         nop
230         nop
231         CPWAIT(r0)
232
233         /* Transition the PC from physical to virtual addressing. */
234         ldr     pc,=mmu_done
235
236 mmu_done:
237         nop
238         adr     r1, .Lstart
239         ldmia   r1, {r1, r2, sp}        /* Set initial stack and */
240         sub     r2, r2, r1              /* get zero init data */
241         mov     r3, #0
242 .L1:
243         str     r3, [r1], #0x0004       /* get zero init data */
244         subs    r2, r2, #4
245         bgt     .L1
246
247 virt_done:
248         mov     r1, #28                 /* loader info size is 28 bytes also second arg */
249         subs    sp, sp, r1              /* allocate arm_boot_params struct on stack */
250         mov     r0, sp                  /* loader info pointer is first arg */
251         bic     sp, sp, #7              /* align stack to 8 bytes */
252         str     r1, [r0]                /* Store length of loader info */
253         str     r9, [r0, #4]            /* Store r0 from boot loader */
254         str     r8, [r0, #8]            /* Store r1 from boot loader */
255         str     ip, [r0, #12]           /* store r2 from boot loader */
256         str     fp, [r0, #16]           /* store r3 from boot loader */
257         str     r5, [r0, #20]           /* store the physical address */
258         adr     r4, Lpagetable          /* load the pagetable address */
259         ldr     r5, [r4, #4]
260         str     r5, [r0, #24]           /* store the pagetable address */
261         mov     fp, #0                  /* trace back starts here */
262         bl      _C_LABEL(initarm)       /* Off we go */
263
264         /* init arm will return the new stack pointer. */
265         mov     sp, r0
266
267         bl      _C_LABEL(mi_startup)    /* call mi_startup()! */
268
269         adr     r0, .Lmainreturned
270         b       _C_LABEL(panic)
271         /* NOTREACHED */
272 END(_start)
273
274 #define VA_TO_PA_POINTER(name, table)    \
275 name:                                   ;\
276         .word   .                       ;\
277         .word   table
278
279 /*
280  * Returns the physical address of a magic va to pa pointer.
281  * r0     - The pagetable data pointer. This must be built using the
282  *          VA_TO_PA_POINTER macro.
283  *          e.g.
284  *            VA_TO_PA_POINTER(Lpagetable, pagetable)
285  *            ...
286  *            adr  r0, Lpagetable
287  *            bl   translate_va_to_pa
288  *            r0 will now contain the physical address of pagetable
289  * r1, r2 - Trashed
290  */
291 translate_va_to_pa:
292         ldr     r1, [r0]
293         sub     r2, r1, r0
294         /* At this point: r2 = VA - PA */
295
296         /*
297          * Find the physical address of the table. After these two
298          * instructions:
299          * r1 = va(pagetable)
300          *
301          * r0 = va(pagetable) - (VA - PA)
302          *    = va(pagetable) - VA + PA
303          *    = pa(pagetable)
304          */
305         ldr     r1, [r0, #4]
306         sub     r0, r1, r2
307         RET
308
309 /*
310  * Builds the page table
311  * r0 - The table base address
312  * r1 - The physical address (trashed)
313  * r2 - The virtual address (trashed)
314  * r3 - The number of 1MiB sections
315  * r4 - Trashed
316  *
317  * Addresses must be 1MiB aligned
318  */
319 build_device_pagetables:
320         ldr     r4, =(L1_TYPE_S|L1_S_AP(AP_KRW))
321         b       1f
322 build_pagetables:
323         /* Set the required page attributed */
324         ldr     r4, =(L1_TYPE_S|L1_S_C|L1_S_AP(AP_KRW))
325 1:
326         orr     r1, r4
327
328         /* Move the virtual address to the correct bit location */
329         lsr     r2, #(L1_S_SHIFT - 2)
330
331         mov     r4, r3
332 2:
333         str     r1, [r0, r2]
334         add     r2, r2, #4
335         add     r1, r1, #(L1_S_SIZE)
336         adds    r4, r4, #-1
337         bhi     2b
338
339         RET
340
341 VA_TO_PA_POINTER(Lpagetable, pagetable)
342
343 Lreal_start:
344         .word   _start
345 Lend:
346         .word   _edata
347
348 .Lstart:
349         .word   _edata
350         .word   _ebss
351         .word   svcstk + INIT_ARM_STACK_SIZE
352
353 .Lvirt_done:
354         .word   virt_done
355
356 .Lmainreturned:
357         .asciz  "main() returned"
358         .align  2
359
360         .bss
361 svcstk:
362         .space  INIT_ARM_STACK_SIZE
363
364 /*
365  * Memory for the initial pagetable. We are unable to place this in
366  * the bss as this will be cleared after the table is loaded.
367  */
368         .section ".init_pagetable", "aw", %nobits
369         .align  14 /* 16KiB aligned */
370 pagetable:
371         .space  L1_TABLE_SIZE
372
373         .text
374         .align  2
375
376 .Lcpufuncs:
377         .word   _C_LABEL(cpufuncs)
378
379 ENTRY_NP(cpu_halt)
380         mrs     r2, cpsr
381         bic     r2, r2, #(PSR_MODE)
382         orr     r2, r2, #(PSR_SVC32_MODE)
383         orr     r2, r2, #(PSR_I | PSR_F)
384         msr     cpsr_fsxc, r2
385
386         ldr     r4, .Lcpu_reset_address
387         ldr     r4, [r4]
388
389         ldr     r0, .Lcpufuncs
390         mov     lr, pc
391         ldr     pc, [r0, #CF_IDCACHE_WBINV_ALL]
392         mov     lr, pc
393         ldr     pc, [r0, #CF_L2CACHE_WBINV_ALL]
394
395         /*
396          * Load the cpu_reset_needs_v4_MMU_disable flag to determine if it's
397          * necessary.
398          */
399
400         ldr     r1, .Lcpu_reset_needs_v4_MMU_disable
401         ldr     r1, [r1]
402         cmp     r1, #0
403         mov     r2, #0
404
405         /*
406          * MMU & IDC off, 32 bit program & data space
407          * Hurl ourselves into the ROM
408          */
409         mov     r0, #(CPU_CONTROL_32BP_ENABLE | CPU_CONTROL_32BD_ENABLE)
410         mcr     CP15_SCTLR(r0)
411         mcrne   p15, 0, r2, c8, c7, 0   /* nail I+D TLB on ARMv4 and greater */
412         mov     pc, r4
413
414         /*
415          * _cpu_reset_address contains the address to branch to, to complete
416          * the cpu reset after turning the MMU off
417          * This variable is provided by the hardware specific code
418          */
419 .Lcpu_reset_address:
420         .word   _C_LABEL(cpu_reset_address)
421
422         /*
423          * cpu_reset_needs_v4_MMU_disable contains a flag that signals if the
424          * v4 MMU disable instruction needs executing... it is an illegal instruction
425          * on f.e. ARM6/7 that locks up the computer in an endless illegal
426          * instruction / data-abort / reset loop.
427          */
428 .Lcpu_reset_needs_v4_MMU_disable:
429         .word   _C_LABEL(cpu_reset_needs_v4_MMU_disable)
430 END(cpu_halt)
431
432
433 /*
434  * setjump + longjmp
435  */
436 ENTRY(setjmp)
437         stmia   r0, {r4-r14}
438         mov     r0, #0x00000000
439         RET
440 END(setjmp)
441
442 ENTRY(longjmp)
443         ldmia   r0, {r4-r14}
444         mov     r0, #0x00000001
445         RET
446 END(longjmp)
447
448         .data
449         .global _C_LABEL(esym)
450 _C_LABEL(esym): .word   _C_LABEL(end)
451
452 ENTRY_NP(abort)
453         b       _C_LABEL(abort)
454 END(abort)
455
456 ENTRY_NP(sigcode)
457         mov     r0, sp
458         add     r0, r0, #SIGF_UC
459
460         /*
461          * Call the sigreturn system call.
462          *
463          * We have to load r7 manually rather than using
464          * "ldr r7, =SYS_sigreturn" to ensure the value of szsigcode is
465          * correct. Using the alternative places esigcode at the address
466          * of the data rather than the address one past the data.
467          */
468
469         ldr     r7, [pc, #12]   /* Load SYS_sigreturn */
470         swi     SYS_sigreturn
471
472         /* Well if that failed we better exit quick ! */
473
474         ldr     r7, [pc, #8]    /* Load SYS_exit */
475         swi     SYS_exit
476
477         /* Branch back to retry SYS_sigreturn */
478         b       . - 16
479 END(sigcode)
480         .word   SYS_sigreturn
481         .word   SYS_exit
482
483         .align  2
484         .global _C_LABEL(esigcode)
485                 _C_LABEL(esigcode):
486
487         .data
488         .global szsigcode
489 szsigcode:
490         .long esigcode-sigcode
491
492 /* End of locore.S */