; Comment:
; The following loop is to direct map RAM VA == PA. i.e.
; VA == 0x50XXXXXX => PA == 0x50XXXXXX for S3C6410
; Fill in 8 entries to have a direct mapping for DRAM
ldr r10, =PT_1ST_BASE ; Restore address of 1st level page table
ldr r0, =DRAM_BASE_PA_START
; The following loop is to direct map RAM VA == PA. i.e.
; VA == 0x50XXXXXX => PA == 0x50XXXXXX for S3C6410
; Fill in 8 entries to have a direct mapping for DRAM
ldr r10, =PT_1ST_BASE ; Restore address of 1st level page table
ldr r0, =DRAM_BASE_PA_START
这部分开始建立虚拟地址到相等的物理地址的映射,因为是S3C6410,所以是0x50000000,如果是2410,则为0x30000000。首先将R10指向页表首地址(验证了前面那句减去0x30000000语句是没用的),R0存储的是0x50000000,既可以当做物理地址操作,也可以当做虚拟地址操作(因为是相等的地址映射)。
add r10, r10, #PTR_1ST_PTE ; (r10) = ptr to 1st PTE for 0x50000000
这条语句用来计算虚拟地址
0x50000000
对应的页表的存储地址,并赋值给
R10
。
PTR_1ST_PTE
在文件最开始处已经进行了定义,其实定义相当于将
0x50000000>>18
,用高
14
位计算相对于页表基地址的偏移量。
add r0, r0, #0x1E ; 1MB cachable bufferable
orr r0, r0, #0x400 ; set kernel r/w permission
mov r1, #0
; mov r3, #64 ; 64MB DRAM
mov r3, #128 ; 128MB DRAM
orr r0, r0, #0x400 ; set kernel r/w permission
mov r1, #0
; mov r3, #64 ; 64MB DRAM
mov r3, #128 ; 128MB DRAM
前两条语句用来设置页表对应页的缓冲读写属性,第四条语句,将
DRAM
的大小赋值给
R3
寄存器,该值的大小选择就是根据全局内存映射表中的
DRAM
设置的大小。该值不会大于
512
,因为
WinCE
最大支持
512MB
的物理内存。
45
mov r2, r1 ; (r2) = virtual address to map Bank at
cmp r2, #0x20000000:SHR:BANK_SHIFT
add r2, r10, r2, LSL #BANK_SHIFT-18
mov r2, r1 ; (r2) = virtual address to map Bank at
cmp r2, #0x20000000:SHR:BANK_SHIFT
add r2, r10, r2, LSL #BANK_SHIFT-18
第一条和第二条语句要结合起来看,
R2
开始是
0
,
cmp
的比较就是为了保证
DRAM
的大小不超过
512M
,注释中的
Bank
大小就是
1MB
,
BANK_SHIFT
在最开始定义,大小为
20
,而
0x20000000>>20=512
。
cmp
指令影响的状态位,在后面的代码判断时使用。第三条语句其实还是计算对应的页表的存储地址的,
LSL #BANK_SHIFT-18
结合前面一条语句,相当于将
R2>>18
,这下就回到了前面介绍的,将高
14
位作为页表基地址的偏移量。
strlo r0, [r2]
add r0, r0, #0x00100000 ; (r0) = PTE for next physical page
subs r3, r3, #1
add r1, r1, #1
bgt %B45
add r0, r0, #0x00100000 ; (r0) = PTE for next physical page
subs r3, r3, #1
add r1, r1, #1
bgt %B45
第一条语句是将
R0
中的页表项写入
R2
指向的地址,但是没有
str
指令,而是
strlo
指令,因为这里有不同的地方,
strlo
实现的效果是,如果还没有超过
512MB
,那么像
str
指令一样,如果超过
512MB
,则不会往地址中写数据,忽略此次操作。个人认为,这样写的用意在于,当以后
DRAM
大小变化的时候,只需要该一个值,其他部分不变,而且如果设置的大于
512MB
,可以实现保护。第二条到第四条语句和前面介绍的部分类似。最后一条语句就是根据上面
cmp
的比较结果进行跳转的,
bgt
表示如果大于则跳转。
ldr r10, =PT_1ST_BASE ; (r10) = restore address of 1st level page table
该语句重新将
R10
指向页表基地址,因为下面会用到它。
; The page tables and exception vectors are setup.
; Initialize the MMU and turn it on.
mov r1, #1
mcr p15, 0, r1, c3, c0, 0 ; setup access to domain 0
mcr p15, 0, r10, c2, c0, 0
; Initialize the MMU and turn it on.
mov r1, #1
mcr p15, 0, r1, c3, c0, 0 ; setup access to domain 0
mcr p15, 0, r10, c2, c0, 0
前面设置好页表以后,这里开始初始化
MMU
,并打开
MMU
。上面代码设置的是域
0
的访问控制属性,同时将页表的基地址存储到
CP15
协处理器的
C2
寄存器中。
mcr p15, 0, r0, c8, c7, 0 ; flush I+D TLBs
这条代码用来无效整个指令
Cache
、数据
Cache
和
TLB
,相当于清空所有
MMU
的相关空间。
mrc p15, 0, r1, c1, c0, 0
orr r1, r1, #0x0071 ; Enable MMU
orr r1, r1, #0x0004 ; Enable the Data Cache
orr r1, r1, #0x0071 ; Enable MMU
orr r1, r1, #0x0004 ; Enable the Data Cache
第一条语句读取
CP15
的
C1
寄存器的数据到
R1
中,下面两条用来设置
MMU
的标志,使能
MMU
,使能数据
Cache
。
ldr r0, =VirtualStart
cmp r0, #0 ; make sure no stall on "mov pc,r0" below
mcr p15, 0, r1, c1, c0, 0
mov pc, r0 ; & jump to new virtual address
nop
cmp r0, #0 ; make sure no stall on "mov pc,r0" below
mcr p15, 0, r1, c1, c0, 0
mov pc, r0 ; & jump to new virtual address
nop
首先R0存储标号VirtualStart的地址,它是一个虚拟地址,因为它出现在启用虚拟地址之后。确保标号VirtualStart的虚拟地址不为0,因为下面有mov pc r0,语句,不可以给pc赋值0。第三天语句将R1中的数据写入CP15的C1寄存器中,设置MMU标志,并启用MMU,最后通过直接给PC赋值,跳转到VirtualStart标号处。
本文转自jazka 51CTO博客,原文链接:http://blog.51cto.com/jazka/572649,如需转载请自行联系原作者