MMU与PTS表格

最近在 FPGA 上仿真调试 Virgo (基于 ARM11 的一款处理器)芯片。 MMU 部分总是出错,具体的现象是查看物理地址和虚拟地址的映射时候芯片经常会挂掉。先是怀疑 MMU 的寄存器配置有问题,后来又怀疑 MMU 映射使用的 PTS 表格有问题,最后发现竟然是 RAM 没有清零导致的,唉,竟然犯了这种的错误,实在是雷人。

为了解决问题,这两天对这部分 代码进行了分析和调试,担心过两天会忘掉,赶紧写下来。

1 MMU 初始化代码分析

其实 MMU 的初始化过程就是 PTS 表格的初始化过程。

那么啥是 PTS 表格呢?

PTS 表格是供 MMU 进行地址映射和察看内存属性信息的表格。

PTS 表格主要记录 了两方面的信息,第一:虚拟地址对应的物理地址在哪个位置,第二:虚拟地址的属性信息,如上面的 0x402/0x40e/0x41e

MMU 详细的初始化 过程参照下面的代码解释:

            b       .

 

        INCLUDE oemaddrtab_cfg.inc

 

;------------------------------------------------------------------

         ; Compute physical address of the OEMAddressTable.

20    add     r11, pc, #g_oalAddressTable - (. + 8)

    ldr     r10, =PTs        ; (r10) = 1st level page table

 

 

    ; Setup 1st level page table ( using section descriptor)    

    ; Fill in first level page table entries to create "un-mapped" regions

    ; from the contents of the MemoryMap array .

    ;

    ;   (r10) = 1st level page table

    ;   (r11) = ptr to MemoryMap array

 

    ; 接下来这 三行代码是配置ptr 指针的位置,以及初始化DRAM 部 分物理地址在PTS 映射表中的标记,即E

    ; 后面会将 这个标记放置到PTS 映射表中

    add     r10, r10, #0x2000       ; (r10) = ptr to 1st PTE for "unmapped space"

    mov     r0, #0x0E           ; (r0) = PTE for 0: 1MB cachable bufferable

    orr     r0, r0, #0x400      ; set kernel r/w permission

25    mov     r1, r11         ; (r1) = ptr to MemoryMap array

 

   

    ; 获取g_oalAddressTable 的参数

    ; 哈哈,这 个就不用解释了

