您的位置:首页 > 其它

ARM920T协处理器以及MMU的分析(三)

2010-11-03 03:12 281 查看
同样,在这里我们通过一段MMU的创建来说明MMU的工作方式:
下面这段代码是OAL进入kernel Start的一段代码,它也就是wince的页表初始化代码,涉及到两部分内如,分别为二级页表的创建和一级页表的创建。这里的一级页表和前面那个有些不同是TTB发生改变了,也就是说系统进入内核后从新创建了页表。
;-------------------------------------------------------------------------------
; KernelStart - kernel main entry point
;
; The OEM layer will setup any platform or CPU specific configuration that is
; required for the kernel to have access to ROM and DRAM and jump here to start up
; the system. Any processor specific cache or MMU initialization should be completed.
; The MMU and caches should not enabled.
;
; This routine will initialize the first-level page table based up the contents of
; the MemoryMap array and enable the MMU and caches.
;
; NOTE: Until the MMU is enabled, kernel symbolic addresses are not valid and must be
; translated via the MemoryMap array to find the correct physical address.
;
; Entry (r0) = pointer to MemoryMap array in physical memory
; Exit returns if MemoryMap is invalid
;-------------------------------------------------------------------------------
LEAF_ENTRY KernelStart

mov r11, r0 ; (r11) = &MemoryMap (save pointer)//这里R11指向OEMadressTable的首地址

; figure out the virtual address of OEMAddressTable
mov r1, r11 ; (r1) = &MemoryMap (2nd argument to VaFromPa)
bl VaFromPa
mov r6, r0 ; (r6) = VA of MemoryMap

; convert base of PTs to Physical address
ldr r4, =PTs ; (r4) = virtual address of FirstPT
mov r0, r4 ; (r0) = virtual address of FirstPT
mov r1, r11 ; (r1) = &MemoryMap (2nd argument to PaFromVa)
bl PaFromVa

mov r10, r0 ; (r10) = ptr to FirstPT (physical)

; Zero out page tables & kernel data page

mov r0, #0 ; (r0-r3) = 0's to store
mov r1, #0
mov r2, #0
mov r3, #0
mov r4, r10 ; (r4) = first address to clear
add r5, r10, #KDEnd-PTs ; (r5) = last address + 1
18 stmia r4!, {r0-r3}
stmia r4!, {r0-r3}
cmp r4, r5
blo %B18 //清空PTs到KDEnd这段物理内存


; 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.

