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

同样,在这里我们通过一段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                              //清空PTsKDEnd这段物理内存

 

 

;       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分配内存为0x400016K

        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

 

 

 

(结束)

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值