ldr r5, =0x1FF00000
and r2, r2, r5 ; VA needs 512MB, 1MB aligned.
and r2, r2, r5 ; VA needs 512MB, 1MB aligned.
原来
R2
中存储的是虚拟地址值(如
0x80000000
),通过上面的代码,将
R2
中数据的
[29-21]
位置为
1
,前面已经说过将空间划分成了多个
1MB
的段,那么就必须以
1MB
对齐,而且
WinCE
最多只能支持
512MB
的物理内存,所以虚拟地址的合法区间是
0x80000000~0x9FFFFFFF
,正好是
512MB
的大小(这段是带缓冲的虚拟地址,相应的不带缓冲的虚拟地址是
0xA0000000~0xBFFFFFFF
)。
R2
中的数据正是虚拟地址对应的页表相对于页表首地址的偏移地址,也就是
R2
用来计算该虚拟地址对应的页表的存储地址,从下面的代码会看出这点。
ldr r5, =0xFFF00000
and r3, r3, r5 ; PA needs 4GB, 1MB aligned.
and r3, r3, r5 ; PA needs 4GB, 1MB aligned.
原来
R3
中存储的是物理地址的地址值,页表项的内容由两部分组成:物理地址的高
12
位(高
12
位)
+
缓冲读写属性(低
12
位),这里的代码正是保留了物理地址的高
12
位,清空低
20
位,正是为了形成页表项内容进行准备。
add r2, r10, r2, LSR #18
add r0, r0, r3 ; (r0) = PTE for next physical page
add r0, r0, r3 ; (r0) = PTE for next physical page
这两条代码正是在前面计算得基础上,用
R2
中虚拟地址的高
14
位的偏移量
+R10
中存储的页表的基地址,从而将该虚拟地址对应的页表要存储的地址计算出来,并赋值给
R2
。而
R0
存储的数据是关于页表对应的虚拟页的缓冲读写属性,再加上
R3
中存储的物理地址的高
12
位,从而形成了相应页表项的内容,并赋值给
R0
。
35
str r0, [r2], #4
add r0, r0, #0x00100000 ; (r0) = PTE for next physical page
sub r4, r4, #1 ; Decrement number of MB left
cmp r4, #0
bne %B35 ; Map next MB
str r0, [r2], #4
add r0, r0, #0x00100000 ; (r0) = PTE for next physical page
sub r4, r4, #1 ; Decrement number of MB left
cmp r4, #0
bne %B35 ; Map next MB
上面的第一条代码,通过
str
指令将
R0
中存储的页表项内容,写入
R2
指向的地址中,同时
R2
指向下一个地址。接下来将页表项的内容增加
1MB
的大小,从
oemaddrtab_cfg.inc
的映射表可以看出,最后一个参数表示的分配存储空间的大小,是以
MB
为单位,所以
R0
指向的是下一个物理地址页(单位
1M
)的页表项的内容。之后将
R4
中空间大小的值减
1
,表示剩余要构造的页表数目,如果不为
0
,则跳转到标号
35
处,继续构造页表,知道这一个页表条目完成为止(或者说这一段存储空间全部映射完成为止)。
bic r0, r0, #0xF0000000 ; Clear Section Base Address Field
bic r0, r0, #0x0FF00000 ; Clear Section Base Address Field
b %B30 ; Get next element
bic r0, r0, #0x0FF00000 ; Clear Section Base Address Field
b %B30 ; Get next element
这部分代码简单的说就是清空
R0
中的高
12
位,即清空上一个物理地址的高
12
位,因为要用来存储下一个物理地址的高
12
位,同时保留低
20
位中的缓冲读写属性,完成后跳转到标号
30
处,继续读取全局内存映射表的内容,构造地址映射的页表。其中
%B30
表示向前寻找标号为
30
的地址(
B=Before
)。
40
tst r0, #8
bic r0, r0, #0x0C ; clear cachable & bufferable bits in PTE
add r10, r10, #0x0800 ; (r10) = ptr to 1st PTE for "unmapped uncached space"
bne %B25 ; go setup PTEs for uncached space
sub r10, r10, #0x3000 ; (r10) = restore address of 1st level page table
tst r0, #8
bic r0, r0, #0x0C ; clear cachable & bufferable bits in PTE
add r10, r10, #0x0800 ; (r10) = ptr to 1st PTE for "unmapped uncached space"
bne %B25 ; go setup PTEs for uncached space
sub r10, r10, #0x3000 ; (r10) = restore address of 1st level page table
一般
WinCE
会根据全局内存映射表进行两份虚实映射,一份带缓冲的虚拟地址和不带缓冲的虚拟地址。到这里的时候,说明
0x80000000~0x9FFFFFFF
这段
512M
的虚拟地址的页表已经构造完成了,这段地址是带缓冲的,下面需要对不带缓冲的虚拟地址构造页表。
第一条
tst
语句表示判断
R0
的位
[7]
的值是否为
1
,从而影响
bne
跳转语句的结果。
R0
的第
7
位在页表项内容中表示的是缓冲的属性,如果为
1
,表明还没有开始构造不带缓冲的虚拟地址对应的页表,如果不为
0
,说明不带缓冲的虚拟地址对应的页表也已经构造完成了(是不是有点晕啊,呵呵,因为当第二次循环运行这条语句的时候,已经就完成了不带缓冲的页表的构造,不行你自己走一遍代码就知道了)。第二条
bic
的语句很简单,就是为了将高速缓冲和写缓冲的属性值去掉。第三条语句有点意思,其实就是为了将
R10
指向存储不带缓冲的虚拟地址对应的页表的存储地址(
0xA0000000
),但是采用的方法是计算偏移量,当前
R10
中存储的是带缓冲的虚拟地址对应的页表的存储地址(
0x80000000
),而
0xA0000000
于
0x8000000
相差
0x20000000
,那么把
0x20000000>>18
得到的结果就是
0x0800
,所以在
R10
的基础加上
0x0800
就是页表应该存储的地址(其实就是依据虚拟地址高
14
位代表的是相对于页表首地址的偏移量,所以也可以直接用
0xA0000000>>18
位来计算页表的存储地址,不信你试试,结果是一样的)。第四条语句就简单了,向前跳转到标号
25
处,像缓冲虚拟地址的页表构造的方法对不带缓冲虚拟地址的页表进行构造。第五条语句为下面的代码做准备,将
R10
指向的地址重新指向页表基地址,即
PT_1ST_BASE
,网上有人说这句有问题,其实没有问题,不过这一句确实没什么用处,因为下面对
R10
进行了重新赋值,即将
PT_1ST_BASE
重新赋给了
R10
。不过为了理解明白,本人还是解释一下这句是怎么计算出来的?首先在最开始
R10
增加了
0x2000
,上这里有两次增加了
0x0800
(为什么是两次呢?好好看代码,上面的第三条语句会被执行两次),加起来正好是
0x3000
,所以减去这个值得到的正是页表的基地址。
;----------------------------------------------
; Setup mmu to map (VA == 0) to (PA == 0x30000000).
; cached area
ldr r0, =PT_1ST_BASE ; PTE entry for VA = 0
ldr r1, =PT_1ST_ENTRY_CNB ; Cache/Unbuffer/RW
str r1, [r0]
; Setup mmu to map (VA == 0) to (PA == 0x30000000).
; cached area
ldr r0, =PT_1ST_BASE ; PTE entry for VA = 0
ldr r1, =PT_1ST_ENTRY_CNB ; Cache/Unbuffer/RW
str r1, [r0]
; uncached area.
add r0, r0, #0x0800 ; PTE entry for VA = 0x02000000
ldr r1, =PT_1ST_ENTRY_NCNB ; Uncache/Unbuffer/RW
str r1, [r0]
add r0, r0, #0x0800 ; PTE entry for VA = 0x02000000
ldr r1, =PT_1ST_ENTRY_NCNB ; Uncache/Unbuffer/RW
str r1, [r0]
这部分用来映射不带缓冲的虚拟地址
0x20000000
(后面的注释不对)到物理地址
0x30000000
,上之前分析的一样,采用计算偏移量的方法,第二条和第三条语句和上一部分的一样,这里不再赘述。
本文转自jazka 51CTO博客,原文链接:http://blog.51cto.com/jazka/572626,如需转载请自行联系原作者