blob: 7c6f9ab47b956d15295ef53c3d4eebe268955390 [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_a:
28#ifdef CONFIG_DEBUG_LL
29 mov r4, r1 @ preserve machine ID
30 adr r0, str_a1
31 bl printascii
32 mov r0, r4
33 bl printhex8
34 adr r0, str_a2
35 bl printascii
Nicolas Pitre158bc5a2009-11-07 07:35:06 +010036 adr r3, 4f
Hyok S. Choi75d90832006-03-27 14:58:25 +010037 ldmia r3, {r4, r5, r6} @ get machine desc list
38 sub r4, r3, r4 @ get offset between virt&phys
39 add r5, r5, r4 @ convert virt addresses to
40 add r6, r6, r4 @ physical address space
411: ldr r0, [r5, #MACHINFO_TYPE] @ get machine type
42 bl printhex8
43 mov r0, #'\t'
44 bl printch
45 ldr r0, [r5, #MACHINFO_NAME] @ get machine name
46 add r0, r0, r4
47 bl printascii
48 mov r0, #'\n'
49 bl printch
50 add r5, r5, #SIZEOF_MACHINE_DESC @ next machine_desc
51 cmp r5, r6
52 blo 1b
53 adr r0, str_a3
54 bl printascii
55 b __error
Catalin Marinas93ed3972008-08-28 11:22:32 +010056ENDPROC(__error_a)
57
Hyok S. Choi75d90832006-03-27 14:58:25 +010058str_a1: .asciz "\nError: unrecognized/unsupported machine ID (r1 = 0x"
59str_a2: .asciz ").\n\nAvailable machine support:\n\nID (hex)\tNAME\n"
60str_a3: .asciz "\nPlease check your kernel config and/or bootloader.\n"
61 .align
62#endif
63
Hyok S. Choi75d90832006-03-27 14:58:25 +010064/*
Russell King4baa9922008-08-02 10:55:55 +010065 * Look in <asm/procinfo.h> and arch/arm/kernel/arch.[ch] for
Hyok S. Choi75d90832006-03-27 14:58:25 +010066 * more information about the __proc_info and __arch_info structures.
67 */
Catalin Marinas88987ef2009-07-24 12:32:52 +010068 .align 2
Catalin Marinasb86040a2009-07-24 12:32:54 +0100694: .long .
Hyok S. Choi75d90832006-03-27 14:58:25 +010070 .long __arch_info_begin
71 .long __arch_info_end
72
73/*
74 * Lookup machine architecture in the linker-build list of architectures.
75 * Note that we can't use the absolute addresses for the __arch_info
76 * lists since we aren't running with the MMU on (and therefore, we are
77 * not in the correct address space). We have to calculate the offset.
78 *
79 * r1 = machine architecture number
80 * Returns:
81 * r3, r4, r6 corrupted
82 * r5 = mach_info pointer in physical address space
83 */
Hyok S. Choi75d90832006-03-27 14:58:25 +010084__lookup_machine_type:
Catalin Marinasb86040a2009-07-24 12:32:54 +010085 adr r3, 4b
Hyok S. Choi75d90832006-03-27 14:58:25 +010086 ldmia r3, {r4, r5, r6}
87 sub r3, r3, r4 @ get offset between virt&phys
88 add r5, r5, r3 @ convert virt addresses to
89 add r6, r6, r3 @ physical address space
901: ldr r3, [r5, #MACHINFO_TYPE] @ get machine type
91 teq r3, r1 @ matches loader number?
92 beq 2f @ found
93 add r5, r5, #SIZEOF_MACHINE_DESC @ next machine_desc
94 cmp r5, r6
95 blo 1b
96 mov r5, #0 @ unknown machine
972: mov pc, lr
Catalin Marinas93ed3972008-08-28 11:22:32 +010098ENDPROC(__lookup_machine_type)
Hyok S. Choi75d90832006-03-27 14:58:25 +010099
Bill Gatliff9d20fdd2007-05-31 22:02:22 +0100100/* Determine validity of the r2 atags pointer. The heuristic requires
101 * that the pointer be aligned, in the first 16k of physical RAM and
102 * that the ATAG_CORE marker is first and present. Future revisions
103 * of this function may be more lenient with the physical address and
104 * may also be able to move the ATAGS block if necessary.
105 *
106 * r8 = machinfo
107 *
108 * Returns:
109 * r2 either valid atags pointer, or zero
110 * r5, r6 corrupted
111 */
Bill Gatliff9d20fdd2007-05-31 22:02:22 +0100112__vet_atags:
113 tst r2, #0x3 @ aligned?
114 bne 1f
115
116 ldr r5, [r2, #0] @ is first tag ATAG_CORE?
David Brown31abdb72009-10-01 17:43:29 +0100117 cmp r5, #ATAG_CORE_SIZE
118 cmpne r5, #ATAG_CORE_SIZE_EMPTY
Bill Gatliff9d20fdd2007-05-31 22:02:22 +0100119 bne 1f
120 ldr r5, [r2, #4]
121 ldr r6, =ATAG_CORE
122 cmp r5, r6
123 bne 1f
124
125 mov pc, lr @ atag pointer is ok
126
1271: mov r2, #0
128 mov pc, lr
Catalin Marinas93ed3972008-08-28 11:22:32 +0100129ENDPROC(__vet_atags)
Russell King5085f3f2010-10-01 15:37:05 +0100130
131/*
Russell King17bb5e22010-10-04 16:29:35 +0100132 * The following fragment of code is executed with the MMU on in MMU mode,
133 * and uses absolute addresses; this is not position independent.
134 *
135 * r0 = cp#15 control register
136 * r1 = machine ID
137 * r2 = atags pointer
138 * r9 = processor ID
139 */
140 __INIT
141__mmap_switched:
142 adr r3, __mmap_switched_data
143
144 ldmia r3!, {r4, r5, r6, r7}
145 cmp r4, r5 @ Copy data segment if needed
1461: cmpne r5, r6
147 ldrne fp, [r4], #4
148 strne fp, [r5], #4
149 bne 1b
150
151 mov fp, #0 @ Clear BSS (and zero fp)
1521: cmp r6, r7
153 strcc fp, [r6],#4
154 bcc 1b
155
156 ARM( ldmia r3, {r4, r5, r6, r7, sp})
157 THUMB( ldmia r3, {r4, r5, r6, r7} )
158 THUMB( ldr sp, [r3, #16] )
159 str r9, [r4] @ Save processor ID
160 str r1, [r5] @ Save machine type
161 str r2, [r6] @ Save atags pointer
162 bic r4, r0, #CR_A @ Clear 'A' bit
163 stmia r7, {r0, r4} @ Save control register values
164 b start_kernel
165ENDPROC(__mmap_switched)
166
167 .align 2
168 .type __mmap_switched_data, %object
169__mmap_switched_data:
170 .long __data_loc @ r4
171 .long _data @ r5
172 .long __bss_start @ r6
173 .long _end @ r7
174 .long processor_id @ r4
175 .long __machine_arch_type @ r5
176 .long __atags_pointer @ r6
177 .long cr_alignment @ r7
178 .long init_thread_union + THREAD_START_SP @ sp
179 .size __mmap_switched_data, . - __mmap_switched_data
180
181/*
182 * This provides a C-API version of __lookup_machine_type
183 */
184ENTRY(lookup_machine_type)
185 stmfd sp!, {r4 - r6, lr}
186 mov r1, r0
187 bl __lookup_machine_type
188 mov r0, r5
189 ldmfd sp!, {r4 - r6, pc}
190ENDPROC(lookup_machine_type)
191
192/*
193 * This provides a C-API version of __lookup_processor_type
194 */
195ENTRY(lookup_processor_type)
196 stmfd sp!, {r4 - r6, r9, lr}
197 mov r9, r0
198 bl __lookup_processor_type
199 mov r0, r5
200 ldmfd sp!, {r4 - r6, r9, pc}
201ENDPROC(lookup_processor_type)
202
203/*
Russell King5085f3f2010-10-01 15:37:05 +0100204 * Read processor ID register (CP#15, CR0), and look up in the linker-built
205 * supported processor list. Note that we can't use the absolute addresses
206 * for the __proc_info lists since we aren't running with the MMU on
207 * (and therefore, we are not in the correct address space). We have to
208 * calculate the offset.
209 *
210 * r9 = cpuid
211 * Returns:
212 * r3, r4, r6 corrupted
213 * r5 = proc_info pointer in physical address space
214 * r9 = cpuid (preserved)
215 */
216 __CPUINIT
217__lookup_processor_type:
218 adr r3, __lookup_processor_type_data
219 ldmia r3, {r4 - r6}
220 sub r3, r3, r4 @ get offset between virt&phys
221 add r5, r5, r3 @ convert virt addresses to
222 add r6, r6, r3 @ physical address space
2231: ldmia r5, {r3, r4} @ value, mask
224 and r4, r4, r9 @ mask wanted bits
225 teq r3, r4
226 beq 2f
227 add r5, r5, #PROC_INFO_SZ @ sizeof(proc_info_list)
228 cmp r5, r6
229 blo 1b
230 mov r5, #0 @ unknown processor
2312: mov pc, lr
232ENDPROC(__lookup_processor_type)
233
234/*
235 * Look in <asm/procinfo.h> for information about the __proc_info structure.
236 */
237 .align 2
238 .type __lookup_processor_type_data, %object
239__lookup_processor_type_data:
240 .long .
241 .long __proc_info_begin
242 .long __proc_info_end
243 .size __lookup_processor_type_data, . - __lookup_processor_type_data
Russell Kingc083c662010-10-04 17:39:20 +0100244
245__error_p:
246#ifdef CONFIG_DEBUG_LL
247 adr r0, str_p1
248 bl printascii
249 mov r0, r9
250 bl printhex8
251 adr r0, str_p2
252 bl printascii
253 b __error
254str_p1: .asciz "\nError: unrecognized/unsupported processor variant (0x"
255str_p2: .asciz ").\n"
256 .align
257#endif
258ENDPROC(__error_p)
259
260__error:
261#ifdef CONFIG_ARCH_RPC
262/*
263 * Turn the screen red on a error - RiscPC only.
264 */
265 mov r0, #0x02000000
266 mov r3, #0x11
267 orr r3, r3, r3, lsl #8
268 orr r3, r3, r3, lsl #16
269 str r3, [r0], #4
270 str r3, [r0], #4
271 str r3, [r0], #4
272 str r3, [r0], #4
273#endif
2741: mov r0, r0
275 b 1b
276ENDPROC(__error)