1.初始化指向--stext标签
通过引导加载项加载内核以后,首先执行的部分就是stext。执行该标签时要如下状态:
MMU = off
D-Cache = off
r0 = 0
r1 = machime number
r2 = atags pointer
在stext标签中,首先转换为SVC模式,并禁用IRQ。然后调用调用多个检查程序,查找CPU和机器信息,并检查atag信息,追加设置页表,启动MMU。
arch/arm/kernel/head.S
ENTRY(stext)
ARM_BE8(setend be )@ ensure we are in BE8 mode
THUMB( adr r9, BSYM(1f) )@ Kernel is always entered in ARM.
THUMB( bx r9 ) @ If this is a Thumb-2 kernel,
THUMB( .thumb)@ switch to Thumb now.
THUMB(1: )
#ifdef CONFIG_ARM_VIRT_EXT
bl __hyp_stub_install
#endif
@ ensure svc mode and all interrupts masked
safe_svcmode_maskall r9 =>转换为SVC模式,并禁用IRQ
mrc p15, 0, r9, c0, c0@ get processor id =>获取CPU ID 并和__lookup_processor_type做比较 r5 = procinfo地址
bl __lookup_processor_type @ r5=procinfo r9=cpuid
movs r10, r5@ invalid processor (r5=0)?
THUMB( it eq )@ force fixup-able long branch encoding
beq __error_p@ yes, error 'p'
... ...
/*
* r1 = machine no, r2 = atags or dtb,
* r8 = phys_offset, r9 = cpuid, r10 = procinfo
*/
bl __vet_atags
#ifdef CONFIG_SMP_ON_UP
bl __fixup_smp
#endif
#ifdef CONFIG_ARM_PATCH_PHYS_VIRT
bl __fixup_pv_table
#endif
bl __create_page_tables
ldr r13, =__mmap_switched @ address to jump to after =>将switch data放在r13中。 Lr(r14)中保存了__enable_mmu的地址,执行PROCINFO_INITFUNC后通 过lr 寄存器中的__enable_mmu执行返回,从而激活MMU
@ mmu has been enabled
adr lr, BSYM(1f)@ return (PIC) address
mov r8, r4@ set TTBR1 to swapper_pg_dir
ARM( add pc, r10, #PROCINFO_INITFUNC ) =>r10中存储了通过__lookup_processor_type获得的proc_info_list结构体的起始地址。该值加上PROCINFO_INITFUNC即可调用__v6_setup子程序。通过arch/arm/kernel/asm-offset.c执行编译时生成的include/asm-offset.h中。PROCINFO_INITFUNC的定义如下:
DEFINE(PROCINFO_INITFUNC, offsetof(struct proc_info_list, __cpu_flush));含义:在struct proc_info_list结构体中,将__cpu_flush成员变量所在偏移量指定为PROCINFO_INITFUNC的值,DEFINE的定义见:http://blog.csdn.net/lory17/article/details/50160947。
THUMB( addr12, r10, #PROCINFO_INITFUNC)
THUMB( ret r12 )
1: b __enable_mmu
ENDPROC(stext)
__look_processor_type标签:
位置:arch/arm/kernel/head-common.S文件。记录了内核中求处理器类型的代码。
bl __lookup_processor_type @ r5=procinfo r9=cpuid
ENTRY(lookup_processor_type)
stmfd sp!, {r4 - r6, r9, lr}
mov r9, r0
bl __lookup_processor_type
mov r0, r5
ldmfd sp!, {r4 - r6, r9, pc}
ENDPROC(lookup_processor_type) =>C代码中调用lookup_processor_type()函数使用。利用stmfd指令在战中备份寄存器值,将r0(CPU ID)参数传递保存在r9中。执行__lookup_processor_type后,将结果值(r5)保存在返回值的寄存器(r0)中。最后还原栈并返回。
__FINIT
.text
/*
* Read processor ID register (CP#15, CR0), and look up in the linker-built
* supported processor list. Note that we can't use the absolute addresses
* for the __proc_info lists since we aren't running with the MMU on
* (and therefore, we are not in the correct address space). We have to
* calculate the offset.
*
* r9 = cpuid
* Returns:
* r3, r4, r6 corrupted
* r5 = proc_info pointer in physical address space
* r9 = cpuid (preserved)
*/
__lookup_processor_type:
adr r3, __lookup_processor_type_data
ldmia r3, {r4 - r6} => r3 <- __lokkup_processor_type_data /*物理地址*/
r5 <- __proc_info_begin /*虚拟地址*/
r6<- __proc_info_end /*虚拟地址*/
sub r3, r3, r4 @ get offset between virt&phys
add r5, r5, r3 @ convert virt addresses to
add r6, r6, r3 @ physical address space =>计算偏倚,将 r5 r6 __proc_info_begin __proc_info_end 虚拟地址转换成物理地址,因为mmu没有激活,无法使用虚拟地址。
1: ldmia r5, {r3, r4} @ value, mask
and r4, r4, r9 @ mask wanted bits
teq r3, r4
beq 2f
add r5, r5, #PROC_INFO_SZ @ sizeof(proc_info_list) => __proc_info_begin __proc_info_end之间保存内核的所有处理器信息。
cmp r5, r6
blo 1b
mov r5, #0 @ unknown processor
2: ret lr
ENDPROC(__lookup_processor_type) => ENDPROC()定义在 include/linux/linkage.h,将__lookup_processor_type标签作为函数注册到符号列表,使其能够从外部调用。
/*
* Look in <asm/procinfo.h> for information about the __proc_info structure.
*/
.align 2
.type __lookup_processor_type_data, %object
__lookup_processor_type_data:
.long .
.long __proc_info_begin
.long __proc_info_end
.size __lookup_processor_type_data, . - __lookup_processor_type_data