1/*
2 *  linux/arch/arm/kernel/head-common.S
3 *
4 *  Copyright (C) 1994-2002 Russell King
5 *  Copyright (c) 2003 ARM Limited
6 *  All Rights Reserved
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 *
12 */
13
14	.type	__switch_data, %object
15__switch_data:
16	.long	__mmap_switched
17	.long	__data_loc			@ r4
18	.long	__data_start			@ r5
19	.long	__bss_start			@ r6
20	.long	_end				@ r7
21	.long	processor_id			@ r4
22	.long	__machine_arch_type		@ r5
23	.long	cr_alignment			@ r6
24	.long	init_thread_union + THREAD_START_SP @ sp
25
26/*
27 * The following fragment of code is executed with the MMU on in MMU mode,
28 * and uses absolute addresses; this is not position independent.
29 *
30 *  r0  = cp#15 control register
31 *  r1  = machine ID
32 *  r9  = processor ID
33 */
34	.type	__mmap_switched, %function
35__mmap_switched:
36	adr	r3, __switch_data + 4
37
38	ldmia	r3!, {r4, r5, r6, r7}
39	cmp	r4, r5				@ Copy data segment if needed
401:	cmpne	r5, r6
41	ldrne	fp, [r4], #4
42	strne	fp, [r5], #4
43	bne	1b
44
45	mov	fp, #0				@ Clear BSS (and zero fp)
461:	cmp	r6, r7
47	strcc	fp, [r6],#4
48	bcc	1b
49
50	ldmia	r3, {r4, r5, r6, sp}
51	str	r9, [r4]			@ Save processor ID
52	str	r1, [r5]			@ Save machine type
53	bic	r4, r0, #CR_A			@ Clear 'A' bit
54	stmia	r6, {r0, r4}			@ Save control register values
55	b	start_kernel
56
57/*
58 * Exception handling.  Something went wrong and we can't proceed.  We
59 * ought to tell the user, but since we don't have any guarantee that
60 * we're even running on the right architecture, we do virtually nothing.
61 *
62 * If CONFIG_DEBUG_LL is set we try to print out something about the error
63 * and hope for the best (useful if bootloader fails to pass a proper
64 * machine ID for example).
65 */
66
67	.type	__error_p, %function
68__error_p:
69#ifdef CONFIG_DEBUG_LL
70	adr	r0, str_p1
71	bl	printascii
72	b	__error
73str_p1:	.asciz	"\nError: unrecognized/unsupported processor variant.\n"
74	.align
75#endif
76
77	.type	__error_a, %function
78__error_a:
79#ifdef CONFIG_DEBUG_LL
80	mov	r4, r1				@ preserve machine ID
81	adr	r0, str_a1
82	bl	printascii
83	mov	r0, r4
84	bl	printhex8
85	adr	r0, str_a2
86	bl	printascii
87	adr	r3, 3f
88	ldmia	r3, {r4, r5, r6}		@ get machine desc list
89	sub	r4, r3, r4			@ get offset between virt&phys
90	add	r5, r5, r4			@ convert virt addresses to
91	add	r6, r6, r4			@ physical address space
921:	ldr	r0, [r5, #MACHINFO_TYPE]	@ get machine type
93	bl	printhex8
94	mov	r0, #'\t'
95	bl	printch
96	ldr     r0, [r5, #MACHINFO_NAME]	@ get machine name
97	add	r0, r0, r4
98	bl	printascii
99	mov	r0, #'\n'
100	bl	printch
101	add	r5, r5, #SIZEOF_MACHINE_DESC	@ next machine_desc
102	cmp	r5, r6
103	blo	1b
104	adr	r0, str_a3
105	bl	printascii
106	b	__error
107str_a1:	.asciz	"\nError: unrecognized/unsupported machine ID (r1 = 0x"
108str_a2:	.asciz	").\n\nAvailable machine support:\n\nID (hex)\tNAME\n"
109str_a3:	.asciz	"\nPlease check your kernel config and/or bootloader.\n"
110	.align
111#endif
112
113	.type	__error, %function
114__error:
115#ifdef CONFIG_ARCH_RPC
116/*
117 * Turn the screen red on a error - RiscPC only.
118 */
119	mov	r0, #0x02000000
120	mov	r3, #0x11
121	orr	r3, r3, r3, lsl #8
122	orr	r3, r3, r3, lsl #16
123	str	r3, [r0], #4
124	str	r3, [r0], #4
125	str	r3, [r0], #4
126	str	r3, [r0], #4
127#endif
1281:	mov	r0, r0
129	b	1b
130
131
132/*
133 * Read processor ID register (CP#15, CR0), and look up in the linker-built
134 * supported processor list.  Note that we can't use the absolute addresses
135 * for the __proc_info lists since we aren't running with the MMU on
136 * (and therefore, we are not in the correct address space).  We have to
137 * calculate the offset.
138 *
139 *	r9 = cpuid
140 * Returns:
141 *	r3, r4, r6 corrupted
142 *	r5 = proc_info pointer in physical address space
143 *	r9 = cpuid (preserved)
144 */
145	.type	__lookup_processor_type, %function
146__lookup_processor_type:
147	adr	r3, 3f
148	ldmda	r3, {r5 - r7}
149	sub	r3, r3, r7			@ get offset between virt&phys
150	add	r5, r5, r3			@ convert virt addresses to
151	add	r6, r6, r3			@ physical address space
1521:	ldmia	r5, {r3, r4}			@ value, mask
153	and	r4, r4, r9			@ mask wanted bits
154	teq	r3, r4
155	beq	2f
156	add	r5, r5, #PROC_INFO_SZ		@ sizeof(proc_info_list)
157	cmp	r5, r6
158	blo	1b
159	mov	r5, #0				@ unknown processor
1602:	mov	pc, lr
161
162/*
163 * This provides a C-API version of the above function.
164 */
165ENTRY(lookup_processor_type)
166	stmfd	sp!, {r4 - r7, r9, lr}
167	mov	r9, r0
168	bl	__lookup_processor_type
169	mov	r0, r5
170	ldmfd	sp!, {r4 - r7, r9, pc}
171
172/*
173 * Look in include/asm-arm/procinfo.h and arch/arm/kernel/arch.[ch] for
174 * more information about the __proc_info and __arch_info structures.
175 */
176	.long	__proc_info_begin
177	.long	__proc_info_end
1783:	.long	.
179	.long	__arch_info_begin
180	.long	__arch_info_end
181
182/*
183 * Lookup machine architecture in the linker-build list of architectures.
184 * Note that we can't use the absolute addresses for the __arch_info
185 * lists since we aren't running with the MMU on (and therefore, we are
186 * not in the correct address space).  We have to calculate the offset.
187 *
188 *  r1 = machine architecture number
189 * Returns:
190 *  r3, r4, r6 corrupted
191 *  r5 = mach_info pointer in physical address space
192 */
193	.type	__lookup_machine_type, %function
194__lookup_machine_type:
195	adr	r3, 3b
196	ldmia	r3, {r4, r5, r6}
197	sub	r3, r3, r4			@ get offset between virt&phys
198	add	r5, r5, r3			@ convert virt addresses to
199	add	r6, r6, r3			@ physical address space
2001:	ldr	r3, [r5, #MACHINFO_TYPE]	@ get machine type
201	teq	r3, r1				@ matches loader number?
202	beq	2f				@ found
203	add	r5, r5, #SIZEOF_MACHINE_DESC	@ next machine_desc
204	cmp	r5, r6
205	blo	1b
206	mov	r5, #0				@ unknown machine
2072:	mov	pc, lr
208
209/*
210 * This provides a C-API version of the above function.
211 */
212ENTRY(lookup_machine_type)
213	stmfd	sp!, {r4 - r6, lr}
214	mov	r1, r0
215	bl	__lookup_machine_type
216	mov	r0, r5
217	ldmfd	sp!, {r4 - r6, pc}
218