kernel/head.S

来源:互联网 发布:javascript display 编辑:程序博客网 时间:2024/06/05 11:52

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



0 0
原创粉丝点击