]> git.saurik.com Git - apple/xnu.git/blame - osfmk/arm/start.s
xnu-7195.101.1.tar.gz
[apple/xnu.git] / osfmk / arm / start.s
CommitLineData
5ba3f43e
A
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
f427ee49 75 mov r5, #TTBCR_N_SETUP // identify the split between 0 and 1
5ba3f43e
A
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
f427ee49 154 mov r5, #TTBCR_N_SETUP // identify the split between 0 and 1
5ba3f43e
A
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)
cb323159 247 add r6, r6, #0xc00 // adjust to last 1MB section
5ba3f43e 248 mov r7, #(ARM_TTE_TABLE_MASK & 0xFFFF) // ARM_TTE_TABLE_MASK low halfword
cb323159 249 movt r7, #(ARM_TTE_TABLE_MASK >> 16) // ARM_TTE_TABLE_MASK top halfword
5ba3f43e
A
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
2a1bd2d3
A
287 add r11, r11, #1 << MMU_I7SET // increment set index
288 tst r11, #1 << (MMU_NSET + MMU_I7SET) // look for overflow
5ba3f43e 289 beq cleanflushline
2a1bd2d3
A
290 bic r11, r11, #1 << (MMU_NSET + MMU_I7SET) // clear set overflow
291 adds r11, r11, #1 << MMU_I7WAY // increment way
5ba3f43e 292 bcc cleanflushway // loop
2a1bd2d3
A
293
294#if __ARM_L2CACHE__
5ba3f43e
A
295 // Invalidate L2 cache
296 mov r11, #2
297invall2flushway:
298invall2flushline:
299 mcr p15, 0, r11, c7, c14, 2 // Invalidate dcache line by way/set
2a1bd2d3
A
300 add r11, r11, #1 << L2_I7SET // increment set index
301 tst r11, #1 << (L2_NSET + L2_I7SET) // look for overflow
5ba3f43e 302 beq invall2flushline
2a1bd2d3
A
303 bic r11, r11, #1 << (L2_NSET + L2_I7SET) // clear set overflow
304 adds r11, r11, #1 << L2_I7WAY // increment way
5ba3f43e 305 bcc invall2flushway // loop
2a1bd2d3
A
306
307#endif
308
5ba3f43e
A
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: */