分类: LINUX
2013-01-15 09:50:48
原文地址:ADS中建立使用二级页表(2) 作者:fpseustar
位 |
说 明 |
Bit[1:0]: |
页描述符类型标识。00:无效;01:大页;10:小页;11:极小页 |
C、B: |
该二级描述符对应的存储空间的cache和Write Buffer特性控制位,如表4-5所示 |
APx: |
访问权限控制位,详见前面“MMU中的域”说明 |
TEX: |
在ARMv5以上版本处理器中有定义,如果TEX等于1,表示系统支持写时分配cache |
大页基地址: |
该描述符对应的大页存储空间的物理基地址,64KB对齐 |
小页基地址: |
该描述符对应的小页存储空间的物理基地址,4KB对齐 |
极小页基地址: |
该描述符对应的极小页存储空间的物理基地址,1KB对齐 |
C |
B |
写通类型cache |
写回类型cache |
可选择写通属性的写回类型cache |
0 |
0 |
Uncached/unbuffered |
Uncached/unbuffered |
Uncached/unbuffered |
0 |
1 |
Uncached/buffered |
Uncached/buffered |
Uncached/buffered |
1 |
0 |
cached/unbuffered |
不可预测 |
写通cached/buffered |
1 |
1 |
Cached/buffered |
Cached/buffered |
写回cached/buffered |
二、在ADS初始化中建立二级页表;
;**************************************************************************************
;* 初始化页表
;**************************************************************************************
; 初始化MMU,Cache以及WB
mov r0, #0 ; 将r0寄存器置0,用于后续对CP15寄存器赋值
mcr p15, 0, r0, c7, c7, 0 ; 失效I/DCache
; mcr p15, 0, r0, c7, c10, 4 ; 挤干WB
mcr p15, 0, r0, c8, c7, 0 ; 失效I/D TLBs
mrc p15, 0, r0, c1, c0, 0 ; 加载控制寄存器C1到R0
bic r0, r0,#0x
bic r0, r0,#0x1100 ; 将R0的I(ICache)S(System Protection)位清零
mcr p15, 0, r0, c1, c0, 0 ; 将R0写到控制寄存器C1
ldr r5, =0x30004000 ; 加载页表基址0x4000到R5,该值不能低于0x4000,因为C2寄存器近31:14位有效,低于该值则1级页表项将从0x0开始,这将和中断向量表以及中断处理函数冲突
mcr p15, 0, r5, c2, c0, 0 ; 将R5写到翻译表CP15协处理器的基址寄存器C2中
; 0.0x4000000映射到0x4000000 得到并写入1级页表
;ldr r0, =0x30004100 ; R0寄存器加载1级页表描述符地址,具体配置如下:
;ldr r1, =0x
;str r1, [r0] ;0x
; 1.0x0(虚地址)映射到0x24000000(实地址即CSB) 得到并写入1级页表
ldr r0, =0x30004000 ; R0寄存器加载1级页表描述符地址,具体配置如下:
ldr r1, =0x
str r1, [r0]
; 2.0x11000000映射到0x11000000(映射SEP4020相应的寄存器空间) 得到并写入1级页表
ldr r0, =0x30004440 ; R0寄存器加载1级页表描述符地址,具体配置如下:
ldr r1, =0x
str r1, [r0]
;3.先建立0x30000000映射到0x30000000的段地址描述符,在这里只建立了
ldr r0, =0x
; Address of First-Level Descriptor:
; 0, 0, 0, 0, 4, 0, 0, 4
; 31 30 29 28, 27 26 25 24, 23 22 21 20, 19 18 17 16, 15 14 13 12, 11 10 09 08, 07 06 05 04, 03 02 01 00
; 0 0 0 0, 0 0 0 0, 0 0 0 0, 0 0 0 0, 0 1 0 0, 0 0 0 0, 0 0 0 0, 0 1 0 0
ldr r1, =0x30008011 ; 二级页表存放的位置为0x3000,8000~0x3000,a000
; First-Level Descriptor:(一级页表中包含256项二级页表项)
; 0, 0, 0, 0, 8, 0, 1 1
; 31 30 29 28, 27 26 25 24, 23 22 21 20, 19 18 17 16, 15 14 13 12, 11 10 09 08, 07 06 05 04, 03 02 01 00
; 0 0 0 0, 0 0 0 0, 0 0 0 0, 0 0 0 0, 1 0 0 0, 0 0 0 |0, 0 0 0 |1, 0 0 |0 1
; Page Table Address |S |Domain |IMP |0 1
add r6, r0, #0x10
first1
str r1, [r0], #4 ; 写入映射1级页表页描述符
add r1, r1, #0x400
teq r0, r6
bne first1
;
; 4.再建立SDRAM的二级页表描述符,这个是存放在得到并写入2级页表,这里先统一建立
ldr r0, =0x30008000 ; 二级页表项存放的位置在0x3000,8000~0x3000,9000
ldr r1, =0x30000FFE ; 二级页表映射的物理地址范围是0x3000,0000 ~~0x3040,0000映射的虚拟地址为0x3000,0000 ~~0x3040,0000 准备第2MB的2级页表项,具体配置为:
; Second-level descriptor:
; 3, 0, 0, 0, 0, F, F, 2
; 31 30 29 28, 27 26 25 24, 23 22 21 20, 19 18 17 16, 15 14 13 12, 11 10 9 8, 7 6 5 4, 3 2 1 1
; 0 0 1 1, 0 0 0 0, 0 0 0 0, 0 0 0 0, 0 0 0 0, |1 1|1 1,|1 1|1 1,|C|B|1 1
; 256B page base address |AP |AP |AP |AP |1|1|1 0
ldr r5, =0x1000 ;映射的大小为0x2,c000大小
add r6, r0, r5 ; 由2级页表描述符初始地址R0和总的页数(4K页)所占页表项空间大小(16K=0x4000)并扣除不在该1级描述符映射的区域,得到2级页表结束地址,保存到R6中
second_one ;
str r1, [r0], #4 ; 循环装载2级页表
add r1, r1, #0x1000 ; 每次加0x1000,为了页号每次自加(偏移)1页
teq r0, r6 ; 和0x8000对比,等于则意味着完成虚地址0x3040,0000~0x3040,0000共4MB的映射
bne second_one ;
; 5.在这里再将页表项存放的位置0x3000,4000~0x3000,a000将他们改为不可cache的,因为页表项不可cache,得到并写入2级页表
ldr r0, =0x30008010 ; 二级页表项存放的位置在0x8010~0x8028
ldr r1, =0x30004FF2 ; 二级页表映射的物理地址范围是0x3000,4000 ~~0x3000,a000映射的虚拟地址为0x3000,4000 ~~0x3000,a000 准备第2MB的2级页表项,具体配置为:
; Second-level descriptor:
; 0, 0, 0, 0, 4, F, F, 2
; 31 30 29 28, 27 26 25 24, 23 22 21 20, 19 18 17 16, 15 14 13 12, 11 10 9 8, 7 6 5 4, 3 2 1 1
; 0 0 0 0, 0 0 0 0, 0 0 0 0, 0 0 0 0, 0 1 0 0, |1 1|1 1,|1 1|1 1,|C|B|1 1
; 256B page base address |AP |AP |AP |AP |0|0|1 0
ldr r5, =0x18 ;映射的大小为0x2,c000大小
add r6, r0, r5 ; 由2级页表描述符初始地址R0和总的页数(4K页)所占页表项空间大小(16K=0x4000)并扣除不在该1级描述符映射的区域,得到2级页表结束地址,保存到R6中
second_two ;
str r1, [r0], #4 ; 循环装载2级页表
add r1, r1, #0x1000 ; 每次加0x1000,为了页号每次自加(偏移)1页
teq r0, r6 ; 和0x8000对比,等于则意味着完成虚地址0x3001,0000~0x3070,0000共7MB的映射
bne second_two ;
; 开启MMU并跳转到主程序开始执行
ldr r0, =0x0 ;
ldr r1, =0x400000ff ; 准备填写Domain域,由于上面用到0和3两个域,所以需要给0x55,最前面的4问题不大
mcr p15, 0, r1, c3, c0, 0 ; 写入Domain域
ldr r1, =0x4005147D ; 准备填写C1控制寄存器
;**************************************************************************************
;* 跳转到主函数 main()
;**************************************************************************************
IMPORT MAIN_DO
ldr r5,=MAIN_DO
mcr p15, 0, r1, c1, c0, 0 ; 打开MMU和Cache等
add pc, r5,#0x0 ; 跳PC到刚才准备的__main的虚地址地址继续执行
mov r0, r0 ; 填充流水线
mov r0, r0 ; 填充流水线
mov r0, r0 ; 填充流水线
;**************************************************************************************
这上面的过程就是建立二级页表的过程,其中需要注意的几个问题是:
(1) 页表建立的地方的虚实映射一定要提前建立好,否则在最好打开cache和MMU的时候就会死掉;
(2) 一定要提前建立好虚地址0的映射,否则会在
mcr p15, 0, r1, c1, c0, 0 ; 打开MMU和Cache等
这句话死掉,会怎么也过不过去的。
(3) 页表描述符存放的位置不要做成cache,这个是MMU规定的,因为mmu会直接从sdram中去页表描述符的,而不会从cache中取描述符的。
(4)注意要使我们的程序跑起来还需要注意程序连接的地址应该是程序运行起来的虚地址,而不是实地址,另外还需要注意的是,程序的堆栈一定要改到我们已经映射的虚地址当中,否则程序会直接跑飞的。