;下面这一段有点特殊。ce5.0最多支持512M的物理RAM,也就是说虚拟地址空间0x80000000-0x9fffffff用来映射最多512M的物理RAM;
;所以r2和0x1FF00000求与后满足上述要求(1M对齐);
;而被映射的物理地址可以是任何4g空间内的地址,所以r3和0xFFF00000求与后满足要求(1M对齐)。
;注意,这里和ce支持4g虚拟内存是不矛盾的。
ldr r5, =0x1FF00000
and r2, r2, r5 ; VA needs 512MB, 1MB aligned.
ldr r5, =0xFFF00000
and r3, r3, r5 ; PA needs 4GB, 1MB aligned.
;r2 = r10 + r2>>18,r2指向一个描述符地址;
;r0 = r0 + r3,r0指向一个描述符的值,也就是高12bit存储一个物理page的起始地址,低20bit存储上面已经设置过的该page(1M)的属性。
add r2, r10, r2, LSR #18
add r0, r0, r3 ; (r0) = PTE for next physical page
;将描述符的值存储在该描述符地址指向的物理空间。然后r2+=4指向下一个描述符地址(注意一个描述符占4byte);
;r0+=0x00100000,指向下一个物理page的起始地址。
;至此,我们完成了一个一级映射描述符的映射过程。
28 str r0, [r2], #4
add r0, r0, #0x00100000 ; (r0) = PTE for next physical page
;r4存储了该内存区域(g_oalAddressTable某一项)的大小,单位为M,正好和page大小相等,所以直接r4-=1即可。
;若r4!=0,说明该内存区域还没有完成映射,则返回B28继续该内存区域其它page的映射;
;若r4==0,说明该内存区域映射完成,则清除r0的高12bit,而保留低20bit(因为全部page采用相同的属性设置),返回B25继续其它内存区域的映射。
sub r4, r4, #1 ; Decrement number of MB left
cmp r4, #0
bne %B28 ; Map next MB
bic r0, r0, #0xF0000000 ; Clear Section Base Address Field
bic r0, r0, #0x0FF00000 ; Clear Section Base Address Field
b %B25 ; Get next element
;此处已经完成C+B空间的映射,接下来要继续0xa00000000-0xbfffffff的非C+B空间的映射,所以首先清除C+B位。
;0x0800*1M/4 = 0x20000000,所以此时r10保存的物理PTE地址对应0xa0000000
29
bic r0, r0, #0x0C ; clear cachable & bufferable bits in PTE
add r10, r10, #0x0800 ; (r10) = ptr to 1st PTE for "unmapped uncached space"
subs r7, r7, #1 ; decrement pass counter
bne %B20 ; go setup PTEs for uncached space if we're not done
;最后恢复r10指向PTs,0x2000+0x0800+0x0800-0x3000=0
sub r10, r10, #0x3000 ; (r10) = restore address of 1st level page table
至此一级映射全部完成。下面再看我们上面跳过的二级映射。
; Setup 2nd level page table to map the high memory area which contains the
; first level page table, 2nd level page tables, kernel data page, etc.
;r4指向物理地址HighPT。HighPT存储二级页表。
add r4, r10, #HighPT-PTs ; (r4) = ptr to high page table
;为映射物理地址PTs构造一个表项。0x051最后两bit是01,说明是Large page(参考2),一个page为64k。
;其余字节说明访问权限。
;注意,这个page是非C+B的。
orr r0, r10, #0x051 ; (r0) = PTE for 64K, kr/w kr/w r/o r/o page, uncached unbuffered
;PTs对应虚拟地址0xFFFD0000,由于一个page是64k,需要4个page来映射0xFFFD0000-0xFFFD3FFF。
;Large page的映射方式在table index上稍微有点特别,使得我们可以使用同一个物理基址r0,具体参考2。
str r0, [r4, #0xD0*4] ; store the entry into 8 consecutive slots
str r0, [r4, #0xD1*4]
str r0, [r4, #0xD2*4]
str r0, [r4, #0xD3*4]
;r8指向中断向量表的物理地址ExceptionVectors。这个page的C和B如何设置由OEM指定,保存在r2中。
add r8, r10, #ExceptionVectors-PTs ; (r8) = ptr to vector page
bl OEMARMCacheMode ; places C and B bit values in r0 as set by OEM
mov r2, r0
;构造PTE。最后两个bit是10,说明是一个4k的Small page。(ExceptionVectors是4k大小)。
;为了将一个物理small page映射到4个第二级页表描述符,这里用了一个小技巧。
;注意到这四个虚拟地址0xFFFF0000,0xFFFF2400,FFFF4900和FFFF6800。通过Page index的不同(0x000,0x400,0x900和0x800 )
;可以将一个物理small page映射到不同的虚拟地址,而通过虚拟地址最后12bit的Page index来避免重叠访问。
orr r0, r8, #0x002 ; construct the PTE
orr r0, r0, r2
str r0, [r4, #0xF0*4] ; store entry for exception vectors
orr r0, r0, #0x500 ; (r0) = PTE for 4k r/o r/o kr/w kr/w C+B page
str r0, [r4, #0xF4*4] ; store entry for abort stack
str r0, [r4, #0xF6*4] ; store entry for FIQ stack (access permissions overlap for abort and FIQ stacks, same 1k)
orr r0, r8, #0x042
orr r0, r0, r2 ; (r0)= PTE for 4K r/o kr/w r/o r/o (C+B as set by OEM)
str r0, [r4, #0xF2*4] ; store entry for interrupt stack
;没什么好说的。
add r9, r10, #KPage-PTs ; (r9) = ptr to kdata page
orr r0, r9, #0x002
orr r0, r0, r2 ; (r0)=PTE for 4K (C+B as set by OEM)
orr r0, r0, #0x250 ; (r0) = set perms kr/w kr/w kr/w+ur/o r/o
str r0, [r4, #0xFC*4] ; store entry for kernel data page
;构建二级映射中的第一级描述符。
orr r0, r4, #0x001 ; (r0) = 1st level PTE for high memory section
add r1, r10, #0x4000
str r0, [r1, #-4] ; store PTE in last slot of 1st level table
;所以r2和0x1FF00000求与后满足上述要求(1M对齐);
;而被映射的物理地址可以是任何4g空间内的地址,所以r3和0xFFF00000求与后满足要求(1M对齐)。
;注意,这里和ce支持4g虚拟内存是不矛盾的。
ldr r5, =0x1FF00000
and r2, r2, r5 ; VA needs 512MB, 1MB aligned.
ldr r5, =0xFFF00000
and r3, r3, r5 ; PA needs 4GB, 1MB aligned.
;r2 = r10 + r2>>18,r2指向一个描述符地址;
;r0 = r0 + r3,r0指向一个描述符的值,也就是高12bit存储一个物理page的起始地址,低20bit存储上面已经设置过的该page(1M)的属性。
add r2, r10, r2, LSR #18
add r0, r0, r3 ; (r0) = PTE for next physical page
;将描述符的值存储在该描述符地址指向的物理空间。然后r2+=4指向下一个描述符地址(注意一个描述符占4byte);
;r0+=0x00100000,指向下一个物理page的起始地址。
;至此,我们完成了一个一级映射描述符的映射过程。
28 str r0, [r2], #4
add r0, r0, #0x00100000 ; (r0) = PTE for next physical page
;r4存储了该内存区域(g_oalAddressTable某一项)的大小,单位为M,正好和page大小相等,所以直接r4-=1即可。
;若r4!=0,说明该内存区域还没有完成映射,则返回B28继续该内存区域其它page的映射;
;若r4==0,说明该内存区域映射完成,则清除r0的高12bit,而保留低20bit(因为全部page采用相同的属性设置),返回B25继续其它内存区域的映射。
sub r4, r4, #1 ; Decrement number of MB left
cmp r4, #0
bne %B28 ; Map next MB
bic r0, r0, #0xF0000000 ; Clear Section Base Address Field
bic r0, r0, #0x0FF00000 ; Clear Section Base Address Field
b %B25 ; Get next element
;此处已经完成C+B空间的映射,接下来要继续0xa00000000-0xbfffffff的非C+B空间的映射,所以首先清除C+B位。
;0x0800*1M/4 = 0x20000000,所以此时r10保存的物理PTE地址对应0xa0000000
29
bic r0, r0, #0x0C ; clear cachable & bufferable bits in PTE
add r10, r10, #0x0800 ; (r10) = ptr to 1st PTE for "unmapped uncached space"
subs r7, r7, #1 ; decrement pass counter
bne %B20 ; go setup PTEs for uncached space if we're not done
;最后恢复r10指向PTs,0x2000+0x0800+0x0800-0x3000=0
sub r10, r10, #0x3000 ; (r10) = restore address of 1st level page table
至此一级映射全部完成。下面再看我们上面跳过的二级映射。
; Setup 2nd level page table to map the high memory area which contains the
; first level page table, 2nd level page tables, kernel data page, etc.
;r4指向物理地址HighPT。HighPT存储二级页表。
add r4, r10, #HighPT-PTs ; (r4) = ptr to high page table
;为映射物理地址PTs构造一个表项。0x051最后两bit是01,说明是Large page(参考2),一个page为64k。
;其余字节说明访问权限。
;注意,这个page是非C+B的。
orr r0, r10, #0x051 ; (r0) = PTE for 64K, kr/w kr/w r/o r/o page, uncached unbuffered
;PTs对应虚拟地址0xFFFD0000,由于一个page是64k,需要4个page来映射0xFFFD0000-0xFFFD3FFF。
;Large page的映射方式在table index上稍微有点特别,使得我们可以使用同一个物理基址r0,具体参考2。
str r0, [r4, #0xD0*4] ; store the entry into 8 consecutive slots
str r0, [r4, #0xD1*4]
str r0, [r4, #0xD2*4]
str r0, [r4, #0xD3*4]
;r8指向中断向量表的物理地址ExceptionVectors。这个page的C和B如何设置由OEM指定,保存在r2中。
add r8, r10, #ExceptionVectors-PTs ; (r8) = ptr to vector page
bl OEMARMCacheMode ; places C and B bit values in r0 as set by OEM
mov r2, r0
;构造PTE。最后两个bit是10,说明是一个4k的Small page。(ExceptionVectors是4k大小)。
;为了将一个物理small page映射到4个第二级页表描述符,这里用了一个小技巧。
;注意到这四个虚拟地址0xFFFF0000,0xFFFF2400,FFFF4900和FFFF6800。通过Page index的不同(0x000,0x400,0x900和0x800 )
;可以将一个物理small page映射到不同的虚拟地址,而通过虚拟地址最后12bit的Page index来避免重叠访问。
orr r0, r8, #0x002 ; construct the PTE
orr r0, r0, r2
str r0, [r4, #0xF0*4] ; store entry for exception vectors
orr r0, r0, #0x500 ; (r0) = PTE for 4k r/o r/o kr/w kr/w C+B page
str r0, [r4, #0xF4*4] ; store entry for abort stack
str r0, [r4, #0xF6*4] ; store entry for FIQ stack (access permissions overlap for abort and FIQ stacks, same 1k)
orr r0, r8, #0x042
orr r0, r0, r2 ; (r0)= PTE for 4K r/o kr/w r/o r/o (C+B as set by OEM)
str r0, [r4, #0xF2*4] ; store entry for interrupt stack
;没什么好说的。
add r9, r10, #KPage-PTs ; (r9) = ptr to kdata page
orr r0, r9, #0x002
orr r0, r0, r2 ; (r0)=PTE for 4K (C+B as set by OEM)
orr r0, r0, #0x250 ; (r0) = set perms kr/w kr/w kr/w+ur/o r/o
str r0, [r4, #0xFC*4] ; store entry for kernel data page
;构建二级映射中的第一级描述符。
orr r0, r4, #0x001 ; (r0) = 1st level PTE for high memory section
add r1, r10, #0x4000
str r0, [r1, #-4] ; store PTE in last slot of 1st level table