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/cpuconf.h> 41#include <machine/pte.h> 42 43__FBSDID("$FreeBSD$"); 44 45/* What size should this really be ? It is only used by initarm() */ 46#define INIT_ARM_STACK_SIZE (2048 * 4) 47 48#define CPWAIT_BRANCH \ 49 sub pc, pc, #4 50 51#define CPWAIT(tmp) \ 52 mrc p15, 0, tmp, c2, c0, 0 /* arbitrary read of CP15 */ ;\ 53 mov tmp, tmp /* wait for it to complete */ ;\ 54 CPWAIT_BRANCH /* branch to next insn */ 55 56/* 57 * This is for kvm_mkdb, and should be the address of the beginning 58 * of the kernel text segment (not necessarily the same as kernbase). 59 */ 60 .text 61 .align 0 62.globl kernbase 63.set kernbase,KERNBASE 64.globl physaddr 65.set physaddr,PHYSADDR 66 67/* 68 * On entry for FreeBSD boot ABI: 69 * r0 - metadata pointer or 0 (boothowto on AT91's boot2) 70 * r1 - if (r0 == 0) then metadata pointer 71 * On entry for Linux boot ABI: 72 * r0 - 0 73 * r1 - machine type (passed as arg2 to initarm) 74 * r2 - Pointer to a tagged list or dtb image (phys addr) (passed as arg1 initarm) 75 * 76 * For both types of boot we gather up the args, put them in a struct arm_boot_params 77 * structure and pass that to initarm. 78 */ 79 .globl btext 80btext: 81ASENTRY_NP(_start) 82 STOP_UNWINDING /* Can't unwind into the bootloader! */ 83 84 mov r9, r0 /* 0 or boot mode from boot2 */ 85 mov r8, r1 /* Save Machine type */ 86 mov ip, r2 /* Save meta data */ 87 mov fp, r3 /* Future expantion */ 88 89 /* Make sure interrupts are disabled. */ 90 mrs r7, cpsr 91 orr r7, r7, #(I32_bit|F32_bit) 92 msr cpsr_c, r7 93 94#if defined (FLASHADDR) && defined(LOADERRAMADDR) 95 /* Check if we're running from flash. */ 96 ldr r7, =FLASHADDR 97 /* 98 * If we're running with MMU disabled, test against the 99 * physical address instead. 100 */ 101 mrc p15, 0, r2, c1, c0, 0 102 ands r2, r2, #CPU_CONTROL_MMU_ENABLE 103 ldreq r6, =PHYSADDR 104 ldrne r6, =LOADERRAMADDR 105 cmp r7, r6 106 bls flash_lower 107 cmp r7, pc 108 bhi from_ram 109 b do_copy 110 111flash_lower: 112 cmp r6, pc 113 bls from_ram 114do_copy: 115 ldr r7, =KERNBASE 116 adr r1, _start 117 ldr r0, Lreal_start 118 ldr r2, Lend 119 sub r2, r2, r0 120 sub r0, r0, r7 121 add r0, r0, r6 122 mov r4, r0 123 bl memcpy 124 ldr r0, Lram_offset 125 add pc, r4, r0 126Lram_offset: .word from_ram-_C_LABEL(_start) 127from_ram: 128 nop 129#endif 130 adr r7, Lunmapped 131 bic r7, r7, #0xf0000000 132 orr r7, r7, #PHYSADDR 133 134 135disable_mmu: 136 /* Disable MMU for a while */ 137 mrc p15, 0, r2, c1, c0, 0 138 bic r2, r2, #(CPU_CONTROL_MMU_ENABLE | CPU_CONTROL_DC_ENABLE |\ 139 CPU_CONTROL_WBUF_ENABLE) 140 bic r2, r2, #(CPU_CONTROL_IC_ENABLE) 141 bic r2, r2, #(CPU_CONTROL_BPRD_ENABLE) 142 mcr p15, 0, r2, c1, c0, 0 143 144 nop 145 nop 146 nop 147 mov pc, r7 148Lunmapped: 149 /* 150 * Build page table from scratch. 151 */ 152 153 /* Find the delta between VA and PA */ 154 adr r0, Lpagetable 155 ldr r1, [r0] 156 sub r2, r1, r0 157 /* At this point: r2 = VA - PA */ 158 159 /* 160 * Find the physical address of the table. After these two 161 * instructions: 162 * r1 = va(pagetable) 163 * 164 * r0 = va(pagetable) - (VA - PA) 165 * = va(pagetable) - VA + PA 166 * = pa(pagetable) 167 */ 168 ldr r1, [r0, #4] 169 sub r0, r1, r2 170 171 /* 172 * Map PA == VA 173 */ 174 /* Find the start kernels load address */ 175 adr r5, _start 176 ldr r2, =(L1_S_OFFSET) 177 bic r5, r2 178 mov r1, r5 179 mov r2, r5 180 /* Map 64MiB, preserved over calls to build_pagetables */ 181 mov r3, #64 182 bl build_pagetables 183 184 /* Create the kernel map to jump to */ 185 mov r1, r5 186 ldr r2, =(KERNVIRTADDR) 187 bl build_pagetables 188 189#if defined(SOCDEV_PA) && defined(SOCDEV_VA) 190 /* Create the custom map */ 191 ldr r1, =SOCDEV_PA 192 ldr r2, =SOCDEV_VA 193 bl build_pagetables 194#endif 195 196#if defined(SMP) 197 orr r0, r0, #2 /* Set TTB shared memory flag */ 198#endif 199 mcr p15, 0, r0, c2, c0, 0 /* Set TTB */ 200 mcr p15, 0, r0, c8, c7, 0 /* Flush TLB */ 201 202#if defined(CPU_ARM1136) || defined(CPU_ARM1176) || defined(CPU_CORTEXA) || defined(CPU_MV_PJ4B) || defined(CPU_KRAIT) 203 mov r0, #0 204 mcr p15, 0, r0, c13, c0, 1 /* Set ASID to 0 */ 205#endif 206 207 /* Set the Domain Access register. Very important! */ 208 mov r0, #((DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)) | DOMAIN_CLIENT) 209 mcr p15, 0, r0, c3, c0, 0 210 /* 211 * Enable MMU. 212 * On armv6 enable extended page tables, and set alignment checking 213 * to modulo-4 (CPU_CONTROL_UNAL_ENABLE) for the ldrd/strd 214 * instructions emitted by clang. 215 */ 216 mrc p15, 0, r0, c1, c0, 0 217#ifdef _ARM_ARCH_6 218 orr r0, r0, #(CPU_CONTROL_V6_EXTPAGE | CPU_CONTROL_UNAL_ENABLE) 219 orr r0, r0, #(CPU_CONTROL_AFLT_ENABLE) 220 orr r0, r0, #(CPU_CONTROL_AF_ENABLE) 221#endif 222 orr r0, r0, #(CPU_CONTROL_MMU_ENABLE) 223 mcr p15, 0, r0, c1, c0, 0 224 nop 225 nop 226 nop 227 CPWAIT(r0) 228 229mmu_done: 230 nop 231 adr r1, .Lstart 232 ldmia r1, {r1, r2, sp} /* Set initial stack and */ 233 sub r2, r2, r1 /* get zero init data */ 234 mov r3, #0 235.L1: 236 str r3, [r1], #0x0004 /* get zero init data */ 237 subs r2, r2, #4 238 bgt .L1 239 ldr pc, .Lvirt_done 240 241virt_done: 242 mov r1, #28 /* loader info size is 28 bytes also second arg */ 243 subs sp, sp, r1 /* allocate arm_boot_params struct on stack */ 244 mov r0, sp /* loader info pointer is first arg */ 245 bic sp, sp, #7 /* align stack to 8 bytes */ 246 str r1, [r0] /* Store length of loader info */ 247 str r9, [r0, #4] /* Store r0 from boot loader */ 248 str r8, [r0, #8] /* Store r1 from boot loader */ 249 str ip, [r0, #12] /* store r2 from boot loader */ 250 str fp, [r0, #16] /* store r3 from boot loader */ 251 str r5, [r0, #20] /* store the physical address */ 252 adr r4, Lpagetable /* load the pagetable address */ 253 ldr r5, [r4, #4] 254 str r5, [r0, #24] /* store the pagetable address */ 255 mov fp, #0 /* trace back starts here */ 256 bl _C_LABEL(initarm) /* Off we go */ 257 258 /* init arm will return the new stack pointer. */ 259 mov sp, r0 260 261 bl _C_LABEL(mi_startup) /* call mi_startup()! */ 262 263 adr r0, .Lmainreturned 264 b _C_LABEL(panic) 265 /* NOTREACHED */ 266END(_start) 267 268/* 269 * Builds the page table 270 * r0 - The table base address 271 * r1 - The physical address (trashed) 272 * r2 - The virtual address (trashed) 273 * r3 - The number of 1MiB sections 274 * r4 - Trashed 275 * 276 * Addresses must be 1MiB aligned 277 */ 278build_pagetables: 279 /* Set the required page attributed */ 280 ldr r4, =(L1_TYPE_S|L1_S_C|L1_S_AP(AP_KRW)) 281#if defined(SMP) 282 orr r4, #(L1_SHARED) 283#endif 284 orr r1, r4 285 286 /* Move the virtual address to the correct bit location */ 287 lsr r2, #(L1_S_SHIFT - 2) 288 289 mov r4, r3 2901: 291 str r1, [r0, r2] 292 add r2, r2, #4 293 add r1, r1, #(L1_S_SIZE) 294 adds r4, r4, #-1 295 bhi 1b 296 297 RET 298 299Lpagetable: 300 .word . 301 .word pagetable 302 303Lvirtaddr: 304 .word KERNVIRTADDR 305Lphysaddr: 306 .word KERNPHYSADDR 307Lreal_start: 308 .word _start 309Lend: 310 .word _edata 311 312.Lstart: 313 .word _edata 314 .word _ebss 315 .word svcstk + INIT_ARM_STACK_SIZE 316 317.Lvirt_done: 318 .word virt_done 319 320.Lmainreturned: 321 .asciz "main() returned" 322 .align 0 323 324 .bss 325svcstk: 326 .space INIT_ARM_STACK_SIZE 327 328/* 329 * Memory for the initial pagetable. We are unable to place this in 330 * the bss as this will be cleared after the table is loaded. 331 */ 332 .section ".init_pagetable" 333 .align 14 /* 16KiB aligned */ 334pagetable: 335 .space L1_TABLE_SIZE 336 337 .text 338 .align 0 339 340.Lcpufuncs: 341 .word _C_LABEL(cpufuncs) 342 343#if defined(SMP) 344 345.Lmpvirt_done: 346 .word mpvirt_done 347Lstartup_pagetable_secondary: 348 .word temp_pagetable 349 350ASENTRY_NP(mpentry) 351 352 /* Make sure interrupts are disabled. */ 353 mrs r7, cpsr 354 orr r7, r7, #(I32_bit|F32_bit) 355 msr cpsr_c, r7 356 357 /* Disable MMU. It should be disabled already, but make sure. */ 358 mrc p15, 0, r2, c1, c0, 0 359 bic r2, r2, #(CPU_CONTROL_MMU_ENABLE | CPU_CONTROL_DC_ENABLE |\ 360 CPU_CONTROL_WBUF_ENABLE) 361 bic r2, r2, #(CPU_CONTROL_IC_ENABLE) 362 bic r2, r2, #(CPU_CONTROL_BPRD_ENABLE) 363 mcr p15, 0, r2, c1, c0, 0 364 nop 365 nop 366 nop 367 CPWAIT(r0) 368 369#if ARM_MMU_V6 370 bl armv6_idcache_inv_all /* Modifies r0 only */ 371#elif ARM_MMU_V7 372 bl armv7_idcache_inv_all /* Modifies r0-r3, ip */ 373#endif 374 375 ldr r0, Lstartup_pagetable_secondary 376 bic r0, r0, #0xf0000000 377 orr r0, r0, #PHYSADDR 378 ldr r0, [r0] 379 orr r0, r0, #2 /* Set TTB shared memory flag */ 380 mcr p15, 0, r0, c2, c0, 0 /* Set TTB */ 381 mcr p15, 0, r0, c8, c7, 0 /* Flush TLB */ 382 383 mov r0, #0 384 mcr p15, 0, r0, c13, c0, 1 /* Set ASID to 0 */ 385 386 /* Set the Domain Access register. Very important! */ 387 mov r0, #((DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)) | DOMAIN_CLIENT) 388 mcr p15, 0, r0, c3, c0, 0 389 /* Enable MMU */ 390 mrc p15, 0, r0, c1, c0, 0 391 orr r0, r0, #CPU_CONTROL_V6_EXTPAGE 392 orr r0, r0, #CPU_CONTROL_AF_ENABLE 393 orr r0, r0, #(CPU_CONTROL_MMU_ENABLE | CPU_CONTROL_DC_ENABLE |\ 394 CPU_CONTROL_WBUF_ENABLE) 395 orr r0, r0, #(CPU_CONTROL_IC_ENABLE) 396 orr r0, r0, #(CPU_CONTROL_BPRD_ENABLE) 397 mcr p15, 0, r0, c1, c0, 0 398 nop 399 nop 400 nop 401 CPWAIT(r0) 402 403 adr r1, .Lstart 404 ldmia r1, {r1, r2, sp} /* Set initial stack and */ 405 mrc p15, 0, r0, c0, c0, 5 406 and r0, r0, #15 407 mov r1, #2048 408 mul r2, r1, r0 409 sub sp, sp, r2 410 str r1, [sp] 411 ldr pc, .Lmpvirt_done 412 413mpvirt_done: 414 415 mov fp, #0 /* trace back starts here */ 416 bl _C_LABEL(init_secondary) /* Off we go */ 417 418 adr r0, .Lmpreturned 419 b _C_LABEL(panic) 420 /* NOTREACHED */ 421 422.Lmpreturned: 423 .asciz "init_secondary() returned" 424 .align 0 425END(mpentry) 426#endif 427 428ENTRY_NP(cpu_halt) 429 mrs r2, cpsr 430 bic r2, r2, #(PSR_MODE) 431 orr r2, r2, #(PSR_SVC32_MODE) 432 orr r2, r2, #(I32_bit | F32_bit) 433 msr cpsr_fsxc, r2 434 435 ldr r4, .Lcpu_reset_address 436 ldr r4, [r4] 437 438 ldr r0, .Lcpufuncs 439 mov lr, pc 440 ldr pc, [r0, #CF_IDCACHE_WBINV_ALL] 441 mov lr, pc 442 ldr pc, [r0, #CF_L2CACHE_WBINV_ALL] 443 444 /* 445 * Load the cpu_reset_needs_v4_MMU_disable flag to determine if it's 446 * necessary. 447 */ 448 449 ldr r1, .Lcpu_reset_needs_v4_MMU_disable 450 ldr r1, [r1] 451 cmp r1, #0 452 mov r2, #0 453 454 /* 455 * MMU & IDC off, 32 bit program & data space 456 * Hurl ourselves into the ROM 457 */ 458 mov r0, #(CPU_CONTROL_32BP_ENABLE | CPU_CONTROL_32BD_ENABLE) 459 mcr 15, 0, r0, c1, c0, 0 460 mcrne 15, 0, r2, c8, c7, 0 /* nail I+D TLB on ARMv4 and greater */ 461 mov pc, r4 462 463 /* 464 * _cpu_reset_address contains the address to branch to, to complete 465 * the cpu reset after turning the MMU off 466 * This variable is provided by the hardware specific code 467 */ 468.Lcpu_reset_address: 469 .word _C_LABEL(cpu_reset_address) 470 471 /* 472 * cpu_reset_needs_v4_MMU_disable contains a flag that signals if the 473 * v4 MMU disable instruction needs executing... it is an illegal instruction 474 * on f.e. ARM6/7 that locks up the computer in an endless illegal 475 * instruction / data-abort / reset loop. 476 */ 477.Lcpu_reset_needs_v4_MMU_disable: 478 .word _C_LABEL(cpu_reset_needs_v4_MMU_disable) 479END(cpu_halt) 480 481 482/* 483 * setjump + longjmp 484 */ 485ENTRY(setjmp) 486 stmia r0, {r4-r14} 487 mov r0, #0x00000000 488 RET 489END(setjmp) 490 491ENTRY(longjmp) 492 ldmia r0, {r4-r14} 493 mov r0, #0x00000001 494 RET 495END(longjmp) 496 497 .data 498 .global _C_LABEL(esym) 499_C_LABEL(esym): .word _C_LABEL(end) 500 501ENTRY_NP(abort) 502 b _C_LABEL(abort) 503END(abort) 504 505ENTRY_NP(sigcode) 506 mov r0, sp 507 add r0, r0, #SIGF_UC 508 509 /* 510 * Call the sigreturn system call. 511 * 512 * We have to load r7 manually rather than using 513 * "ldr r7, =SYS_sigreturn" to ensure the value of szsigcode is 514 * correct. Using the alternative places esigcode at the address 515 * of the data rather than the address one past the data. 516 */ 517 518 ldr r7, [pc, #12] /* Load SYS_sigreturn */ 519 swi SYS_sigreturn 520 521 /* Well if that failed we better exit quick ! */ 522 523 ldr r7, [pc, #8] /* Load SYS_exit */ 524 swi SYS_exit 525 526 /* Branch back to retry SYS_sigreturn */ 527 b . - 16 528END(sigcode) 529 .word SYS_sigreturn 530 .word SYS_exit 531 532 .align 0 533 .global _C_LABEL(esigcode) 534 _C_LABEL(esigcode): 535 536 .data 537 .global szsigcode 538szsigcode: 539 .long esigcode-sigcode 540 541/* End of locore.S */ 542