1/* 2 * Copyright (c) 2007-2014 Apple Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28 29#include <arm/asm.h> 30#include <arm/proc_reg.h> 31#include <mach_kdp.h> 32#include "assym.s" 33 34 .text 35 .align 12 36 37 .align 2 38 .globl EXT(resume_idle_cpu) 39LEXT(resume_idle_cpu) 40 // r0 set to BootArgs phys address 41 // r1 set to cpu data phys address 42 LOAD_ADDR(lr, arm_init_idle_cpu) 43 b L_start_cpu_0 44 45 .globl EXT(start_cpu) 46LEXT(start_cpu) 47 // r0 set to BootArgs phys address 48 // r1 set to cpu data phys address 49 LOAD_ADDR(lr, arm_init_cpu) 50 b L_start_cpu_0 51 52L_start_cpu_0: 53 cpsid if // Disable IRQ FIQ 54 55 // Turn on L1 I-Cache, Branch prediction early 56 mcr p15, 0, r11, c7, c5, 0 // invalidate the icache 57 isb // before moving on 58 mrc p15, 0, r11, c1, c0, 0 // read mmu control into r11 59 orr r11, r11, #(SCTLR_ICACHE | SCTLR_PREDIC) // enable i-cache, b-prediction 60 mcr p15, 0, r11, c1, c0, 0 // set mmu control 61 dsb // ensure mmu settings are inplace 62 isb // before moving on 63 64 // Get the kernel's phys & virt addr, and size from BootArgs 65 ldr r8, [r0, BA_PHYS_BASE] // Get the phys base in r8 66 ldr r9, [r0, BA_VIRT_BASE] // Get the virt base in r9 67 ldr r10, [r0, BA_MEM_SIZE] // Get the mem size in r10 68 69 // Set the base of the translation table into the MMU 70 ldr r4, [r0, BA_TOP_OF_KERNEL_DATA] // Get the top of kernel data 71 orr r5, r4, #(TTBR_SETUP & 0x00FF) // Setup PTWs memory attribute 72 orr r5, r5, #(TTBR_SETUP & 0xFF00) // Setup PTWs memory attribute 73 mcr p15, 0, r5, c2, c0, 0 // write kernel to translation table base 0 74 mcr p15, 0, r5, c2, c0, 1 // also to translation table base 1 75 mov r5, #TTBCR_N_SETUP // identify the split between 0 and 1 76 mcr p15, 0, r5, c2, c0, 2 // and set up the translation control reg 77 ldr r2, [r1, CPU_NUMBER_GS] // Get cpu number 78 mcr p15, 0, r2, c13, c0, 3 // Write TPIDRURO 79 ldr sp, [r1, CPU_INTSTACK_TOP] // Get interrupt stack top 80 sub sp, sp, SS_SIZE // Set stack pointer 81 sub r0, r1, r8 // Convert to virtual address 82 add r0, r0, r9 83 b join_start 84 85 .align 2 86 .globl EXT(_start) 87LEXT(_start) 88 // r0 has the boot-args pointer 89 // r1 set to zero 90 mov r1, #0 91 LOAD_ADDR(lr, arm_init) 92 cpsid if // Disable IRQ FIQ 93 94 // Turn on L1 I-Cache, Branch prediction early 95 mcr p15, 0, r11, c7, c5, 0 // invalidate the icache 96 isb // before moving on 97 mrc p15, 0, r11, c1, c0, 0 // read mmu control into r11 98 orr r11, r11, #(SCTLR_ICACHE | SCTLR_PREDIC) // enable i-cache, b-prediction 99 mcr p15, 0, r11, c1, c0, 0 // set mmu control 100 dsb // ensure mmu settings are inplace 101 isb // before moving on 102 103 // Get the kernel's phys & virt addr, and size from boot_args. 104 ldr r8, [r0, BA_PHYS_BASE] // Get the phys base in r8 105 ldr r9, [r0, BA_VIRT_BASE] // Get the virt base in r9 106 ldr r10, [r0, BA_MEM_SIZE] // Get the mem size in r10 107 108#define LOAD_PHYS_ADDR(reg, label) \ 109 LOAD_ADDR(reg, label); \ 110 sub reg, reg, r9; \ 111 add reg, reg, r8 112 113 // Take this opportunity to patch the targets for the exception vectors 114 LOAD_ADDR(r4, fleh_reset) 115 LOAD_PHYS_ADDR(r5, ExceptionVectorsTable) 116 str r4, [r5] 117 LOAD_ADDR(r4, fleh_undef) 118 add r5, #4 119 str r4, [r5] 120 LOAD_ADDR(r4, fleh_swi) 121 add r5, #4 122 str r4, [r5] 123 LOAD_ADDR(r4, fleh_prefabt) 124 add r5, #4 125 str r4, [r5] 126 LOAD_ADDR(r4, fleh_dataabt) 127 add r5, #4 128 str r4, [r5] 129 LOAD_ADDR(r4, fleh_addrexc) 130 add r5, #4 131 str r4, [r5] 132 LOAD_ADDR(r4, fleh_irq) 133 add r5, #4 134 str r4, [r5] 135 LOAD_ADDR(r4, fleh_decirq) 136 add r5, #4 137 str r4, [r5] 138 139 // arm_init_tramp is sensitive, so for the moment, take the opportunity to store the 140 // virtual address locally, so that we don't run into issues retrieving it later. 141 // This is a pretty miserable solution, but it should be enough for the moment 142 LOAD_ADDR(r4, arm_init_tramp) 143 adr r5, arm_init_tramp_addr 144 str r4, [r5] 145 146#undef LOAD_PHYS_ADDR 147 148 // Set the base of the translation table into the MMU 149 ldr r4, [r0, BA_TOP_OF_KERNEL_DATA] // Get the top of kernel data 150 orr r5, r4, #(TTBR_SETUP & 0x00FF) // Setup PTWs memory attribute 151 orr r5, r5, #(TTBR_SETUP & 0xFF00) // Setup PTWs memory attribute 152 mcr p15, 0, r5, c2, c0, 0 // write kernel to translation table base 0 153 mcr p15, 0, r5, c2, c0, 1 // also to translation table base 1 154 mov r5, #TTBCR_N_SETUP // identify the split between 0 and 1 155 mcr p15, 0, r5, c2, c0, 2 // and set up the translation control reg 156 157 // Mark the entries invalid in the 4 page trampoline translation table 158 // Mark the entries invalid in the 4 page CPU translation table 159 // Mark the entries invalid in the one page table for the final 1MB (if used) 160 // Mark the entries invalid in the one page table for HIGH_EXC_VECTORS 161 mov r5, r4 // local copy of base 162 mov r11, #ARM_TTE_TYPE_FAULT // invalid entry template 163 mov r2, PGBYTES >> 2 // number of ttes/page 164 add r2, r2, r2, LSL #2 // 8 ttes + 2 ptes to clear. Multiply by 5... 165 mov r2, r2, LSL #1 // ...then multiply by 2 166invalidate_tte: 167 str r11, [r5] // store the invalid tte 168 add r5, r5, #4 // increment tte pointer 169 subs r2, r2, #1 // decrement count 170 bne invalidate_tte 171 172 // create default section tte template 173 mov r6, #ARM_TTE_TYPE_BLOCK // use block mapping entries 174 mov r7, #(ARM_TTE_BLOCK_ATTRINDX(CACHE_ATTRINDX_DEFAULT) & 0xFF) 175 orr r7, r7, #(ARM_TTE_BLOCK_ATTRINDX(CACHE_ATTRINDX_DEFAULT) & 0xFF00) 176 orr r7, r7, #(ARM_TTE_BLOCK_ATTRINDX(CACHE_ATTRINDX_DEFAULT) & 0xF0000) 177 orr r6, r6, r7 // with default cache attrs 178 mov r7, #ARM_TTE_BLOCK_AP(AP_RWNA) // Set kernel rw, user no access 179 orr r7, r7, #(ARM_TTE_BLOCK_AP(AP_RWNA) & 0xFF00) 180 orr r7, r7, #(ARM_TTE_BLOCK_AP(AP_RWNA) & 0xF0000) 181 orr r6, r6, r7 // Set RWNA protection 182 183 orr r6, r6, #ARM_TTE_BLOCK_AF // Set access protection 184 orr r6, r6, #ARM_TTE_BLOCK_SH // Set shareability 185 186 // Set up the V=P mapping for the 1 MB section around the current pc 187 lsr r7, pc, #ARM_TT_L1_SHIFT // Extract tte index for pc addr 188 add r5, r4, r7, LSL #2 // convert tte index to tte pointer 189 lsl r7, r7, #ARM_TT_L1_SHIFT // Truncate pc to 1MB aligned addr 190 orr r11, r7, r6 // make tte entry value 191 str r11, [r5] // store tte 192 193 // Set up the virtual mapping for the kernel using 1Mb direct section TTE entries 194 mov r7, r8 // Save original phys base 195 add r5, r4, r9, LSR #ARM_TT_L1_SHIFT-2 // convert vaddr to tte pointer 196 mov r3, #ARM_TT_L1_SIZE // set 1MB boundary 197 198mapveqp: 199 cmp r3, r10 // Check if we're beyond the last 1MB section 200 bgt mapveqpL2 // If so, a coarse entry is required 201 202 orr r11, r7, r6 // make tte entry value 203 str r11, [r5], #4 // store tte and move to next 204 add r7, r7, #ARM_TT_L1_SIZE // move to next phys addr 205 subs r10, r10, #ARM_TT_L1_SIZE // subtract tte size 206 bne mapveqp 207 b doneveqp // end is 1MB aligned, and we're done 208 209mapveqpL2: 210 // The end is not 1MB aligned, so steal a page and set up L2 entries within 211 212 // Coarse entry first 213 add r6, r4, PGBYTES * 8 // add L2 offset 214 mov r11, r6 215 216 orr r6, #ARM_TTE_TYPE_TABLE // coarse entry 217 218 str r6, [r5] // store coarse tte entry 219 220 // Fill in the L2 entries 221 mov r5, r11 222 223 // create pte template 224 mov r2, #ARM_PTE_TYPE // default pte type 225 orr r2, r2, #(ARM_PTE_ATTRINDX(CACHE_ATTRINDX_DEFAULT) & 0xff) // with default cache attrs 226 orr r2, r2, #(ARM_PTE_ATTRINDX(CACHE_ATTRINDX_DEFAULT) & 0xff00) 227 orr r2, r2, #(ARM_PTE_AP(AP_RWNA) & 0xff) // with default cache attrs 228 orr r2, r2, #(ARM_PTE_AP(AP_RWNA) & 0xff00) 229 orr r2, r2, #ARM_PTE_AF // Set access 230 orr r2, r2, #ARM_PTE_SH // Set shareability 231 232storepte: 233 orr r11, r7, r2 // make pte entry value 234 str r11, [r5], #4 // store pte and move to next 235 add r7, r7, PGBYTES // move to next phys addr 236 subs r10, r10, PGBYTES // subtract pte size 237 bne storepte 238 239doneveqp: 240 // Insert page table page for high address exception vectors into translation table 241 mov r5, #0xff000000 // part of virt HIGH_EXC_VECTORS (HACK!) 242 orr r5, r5, #0x00ff0000 // rest of virt HIGH_EXC_VECTORS (HACK!) 243 mov r5, r5, LSR #ARM_TT_L1_SHIFT // convert virt addr to index 244 add r5, r4, r5, LSL #2 // convert to tte pointer 245 246 add r6, r4, PGBYTES * 9 // get page table base (past 4 + 4 + 1 tte/pte pages) 247 add r6, r6, #0xc00 // adjust to last 1MB section 248 mov r7, #(ARM_TTE_TABLE_MASK & 0xFFFF) // ARM_TTE_TABLE_MASK low halfword 249 movt r7, #(ARM_TTE_TABLE_MASK >> 16) // ARM_TTE_TABLE_MASK top halfword 250 and r11, r6, r7 // apply mask 251 orr r11, r11, #ARM_TTE_TYPE_TABLE // mark it as a coarse page table 252 str r11, [r5] // store tte entry for page table 253 254 // create pte template 255 mov r2, #ARM_PTE_TYPE // pte type 256 orr r2, r2, #(ARM_PTE_ATTRINDX(CACHE_ATTRINDX_DEFAULT) & 0x00ff) // default cache attrs 257 orr r2, r2, #(ARM_PTE_ATTRINDX(CACHE_ATTRINDX_DEFAULT) & 0xff00) 258 orr r2, r2, #(ARM_PTE_AP(AP_RWNA) & 0x00ff) // set RWNA protection 259 orr r2, r2, #(ARM_PTE_AP(AP_RWNA) & 0xff00) 260 orr r2, r2, #ARM_PTE_AF // Set access 261 orr r2, r2, #ARM_PTE_SH // Set shareability 262 263 // Now initialize the page table entry for the exception vectors 264 mov r5, #0xff000000 // part of HIGH_EXC_VECTORS 265 orr r5, r5, #0x00ff0000 // rest of HIGH_EXC_VECTORS 266 mov r7, #(ARM_TT_L2_INDEX_MASK & 0xFFFF) // ARM_TT_L2_INDEX_MASK low halfword 267 movt r7, #(ARM_TT_L2_INDEX_MASK >> 16) // ARM_TT_L2_INDEX_MASK top halfword 268 and r5, r5, r7 // mask for getting index 269 mov r5, r5, LSR #ARM_TT_L2_SHIFT // get page table index 270 add r5, r6, r5, LSL #2 // convert to pte pointer 271 272 LOAD_ADDR(r11, ExceptionVectorsBase) // get address of vectors addr 273 sub r11, r11, r9 // convert to physical address 274 add r11, r11, r8 275 276 mov r7, #(ARM_PTE_PAGE_MASK & 0xFFFF) // ARM_PTE_PAGE_MASK low halfword 277 movt r7, #(ARM_PTE_PAGE_MASK >> 16) // ARM_PTE_PAGE_MASK top halfword 278 and r11, r11, r7 // insert masked address into pte 279 orr r11, r11, r2 // add template bits 280 str r11, [r5] // store pte by base and index 281 282 // clean the dcache 283 mov r11, #0 284cleanflushway: 285cleanflushline: 286 mcr p15, 0, r11, c7, c14, 2 // cleanflush dcache line by way/set 287 add r11, r11, #1 << MMU_I7SET // increment set index 288 tst r11, #1 << (MMU_NSET + MMU_I7SET) // look for overflow 289 beq cleanflushline 290 bic r11, r11, #1 << (MMU_NSET + MMU_I7SET) // clear set overflow 291 adds r11, r11, #1 << MMU_I7WAY // increment way 292 bcc cleanflushway // loop 293 294#if __ARM_L2CACHE__ 295 // Invalidate L2 cache 296 mov r11, #2 297invall2flushway: 298invall2flushline: 299 mcr p15, 0, r11, c7, c14, 2 // Invalidate dcache line by way/set 300 add r11, r11, #1 << L2_I7SET // increment set index 301 tst r11, #1 << (L2_NSET + L2_I7SET) // look for overflow 302 beq invall2flushline 303 bic r11, r11, #1 << (L2_NSET + L2_I7SET) // clear set overflow 304 adds r11, r11, #1 << L2_I7WAY // increment way 305 bcc invall2flushway // loop 306 307#endif 308 309 mov r11, #0 310 mcr p15, 0, r11, c13, c0, 3 // Write TPIDRURO 311 LOAD_ADDR(sp, intstack_top) // Get interrupt stack top 312 sub sp, sp, SS_SIZE // Set stack pointer 313 sub r0, r0, r8 // Convert to virtual address 314 add r0, r0, r9 315 316join_start: 317 // kernel page table is setup 318 // lr set to return handler function virtual address 319 // r0 set to return handler argument virtual address 320 // sp set to interrupt context stack virtual address 321 322 // Cpu specific configuration 323 324#ifdef ARMA7 325#if __ARMA7_SMP__ 326 mrc p15, 0, r11, c1, c0, 1 327 orr r11, r11, #(1<<6) // SMP 328 mcr p15, 0, r11, c1, c0, 1 329 isb 330#endif 331#endif 332 333 mrs r11, cpsr // Get cpsr 334 bic r11, #0x100 // Allow async aborts 335 msr cpsr_x, r11 // Update cpsr 336 337 mov r11, #0 338 mcr p15, 0, r11, c8, c7, 0 // invalidate all TLB entries 339 mcr p15, 0, r11, c7, c5, 0 // invalidate the icache 340 341 // set DACR 342 mov r11, #(ARM_DAC_SETUP & 0xFFFF) // ARM_DAC_SETUP low halfword 343 movt r11, #(ARM_DAC_SETUP >> 16) // ARM_DAC_SETUP top halfword 344 mcr p15, 0, r11, c3, c0, 0 // write to dac register 345 346 // Set PRRR 347 mov r11, #(PRRR_SETUP & 0xFFFF) // PRRR_SETUP low halfword 348 movt r11, #(PRRR_SETUP >> 16) // PRRR_SETUP top halfword 349 mcr p15, 0, r11, c10,c2,0 // write to PRRR register 350 351 // Set NMRR 352 mov r11, #(NMRR_SETUP & 0xFFFF) // NMRR_SETUP low halfword 353 movt r11, #(NMRR_SETUP >> 16) // NMRR_SETUP top halfword 354 mcr p15, 0, r11, c10,c2,1 // write to NMRR register 355 356 // set SCTLR 357 mrc p15, 0, r11, c1, c0, 0 // read system control 358 359 bic r11, r11, #SCTLR_ALIGN // force off alignment exceptions 360 mov r7, #(SCTLR_AFE|SCTLR_TRE) // Access flag, TEX remap 361 orr r7, r7, #(SCTLR_HIGHVEC | SCTLR_ICACHE | SCTLR_PREDIC) 362 orr r7, r7, #(SCTLR_DCACHE | SCTLR_ENABLE) 363#if (__ARM_ENABLE_SWAP__ == 1) 364 orr r7, r7, #SCTLR_SW // SWP/SWPB Enable 365#endif 366 orr r11, r11, r7 // or in the default settings 367 mcr p15, 0, r11, c1, c0, 0 // set mmu control 368 369 dsb // ensure mmu settings are inplace 370 isb // before moving on 371 372#if __ARM_VFP__ 373 // Initialize the VFP coprocessors. 374 mrc p15, 0, r2, c1, c0, 2 // read coprocessor control register 375 mov r3, #15 // 0xF 376 orr r2, r2, r3, LSL #20 // enable 10 and 11 377 mcr p15, 0, r2, c1, c0, 2 // write coprocessor control register 378 isb 379#endif /* __ARM_VFP__ */ 380 381 // Running virtual. Prepare to call init code 382 cmp r1, #0 // Test if invoked from start 383 beq join_start_1 // Branch if yes 384 ldr r7, arm_init_tramp_addr // Load trampoline address 385 bx r7 // Branch to virtual trampoline address 386 387 // Loading the virtual address for arm_init_tramp is a rather ugly 388 // problem. There is probably a better solution, but for the moment, 389 // patch the address in locally so that loading it is trivial 390arm_init_tramp_addr: 391 .long 0 392 .globl EXT(arm_init_tramp) 393LEXT(arm_init_tramp) 394 mrc p15, 0, r5, c2, c0, 0 // Read to translation table base 0 395 add r5, r5, PGBYTES * 4 // get kernel page table base (past 4 boot tte pages) 396 mcr p15, 0, r5, c2, c0, 0 // write kernel to translation table base 0 397 mcr p15, 0, r5, c2, c0, 1 // also to translation table base 1 398 isb 399 mov r5, #0 400 mcr p15, 0, r5, c8, c7, 0 // Flush all TLB entries 401 dsb // ensure mmu settings are inplace 402 isb // before moving on 403 404join_start_1: 405#if __ARM_VFP__ 406 // Enable VFP for the bootstrap thread context. 407 // VFP is enabled for the arm_init path as we may 408 // execute VFP code before we can handle an undef. 409 fmrx r2, fpexc // get fpexc 410 orr r2, #FPEXC_EN // set the enable bit 411 fmxr fpexc, r2 // set fpexc 412 mov r2, #FPSCR_DEFAULT // set default fpscr 413 fmxr fpscr, r2 // set fpscr 414#endif /* __ARM_VFP__ */ 415 416 mov r7, #0 // Set stack frame 0 417 bx lr 418 419LOAD_ADDR_GEN_DEF(arm_init) 420LOAD_ADDR_GEN_DEF(arm_init_cpu) 421LOAD_ADDR_GEN_DEF(arm_init_idle_cpu) 422LOAD_ADDR_GEN_DEF(arm_init_tramp) 423LOAD_ADDR_GEN_DEF(fleh_reset) 424LOAD_ADDR_GEN_DEF(ExceptionVectorsTable) 425LOAD_ADDR_GEN_DEF(fleh_undef) 426LOAD_ADDR_GEN_DEF(fleh_swi) 427LOAD_ADDR_GEN_DEF(fleh_prefabt) 428LOAD_ADDR_GEN_DEF(fleh_dataabt) 429LOAD_ADDR_GEN_DEF(fleh_addrexc) 430LOAD_ADDR_GEN_DEF(fleh_irq) 431LOAD_ADDR_GEN_DEF(fleh_decirq) 432 433#include "globals_asm.h" 434 435/* vim: set ts=4: */ 436