blob: dbfaef07a1f432eb523c877e3df93dac8d62e358 [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)
16
Catalin Marinas88987ef2009-07-24 12:32:52 +010017 .align 2
Hyok S. Choi75d90832006-03-27 14:58:25 +010018 .type __switch_data, %object
19__switch_data:
20 .long __mmap_switched
21 .long __data_loc @ r4
Russell King37efe642008-12-01 11:53:07 +000022 .long _data @ r5
Hyok S. Choi75d90832006-03-27 14:58:25 +010023 .long __bss_start @ r6
24 .long _end @ r7
25 .long processor_id @ r4
26 .long __machine_arch_type @ r5
Bill Gatliff9d20fdd2007-05-31 22:02:22 +010027 .long __atags_pointer @ r6
28 .long cr_alignment @ r7
Hyok S. Choi75d90832006-03-27 14:58:25 +010029 .long init_thread_union + THREAD_START_SP @ sp
30
31/*
32 * The following fragment of code is executed with the MMU on in MMU mode,
33 * and uses absolute addresses; this is not position independent.
34 *
35 * r0 = cp#15 control register
36 * r1 = machine ID
Bill Gatliff9d20fdd2007-05-31 22:02:22 +010037 * r2 = atags pointer
Hyok S. Choi75d90832006-03-27 14:58:25 +010038 * r9 = processor ID
39 */
Hyok S. Choi75d90832006-03-27 14:58:25 +010040__mmap_switched:
41 adr r3, __switch_data + 4
42
43 ldmia r3!, {r4, r5, r6, r7}
44 cmp r4, r5 @ Copy data segment if needed
451: cmpne r5, r6
46 ldrne fp, [r4], #4
47 strne fp, [r5], #4
48 bne 1b
49
50 mov fp, #0 @ Clear BSS (and zero fp)
511: cmp r6, r7
52 strcc fp, [r6],#4
53 bcc 1b
54
Bill Gatliff9d20fdd2007-05-31 22:02:22 +010055 ldmia r3, {r4, r5, r6, r7, sp}
Hyok S. Choi75d90832006-03-27 14:58:25 +010056 str r9, [r4] @ Save processor ID
57 str r1, [r5] @ Save machine type
Bill Gatliff9d20fdd2007-05-31 22:02:22 +010058 str r2, [r6] @ Save atags pointer
Hyok S. Choi75d90832006-03-27 14:58:25 +010059 bic r4, r0, #CR_A @ Clear 'A' bit
Bill Gatliff9d20fdd2007-05-31 22:02:22 +010060 stmia r7, {r0, r4} @ Save control register values
Hyok S. Choi75d90832006-03-27 14:58:25 +010061 b start_kernel
Catalin Marinas93ed3972008-08-28 11:22:32 +010062ENDPROC(__mmap_switched)
Hyok S. Choi75d90832006-03-27 14:58:25 +010063
64/*
65 * Exception handling. Something went wrong and we can't proceed. We
66 * ought to tell the user, but since we don't have any guarantee that
67 * we're even running on the right architecture, we do virtually nothing.
68 *
69 * If CONFIG_DEBUG_LL is set we try to print out something about the error
70 * and hope for the best (useful if bootloader fails to pass a proper
71 * machine ID for example).
72 */
Hyok S. Choi75d90832006-03-27 14:58:25 +010073__error_p:
74#ifdef CONFIG_DEBUG_LL
75 adr r0, str_p1
76 bl printascii
Lennert Buytenhek84081bd2008-03-28 21:11:47 +010077 mov r0, r9
78 bl printhex8
79 adr r0, str_p2
80 bl printascii
Hyok S. Choi75d90832006-03-27 14:58:25 +010081 b __error
Lennert Buytenhek84081bd2008-03-28 21:11:47 +010082str_p1: .asciz "\nError: unrecognized/unsupported processor variant (0x"
83str_p2: .asciz ").\n"
Hyok S. Choi75d90832006-03-27 14:58:25 +010084 .align
85#endif
Catalin Marinas93ed3972008-08-28 11:22:32 +010086ENDPROC(__error_p)
Hyok S. Choi75d90832006-03-27 14:58:25 +010087
Hyok S. Choi75d90832006-03-27 14:58:25 +010088__error_a:
89#ifdef CONFIG_DEBUG_LL
90 mov r4, r1 @ preserve machine ID
91 adr r0, str_a1
92 bl printascii
93 mov r0, r4
94 bl printhex8
95 adr r0, str_a2
96 bl printascii
97 adr r3, 3f
98 ldmia r3, {r4, r5, r6} @ get machine desc list
99 sub r4, r3, r4 @ get offset between virt&phys
100 add r5, r5, r4 @ convert virt addresses to
101 add r6, r6, r4 @ physical address space
1021: ldr r0, [r5, #MACHINFO_TYPE] @ get machine type
103 bl printhex8
104 mov r0, #'\t'
105 bl printch
106 ldr r0, [r5, #MACHINFO_NAME] @ get machine name
107 add r0, r0, r4
108 bl printascii
109 mov r0, #'\n'
110 bl printch
111 add r5, r5, #SIZEOF_MACHINE_DESC @ next machine_desc
112 cmp r5, r6
113 blo 1b
114 adr r0, str_a3
115 bl printascii
116 b __error
Catalin Marinas93ed3972008-08-28 11:22:32 +0100117ENDPROC(__error_a)
118
Hyok S. Choi75d90832006-03-27 14:58:25 +0100119str_a1: .asciz "\nError: unrecognized/unsupported machine ID (r1 = 0x"
120str_a2: .asciz ").\n\nAvailable machine support:\n\nID (hex)\tNAME\n"
121str_a3: .asciz "\nPlease check your kernel config and/or bootloader.\n"
122 .align
123#endif
124
Hyok S. Choi75d90832006-03-27 14:58:25 +0100125__error:
126#ifdef CONFIG_ARCH_RPC
127/*
128 * Turn the screen red on a error - RiscPC only.
129 */
130 mov r0, #0x02000000
131 mov r3, #0x11
132 orr r3, r3, r3, lsl #8
133 orr r3, r3, r3, lsl #16
134 str r3, [r0], #4
135 str r3, [r0], #4
136 str r3, [r0], #4
137 str r3, [r0], #4
138#endif
1391: mov r0, r0
140 b 1b
Catalin Marinas93ed3972008-08-28 11:22:32 +0100141ENDPROC(__error)
Hyok S. Choi75d90832006-03-27 14:58:25 +0100142
143
144/*
145 * Read processor ID register (CP#15, CR0), and look up in the linker-built
146 * supported processor list. Note that we can't use the absolute addresses
147 * for the __proc_info lists since we aren't running with the MMU on
148 * (and therefore, we are not in the correct address space). We have to
149 * calculate the offset.
150 *
151 * r9 = cpuid
152 * Returns:
153 * r3, r4, r6 corrupted
154 * r5 = proc_info pointer in physical address space
155 * r9 = cpuid (preserved)
156 */
Hyok S. Choi75d90832006-03-27 14:58:25 +0100157__lookup_processor_type:
158 adr r3, 3f
159 ldmda r3, {r5 - r7}
160 sub r3, r3, r7 @ get offset between virt&phys
161 add r5, r5, r3 @ convert virt addresses to
162 add r6, r6, r3 @ physical address space
1631: ldmia r5, {r3, r4} @ value, mask
164 and r4, r4, r9 @ mask wanted bits
165 teq r3, r4
166 beq 2f
167 add r5, r5, #PROC_INFO_SZ @ sizeof(proc_info_list)
168 cmp r5, r6
169 blo 1b
170 mov r5, #0 @ unknown processor
1712: mov pc, lr
Catalin Marinas93ed3972008-08-28 11:22:32 +0100172ENDPROC(__lookup_processor_type)
Hyok S. Choi75d90832006-03-27 14:58:25 +0100173
174/*
175 * This provides a C-API version of the above function.
176 */
177ENTRY(lookup_processor_type)
178 stmfd sp!, {r4 - r7, r9, lr}
179 mov r9, r0
180 bl __lookup_processor_type
181 mov r0, r5
182 ldmfd sp!, {r4 - r7, r9, pc}
Catalin Marinas93ed3972008-08-28 11:22:32 +0100183ENDPROC(lookup_processor_type)
Hyok S. Choi75d90832006-03-27 14:58:25 +0100184
185/*
Russell King4baa9922008-08-02 10:55:55 +0100186 * Look in <asm/procinfo.h> and arch/arm/kernel/arch.[ch] for
Hyok S. Choi75d90832006-03-27 14:58:25 +0100187 * more information about the __proc_info and __arch_info structures.
188 */
Catalin Marinas88987ef2009-07-24 12:32:52 +0100189 .align 2
Hyok S. Choi75d90832006-03-27 14:58:25 +0100190 .long __proc_info_begin
191 .long __proc_info_end
1923: .long .
193 .long __arch_info_begin
194 .long __arch_info_end
195
196/*
197 * Lookup machine architecture in the linker-build list of architectures.
198 * Note that we can't use the absolute addresses for the __arch_info
199 * lists since we aren't running with the MMU on (and therefore, we are
200 * not in the correct address space). We have to calculate the offset.
201 *
202 * r1 = machine architecture number
203 * Returns:
204 * r3, r4, r6 corrupted
205 * r5 = mach_info pointer in physical address space
206 */
Hyok S. Choi75d90832006-03-27 14:58:25 +0100207__lookup_machine_type:
208 adr r3, 3b
209 ldmia r3, {r4, r5, r6}
210 sub r3, r3, r4 @ get offset between virt&phys
211 add r5, r5, r3 @ convert virt addresses to
212 add r6, r6, r3 @ physical address space
2131: ldr r3, [r5, #MACHINFO_TYPE] @ get machine type
214 teq r3, r1 @ matches loader number?
215 beq 2f @ found
216 add r5, r5, #SIZEOF_MACHINE_DESC @ next machine_desc
217 cmp r5, r6
218 blo 1b
219 mov r5, #0 @ unknown machine
2202: mov pc, lr
Catalin Marinas93ed3972008-08-28 11:22:32 +0100221ENDPROC(__lookup_machine_type)
Hyok S. Choi75d90832006-03-27 14:58:25 +0100222
223/*
224 * This provides a C-API version of the above function.
225 */
226ENTRY(lookup_machine_type)
227 stmfd sp!, {r4 - r6, lr}
228 mov r1, r0
229 bl __lookup_machine_type
230 mov r0, r5
231 ldmfd sp!, {r4 - r6, pc}
Catalin Marinas93ed3972008-08-28 11:22:32 +0100232ENDPROC(lookup_machine_type)
Bill Gatliff9d20fdd2007-05-31 22:02:22 +0100233
234/* Determine validity of the r2 atags pointer. The heuristic requires
235 * that the pointer be aligned, in the first 16k of physical RAM and
236 * that the ATAG_CORE marker is first and present. Future revisions
237 * of this function may be more lenient with the physical address and
238 * may also be able to move the ATAGS block if necessary.
239 *
240 * r8 = machinfo
241 *
242 * Returns:
243 * r2 either valid atags pointer, or zero
244 * r5, r6 corrupted
245 */
Bill Gatliff9d20fdd2007-05-31 22:02:22 +0100246__vet_atags:
247 tst r2, #0x3 @ aligned?
248 bne 1f
249
250 ldr r5, [r2, #0] @ is first tag ATAG_CORE?
251 subs r5, r5, #ATAG_CORE_SIZE
252 bne 1f
253 ldr r5, [r2, #4]
254 ldr r6, =ATAG_CORE
255 cmp r5, r6
256 bne 1f
257
258 mov pc, lr @ atag pointer is ok
259
2601: mov r2, #0
261 mov pc, lr
Catalin Marinas93ed3972008-08-28 11:22:32 +0100262ENDPROC(__vet_atags)