add r4, r10, #HighPT-PTs ; (r4) = ptr to high page table
orr r0, r10, #0x051 ; (r0) = PTE for 64K, kr/w kr/w r/o r/o page, uncached unbuffered//设置二级页表存储的地方为大页,因为PTs分配内存为0x4000(16K)
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] //填充二级页表,由于是大页有重复,所以无论D0/1/2/3实际在查询的时候都是[15:0],与0/1/2/3无关
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
orr r0, r8, #0x002 ; construct the PTE//由于中断中最大分配内存为0x700+0x400+0x400+0x100(=4kK),所以这里用小页即可
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
//设计KPAGE的二级页表
orr r0, r4, #0x001 ; (r0) = 1st level PTE for high memory section
//设置为coarse page(粗颗粒)
add r1, r10, #0x4000
str r0, [r1, #-4] ; store PTE in last slot of 1st level table
//设计这些高位虚拟地址的一级描述符在0xFFF*4
即c2 + 0x3ffc
IF {FALSE}
mov r0, r4
mov r1, #256 ; dump 256 words
CALL WriteHex
ENDIF

; Fill in first level page table entries to create "un-mapped" regions
; from the contents of the MemoryMap array.
;
; (r9) = ptr to KData page
; (r10) = ptr to 1st level page table
; (r11) = ptr to MemoryMap array

add r10, r10, #0x2000 ; (r10) = ptr to 1st PTE for "unmapped space"
mov r7, #2 ; (r7) = pass counter

mov r0, #0x02
orr r0, r0, r2 ; (r0)=PTE for 0: 1MB (C+B as set by OEM)
orr r0, r0, #0x400 ; set kernel r/w permission
20 mov r1, r11 ; (r1) = ptr to MemoryMap array


25 ldr r2, [r1], #4 ; (r2) = virtual address to map Bank at
ldr r3, [r1], #4 ; (r3) = physical address to map from
ldr r4, [r1], #4 ; (r4) = num MB to map

cmp r4, #0 ; End of table?
beq %F29

ldr r5, =0x1FF00000
and r2, r2, r5 ; VA needs 512MB, 1MB aligned.

ldr r5, =0xFFF00000
and r3, r3, r5 ; PA needs 4GB, 1MB aligned.

add r2, r10, r2, LSR #18
add r0, r0, r3 ; (r0) = PTE for next physical page

28 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 %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


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
sub r10, r10, #0x3000 ; (r10) = restore address of 1st level page table
IF {FALSE}
mov r0, r10
mov r1, #4096 ; dump 4096 words
CALL WriteHex
ENDIF
//以上为一级页表设置,即为一级段组设计,前面已经很详细讨论,,这里不再重复
; Set up page table entry for PSL calls to turn the pre-fetch abort into a permission fault rather
; than a translation fault. This speeds up the time to execute a PSL call, as this entry can be
; cached in the TLB
;
; (r10) = ptr to first level page table

add r0, r10, #0x3C00 ; Page table entry for 0xF0000000 -> 0xF0100000
mov r1, #PTL1_SECTION + PTL1_XN ; Level 1 Section, with Cachable/bufferable, access
; bits and phys address set to zero
;; Because the CP15 R1 R bit is set, there are no unreadable settings via the AP permission bits.
orr r1, r1, #0x1E0 ; Set Domain to 15 (to cause domain access fault)
; Domain access is set up below..
str r1, [r0] ; Store the level 1 PTE


; Setup the vector area.
;
; (r8) = ptr to exception vectors

add r7, pc, #VectorInstructions - (.+8)
ldmia r7!, {r0-r3} ; load 4 instructions
stmia r8!, {r0-r3} ; store the 4 vector instructions
ldmia r7!, {r0-r3} ; load 4 instructions
stmia r8!, {r0-r3} ; store the 4 vector instructions
IF {FALSE}
sub r0, r8, #8*4
mov r1, #8 ; dump 8 words
CALL WriteHex
ENDIF
; convert VectorTable to Physical Address
ldr r0, =VectorTable ; (r0) = VA of VectorTable
mov r1, r11 ; (r1) = &OEMAddressTable[0]
bl PaFromVa
mov r7, r0 ; (r7) = PA of VectorTable
add r8, r8, #0x3E0-(8*4) ; (r8) = target location of the vector table
ldmia r7!, {r0-r3}
stmia r8!, {r0-r3}
ldmia r7!, {r0-r3}
stmia r8!, {r0-r3}
IF {FALSE}
sub r0, r8, #8*4
mov r1, #8 ; dump 8 words
CALL WriteHex
ENDIF

; The page tables and exception vectors are setup. Initialize the MMU and turn it on.

mov r1, #1
mtc15 r1, c3 ; Setup access to domain 0 and clear other//仅DOMAIN0,为client权限。其它的禁止
; domains including 15 for PSL calls (see above)
mtc15 r10, c2 //将页表的基地址传给c2,等待MMU的启动

mov r0, #0
mcr p15, 0, r0, c8, c7, 0 ; Flush the I&D TLBs

mfc15 r1, c1
orr r1, r1, #0x007F ; changed to read-mod-write for ARM920 Enable: MMU, Align, DCache, WriteBuffer
orr r1, r1, #0x3200 ; vector adjust, ICache, ROM protection
ldr r0, VirtualStart
cmp r0, #0 ; make sure no stall on "mov pc,r0" below
mtc15 r1, c1 ; enable the MMU & Caches
mov pc, r0 ; & jump to new virtual address
nop
整个代码实际比较简单,中间也用了大量的注释,但是理解这段代码需要对wince的内存分配和虚拟地址分配有一个详细的了解。还有就是wince为什么要进行这个复杂的映射,比如为什么不全部映射为段组模式就可以了,而要弄出二级页表复杂化系统呢。如果你仔细的去思考了这些问题,理解MMU的功能和建立以及查询方法将会变得特别简单。
下面我对WINCE内核的一些东西进行简单的介绍,希望可以帮助理解以上的内容:
首先wince内核对虚拟的高位地址做了一些规定,也就是把中断以及一些堆栈都放在了高位,其资源分配如下表:













即产生了下面的资源分配设置;
^ 0xFFFD0000
FirstPT # 0x4000
# 0x4000
# 0x8000
# 0x10000 ; not mapped
ExVector # 0x1000
# 0x1400 ; not mapped
# 0x0400 ; 1K interrupt stack
IntStack # 0x2000 ; not mapped (ffff2800)
# 0x0100 ; not mapped (FIQ stack) (ffff4800)
# 0x0700 ; 2K-256 abort stack (ffff4900)
AbortStack # 0x1800 ; not mapped (ffff5000)
# 0x0100 ; not mapped (FIQ stack) (ffff6800)
FIQStack # 0xC000-0x6900 ; not mapped (ffff6900)
KDBase # 0x07E0 ; 2K-32 kernel stack
KStack # 0x0020 ; temporary register save area
KData # 0x400 ; kernel data area


但是系统为了页表的方便是将所有这些东西挖掉保留的地址,剩下的东西放在一个连续的内存块中,这个内存块就是所谓的KDATA区域,其定义如下:














也正是因为这块内存决定了所有高位页表的建立,除了这块系统的关键区域外,剩下的所有页表都是以段组形式存在的。
对于这些东西的理解,我研究了一段时间,希望可以给初学者一些借鉴,由于本人的水平有限,理解不对地方还希望大家纠正。这段代码中时钟有一个问题我也没有理解,在这里提出来如果谁发现了答案可以告诉我一下。
问题如下:在需找PTs地址的时候,代码是将虚拟地址通过OEMAdressTable查询找到物理地址的。我经过对PAFromVA的分析发现这个是查询OEMAdressTable东西的。我的问题是PTs是高位,虚拟地址为0xFFFD0000,而这个虚拟地址在OEMAdressTable是没有定义的。是不是系统用的另外一张我没找到的OEMAdressTable还是有其他的原因。希望朋友指点。
我的联系方式: 邮箱:gsujianwen@163.com



(结束)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: