1/*- 2 * Copyright 2004-2014 Olivier Houchard <[email protected]> 3 * Copyright 2012-2014 Ian Lepore <[email protected]> 4 * Copyright 2013-2014 Andrew Turner <[email protected]> 5 * Copyright 2014 Svatopluk Kraus <[email protected]> 6 * Copyright 2014 Michal Meloun <[email protected]> 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.inc" 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/pte-v6.h> 38 39__FBSDID("$FreeBSD$"); 40 41/* We map 64MB of kernel unless overridden in assym.inc by the kernel option. */ 42#ifndef LOCORE_MAP_MB 43#define LOCORE_MAP_MB 64 44#endif 45 46#if __ARM_ARCH >= 7 47#if defined(__ARM_ARCH_7VE__) || defined(__clang__) 48/* 49 * HYP support is in bintuils >= 2.21 and gcc >= 4.9 defines __ARM_ARCH_7VE__ 50 * when enabled. llvm >= 3.6 supports it too. 51 */ 52.arch_extension virt 53#endif 54#endif /* __ARM_ARCH >= 7 */ 55 56/* A small statically-allocated stack used only during initarm() and AP startup. */ 57#define INIT_ARM_STACK_SIZE 2048 58 59 .text 60 .align 2 61 62 .globl kernbase 63 .set kernbase,KERNVIRTADDR 64 65#if __ARM_ARCH >= 7 66#define HANDLE_HYP \ 67 /* Leave HYP mode */ ;\ 68 mrs r0, cpsr ;\ 69 and r0, r0, #(PSR_MODE) /* Mode is in the low 5 bits of CPSR */ ;\ 70 teq r0, #(PSR_HYP32_MODE) /* Hyp Mode? */ ;\ 71 bne 1f ;\ 72 /* Install Hypervisor Stub Exception Vector */ ;\ 73 bl hypervisor_stub_vect_install ;\ 74 mov r0, 0 ;\ 75 adr r1, hypmode_enabled ;\ 76 str r0, [r1] ;\ 77 /* Ensure that IRQ, FIQ and Aborts will be disabled after eret */ ;\ 78 mrs r0, cpsr ;\ 79 bic r0, r0, #(PSR_MODE) ;\ 80 orr r0, r0, #(PSR_SVC32_MODE) ;\ 81 orr r0, r0, #(PSR_I | PSR_F | PSR_A) ;\ 82 msr spsr_cxsf, r0 ;\ 83 /* Exit hypervisor mode */ ;\ 84 adr lr, 2f ;\ 85 MSR_ELR_HYP(14) ;\ 86 ERET ;\ 871: ;\ 88 mov r0, -1 ;\ 89 adr r1, hypmode_enabled ;\ 90 str r0, [r1] ;\ 912: 92#else 93#define HANDLE_HYP 94#endif /* __ARM_ARCH >= 7 */ 95 96/* 97 * On entry for FreeBSD boot ABI: 98 * r0 - metadata pointer or 0 (boothowto on AT91's boot2) 99 * r1 - if (r0 == 0) then metadata pointer 100 * On entry for Linux boot ABI: 101 * r0 - 0 102 * r1 - machine type (passed as arg2 to initarm) 103 * r2 - Pointer to a tagged list or dtb image (phys addr) (passed as arg1 initarm) 104 * 105 * For both types of boot we gather up the args, put them in a struct arm_boot_params 106 * structure and pass that to initarm. 107 */ 108 .globl btext 109btext: 110ASENTRY_NP(_start) 111 STOP_UNWINDING /* Can't unwind into the bootloader! */ 112 113 /* Make sure interrupts are disabled. */ 114 cpsid ifa 115 116 mov r8, r0 /* 0 or boot mode from boot2 */ 117 mov r9, r1 /* Save Machine type */ 118 mov r10, r2 /* Save meta data */ 119 mov r11, r3 /* Future expansion */ 120 121 # If HYP-MODE is active, install an exception vector stub 122 HANDLE_HYP 123 124 /* 125 * Check whether data cache is enabled. If it is, then we know 126 * current tags are valid (not power-on garbage values) and there 127 * might be dirty lines that need cleaning. Disable cache to prevent 128 * new lines being allocated, then call wbinv_poc_all to clean it. 129 */ 130 mrc CP15_SCTLR(r7) 131 tst r7, #CPU_CONTROL_DC_ENABLE 132 blne dcache_wbinv_poc_all 133 134 /* ! Do not write to memory between wbinv and disabling cache ! */ 135 136 /* 137 * Now there are no dirty lines, but there may still be lines marked 138 * valid. Disable all caches and the MMU, and invalidate everything 139 * before setting up new page tables and re-enabling the mmu. 140 */ 1411: 142 bic r7, #CPU_CONTROL_DC_ENABLE 143 bic r7, #CPU_CONTROL_AFLT_ENABLE 144 bic r7, #CPU_CONTROL_MMU_ENABLE 145 bic r7, #CPU_CONTROL_IC_ENABLE 146 bic r7, #CPU_CONTROL_BPRD_ENABLE 147 bic r7, #CPU_CONTROL_SW_ENABLE 148 orr r7, #CPU_CONTROL_UNAL_ENABLE 149 orr r7, #CPU_CONTROL_VECRELOC 150 mcr CP15_SCTLR(r7) 151 DSB 152 ISB 153 bl dcache_inv_poc_all 154 mcr CP15_ICIALLU 155 DSB 156 ISB 157 158 /* 159 * Build page table from scratch. 160 */ 161 162 /* 163 * Figure out the physical address we're loaded at by assuming this 164 * entry point code is in the first L1 section and so if we clear the 165 * offset bits of the pc that will give us the section-aligned load 166 * address, which remains in r5 throughout all the following code. 167 */ 168 ldr r2, =(L1_S_OFFSET) 169 bic r5, pc, r2 170 171 /* Find the delta between VA and PA, result stays in r0 throughout. */ 172 adr r0, Lpagetable 173 bl translate_va_to_pa 174 175 /* 176 * First map the entire 4GB address space as VA=PA. It's mapped as 177 * normal (cached) memory because it's for things like accessing the 178 * parameters passed in from the bootloader, which might be at any 179 * physical address, different for every platform. 180 */ 181 mov r1, #0 182 mov r2, #0 183 mov r3, #4096 184 bl build_pagetables 185 186 /* 187 * Next we map the kernel starting at the physical load address, mapped 188 * to the VA the kernel is linked for. The default size we map is 64MiB 189 * but it can be overridden with a kernel option. 190 */ 191 mov r1, r5 192 ldr r2, =(KERNVIRTADDR) 193 ldr r3, =(LOCORE_MAP_MB) 194 bl build_pagetables 195 196 /* Create a device mapping for early_printf if specified. */ 197#if defined(SOCDEV_PA) && defined(SOCDEV_VA) 198 ldr r1, =SOCDEV_PA 199 ldr r2, =SOCDEV_VA 200 mov r3, #1 201 bl build_device_pagetables 202#endif 203 bl init_mmu 204 205 /* Transition the PC from physical to virtual addressing. */ 206 ldr pc, =1f 2071: 208 209 /* Setup stack, clear BSS */ 210 ldr r1, =.Lstart 211 ldmia r1, {r1, r2, sp} /* Set initial stack and */ 212 add sp, sp, #INIT_ARM_STACK_SIZE 213 sub r2, r2, r1 /* get zero init data */ 214 mov r3, #0 2152: 216 str r3, [r1], #0x0004 /* get zero init data */ 217 subs r2, r2, #4 218 bgt 2b 219 220 mov r1, #28 /* loader info size is 28 bytes also second arg */ 221 subs sp, sp, r1 /* allocate arm_boot_params struct on stack */ 222 mov r0, sp /* loader info pointer is first arg */ 223 bic sp, sp, #7 /* align stack to 8 bytes */ 224 str r1, [r0] /* Store length of loader info */ 225 str r8, [r0, #4] /* Store r0 from boot loader */ 226 str r9, [r0, #8] /* Store r1 from boot loader */ 227 str r10, [r0, #12] /* store r2 from boot loader */ 228 str r11, [r0, #16] /* store r3 from boot loader */ 229 str r5, [r0, #20] /* store the physical address */ 230 adr r4, Lpagetable /* load the pagetable address */ 231 ldr r5, [r4, #4] 232 str r5, [r0, #24] /* store the pagetable address */ 233 mov fp, #0 /* trace back starts here */ 234 bl _C_LABEL(initarm) /* Off we go */ 235 236 /* init arm will return the new stack pointer. */ 237 mov sp, r0 238 239 bl _C_LABEL(mi_startup) /* call mi_startup()! */ 240 241 ldr r0, =.Lmainreturned 242 b _C_LABEL(panic) 243 /* NOTREACHED */ 244END(_start) 245 246#define VA_TO_PA_POINTER(name, table) \ 247name: ;\ 248 .word . ;\ 249 .word table 250 251/* 252 * Returns the physical address of a magic va to pa pointer. 253 * r0 - The pagetable data pointer. This must be built using the 254 * VA_TO_PA_POINTER macro. 255 * e.g. 256 * VA_TO_PA_POINTER(Lpagetable, pagetable) 257 * ... 258 * adr r0, Lpagetable 259 * bl translate_va_to_pa 260 * r0 will now contain the physical address of pagetable 261 * r1, r2 - Trashed 262 */ 263translate_va_to_pa: 264 ldr r1, [r0] 265 sub r2, r1, r0 266 /* At this point: r2 = VA - PA */ 267 268 /* 269 * Find the physical address of the table. After these two 270 * instructions: 271 * r1 = va(pagetable) 272 * 273 * r0 = va(pagetable) - (VA - PA) 274 * = va(pagetable) - VA + PA 275 * = pa(pagetable) 276 */ 277 ldr r1, [r0, #4] 278 sub r0, r1, r2 279 mov pc, lr 280 281/* 282 * Init MMU 283 * r0 - the table base address 284 */ 285 286ASENTRY_NP(init_mmu) 287 288 /* Setup TLB and MMU registers */ 289 mcr CP15_TTBR0(r0) /* Set TTB */ 290 mov r0, #0 291 mcr CP15_CONTEXTIDR(r0) /* Set ASID to 0 */ 292 293 /* Set the Domain Access register */ 294 mov r0, #DOMAIN_CLIENT /* Only domain #0 is used */ 295 mcr CP15_DACR(r0) 296 297 /* 298 * Set TEX remap registers 299 * - All is set to uncacheable memory 300 */ 301 ldr r0, =0xAAAAA 302 mcr CP15_PRRR(r0) 303 mov r0, #0 304 mcr CP15_NMRR(r0) 305 mcr CP15_TLBIALL /* Flush TLB */ 306 DSB 307 ISB 308 309 /* Enable MMU */ 310 mrc CP15_SCTLR(r0) 311 orr r0, r0, #CPU_CONTROL_MMU_ENABLE 312 orr r0, r0, #CPU_CONTROL_V6_EXTPAGE 313 orr r0, r0, #CPU_CONTROL_TR_ENABLE 314 orr r0, r0, #CPU_CONTROL_AF_ENABLE 315 mcr CP15_SCTLR(r0) 316 DSB 317 ISB 318 mcr CP15_TLBIALL /* Flush TLB */ 319 mcr CP15_BPIALL /* Flush Branch predictor */ 320 DSB 321 ISB 322 323 mov pc, lr 324END(init_mmu) 325 326 327/* 328 * Init SMP coherent mode, enable caching and switch to final MMU table. 329 * Called with disabled caches 330 * r0 - The table base address 331 * r1 - clear bits for aux register 332 * r2 - set bits for aux register 333 */ 334ASENTRY_NP(reinit_mmu) 335 push {r4-r11, lr} 336 mov r4, r0 337 mov r5, r1 338 mov r6, r2 339 340 /* !! Be very paranoid here !! */ 341 /* !! We cannot write single bit here !! */ 342 343#if 0 /* XXX writeback shouldn't be necessary */ 344 /* Write back and invalidate all integrated caches */ 345 bl dcache_wbinv_poc_all 346#else 347 bl dcache_inv_pou_all 348#endif 349 mcr CP15_ICIALLU 350 DSB 351 ISB 352 353 /* Set auxiliary register */ 354 mrc CP15_ACTLR(r7) 355 bic r8, r7, r5 /* Mask bits */ 356 eor r8, r8, r6 /* Set bits */ 357 teq r7, r8 358 mcrne CP15_ACTLR(r8) 359 DSB 360 ISB 361 362 /* Enable caches. */ 363 mrc CP15_SCTLR(r7) 364 orr r7, #CPU_CONTROL_DC_ENABLE 365 orr r7, #CPU_CONTROL_IC_ENABLE 366 orr r7, #CPU_CONTROL_BPRD_ENABLE 367 mcr CP15_SCTLR(r7) 368 DSB 369 370 mcr CP15_TTBR0(r4) /* Set new TTB */ 371 DSB 372 ISB 373 374 mcr CP15_TLBIALL /* Flush TLB */ 375 mcr CP15_BPIALL /* Flush Branch predictor */ 376 DSB 377 ISB 378 379#if 0 /* XXX writeback shouldn't be necessary */ 380 /* Write back and invalidate all integrated caches */ 381 bl dcache_wbinv_poc_all 382#else 383 bl dcache_inv_pou_all 384#endif 385 mcr CP15_ICIALLU 386 DSB 387 ISB 388 389 pop {r4-r11, pc} 390END(reinit_mmu) 391 392 393/* 394 * Builds the page table 395 * r0 - The table base address 396 * r1 - The physical address (trashed) 397 * r2 - The virtual address (trashed) 398 * r3 - The number of 1MiB sections 399 * r4 - Trashed 400 * 401 * Addresses must be 1MiB aligned 402 */ 403build_device_pagetables: 404 ldr r4, =PTE1_V|PTE1_A|PTE1_AP_KRW|TEX1_CLASS_0 405 b 1f 406build_pagetables: 407 /* Set the required page attributed */ 408 ldr r4, =PTE1_V|PTE1_A|PTE1_AP_KRW|TEX1_CLASS_0 4091: 410 orr r1, r4 411 412 /* Move the virtual address to the correct bit location */ 413 lsr r2, #(PTE1_SHIFT - 2) 414 415 mov r4, r3 4162: 417 str r1, [r0, r2] 418 add r2, r2, #4 419 add r1, r1, #(PTE1_SIZE) 420 adds r4, r4, #-1 421 bhi 2b 422 423 mov pc, lr 424 425VA_TO_PA_POINTER(Lpagetable, boot_pt1) 426 427 .global _C_LABEL(hypmode_enabled) 428_C_LABEL(hypmode_enabled): 429 .word 0 430 431.Lstart: 432 .word _edata /* Note that these three items are */ 433 .word _ebss /* loaded with a single ldmia and */ 434 .word svcstk /* must remain in order together. */ 435 436.Lmainreturned: 437 .asciz "main() returned" 438 .align 2 439 440 .bss 441svcstk: 442 .space INIT_ARM_STACK_SIZE * MAXCPU 443 444/* 445 * Memory for the initial pagetable. We are unable to place this in 446 * the bss as this will be cleared after the table is loaded. 447 */ 448 .section ".init_pagetable", "aw", %nobits 449 .align 14 /* 16KiB aligned */ 450 .globl boot_pt1 451boot_pt1: 452 .space L1_TABLE_SIZE 453 454 .text 455 .align 2 456 457#if defined(SMP) 458 459ASENTRY_NP(mpentry) 460 /* Make sure interrupts are disabled. */ 461 cpsid ifa 462 463 HANDLE_HYP 464 465 /* Setup core, disable all caches. */ 466 mrc CP15_SCTLR(r0) 467 bic r0, #CPU_CONTROL_MMU_ENABLE 468 bic r0, #CPU_CONTROL_AFLT_ENABLE 469 bic r0, #CPU_CONTROL_DC_ENABLE 470 bic r0, #CPU_CONTROL_IC_ENABLE 471 bic r0, #CPU_CONTROL_BPRD_ENABLE 472 bic r0, #CPU_CONTROL_SW_ENABLE 473 orr r0, #CPU_CONTROL_UNAL_ENABLE 474 orr r0, #CPU_CONTROL_VECRELOC 475 mcr CP15_SCTLR(r0) 476 DSB 477 ISB 478 479 /* Invalidate L1 cache I+D cache */ 480 bl dcache_inv_pou_all 481 mcr CP15_ICIALLU 482 DSB 483 ISB 484 485 /* Find the delta between VA and PA */ 486 adr r0, Lpagetable 487 bl translate_va_to_pa 488 489 bl init_mmu 490 491 adr r1, .Lstart+8 /* Get initstack pointer from */ 492 ldr sp, [r1] /* startup data. */ 493 mrc CP15_MPIDR(r0) /* Get processor id number. */ 494 and r0, r0, #0x0f 495 mov r1, #INIT_ARM_STACK_SIZE 496 mul r2, r1, r0 /* Point sp to initstack */ 497 add sp, sp, r2 /* area for this processor. */ 498 499 /* Switch to virtual addresses. */ 500 ldr pc, =1f 5011: 502 mov fp, #0 /* trace back starts here */ 503 bl _C_LABEL(init_secondary)/* Off we go, cpu id in r0. */ 504 505 adr r0, .Lmpreturned 506 b _C_LABEL(panic) 507 /* NOTREACHED */ 508END(mpentry) 509 510.Lmpreturned: 511 .asciz "init_secondary() returned" 512 .align 2 513#endif 514 515ENTRY_NP(cpu_halt) 516 517 /* XXX re-implement !!! */ 518 cpsid ifa 519 bl dcache_wbinv_poc_all 520 521 ldr r4, .Lcpu_reset_address 522 ldr r4, [r4] 523 teq r4, #0 524 movne pc, r4 5251: 526 WFI 527 b 1b 528 529 /* 530 * _cpu_reset_address contains the address to branch to, to complete 531 * the cpu reset after turning the MMU off 532 * This variable is provided by the hardware specific code 533 */ 534.Lcpu_reset_address: 535 .word _C_LABEL(cpu_reset_address) 536END(cpu_halt) 537 538 539/* 540 * setjump + longjmp 541 */ 542ENTRY(setjmp) 543 stmia r0, {r4-r14} 544 mov r0, #0x00000000 545 RET 546END(setjmp) 547 548ENTRY(longjmp) 549 ldmia r0, {r4-r14} 550 mov r0, #0x00000001 551 RET 552END(longjmp) 553 554 .data 555 .global _C_LABEL(esym) 556_C_LABEL(esym): .word _C_LABEL(end) 557 558ENTRY_NP(abort) 559 b _C_LABEL(abort) 560END(abort) 561 562ENTRY_NP(sigcode) 563 mov r0, sp 564 add r0, r0, #SIGF_UC 565 566 /* 567 * Call the sigreturn system call. 568 * 569 * We have to load r7 manually rather than using 570 * "ldr r7, =SYS_sigreturn" to ensure the value of szsigcode is 571 * correct. Using the alternative places esigcode at the address 572 * of the data rather than the address one past the data. 573 */ 574 575 ldr r7, [pc, #12] /* Load SYS_sigreturn */ 576 swi SYS_sigreturn 577 578 /* Well if that failed we better exit quick ! */ 579 580 ldr r7, [pc, #8] /* Load SYS_exit */ 581 swi SYS_exit 582 583 /* Branch back to retry SYS_sigreturn */ 584 b . - 16 585END(sigcode) 586 .word SYS_sigreturn 587 .word SYS_exit 588 589 .align 2 590 .global _C_LABEL(esigcode) 591 _C_LABEL(esigcode): 592 593 .data 594 .global szsigcode 595szsigcode: 596 .long esigcode-sigcode 597 598/* End of locore.S */ 599