kernel/head.S

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



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值