1/* 2 * linux/arch/arm/kernel/head-nommu.S 3 * 4 * Copyright (C) 1994-2002 Russell King 5 * Copyright (C) 2003-2006 Hyok S. Choi 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License version 2 as 9 * published by the Free Software Foundation. 10 * 11 * Common kernel startup code (non-paged MM) 12 * 13 */ 14#include <linux/linkage.h> 15#include <linux/init.h> 16#include <linux/errno.h> 17 18#include <asm/assembler.h> 19#include <asm/ptrace.h> 20#include <asm/asm-offsets.h> 21#include <asm/memory.h> 22#include <asm/cp15.h> 23#include <asm/thread_info.h> 24#include <asm/v7m.h> 25#include <asm/mpu.h> 26#include <asm/page.h> 27 28/* 29 * Kernel startup entry point. 30 * --------------------------- 31 * 32 * This is normally called from the decompressor code. The requirements 33 * are: MMU = off, D-cache = off, I-cache = dont care, r0 = 0, 34 * r1 = machine nr. 35 * 36 * See linux/arch/arm/tools/mach-types for the complete list of machine 37 * numbers for r1. 38 * 39 */ 40 41 __HEAD 42 43#ifdef CONFIG_CPU_THUMBONLY 44 .thumb 45ENTRY(stext) 46#else 47 .arm 48ENTRY(stext) 49 50 THUMB( badr r9, 1f ) @ Kernel is always entered in ARM. 51 THUMB( bx r9 ) @ If this is a Thumb-2 kernel, 52 THUMB( .thumb ) @ switch to Thumb now. 53 THUMB(1: ) 54#endif 55 56 setmode PSR_F_BIT | PSR_I_BIT | SVC_MODE, r9 @ ensure svc mode 57 @ and irqs disabled 58#if defined(CONFIG_CPU_CP15) 59 mrc p15, 0, r9, c0, c0 @ get processor id 60#elif defined(CONFIG_CPU_V7M) 61 ldr r9, =BASEADDR_V7M_SCB 62 ldr r9, [r9, V7M_SCB_CPUID] 63#else 64 ldr r9, =CONFIG_PROCESSOR_ID 65#endif 66 bl __lookup_processor_type @ r5=procinfo r9=cpuid 67 movs r10, r5 @ invalid processor (r5=0)? 68 beq __error_p @ yes, error 'p' 69 70#ifdef CONFIG_ARM_MPU 71 bl __setup_mpu 72#endif 73 74 badr lr, 1f @ return (PIC) address 75 ldr r12, [r10, #PROCINFO_INITFUNC] 76 add r12, r12, r10 77 ret r12 781: ldr lr, =__mmap_switched 79 b __after_proc_init 80ENDPROC(stext) 81 82#ifdef CONFIG_SMP 83 .text 84ENTRY(secondary_startup) 85 /* 86 * Common entry point for secondary CPUs. 87 * 88 * Ensure that we're in SVC mode, and IRQs are disabled. Lookup 89 * the processor type - there is no need to check the machine type 90 * as it has already been validated by the primary processor. 91 */ 92 setmode PSR_F_BIT | PSR_I_BIT | SVC_MODE, r9 93#ifndef CONFIG_CPU_CP15 94 ldr r9, =CONFIG_PROCESSOR_ID 95#else 96 mrc p15, 0, r9, c0, c0 @ get processor id 97#endif 98 bl __lookup_processor_type @ r5=procinfo r9=cpuid 99 movs r10, r5 @ invalid processor? 100 beq __error_p @ yes, error 'p' 101 102 ldr r7, __secondary_data 103 104#ifdef CONFIG_ARM_MPU 105 bl __secondary_setup_mpu @ Initialize the MPU 106#endif 107 108 badr lr, 1f @ return (PIC) address 109 ldr r12, [r10, #PROCINFO_INITFUNC] 110 add r12, r12, r10 111 ret r12 1121: bl __after_proc_init 113 ldr sp, [r7, #12] @ set up the stack pointer 114 mov fp, #0 115 b secondary_start_kernel 116ENDPROC(secondary_startup) 117 118 .type __secondary_data, %object 119__secondary_data: 120 .long secondary_data 121#endif /* CONFIG_SMP */ 122 123/* 124 * Set the Control Register and Read the process ID. 125 */ 126 .text 127__after_proc_init: 128#ifdef CONFIG_ARM_MPU 129M_CLASS(movw r12, #:lower16:BASEADDR_V7M_SCB) 130M_CLASS(movt r12, #:upper16:BASEADDR_V7M_SCB) 131M_CLASS(ldr r3, [r12, 0x50]) 132AR_CLASS(mrc p15, 0, r3, c0, c1, 4) @ Read ID_MMFR0 133 and r3, r3, #(MMFR0_PMSA) @ PMSA field 134 teq r3, #(MMFR0_PMSAv7) @ PMSA v7 135 beq 1f 136 teq r3, #(MMFR0_PMSAv8) @ PMSA v8 137 /* 138 * Memory region attributes for PMSAv8: 139 * 140 * n = AttrIndx[2:0] 141 * n MAIR 142 * DEVICE_nGnRnE 000 00000000 143 * NORMAL 001 11111111 144 */ 145 ldreq r3, =PMSAv8_MAIR(0x00, PMSAv8_RGN_DEVICE_nGnRnE) | \ 146 PMSAv8_MAIR(0xff, PMSAv8_RGN_NORMAL) 147AR_CLASS(mcreq p15, 0, r3, c10, c2, 0) @ MAIR 0 148M_CLASS(streq r3, [r12, #PMSAv8_MAIR0]) 149 moveq r3, #0 150AR_CLASS(mcreq p15, 0, r3, c10, c2, 1) @ MAIR 1 151M_CLASS(streq r3, [r12, #PMSAv8_MAIR1]) 152 1531: 154#endif 155#ifdef CONFIG_CPU_CP15 156 /* 157 * CP15 system control register value returned in r0 from 158 * the CPU init function. 159 */ 160 161#ifdef CONFIG_ARM_MPU 162 biceq r0, r0, #CR_BR @ Disable the 'default mem-map' 163 orreq r0, r0, #CR_M @ Set SCTRL.M (MPU on) 164#endif 165#if defined(CONFIG_ALIGNMENT_TRAP) && __LINUX_ARM_ARCH__ < 6 166 orr r0, r0, #CR_A 167#else 168 bic r0, r0, #CR_A 169#endif 170#ifdef CONFIG_CPU_DCACHE_DISABLE 171 bic r0, r0, #CR_C 172#endif 173#ifdef CONFIG_CPU_BPREDICT_DISABLE 174 bic r0, r0, #CR_Z 175#endif 176#ifdef CONFIG_CPU_ICACHE_DISABLE 177 bic r0, r0, #CR_I 178#endif 179 mcr p15, 0, r0, c1, c0, 0 @ write control reg 180 instr_sync 181#elif defined (CONFIG_CPU_V7M) 182#ifdef CONFIG_ARM_MPU 183 ldreq r3, [r12, MPU_CTRL] 184 biceq r3, #MPU_CTRL_PRIVDEFENA 185 orreq r3, #MPU_CTRL_ENABLE 186 streq r3, [r12, MPU_CTRL] 187 isb 188#endif 189 /* For V7M systems we want to modify the CCR similarly to the SCTLR */ 190#ifdef CONFIG_CPU_DCACHE_DISABLE 191 bic r0, r0, #V7M_SCB_CCR_DC 192#endif 193#ifdef CONFIG_CPU_BPREDICT_DISABLE 194 bic r0, r0, #V7M_SCB_CCR_BP 195#endif 196#ifdef CONFIG_CPU_ICACHE_DISABLE 197 bic r0, r0, #V7M_SCB_CCR_IC 198#endif 199 str r0, [r12, V7M_SCB_CCR] 200#endif /* CONFIG_CPU_CP15 elif CONFIG_CPU_V7M */ 201 ret lr 202ENDPROC(__after_proc_init) 203 .ltorg 204 205#ifdef CONFIG_ARM_MPU 206 207 208#ifndef CONFIG_CPU_V7M 209/* Set which MPU region should be programmed */ 210.macro set_region_nr tmp, rgnr, unused 211 mov \tmp, \rgnr @ Use static region numbers 212 mcr p15, 0, \tmp, c6, c2, 0 @ Write RGNR 213.endm 214 215/* Setup a single MPU region, either D or I side (D-side for unified) */ 216.macro setup_region bar, acr, sr, side = PMSAv7_DATA_SIDE, unused 217 mcr p15, 0, \bar, c6, c1, (0 + \side) @ I/DRBAR 218 mcr p15, 0, \acr, c6, c1, (4 + \side) @ I/DRACR 219 mcr p15, 0, \sr, c6, c1, (2 + \side) @ I/DRSR 220.endm 221#else 222.macro set_region_nr tmp, rgnr, base 223 mov \tmp, \rgnr 224 str \tmp, [\base, #PMSAv7_RNR] 225.endm 226 227.macro setup_region bar, acr, sr, unused, base 228 lsl \acr, \acr, #16 229 orr \acr, \acr, \sr 230 str \bar, [\base, #PMSAv7_RBAR] 231 str \acr, [\base, #PMSAv7_RASR] 232.endm 233 234#endif 235/* 236 * Setup the MPU and initial MPU Regions. We create the following regions: 237 * Region 0: Use this for probing the MPU details, so leave disabled. 238 * Region 1: Background region - covers the whole of RAM as strongly ordered 239 * Region 2: Normal, Shared, cacheable for RAM. From PHYS_OFFSET, size from r6 240 * Region 3: Normal, shared, inaccessible from PL0 to protect the vectors page 241 * 242 * r6: Value to be written to DRSR (and IRSR if required) for PMSAv7_RAM_REGION 243*/ 244 __HEAD 245 246ENTRY(__setup_mpu) 247 248 /* Probe for v7 PMSA compliance */ 249M_CLASS(movw r12, #:lower16:BASEADDR_V7M_SCB) 250M_CLASS(movt r12, #:upper16:BASEADDR_V7M_SCB) 251 252AR_CLASS(mrc p15, 0, r0, c0, c1, 4) @ Read ID_MMFR0 253M_CLASS(ldr r0, [r12, 0x50]) 254 and r0, r0, #(MMFR0_PMSA) @ PMSA field 255 teq r0, #(MMFR0_PMSAv7) @ PMSA v7 256 beq __setup_pmsa_v7 257 teq r0, #(MMFR0_PMSAv8) @ PMSA v8 258 beq __setup_pmsa_v8 259 260 ret lr 261ENDPROC(__setup_mpu) 262 263ENTRY(__setup_pmsa_v7) 264 /* Calculate the size of a region covering just the kernel */ 265 ldr r5, =PLAT_PHYS_OFFSET @ Region start: PHYS_OFFSET 266 ldr r6, =(_end) @ Cover whole kernel 267 sub r6, r6, r5 @ Minimum size of region to map 268 clz r6, r6 @ Region size must be 2^N... 269 rsb r6, r6, #31 @ ...so round up region size 270 lsl r6, r6, #PMSAv7_RSR_SZ @ Put size in right field 271 orr r6, r6, #(1 << PMSAv7_RSR_EN) @ Set region enabled bit 272 273 /* Determine whether the D/I-side memory map is unified. We set the 274 * flags here and continue to use them for the rest of this function */ 275AR_CLASS(mrc p15, 0, r0, c0, c0, 4) @ MPUIR 276M_CLASS(ldr r0, [r12, #MPU_TYPE]) 277 ands r5, r0, #MPUIR_DREGION_SZMASK @ 0 size d region => No MPU 278 bxeq lr 279 tst r0, #MPUIR_nU @ MPUIR_nU = 0 for unified 280 281 /* Setup second region first to free up r6 */ 282 set_region_nr r0, #PMSAv7_RAM_REGION, r12 283 isb 284 /* Full access from PL0, PL1, shared for CONFIG_SMP, cacheable */ 285 ldr r0, =PLAT_PHYS_OFFSET @ RAM starts at PHYS_OFFSET 286 ldr r5,=(PMSAv7_AP_PL1RW_PL0RW | PMSAv7_RGN_NORMAL) 287 288 setup_region r0, r5, r6, PMSAv7_DATA_SIDE, r12 @ PHYS_OFFSET, shared, enabled 289 beq 1f @ Memory-map not unified 290 setup_region r0, r5, r6, PMSAv7_INSTR_SIDE, r12 @ PHYS_OFFSET, shared, enabled 2911: isb 292 293 /* First/background region */ 294 set_region_nr r0, #PMSAv7_BG_REGION, r12 295 isb 296 /* Execute Never, strongly ordered, inaccessible to PL0, rw PL1 */ 297 mov r0, #0 @ BG region starts at 0x0 298 ldr r5,=(PMSAv7_ACR_XN | PMSAv7_RGN_STRONGLY_ORDERED | PMSAv7_AP_PL1RW_PL0NA) 299 mov r6, #PMSAv7_RSR_ALL_MEM @ 4GB region, enabled 300 301 setup_region r0, r5, r6, PMSAv7_DATA_SIDE, r12 @ 0x0, BG region, enabled 302 beq 2f @ Memory-map not unified 303 setup_region r0, r5, r6, PMSAv7_INSTR_SIDE r12 @ 0x0, BG region, enabled 3042: isb 305 306#ifdef CONFIG_XIP_KERNEL 307 set_region_nr r0, #PMSAv7_ROM_REGION, r12 308 isb 309 310 ldr r5,=(PMSAv7_AP_PL1RO_PL0NA | PMSAv7_RGN_NORMAL) 311 312 ldr r0, =CONFIG_XIP_PHYS_ADDR @ ROM start 313 ldr r6, =(_exiprom) @ ROM end 314 sub r6, r6, r0 @ Minimum size of region to map 315 clz r6, r6 @ Region size must be 2^N... 316 rsb r6, r6, #31 @ ...so round up region size 317 lsl r6, r6, #PMSAv7_RSR_SZ @ Put size in right field 318 orr r6, r6, #(1 << PMSAv7_RSR_EN) @ Set region enabled bit 319 320 setup_region r0, r5, r6, PMSAv7_DATA_SIDE, r12 @ XIP_PHYS_ADDR, shared, enabled 321 beq 3f @ Memory-map not unified 322 setup_region r0, r5, r6, PMSAv7_INSTR_SIDE, r12 @ XIP_PHYS_ADDR, shared, enabled 3233: isb 324#endif 325 ret lr 326ENDPROC(__setup_pmsa_v7) 327 328ENTRY(__setup_pmsa_v8) 329 mov r0, #0 330AR_CLASS(mcr p15, 0, r0, c6, c2, 1) @ PRSEL 331M_CLASS(str r0, [r12, #PMSAv8_RNR]) 332 isb 333 334#ifdef CONFIG_XIP_KERNEL 335 ldr r5, =CONFIG_XIP_PHYS_ADDR @ ROM start 336 ldr r6, =(_exiprom) @ ROM end 337 sub r6, r6, #1 338 bic r6, r6, #(PMSAv8_MINALIGN - 1) 339 340 orr r5, r5, #(PMSAv8_AP_PL1RW_PL0NA | PMSAv8_RGN_SHARED) 341 orr r6, r6, #(PMSAv8_LAR_IDX(PMSAv8_RGN_NORMAL) | PMSAv8_LAR_EN) 342 343AR_CLASS(mcr p15, 0, r5, c6, c8, 0) @ PRBAR0 344AR_CLASS(mcr p15, 0, r6, c6, c8, 1) @ PRLAR0 345M_CLASS(str r5, [r12, #PMSAv8_RBAR_A(0)]) 346M_CLASS(str r6, [r12, #PMSAv8_RLAR_A(0)]) 347#endif 348 349 ldr r5, =KERNEL_START 350 ldr r6, =KERNEL_END 351 sub r6, r6, #1 352 bic r6, r6, #(PMSAv8_MINALIGN - 1) 353 354 orr r5, r5, #(PMSAv8_AP_PL1RW_PL0NA | PMSAv8_RGN_SHARED) 355 orr r6, r6, #(PMSAv8_LAR_IDX(PMSAv8_RGN_NORMAL) | PMSAv8_LAR_EN) 356 357AR_CLASS(mcr p15, 0, r5, c6, c8, 4) @ PRBAR1 358AR_CLASS(mcr p15, 0, r6, c6, c8, 5) @ PRLAR1 359M_CLASS(str r5, [r12, #PMSAv8_RBAR_A(1)]) 360M_CLASS(str r6, [r12, #PMSAv8_RLAR_A(1)]) 361 362 /* Setup Background: 0x0 - min(KERNEL_START, XIP_PHYS_ADDR) */ 363#ifdef CONFIG_XIP_KERNEL 364 ldr r6, =KERNEL_START 365 ldr r5, =CONFIG_XIP_PHYS_ADDR 366 cmp r6, r5 367 movcs r6, r5 368#else 369 ldr r6, =KERNEL_START 370#endif 371 cmp r6, #0 372 beq 1f 373 374 mov r5, #0 375 sub r6, r6, #1 376 bic r6, r6, #(PMSAv8_MINALIGN - 1) 377 378 orr r5, r5, #(PMSAv8_AP_PL1RW_PL0NA | PMSAv8_RGN_SHARED | PMSAv8_BAR_XN) 379 orr r6, r6, #(PMSAv8_LAR_IDX(PMSAv8_RGN_DEVICE_nGnRnE) | PMSAv8_LAR_EN) 380 381AR_CLASS(mcr p15, 0, r5, c6, c9, 0) @ PRBAR2 382AR_CLASS(mcr p15, 0, r6, c6, c9, 1) @ PRLAR2 383M_CLASS(str r5, [r12, #PMSAv8_RBAR_A(2)]) 384M_CLASS(str r6, [r12, #PMSAv8_RLAR_A(2)]) 385 3861: 387 /* Setup Background: max(KERNEL_END, _exiprom) - 0xffffffff */ 388#ifdef CONFIG_XIP_KERNEL 389 ldr r5, =KERNEL_END 390 ldr r6, =(_exiprom) 391 cmp r5, r6 392 movcc r5, r6 393#else 394 ldr r5, =KERNEL_END 395#endif 396 mov r6, #0xffffffff 397 bic r6, r6, #(PMSAv8_MINALIGN - 1) 398 399 orr r5, r5, #(PMSAv8_AP_PL1RW_PL0NA | PMSAv8_RGN_SHARED | PMSAv8_BAR_XN) 400 orr r6, r6, #(PMSAv8_LAR_IDX(PMSAv8_RGN_DEVICE_nGnRnE) | PMSAv8_LAR_EN) 401 402AR_CLASS(mcr p15, 0, r5, c6, c9, 4) @ PRBAR3 403AR_CLASS(mcr p15, 0, r6, c6, c9, 5) @ PRLAR3 404M_CLASS(str r5, [r12, #PMSAv8_RBAR_A(3)]) 405M_CLASS(str r6, [r12, #PMSAv8_RLAR_A(3)]) 406 407#ifdef CONFIG_XIP_KERNEL 408 /* Setup Background: min(_exiprom, KERNEL_END) - max(KERNEL_START, XIP_PHYS_ADDR) */ 409 ldr r5, =(_exiprom) 410 ldr r6, =KERNEL_END 411 cmp r5, r6 412 movcs r5, r6 413 414 ldr r6, =KERNEL_START 415 ldr r0, =CONFIG_XIP_PHYS_ADDR 416 cmp r6, r0 417 movcc r6, r0 418 419 sub r6, r6, #1 420 bic r6, r6, #(PMSAv8_MINALIGN - 1) 421 422 orr r5, r5, #(PMSAv8_AP_PL1RW_PL0NA | PMSAv8_RGN_SHARED | PMSAv8_BAR_XN) 423 orr r6, r6, #(PMSAv8_LAR_IDX(PMSAv8_RGN_DEVICE_nGnRnE) | PMSAv8_LAR_EN) 424 425#ifdef CONFIG_CPU_V7M 426 /* There is no alias for n == 4 */ 427 mov r0, #4 428 str r0, [r12, #PMSAv8_RNR] @ PRSEL 429 isb 430 431 str r5, [r12, #PMSAv8_RBAR_A(0)] 432 str r6, [r12, #PMSAv8_RLAR_A(0)] 433#else 434 mcr p15, 0, r5, c6, c10, 1 @ PRBAR4 435 mcr p15, 0, r6, c6, c10, 2 @ PRLAR4 436#endif 437#endif 438 ret lr 439ENDPROC(__setup_pmsa_v8) 440 441#ifdef CONFIG_SMP 442/* 443 * r6: pointer at mpu_rgn_info 444 */ 445 446 .text 447ENTRY(__secondary_setup_mpu) 448 /* Use MPU region info supplied by __cpu_up */ 449 ldr r6, [r7] @ get secondary_data.mpu_rgn_info 450 451 /* Probe for v7 PMSA compliance */ 452 mrc p15, 0, r0, c0, c1, 4 @ Read ID_MMFR0 453 and r0, r0, #(MMFR0_PMSA) @ PMSA field 454 teq r0, #(MMFR0_PMSAv7) @ PMSA v7 455 beq __secondary_setup_pmsa_v7 456 teq r0, #(MMFR0_PMSAv8) @ PMSA v8 457 beq __secondary_setup_pmsa_v8 458 b __error_p 459ENDPROC(__secondary_setup_mpu) 460 461/* 462 * r6: pointer at mpu_rgn_info 463 */ 464ENTRY(__secondary_setup_pmsa_v7) 465 /* Determine whether the D/I-side memory map is unified. We set the 466 * flags here and continue to use them for the rest of this function */ 467 mrc p15, 0, r0, c0, c0, 4 @ MPUIR 468 ands r5, r0, #MPUIR_DREGION_SZMASK @ 0 size d region => No MPU 469 beq __error_p 470 471 ldr r4, [r6, #MPU_RNG_INFO_USED] 472 mov r5, #MPU_RNG_SIZE 473 add r3, r6, #MPU_RNG_INFO_RNGS 474 mla r3, r4, r5, r3 475 4761: 477 tst r0, #MPUIR_nU @ MPUIR_nU = 0 for unified 478 sub r3, r3, #MPU_RNG_SIZE 479 sub r4, r4, #1 480 481 set_region_nr r0, r4 482 isb 483 484 ldr r0, [r3, #MPU_RGN_DRBAR] 485 ldr r6, [r3, #MPU_RGN_DRSR] 486 ldr r5, [r3, #MPU_RGN_DRACR] 487 488 setup_region r0, r5, r6, PMSAv7_DATA_SIDE 489 beq 2f 490 setup_region r0, r5, r6, PMSAv7_INSTR_SIDE 4912: isb 492 493 mrc p15, 0, r0, c0, c0, 4 @ Reevaluate the MPUIR 494 cmp r4, #0 495 bgt 1b 496 497 ret lr 498ENDPROC(__secondary_setup_pmsa_v7) 499 500ENTRY(__secondary_setup_pmsa_v8) 501 ldr r4, [r6, #MPU_RNG_INFO_USED] 502#ifndef CONFIG_XIP_KERNEL 503 add r4, r4, #1 504#endif 505 mov r5, #MPU_RNG_SIZE 506 add r3, r6, #MPU_RNG_INFO_RNGS 507 mla r3, r4, r5, r3 508 5091: 510 sub r3, r3, #MPU_RNG_SIZE 511 sub r4, r4, #1 512 513 mcr p15, 0, r4, c6, c2, 1 @ PRSEL 514 isb 515 516 ldr r5, [r3, #MPU_RGN_PRBAR] 517 ldr r6, [r3, #MPU_RGN_PRLAR] 518 519 mcr p15, 0, r5, c6, c3, 0 @ PRBAR 520 mcr p15, 0, r6, c6, c3, 1 @ PRLAR 521 522 cmp r4, #0 523 bgt 1b 524 525 ret lr 526ENDPROC(__secondary_setup_pmsa_v8) 527#endif /* CONFIG_SMP */ 528#endif /* CONFIG_ARM_MPU */ 529#include "head-common.S" 530