blob: 24dfa14b0bf94a144583fa961315cf8e57f98d8c [file] [log] [blame]
Hyok S. Choi75d90832006-03-27 14:58:25 +01001/*
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
Greg Ungerer9c4c9f32008-03-05 06:50:07 +010014#define ATAG_CORE 0x54410001
15#define ATAG_CORE_SIZE ((2*4 + 3*4) >> 2)
David Brown31abdb72009-10-01 17:43:29 +010016#define ATAG_CORE_SIZE_EMPTY ((2*4) >> 2)
Greg Ungerer9c4c9f32008-03-05 06:50:07 +010017
Hyok S. Choi75d90832006-03-27 14:58:25 +010018/*
19 * Exception handling. Something went wrong and we can't proceed. We
20 * ought to tell the user, but since we don't have any guarantee that
21 * we're even running on the right architecture, we do virtually nothing.
22 *
23 * If CONFIG_DEBUG_LL is set we try to print out something about the error
24 * and hope for the best (useful if bootloader fails to pass a proper
25 * machine ID for example).
26 */
Hyok S. Choi75d90832006-03-27 14:58:25 +010027__error_p:
28#ifdef CONFIG_DEBUG_LL
29 adr r0, str_p1
30 bl printascii
Lennert Buytenhek84081bd2008-03-28 21:11:47 +010031 mov r0, r9
32 bl printhex8
33 adr r0, str_p2
34 bl printascii
Hyok S. Choi75d90832006-03-27 14:58:25 +010035 b __error
Lennert Buytenhek84081bd2008-03-28 21:11:47 +010036str_p1: .asciz "\nError: unrecognized/unsupported processor variant (0x"
37str_p2: .asciz ").\n"
Hyok S. Choi75d90832006-03-27 14:58:25 +010038 .align
39#endif
Catalin Marinas93ed3972008-08-28 11:22:32 +010040ENDPROC(__error_p)
Hyok S. Choi75d90832006-03-27 14:58:25 +010041
Hyok S. Choi75d90832006-03-27 14:58:25 +010042__error_a:
43#ifdef CONFIG_DEBUG_LL
44 mov r4, r1 @ preserve machine ID
45 adr r0, str_a1
46 bl printascii
47 mov r0, r4
48 bl printhex8
49 adr r0, str_a2
50 bl printascii
Nicolas Pitre158bc5a2009-11-07 07:35:06 +010051 adr r3, 4f
Hyok S. Choi75d90832006-03-27 14:58:25 +010052 ldmia r3, {r4, r5, r6} @ get machine desc list
53 sub r4, r3, r4 @ get offset between virt&phys
54 add r5, r5, r4 @ convert virt addresses to
55 add r6, r6, r4 @ physical address space
561: ldr r0, [r5, #MACHINFO_TYPE] @ get machine type
57 bl printhex8
58 mov r0, #'\t'
59 bl printch
60 ldr r0, [r5, #MACHINFO_NAME] @ get machine name
61 add r0, r0, r4
62 bl printascii
63 mov r0, #'\n'
64 bl printch
65 add r5, r5, #SIZEOF_MACHINE_DESC @ next machine_desc
66 cmp r5, r6
67 blo 1b
68 adr r0, str_a3
69 bl printascii
70 b __error
Catalin Marinas93ed3972008-08-28 11:22:32 +010071ENDPROC(__error_a)
72
Hyok S. Choi75d90832006-03-27 14:58:25 +010073str_a1: .asciz "\nError: unrecognized/unsupported machine ID (r1 = 0x"
74str_a2: .asciz ").\n\nAvailable machine support:\n\nID (hex)\tNAME\n"
75str_a3: .asciz "\nPlease check your kernel config and/or bootloader.\n"
76 .align
77#endif
78
Hyok S. Choi75d90832006-03-27 14:58:25 +010079__error:
80#ifdef CONFIG_ARCH_RPC
81/*
82 * Turn the screen red on a error - RiscPC only.
83 */
84 mov r0, #0x02000000
85 mov r3, #0x11
86 orr r3, r3, r3, lsl #8
87 orr r3, r3, r3, lsl #16
88 str r3, [r0], #4
89 str r3, [r0], #4
90 str r3, [r0], #4
91 str r3, [r0], #4
92#endif
931: mov r0, r0
94 b 1b
Catalin Marinas93ed3972008-08-28 11:22:32 +010095ENDPROC(__error)
Hyok S. Choi75d90832006-03-27 14:58:25 +010096
97
98/*
Russell King4baa9922008-08-02 10:55:55 +010099 * Look in <asm/procinfo.h> and arch/arm/kernel/arch.[ch] for
Hyok S. Choi75d90832006-03-27 14:58:25 +0100100 * more information about the __proc_info and __arch_info structures.
101 */
Catalin Marinas88987ef2009-07-24 12:32:52 +0100102 .align 2
Catalin Marinasb86040a2009-07-24 12:32:54 +01001034: .long .
Hyok S. Choi75d90832006-03-27 14:58:25 +0100104 .long __arch_info_begin
105 .long __arch_info_end
106
107/*
108 * Lookup machine architecture in the linker-build list of architectures.
109 * Note that we can't use the absolute addresses for the __arch_info
110 * lists since we aren't running with the MMU on (and therefore, we are
111 * not in the correct address space). We have to calculate the offset.
112 *
113 * r1 = machine architecture number
114 * Returns:
115 * r3, r4, r6 corrupted
116 * r5 = mach_info pointer in physical address space
117 */
Hyok S. Choi75d90832006-03-27 14:58:25 +0100118__lookup_machine_type:
Catalin Marinasb86040a2009-07-24 12:32:54 +0100119 adr r3, 4b
Hyok S. Choi75d90832006-03-27 14:58:25 +0100120 ldmia r3, {r4, r5, r6}
121 sub r3, r3, r4 @ get offset between virt&phys
122 add r5, r5, r3 @ convert virt addresses to
123 add r6, r6, r3 @ physical address space
1241: ldr r3, [r5, #MACHINFO_TYPE] @ get machine type
125 teq r3, r1 @ matches loader number?
126 beq 2f @ found
127 add r5, r5, #SIZEOF_MACHINE_DESC @ next machine_desc
128 cmp r5, r6
129 blo 1b
130 mov r5, #0 @ unknown machine
1312: mov pc, lr
Catalin Marinas93ed3972008-08-28 11:22:32 +0100132ENDPROC(__lookup_machine_type)
Hyok S. Choi75d90832006-03-27 14:58:25 +0100133
Bill Gatliff9d20fdd2007-05-31 22:02:22 +0100134/* Determine validity of the r2 atags pointer. The heuristic requires
135 * that the pointer be aligned, in the first 16k of physical RAM and
136 * that the ATAG_CORE marker is first and present. Future revisions
137 * of this function may be more lenient with the physical address and
138 * may also be able to move the ATAGS block if necessary.
139 *
140 * r8 = machinfo
141 *
142 * Returns:
143 * r2 either valid atags pointer, or zero
144 * r5, r6 corrupted
145 */
Bill Gatliff9d20fdd2007-05-31 22:02:22 +0100146__vet_atags:
147 tst r2, #0x3 @ aligned?
148 bne 1f
149
150 ldr r5, [r2, #0] @ is first tag ATAG_CORE?
David Brown31abdb72009-10-01 17:43:29 +0100151 cmp r5, #ATAG_CORE_SIZE
152 cmpne r5, #ATAG_CORE_SIZE_EMPTY
Bill Gatliff9d20fdd2007-05-31 22:02:22 +0100153 bne 1f
154 ldr r5, [r2, #4]
155 ldr r6, =ATAG_CORE
156 cmp r5, r6
157 bne 1f
158
159 mov pc, lr @ atag pointer is ok
160
1611: mov r2, #0
162 mov pc, lr
Catalin Marinas93ed3972008-08-28 11:22:32 +0100163ENDPROC(__vet_atags)
Russell King5085f3f2010-10-01 15:37:05 +0100164
165/*
Russell King17bb5e22010-10-04 16:29:35 +0100166 * The following fragment of code is executed with the MMU on in MMU mode,
167 * and uses absolute addresses; this is not position independent.
168 *
169 * r0 = cp#15 control register
170 * r1 = machine ID
171 * r2 = atags pointer
172 * r9 = processor ID
173 */
174 __INIT
175__mmap_switched:
176 adr r3, __mmap_switched_data
177
178 ldmia r3!, {r4, r5, r6, r7}
179 cmp r4, r5 @ Copy data segment if needed
1801: cmpne r5, r6
181 ldrne fp, [r4], #4
182 strne fp, [r5], #4
183 bne 1b
184
185 mov fp, #0 @ Clear BSS (and zero fp)
1861: cmp r6, r7
187 strcc fp, [r6],#4
188 bcc 1b
189
190 ARM( ldmia r3, {r4, r5, r6, r7, sp})
191 THUMB( ldmia r3, {r4, r5, r6, r7} )
192 THUMB( ldr sp, [r3, #16] )
193 str r9, [r4] @ Save processor ID
194 str r1, [r5] @ Save machine type
195 str r2, [r6] @ Save atags pointer
196 bic r4, r0, #CR_A @ Clear 'A' bit
197 stmia r7, {r0, r4} @ Save control register values
198 b start_kernel
199ENDPROC(__mmap_switched)
200
201 .align 2
202 .type __mmap_switched_data, %object
203__mmap_switched_data:
204 .long __data_loc @ r4
205 .long _data @ r5
206 .long __bss_start @ r6
207 .long _end @ r7
208 .long processor_id @ r4
209 .long __machine_arch_type @ r5
210 .long __atags_pointer @ r6
211 .long cr_alignment @ r7
212 .long init_thread_union + THREAD_START_SP @ sp
213 .size __mmap_switched_data, . - __mmap_switched_data
214
215/*
216 * This provides a C-API version of __lookup_machine_type
217 */
218ENTRY(lookup_machine_type)
219 stmfd sp!, {r4 - r6, lr}
220 mov r1, r0
221 bl __lookup_machine_type
222 mov r0, r5
223 ldmfd sp!, {r4 - r6, pc}
224ENDPROC(lookup_machine_type)
225
226/*
227 * This provides a C-API version of __lookup_processor_type
228 */
229ENTRY(lookup_processor_type)
230 stmfd sp!, {r4 - r6, r9, lr}
231 mov r9, r0
232 bl __lookup_processor_type
233 mov r0, r5
234 ldmfd sp!, {r4 - r6, r9, pc}
235ENDPROC(lookup_processor_type)
236
237/*
Russell King5085f3f2010-10-01 15:37:05 +0100238 * Read processor ID register (CP#15, CR0), and look up in the linker-built
239 * supported processor list. Note that we can't use the absolute addresses
240 * for the __proc_info lists since we aren't running with the MMU on
241 * (and therefore, we are not in the correct address space). We have to
242 * calculate the offset.
243 *
244 * r9 = cpuid
245 * Returns:
246 * r3, r4, r6 corrupted
247 * r5 = proc_info pointer in physical address space
248 * r9 = cpuid (preserved)
249 */
250 __CPUINIT
251__lookup_processor_type:
252 adr r3, __lookup_processor_type_data
253 ldmia r3, {r4 - r6}
254 sub r3, r3, r4 @ get offset between virt&phys
255 add r5, r5, r3 @ convert virt addresses to
256 add r6, r6, r3 @ physical address space
2571: ldmia r5, {r3, r4} @ value, mask
258 and r4, r4, r9 @ mask wanted bits
259 teq r3, r4
260 beq 2f
261 add r5, r5, #PROC_INFO_SZ @ sizeof(proc_info_list)
262 cmp r5, r6
263 blo 1b
264 mov r5, #0 @ unknown processor
2652: mov pc, lr
266ENDPROC(__lookup_processor_type)
267
268/*
269 * Look in <asm/procinfo.h> for information about the __proc_info structure.
270 */
271 .align 2
272 .type __lookup_processor_type_data, %object
273__lookup_processor_type_data:
274 .long .
275 .long __proc_info_begin
276 .long __proc_info_end
277 .size __lookup_processor_type_data, . - __lookup_processor_type_data