ARM linux的启动部分源代码简略分析
arm/include/asm/unified.h中定义,为:
#define BSYM(sym) sym
也就是说这个语句也仅仅是把__enable_mmu例程的地址加载进lr寄存器中。为了方便之后调用的函数返回时,直接执行__enable_mmu例程。
接着看stext下一句:
ARM( add pc, r10, #PROCINFO_INITFUNC )
ARM()也是一个宏,同样在文件arch/arm/include/asm/unified.h中定义,当配置内核为生成ARM镜像,则为:#define ARM(x...) x
所以这一条语句也就是在调用一个例程。R10中保存的是procinfo结构的地址。PROCINFO_INITFUNC符号在arch/arm/kernel/asm-offsets.c文件中定义,为:
DEFINE(PROCINFO_INITFUNC, offsetof(struct proc_info_list, __cpu_flush));
也就是调用结构体proc_info_list的__cpu_flush成员函数。回去查看arch/arm/mm/proc-arm920.S文件中struct proc_info_list结构体的变量的定义,可以看到这个成员为:
b __arm920_setup
也就是说,在设置好内核临时页表之后调用了例程__arm920_setup,这个例程同样在arch/arm/mm/proc-arm920.S中:
__arm920_setup:
mov r0, #0
mcr p15, 0, r0, c7, c7 @ invalidate I,D caches on v4
mcr p15, 0, r0, c7, c10, 4 @ drain write buffer on v4
#ifdef CONFIG_MMU
mcr p15, 0, r0, c8, c7 @ invalidate I,D TLBs on v4
#endif
adr r5, arm920_crval
ldmia r5, {r5, r6}
mrc p15, 0, r0, c1, c0 @ get control register v4
bic r0, r0, r5
orr r0, r0, r6
mov pc, lr
这一段首先使i,dcaches内容无效,然后清除writebuffer,接着使TLB内容无效。接下来加载变量arm920_crval的地址,我们看到arm920_crval变量的内容为:
rm920_crval:
crval clear=0x00003f3f, mmuset=0x00003135, ucset=0x00001130
crval为一个宏,在arch/arm/mm/proc-macros.S中定义:
.macro crval, clear, mmuset, ucset
#ifdef CONFIG_MMU
.word \clear
.word \mmuset
#else
.word \clear
.word \ucset
#endif
.endm
其实也就是定义两个变量而已。之后,在r0中,得到了我们想要往协处理器相应寄存器中写入的内容。
之后的__arm920_setup返回,mov pc, lr,即是调用例程__enable_mmu,这个例程在文件arch/arm/kernel/head.S中:
__enable_mmu:
#ifdef CONFIG_ALIGNMENT_TRAP
orr r0, r0, #CR_A
#else
bic r0, r0, #CR_A
#endif
#ifdef CONFIG_CPU_DCACHE_DISABLE
bic r0, r0, #CR_C
#endif
#ifdef CONFIG_CPU_BPREDICT_DISABLE
bic r0, r0, #CR_Z
#endif
#ifdef CONFIG_CPU_ICACHE_DISABLE
bic r0, r0, #CR_I
#endif
mov r5, #(domain_val(DOMAIN_USER, DOMAIN_MANAGER) | \
domain_val(DOMAIN_KERNEL, DOMAIN_MANAGER) | \
domain_val(DOMAIN_TABLE, DOMAIN_MANAGER) | \
domain_val(DOMAIN_IO, DOMAIN_CLIENT))
mcr p15, 0, r5, c3, c0, 0 @ load domain access register
mcr p15, 0, r4, c2, c0, 0 @ load page table pointer
b __turn_mmu_on
在这儿设置了页目录地址(r4寄存器中保存),然后设置domain的保护,在前面建立页表的例程中,注意到,页表项的控制信息,是从struct proc_info_list结构体的某字段中取的,其页目录项的 domain都是0,domain寄存器中的domain0对应的是0b11,表示访问模式为manager,不受限制。在这里同时也完成r0的某些位的进一步设置。
然后,__enable_mmu例程又调用了__turn_mmu_on,在同一个文件中定义:
__turn_mmu_on:
mov r0, r0
mcr p15, 0, r0, c1, c0, 0 @ write control reg
mrc p15, 0, r3, c0, c0, 0 @ read id reg
mov r3, r3
mov r3, r13
mov pc, r3
ENDPROC(__turn_mmu_on)
接下来写控制寄存器:
mcrp15,0,r0,c1,c0,0
一切设置就此生效,到此算是完成了打开d,icache和mmu的工作。
注意:arm的dcache必须和mmu一起打开,而icache可以单独打开。其实,cache和mmu的关系实在是紧密,每一个页表项都有标志标示是否是cacheable的,可以说本来就是设计一起使用的
前面有提到过,r13中存放的其实是另外一个例程的地址,其值是变量__switch_data的第一个字段,即一个函数指针的值,__switch_data变量是在arch/arm/kernel/head-common.S中定义的:
__switch_data:
.long __mmap_switched
.long __data_loc @ r4
.long _data @ r5
.long __bss_start @ r6
.long _end @ r7
.long processor_id @ r4
.long __machine_arch_type @ r5
.long __atags_pointer @ r6
.long cr_alignment @ r7
.long init_thread_union + THREAD_START_SP @ sp
前面的ldr r13 __switch_data,实际上也就是加载符号__mmap_sw
ARMlinux启 相关文章:
- ARM Linux 更新启动画面(11-21)
- ARM Linux启动分析headarmv.S内幕(11-09)
- arm linux 启动流程(11-09)
- ARM Linux 的启动过程(11-09)
- arm linux 启动流程之 进入内核(11-09)
- ARM Linux启动代码分析(11-09)