转载地址:https://blog.youkuaiyun.com/coldsnow33/article/details/37904799
-
__setup_mmu: sub r3, r4, #16384 @ Page directory size,r3 = 0x20004000
-
bic r3, r3, #0xff @ Align the pointer
-
bic r3, r3, #0x3f00
-
@ 这里r4中存放着内核执行地址,将16K的一级页表放在这个内核执行地址下面的16K空间里,
-
@ 上面通过 sub r3, r4, #16384 获得16K空间后,
-
@ 又将页表的起始地址进行16K对齐放在r3中。即ttb的低14位清零。
-
/*
-
* Initialise the page tables, turning on the cacheable and bufferable
-
* bits for the RAM area only.
-
*/
-
mov r0, r3 @ r0 = 0x20004000
-
mov r9, r0, lsr #18 @ r9 = 0x2000
-
mov r9, r9, lsl #18 @ start of RAM,r9 = 0x20000000,先>>18,后<<18,就是256K对齐
-
add r10, r9, #0x10000000 @ a reasonable RAM size,r10 = 0x30000000,0x10000000==256M
-
@ 上面这几行把一级页表的起始地址保存在r0中,并通过r0获得一个ram起始地址(256K对齐),
-
@ 并从这个起始地址开始的256M ram空间对应的描述符的C和B位均置”1”,
-
@ r9和r10中存放了这段内存的起始地址和结束地址。
-
mov r1, #0x12 @ XN|U + section mapping
-
@ 一级描述符的bit[1:0]为10,表示这是一个section描述符。
-
@ bit[4]为1,
-
@ 此时bit[8:5]均为0,选择了D0域。
-
orr r1, r1, #3 << 10 @ AP=11,r1 = 0xC12
-
@ 一级描述符的AP(access permission bits) bit[11:10]为11,
-
@ 即all access types permitted in both modes
-
@ bit[31:20]为physical address,为0
-
add r2, r3, #16384 @ r2 = 0x20008000
-
@ 一级描述符表(页表)的结束地址存放在r2中。
-
1: cmp r1, r9 @ if virt > start of RAM
-
cmphs r10, r1 @ && end of RAM > virt
-
bic r1, r1, #0x1c @ clear XN|U + C + B
-
orrlo r1, r1, #0x10 @ Set XN|U for non-RAM
-
orrhs r1, r1, r6 @ set RAM section settings
-
str r1, [r0], #4 @ 1:1 mapping
-
add r1, r1, #1048576@ == 0x100000 = 1M
-
teq r0, r2 @ r0==r2时,不在jump 1处执行,此时r1=4G=0
-
bne 1b
-
/* case 1:
-
1: cmp r1, r9 @ if virt > start of RAM
-
cmphs r10, r1 @ && end of RAM > virt
-
bic r1, r1, #0x1c @ clear XN|U + C + B
-
orrlo r1, r1, #0x10 @ Set XN|U for non-RAM
-
*/
-
/* case 2:
-
1: cmp r1, r9 @ if virt > start of RAM
-
bic r1, r1, #0x1c @ clear XN|U + C + B
-
orrlo r1, r1, #0x10 @ Set XN|U for non-RAM
-
*/
-
/* case 3:
-
1: cmp r1, r9 @ if virt > start of RAM
-
cmphs r10, r1 @ && end of RAM > virt
-
bic r1, r1, #0x1c @ clear XN|U + C + B
-
orrhs r1, r1, r6 @ set RAM section settings
-
*/
-
@ r1 &= ~0x1c
-
@ 1->r1 |= 0x10
-
@ r10 end 0x300000000
-
@ 2->r1 |= r6,r1 |= 0x0d,在256M范围内
-
@ r9 start 0x20000000
-
@ 3->r1 |= 0x10
-
@ 上面这段就是对一级描述符表(页表)的初始化,
-
@ 首先比较这个描述符所描述的地址是否在那个256M的空间中,如果在则这个描述符对应的内存区域是 cacheable ,bufferable。
-
@ 如果不在则noncacheable, nonbufferable。
-
@ 然后将描述符写入一个一级描述符表(页表)的入口,并将一级描述符表(页表)入口地址加4,而指向下一个1M section的基地址。
-
@ 如果页表入口未初始化完,则继续初始化。
-
@ 一级描述符结构如下:
-
@ 31 20 19 12 11 10 9 8 5 4 3 2 1 0
-
@ 物理地址的基址 0 AP 0 域 1 C B 1 0
-
@ || 1:1映射
-
@ ||
-
@ 0 <=> 0~(1M-1)
-
@ 1 <=> 1M~(2M-1)
-
@ 2 <=> 2M~(3M-1)
-
@ 4095 <=> (4G-1M)~(4G-1)
-
@ 一级描述符表(页表)的高12位是每个setcion的基地址,可以描述4096个section。
-
@ 一级页表大小为16K,每个页表项,即描述符占4字节,刚好可以容纳4096个描述符,
-
@ 所以这里就映射了4096*1M = 4G的空间。
-
/*
-
* If ever we are running from Flash, then we surely want the cache
-
* to be enabled also for our execution instance... We map 2MB of it
-
* so there is no map overlap problem for up to 1 MB compressed kernel.
-
* If the execution is in RAM then we would only be duplicating the above.
-
*/
-
/*
-
*/
-
orr r1, r6, #0x04 @ ensure B is set for this
-
orr r1, r1, #3 << 10
-
@ 这两行是设置AP和B
-
mov r2, pc
-
mov r2, r2, lsr #20
-
orr r1, r1, r2, lsl #20
-
@ 将当前地址1M对齐,并与r1中的内容结合形成一个描述当前指令所在section的描述符。
-
add r0, r3, r2, lsl #2
-
@ r3为刚建立的一级描述符表(页表)的起始地址0x20004000。
-
@ 将当前地址(pc)的高12位左移两位(形成14位索引)与r3中的地址
-
@ (低14位为0)相加形成一个4字节对齐的地址
-
@ 这个地址也在16K的一级描述符表(页表)内,r0的[31:14]为0,所以该地址<2^14=16K。
-
@ 当前地址对应着描述符(貌似这就是一个一级描述符)在一级描述符表(页表)中的位置,这个位置之前已经初始化过了。
-
@ 对于从ram中运行这里只是又重新设置了一次,从flash中运行,会多映射2MB
-
@ 一级页表中索引为r2左移2位。
-
@ r0地址结构如下:
-
@ 31 14 13 2 1 0
-
@ 页表基址 页表index 0 0
-
@ r0里存储的描述符格式如下:
-
@ 31 20 19 12 11 10 9 8 5 4 3 2 1 0
-
@ PC高12bit 0 AP 0 域 1 C B 1 0
-
str r1, [r0], #4
-
add r1, r1, #1048576
-
str r1, [r0]
-
@ 这里将上面形成的描述符及其连续的下一个section描述
-
@ 写入上面4字节对齐地址处
-
mov pc, lr
-
ENDPROC(__setup_mmu)
mcrne p15, 0, r3, c2, c0, 0 @ load page table pointer,r3 = 0x20004000
MMU的段页表的虚拟地址与物理地址的转换过程