xref: /xnu-8020.101.4/osfmk/arm/start.s (revision e7776783b89a353188416a9a346c6cdb4928faad)
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