14 #define ATAG_CORE 0x54410001
15 #define ATAG_CORE_SIZE ((2*4 + 3*4) >> 2)
这个部分head.S里面开启MMU后执行。此处开始准备执行C代码做准备:主要是text段,初始化数据段的定位!起始kernel本身的段结构跟普通进程大致相同,这也是为什么它被成文宏内核的原因!
__data_loc是kernel的text段的开始
__bss_start是__data_loc的结束也是bss段的开始
从上图看得出,kernel必须将text段跟初始化数据段准备好,对于未初始化数据段跟stack段,heap段都是不需要进行准备的!只需要设置stack指针以及heap起始地址就好!因此到了22行后未出现stack跟heap段的定义!
17 .type __switch_data, %object
18 __switch_data:
19 .long __mmap_switched
20 .long __data_loc @ r4
21 .long __data_start @ r5
22 .long __bss_start @ r6
23 .long _end @ r7
该内存位置存储了处理器的id,也就是r4寄存器的内容,以防后面的代码丢弃r4的内容
24 .long processor_id @ r4
该内存位置存储了machine type的信息也是放置r5的内容被丢弃
25 .long __machine_arch_type @ r5
该内存存储了atag的地址指针,同理防止r6被丢弃了
26 .long __atags_pointer @ r6
27 .long cr_alignment @ r7
这个内存位置放置了kernel的stack & heap的内存位置信息以后,只要将pc pointer指向这里就能执行C代码了!
28 .long init_thread_union + THREAD_START_SP @ sp
29
此前的代码可能在NOR flash中以XIP方式运行(其实Nand flash也可以XIP,只是有点技术障碍),但是kernel的代码不能总在flash内运行,该函数会进行kernel段的搬移以及处理!
39 .type __mmap_switched, %function
40 __mmap_switched:
41 adr r3, __switch_data + 4 // r3 point to __mmap_switched本处的注释错误!r3指向__data_loc!
将代码段,初始化数据段以及未初始化的数据段地址分别加载进入r4~r7
43 ldmia r3!, {r4, r5, r6, r7} // load the function's addr into r4~r7;r3 point to processor_id
此处比较难以理解,r4=__data_loc是物理上段的存储位置(可能在flash中而不是在RAM中);r5=_data_start是数据在内存的地址,如果二者相等说明已经在RAM中不必做copy,如果不在RAM中则执行copy使之在内存中运行!
44 cmp r4, r5 // Copy data segment if needed __data_start is the destination and __data_loc is the src!
copy相关操作
45 1: cmpne r5, r6 // if __data_start and __data_loc is not the same start the transfer session
46 ldrne fp, [r4], #4
47 strne fp, [r5], #4
48 bne 1b
清空未初始化数据段,为执行C代码扫清障碍
50 mov fp, #0 @ Clear BSS (and zero fp)
51 1: cmp r6, r7
52 strcc fp, [r6],#4
53 bcc 1b
执行保存操作。此处最重要的是sp指针的加载!该语句后sp已经指向了kernel的stack上,执行C代码的条件就绪了(代码段ok,初始化数据段ok,未初始化数据段ok,stack ok)
55 ldmia r3, {r4, r5, r6, r7, sp}
56 str r9, [r4] @ Save processor ID
57 str r1, [r5] @ Save machine type
58 str r2, [r6] @ Save atags pointer
59 bic r4, r0, #CR_A @ Clear 'A' bit
60 stmia r7, {r0, r4} @ Save control register values
61 @Now we will enter the world of C code and the MMU is on now!
62 b entry_for_C_call
63 //b start_kernel @For ARM start_kernel is defined in the init/main.c we will never return from start_kernel at all
144
145 /*
146 * Read processor ID register (CP#15, CR0), and look up in the linker-built
147 * supported processor list. Note that we can't use the absolute addresses
148 * for the __proc_info lists since we aren't running with the MMU on
149 * (and therefore, we are not in the correct address space). We have to
150 * calculate the offset.
151 *
152 * r9 = cpuid
153 * Returns:
154 * r3, r4, r6 corrupted
155 * r5 = proc_info pointer in physical address space
156 * r9 = cpuid (preserved)
157 */
158 .type __lookup_processor_type, %function
159 __lookup_processor_type:
160 adr r3, 3f
161 ldmda r3, {r5 - r7}
162 sub r3, r3, r7 @ get offset between virt&phys
163 add r5, r5, r3 @ convert virt addresses to
164 add r6, r6, r3 @ physical address space
165 1: ldmia r5, {r3, r4} @ value, mask
166 and r4, r4, r9 @ mask wanted bits
167 teq r3, r4
168 beq 2f
169 add r5, r5, #PROC_INFO_SZ @ sizeof(proc_info_list)
170 cmp r5, r6
171 blo 1b
172 mov r5, #0 @ unknown processor
173 2: mov pc, lr
174
175 /*
176 * This provides a C-API version of the above function.
177 */
178 ENTRY(lookup_processor_type)
179 stmfd sp!, {r4 - r7, r9, lr}
180 mov r9, r0
181 bl __lookup_processor_type
182 mov r0, r5
183 ldmfd sp!, {r4 - r7, r9, pc}
184
185 /*
186 * Look in
and arch/arm/kernel/arch.[ch] for187 * more information about the __proc_info and __arch_info structures.
188 */
189 .long __proc_info_begin
190 .long __proc_info_end
191 3: .long .
192 .long __arch_info_begin
193 .long __arch_info_end
194
195 /*
196 * Lookup machine architecture in the linker-build list of architectures.
197 * Note that we can't use the absolute addresses for the __arch_info
198 * lists since we aren't running with the MMU on (and therefore, we are
199 * not in the correct address space). We have to calculate the offset.
200 *
201 * r1 = machine architecture number
202 * Returns:
203 * r3, r4, r6 corrupted
204 * r5 = mach_info pointer in physical address space
205 */
206 .type __lookup_machine_type, %function
207 __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
213 1: 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
220 2: mov pc, lr
221
222 /*
223 * This provides a C-API version of the above function.
224 */
225 ENTRY(lookup_machine_type)
226 stmfd sp!, {r4 - r6, lr}
227 mov r1, r0
228 bl __lookup_machine_type
229 mov r0, r5
230 ldmfd sp!, {r4 - r6, pc}
231
232 /* Determine validity of the r2 atags pointer. The heuristic requires
233 * that the pointer be aligned, in the first 16k of physical RAM and
234 * that the ATAG_CORE marker is first and present. Future revisions
235 * of this function may be more lenient with the physical address and
236 * may also be able to move the ATAGS block if necessary.
237 *
238 * r8 = machinfo
239 *
240 * Returns:
241 * r2 either valid atags pointer, or zero
242 * r5, r6 corrupted
243 */
244
245 .type __vet_atags, %function
246 __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
260 1: mov r2, #0
261 mov pc, lr