微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > ARM linux的启动部分源代码简略分析

ARM linux的启动部分源代码简略分析

时间:11-09 来源:互联网 点击:

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

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top