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