30    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

 

    ; g_oalAddressTable 表格的最后一行是DCD     0x00000000, 0x00000000,  0 

    ; 也即r4 = 0

    cmp     r4, #0          ; End of table?

    beq     %f40

 

    ; 这里也不 用说了,就是限定最大值为MBGB

    ldr     r5, =0x1FF00000

    and     r2, r2, r5          ; VA needs 512MB, 1MB aligned.       

 

    ldr     r5, =0xFFF00000

    and     r3, r3, r5          ; PA needs 4GB, 1MB aligned.

 

    ; 值得一提 的是下面的这个值,网上的争论也比较多

    ; PTS 表格中的 最小元素代表了MB 的物理地址空间,这也是g_oalAddressTable 中 映射的最小单位是MB 的原因

    ; 假如说有MBDRAM 需要进行映射,每MBPTS 表格中占据一个元素(四个字节的位置),最 终就是:

    ; 第一个MB 放置在PTS 表格偏移为x0 的位置,假如说这段MB DRAM 的物理地址是x3000 0000 ,则存放到这里的数据就是x3000 0000

    ; 第二个MB 放置在PTS 表格中偏移为x4 的位置,数据是x3010 0000[ 即这MB 空间的起始物理地址]

    ; 第三个MB 放置在PTS 表格中偏移为x8 的位置,数据是x3020 0000[ 即这MB 空间的起始物理地址]

    ; 第四个MB 放置在PTS 表格中偏移为xc 的位置,数据是x3030 0000[ 即这MB 空间的起始物理地址]

    ; 如果DRAM 很大的话,依次类推

    ; 注意观察 一下上面的偏移x0 ,其实可以通过(x3000 0000-0x3000 0000>>18 计算出来

    ; 注意观察 一下上面的偏移x4 ,其实可以通过(x3010 0000-0x3000 0000>>18 计算出来

    ; 注意观察 一下上面的偏移x8 ,其实可以通过(x3020 0000-0x3000 0000>>18 计算出来

    ; 注意观察 一下上面的偏移xc ,其实可以通过(x3030 0000-0x3000 0000>>18 计算出来

    ; 很明显, 这个为的右移值是由PTS 的最小元素所代表的物理空间大小决定的

    add     r2, r10, r2, LSR #18

    add     r0, r0, r3          ; (r0) = PTE for next physical page

 

    ; 接下来这 四行代码就是将DRAM 或者寄存器对应的物理地址填充到PTS 表 格中,r2 是表格的指针,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

 

    bic     r0, r0, #0xF0000000      ; Clear Section Base Address Field

    bic     r0, r0, #0x0FF00000     ; Clear Section Base Address Field

    ; 查询g_oalAddressTable 表格的下一个Element (不 知道该咋翻译)

    ; 起始一个Element 就对应表格g_oalAddressTable 的 一行,如DCD     0x93300000, 0xD0102000,  1 就是一个element

    b       %b30            ; Get next element

   

    ; 下面这行 代码是用来将g_oalAddressTable 表格中的物理地址同时也映射到xa000 0000~0xbfff ffff 这个Uncache 空 间中

    ; tst     r0, #8 bic     r0, r0, #0x0C 是用来计算后需要 填充PTS 表格中的标记,其实结果就是x402

    ; 第三行add     r10, r10, #0x0800 中的x0800 其实就是xa000 0000PTS 表格中的相对偏移(相对于虚拟地址x8000 0000

    ; pts 表格中位置的偏移),可以这样计算

    ; (0xa000 0000-0x8000 0000)>>18 = 0x0800

    ; 第行代码 没有意义,可以删除

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 ?

 

    ; 接下来是 将虚拟地址x0000 0000~0x000f ffff 这段空间映射到物理RAM 的前MB 空间

    ; 该芯片上RAM 的物理基址在x7000 0000 ,所以对应的 就是x7000 0000~0x700f ffff

    ; 值得说明 的是x7000040E ,表示位于x7000 0000MB 空间的基址

    ; r0 表示虚拟地址x0000 0000PTS 表格中的位置,其实就在PTS 表格中的最开始位置

    ; 1. Setup mmu to map (VA == 0) to (PA == 0x70000000).

    ; 1-1. cached area.

    ldr     r0, =PTs        ; PTE entry for VA = 0

    ldr     r1, =0x7000040E     ; cache/buffer/rw, PA base == 0x70000000

    ;ldr      r1, =0x70000402     ; cache/buffer/rw, PA base == 0x70000000

    str     r1, [r0]

 

    ; 下面三行 其实和上面的四行代码类似,表示将虚拟地址x2000 0000 映射到物理地址x7000 0000

    ; 第一行代 码中的x0800 表示虚拟地址x2000 0000PTS 表格中的偏移

    ; 而是UNCACHE ram 的标记

    ; 1-2. uncached area.

    add     r0, r0, #0x0800     ; PTE entry for VA = 0x0200.0000 , uncached    

    ldr     r1, =0x70000402     ; uncache/unbuffer/rw, base == 0x70000000

    str     r1, [r0]

   

   

    ; 接下来这 段代码将虚拟地址x7000 0000 映射到物理地址x7000 0000 ,这段映射空间的大小是MB

    ; DRAM 空间的大小

    ; Comment:

    ; The following loop is to direct map RAM VA == PA. i.e.

    ;   VA == 0x70XXXXXX => PA == 0x70XXXXXX for Virgo

    ; Fill in 8 entries to have a direct mapping for DRAM

    ;

    ldr     r10, =PTs           ; restore address of 1st level page table

    ldr     r0,  =PHYBASE

 

    ; 下面这一 行 # (0x7000 / 4) 同样是计算虚拟地址x7000 0000PTS 表格中的偏移

    ; 下面这段 代码我没有改,抄袭了三星的做法,它们没有写好,正确的写法应该是:

    ; (0x7000 0000>>18) ,是不是搞得你云里雾里的,鄙视Samsung ,将来Vrigo 的方案

    ; 出去之 后,一定要把公版BSP 给改的简单易懂,要不然OEM 厂 家又要骂了

    add     r10, r10, # (0x7000 / 4) ; (r10) = ptr to 1st PTE for (0x70000000>>16)/ sizeof (DWORD)

 

    ; 下面的#0x1E#0x400 最终组合成一个标记x40e ,类似于前面的x402x40e

    add     r0, r0, #0x1E       ; 1MB cachable bufferable

    orr     r0, r0, #0x400      ; set kernel r/w permission

    mov     r1, #0

    mov     r3, #64          ; 128MB SDRAM

    ;mov      r3, #128        ; 128MB SDRAM

    ; 下面的r2 表示当前的映射在PTS 表格中的偏移

    ; 第三行代 码纯属三星的人发贱,正确易懂的写法是add     r2, r10, r2, LSL2

    ; 干脆用C 语言写更加易懂一些,就是r2 = r2*4 + r10 , 这里的左移Bit 主要原因还是PTS 中的每 个元素是个字节

45    mov     r2, r1          ; (r2) = virtual address to map Bank at

    cmp      r2, #0x20000000:SHR:BANK_SHIFT

    add     r2, r10, r2, LSL #BANK_SHIFT-18

    strlo    r0, [r2]

    add     r0, r0, #0x00100000     ; (r0) = PTE for next physical page

    subs     r3, r3, #1

    add     r1, r1, #1

    bgt     %b45

 

 

    ; 兄弟们肯 定在想,我考你在这里搞了大半天,修改的都是PTS ,那MMU 咋 能知道呢?

    ; 呵呵,不 要急,到了,下面的p15, 0, r10, c2, c0, 0 不是把PTS 的地址给MMU 了么,哈哈,大功告成

    ; 就剩下启 动MMU

    ldr     r10, =PTs           ; (r10) = restore address of 1st level page table

 

    ; The page tables and exception vectors are setup.

    ; Initialize the MMU and turn it on.

    mov     r1, #1

    mcr     p15, 0, r1, c3, c0, 0   ; setup access to domain 0

    mcr     p15, 0, r10, c2, c0, 0

 

    mcr     p15, 0, r0, c8, c7, 0   ; flush I+D TLBs

   

;    mrc     p15,0,r1,c1,c0,0

   

    orr     r1, r1, #0x0071         ; Enable: MMU

    orr     r1, r1, #0x0004     ; Enable the cache

 

 

    ldr     r0, =VirtualStart

 

    cmp     r0, #0          ; make sure no stall on "mov pc,r0" below

    ; OK ,终于把MMUenable 了,可以用了,哈哈,爽

    mcr     p15, 0, r1, c1, c0, 0

 

    mov     pc, r0          ;  & jump to new virtual address

    nop

 

 

    ; MMU & caches now enabled.

    ;   (r10) = physcial address of 1st level page table

    ;

;------------------------------------------------------------------

 

VirtualStart

 

        mrs     r0, cpsr

 

        ; 下面这段 是堆栈的配置,如果你发现EBoot 下面的变量和数组比较多的话,一定要调整下面

        ; Samsungwhimory.eboot 就需要相 当大的Stack 空间,小的话就会出莫名其妙的问题

        ; 哦,对 了,差点忘了,Stack 是从上朝下增长的,而Ram 是 从从下朝上增长的,不要越界了

        bic     r0, r0, #Mode_MASK

        orr     r1, r0, #Mode_IRQ | NOINT

        msr     cpsr_cxsf, r1               ; IRQMode

         mov     sp, #0x80000000

        add     sp, sp, #0x3d000        ;

 

        bic     r0, r0, #Mode_MASK | NOINT

        orr     r1, r0, #Mode_SVC

        msr     cpsr_cxsf, r1               ; SVCMode      

        mov     sp, #0x80000000

        add     sp, sp, #0x40000        ;

        b       main

 

        ENTRY_END

 

        LTORG

2 .最终生成的 PTS 表格

上面的代码太抽象了,我把 PTS 表格 Dump 出来之后用表格列写了以下,如下:

其中,第四列表示虚拟地址,第 三列表示虚拟地址对应物理地址,第一列表示 PTS 表格中的位置 偏移,而第二列为 PTS 表格中存放的数据。每 1MB 的虚拟地址在下面的表格中都对应一行。

address

value

physical address

VIRTUAL ADD

CHIP

SPACE

0X70012000

0X7000040E

0X70000000

0x80000000

DDR

Cached Space

0X70012004

0X7010040E

0X70100000

 

0X70012008

0X7020040E

0X70200000

 

0X7001200C

0X7030040E

0X70300000

 

 

0X700121FC

0X77F0040E

0X77F00000

 

0x700124C8

0xD010040E

0xD0101000

0x93200000

UART0

0X70012800

0x70000402

0X70000000

0xA0000000

DDR

UNCACHED SPACE

0X70012804

0x70100402

0X70100000

0xA0100000

 

0x70012CC8

0xD0100402

0xD0101000

0xA3200000

UART0

0X70010000

0X7000040E

0X70000000

0X00000000

DDR  

  映射0 地址到物理内存的开始位置,这里只映射1MB 的空间,属性为Cache

0X70010800

0xD0100402

0X70000000

0X20000000

DDR

 映射0x20000000 地 址到物理内存的开始位置,这里也是仅仅映射1MB 的空间,属性为UnCache

 

 

 

 

 

 

0X70011C00

0X7000041E

0X70000000

 X70000000

 

DDR  

 

 

 

映射地址0X70000000 到物理内存开始的位置 

0X70011C04

0X7010041E

0X70100000

0X70100000

 

0X70011C08

0X7020041E

0X70200000

0X70200000

 

 

0X70011DFC

0X77F0041E

0X77F00000

0X77F00000

 

最终赋值给 MMU 的值如下:

Value

MMU.SFR

About

1

c3&c0

Open MMU

PTs 0x70010000

c2&c0

set up access to domain 0

7800041e

c8&c7

flush I+D TLBs

5007d

c0&c1

Enable: MMU and cache

3 .物理地址和虚拟地址映射关系图形化显示

感觉上面的物理地址和虚拟地址的映射不够形象,我把他们的映射关系用下面的图形表示。

1>   0x0000 0000~0x000f ffff 0x7000 0000~0x700f ffff 的映射如下

 

2>   0x2000 0000~0x200f ffff 0x7000 0000~0x700f ffff 的映射如下

 

3>   0x8000 0000~0x83ff ffff 0x7000 0000~0x73ff ffff 的映射如下

 

4>   0xa000 0000~0xa3ff ffff 0x7000 0000~0x73ff ffff 的映射如下

 

5>   UART 寄存器的映射如下

 

 

4 .附 g_oalAddressTable 表格

; Export Definition

 

        EXPORT  g_oalAddressTable[DATA]

 

;------------------------------------------------------------------------------

;

; TABLE FORMAT

;       cached address, physical address, size

;------------------------------------------------------------------------------

 

g_oalAddressTable

 

       DCD     0x80000000, 0x70000000, 64     ; 512 MB DRAM BANK         

DCD     0x93200000, 0xD0101000,  1      ; uart0 slv register

       DCD     0x00000000, 0x00000000,  0      ; end of table

;------------------------------------------------------------------------------

        END

 

累死我了,终于写完了。

如果有没写清楚的地方, 欢迎发邮件到 guopeixin@126.com 或者在此留言。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值