MMU及PTS说明

MMUPTS表格

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

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

1MMU初始化代码分析

其实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, #8bic     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

PTs0x70010000

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 ffff0x7000 0000~0x700f ffff的映射如下

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

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

 

4>  0xa000 0000~0xa3ff ffff0x7000 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或者在此留言。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/243310.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

bug?VS2010中CImageList::DrawIndirect总是返回失败

//VS2010 #if _MSC_VER > 1600pImageList->Draw(pDC, nImage, point, ILD_NORMAL); #elseSIZE size;size.cx rect.Width() < sizeImage.cx ? rect.Width() : sizeImage.cx;size.cy rect.Height() < sizeImage.cy ? rect.Height() : sizeImage.cy;pImageList-&g…

VHDL基本结构

VHDL基本结构 (1)实体(Entity):描述所设计的系统的外部接口信号,定义电路设计中得到所有的输入和输出端口。 (2)结构体(Architecture):描述系统内部的结构和行为 (3)包集合(Package):存放各设计模块能共享的数据类型、常数和子程序等; (4)配置(Configurat…

Source Code Collection for Reproducible Research

转自&#xff1a;http://www.csee.wvu.edu/~xinl/source.html “It doesnt matter how beautiful your theory is, it doesnt matter how smart you are. If it doesnt agree with experiment, its wrong” - Richard Feynman "As a method for finding things out, scien…

IClass与电源管理

IClass与电源管理 前段时间为J9项目上添加电源管理&#xff0c;中间走了一些弯路。之前错误的认为&#xff0c;IClass只是与电源状态的改变方法有关&#xff0c;也就是说IClass的正确与否只会影响到设备电源状态的正确与否&#xff0c;而不会造成设备是否可以支持设备电源状态的…

状态机在VHDL中的实现

状态机在VHDL中的实现 1、Moore状态机的VHDL描述 输出仅取决于所处的状态 LIBRARY IEEE; --库、程序包的说明调用 USE IEEE.STD_LOGIC_1164.ALL;ENTITY Moore IS PORT (RESET,CLOCK,DIN : IN STD_LOGIC;DOUT : OUT STD_LOGIC_VECTOR(2 DOWNTO 0) ); END;ARCHITECTURE Mo…

Linux : find big file in the all directories

1. Juniper Firewall find . -type f -size 10000 -exec ls -lh {} ; Sample output: [email protected]% find . -type f -size 10000 -exec ls -lh {} ; -rw-r–r– 1 930 929 134M Jan 5 17:34 ./cf/packages/junos-11.4R6.6-domestic-rw-r–r– 1 root wheel 1…

VC++静态文本框/PICTURE控件的notify属性

RT&#xff0c;该属性对应的是SS_NOTIFY&#xff0c;但是很多人误以为是WM_NOTIFY 。该属性可以用ModifyStyle函数修改。

VHDL仿真

VHDL仿真 仿真(Simulation也称模拟),不接触具体的硬件系统利用计算机对电路设计的逻辑行为和运行功能进行模拟检测,较大规模的VHDL系统设计的最后完成必须经历多层次的仿真测试过程,包括针对系统的VHDL行为仿真、分模块的时序仿真和硬件仿真,直至最后系统级的硬件仿真测…

从Var Tick角度来对CE电源管理

从Var Tick角度来对CE电源管理 一&#xff0e;相关的基础知识如下 1&#xff0e;OAL中Timer相关函数说明 1> OALTimerInit 参数&#xff1a; msecPerSysTick: 每个系统调度Tick对应多少ms&#xff1b; countsPerMSec: Timer的Counter变化多少为1ms&#xff0c;其值为T…

变量初始化的确定性

变量初始化的确定性 SystemVerilog初始化顺序 SystemVerilog标准增强了变量的内嵌初始化。SystemVerilog规定所有内嵌初始化先于仿真时刻0执行的事件。这就保证了如果Initial或者always过程块读取具有内嵌初始值的变量时取得正确的初始值&#xff0c;这个确定行为消除了Verilo…

很好的Android论坛

需要的兄弟可以看一下 http://www.eoeandroid.com/?fromuid9379

用户自定义和枚举数据类型

用户自定义和枚举数据类型 用户自定义 1、typedef定义用户自定义类型 SystemVerilog同C一样&#xff0c;使用typedef关键字来建立用户自定义类型。用户自定义类型允许使用现有的数据类型建立新的数据类型。新的数据类型定义后&#xff0c;可以声明这个类型的变量 typedef int…

Keyboard驱动介绍

Keyboard驱动介绍 最近手里面没啥事&#xff0c;就想看看一些Driver的MDD层。 以前改过Keyboard Driver的PDD层&#xff0c;但是对它的MDD层还真是一片空白&#xff0c;这两天随便看了看Keyboard的MDD层&#xff0c;赶紧把东西记录下来&#xff0c;以防以过段时间忘记了。 很多…

GDI+不同的地方

研究了GDI处理图像的地方&#xff0c;发现它一些与众不同的地方&#xff0c;被它坑了一天。。。。。1、GDI的像素的原点默认你在左下角的&#xff0c;所以读取像素的顺序是从最低一行开始的(bottom-left)&#xff0c;其他一般的图像处理软件&#xff0c;像Photoshop&#xff0c…

关于结构体的内容

关于结构体的内容 结构体使用类似于C语言的语法来定义 结构体使用struct关键字声明。结构体内的成员可以是任何数据类型&#xff0c;包括用户自定义类型和其他的结构体类型。 struct{int a,b; //32位变量opcode_t opcode;//用户定义类型logic [23:0] adress;//24位变量bit er…

Pushing Policy Failed because Checkpoint Firewall “Load on module failed – no memory”

One day when pushing firewall policy from Checkpoint management server to UTM 272 cluster gateways, it failed and I got error message “Load on module failed – no memory” on one of cluster members. “Network Security Policy ‘Montreal_DMZ’ was prepared …

电池驱动介绍

电池驱动介绍 一&#xff0e;整体框架 电池驱动代码量很小&#xff0c;可是麻雀虽小&#xff0c;五脏俱全。与其他的很多Driver一样&#xff0c;分为PDDMDD层&#xff0c;双层之间通过PDD的如下导出接口相联系。 Programming element Description BatteryDrvrGetLevels…

将1bpp的bmp图像存储为1bpp或者2bpp的tiff格式

// 将1bpp的位图转换为 1bit/2bit tiff /** 参数&#xff1a;BYTE *src 二值图像的像素数据&#xff0c;不包含头部信息&#xff0c; 1bpp, int src_width 原图的宽度, in pixles,int src_height 原图的高度, in pixlesint bpp 转换tiff指定的bpp */ static BYTE *BW2Tif(…

关于联合体的内容

关于联合体的内容 联合体只储存一个值 联合体只存储一个元素&#xff0c;但这个元素可以有多种表示方法&#xff0c;每种表示可以是不同的数据类型。 联合体的声明语法类似于结构体&#xff0c;联合体的成员的引用也跟结构体一样。 union{int i;int unsigned u; }data; ... d…

Point-BERT:一种基于Transformer架构的点云深度网络

目录 1. 前言 2. Point Tokenization 3. Transformer Backbone 4. Masked Point Modeling 5. Experiments Reference 1. 前言 从PointNet [1] 开始&#xff0c;点云深度网络逐渐成为解决点云特征提取与语义分析的主要研究方向。尤其在OpenAI的GPT模型获得了突破性成果后&#…