|
本帖最后由 吕氏春秋8266 于 2010-12-11 13:41 编辑
第四节 具体编程实现
好了,通过对以上知识的学习,我们已经对ARM地址转换及CACHE的读写有了深刻的认识,因此启动MMU及CACHE,需要如下步骤:
1. 禁止数据CACHE,将C15中寄存器的c1寄存器C[2]清零
mrc p15,0,r0,c1,c0,0
bic r0,r0,#(0x1<<2)
mcr p15,0,r0,c1,c0,0
2. 禁止代码CACHE,将C15中寄存器的c1寄存器I[12]清零
mrc p15,0,r0,c1,c0,0
bic r0,r0,#(0x1<<12)
mcr p15,0,r0,c1,c0,0
3. 禁止MMU,将C15中寄存器的c1寄存器M[0]清零
mrc p15,0,r0,c1,c0,0
bic r0,r0,#0x1
mcr p15,0,r0,c1,c0,0
4. 使数据及代码段CACHE无效
mcr p15,0,r0,c7,c7,0
5. 清空写缓冲区
mcr p15,0,r0,c7,c10,4
6. 使TLB整个页表无效
mcr p15,0,r0,c8,c7,0
7. 设置控制域
mcr p15,0,r0,c3,c0,0 R0->C3;
8. 设置进程PID号
mcr p15,0,r0,c13,c0,0
9. 设置页表基地址
mcr p15,0,r0,c2,c0,0 R0->C2
10. 计算描述符表并添加到TLB指定的内存单元中
由于一级页表由虚地址[31:20]进行索引,共计4096个为16k,由于TQ2440开发板为64M内存,故我们将其放在0x33ffc000处,即64M内存的最未端的16K内存中。
11. 在设置好页表描述符的基础上, 我们启用地址对齐功能,将C1寄存器A[1]赋值为1
mrc p15,0,r0,c1,c0,0
orr r0,r0,#(0x1<<1)
mcr p15,0,r0,c1,c0,0
12. 开启MMU功能,将C1寄存器M[0]赋值为1
mrc p15,0,r0,c1,c0,0
orr r0,r0,#0x1
mcr p15,0,r0,c1,c0,0
13. 开启代码及数据CACHE,将C1寄存器C[2]位,I[12]位赋值为1
mrc p15,0,r0,c1,c0,0
bic r0,r0,#(0x1<<12+0x1<<2)
mcr p15,0,r0,c1,c0,0
经过以上步骤,我们成功开启了MMU及CACHE功能。在本程序中,为了能使用中断功能,我们将0~0x20000000(32M)的地址空间映射到了0x30000000~0x32000000处,这样当中断发生时,CPU到0x18处执行时,实际到物理地址0x30000018处执行,中断就能正常运行了。
虽然我们成功对0x0开始的地址进行了映射,但还有一个关键问题未解决,当CPU执行mcr p15,0,r0,c1,c0,0这条指令后,MMU功能开启,而这条指令的下一条指令已经开始译码并执行,而这条指令的地址已经通过MMU进行转换,那么此时程序如何保证能得到正确的物理地址而正确执行呢?如果我们将0x30000000映射到0x30000000,即虚拟地址与物理地址一致,显然程序能够正确执行。这也是ARM推荐使用这种方法。
TQ2440-TEST程序映射关系:
通过以上分析,我们确保了程序的正确运行,但又产生了新的问题,也就是说我们的程序必须保证在0x0和0x30000000均能正确运行,对于这个问题,我在前几章已经做过分析。一句话,确保程序是基于PC+8+偏移量的寻址方式。
我们完全可以将0x0处的地址映射到0x30000000处,其它地址映射保持不变,即虚拟地址与物理地址一致。这样地址映射对我们来说完全是透明的,在开发程序时,我们完全可以不用考虑它,最后调用它就行。
说明:由于将主要精力放在MMU功能的分析上了,程序未实现从内部RAM拷贝至SDRAM的功能,请用7命令直接下载到SDRAM中运行
终于完成了MMU功能的分析及实现,下步打算深入研究NAND的读写问题,请大侠推荐几篇这方面的资料,谢谢了! |
|