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