一个人勃一次不难,难的是勃一辈子……
最近分心的事很多,勃得越来越少了!
打开mmu是一件神圣的工作,需要仔细、再仔细……
从__v7_setup函数返回来,进入到__enable_mmu过程,做起飞前的最后确认:
__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))
结合数据手册,此段是将D0、D1两个域,D1对应于USER域,D0对应于KERNEL和TABLE域,配置为管理模式,对这两个域的访问和执行不受TLB中相应标志位影响,D2域,对应于IO域,配置为客户模式,对此域的访问受TLB中相应标志位的检查;
mcr p15, 0, r5, c3, c0, 0 @ load domain access register
写入域访问控制寄存器,其实和__v7_setup函数中写入的值相同;
mcr p15, 0, r4, c2, c0, 0 @ load page table pointer
__v7_setup函数中也已经写过这个寄存器了;
b __turn_mmu_on
__turn_mmu_on就在后面紧跟着,不明白为何还要b一下;
ENDPROC(__enable_mmu)
再看看紧接着的__turn_mmu_on函数:
/*
* Enable the MMU. This completely changes the structure of the visible
* memory space. You will not be able to trace execution through this.
* If you have an enquiry about this, *please* check the linux-arm-kernel
* mailing list archives BEFORE sending another post to the list.
*
* r0 = cp#15 control register
* r13 = *virtual* address to jump to upon completion
*
* other registers depend on the function called upon completion
*/
.align 5
原来是因为有这个,所以要b过来,但为什么是以5对齐?在网上搜索了一下,原来.align n的语法,有按照n对齐的,也有按照2的n次方对齐的,而arm-linux是按照2的n次方对齐的,即,是以20字节位置对齐的,详见某篇博文:http://www.eetop.cn/blog/html/45/11145-1211.html
__turn_mmu_on:
mov r0, r0
暂时认为这是常规的nop语句……
mcr p15, 0, r0, c1, c0, 0 @ write control reg
终于将寄存器r0的值写入到了mmu控制寄存器中,此时的CPU终于可以“内牛满面”!
mrc p15, 0, r3, c0, c0, 0 @ read id reg
对于Cortex A8处理器来说,此时寄存器r3的值也许是:0x413fc082字样,其中41代表ARM,c08就是Cortex A8;
mov r3, r3
mov r3, r3
继续认为这是nop语句,或者说,在这里是清除流水线,那么,之后的CPU,已经平稳过渡到了虚拟地址空间的环境?(我不敢确认)……
mov pc, r13
无需废话了,很久以前,寄存器r13就准备好了__switch_data的入口地址;
ENDPROC(__turn_mmu_on)