u-boot mmu映射分析

一、映射过程详解

关于页表:ARMv6的MMU进行地址映射时涉及到两种页表,一级页表(first level page table)和二级页表(coarse page table)。

关于映射方式:映射方式有两种,段映射和页映射。段映射只用到一级页表,页映射用到一级页表和二级页表。

关于映射粒度:段映射的映射粒度有两种,1M section和16M supersection;页映射的映射粒度也有两种,4K small page和64K large page。

硬件在做地址转换时,如何知道当前是什么映射方式以及映射粒度是多少呢?

这些信息可以从页表的入口描述符中获得。

一级页表的入口描述符(first-level descriptor)格式如下:

第[1:0]位决定映射方式:

[1:0]=10b时,是段映射,此时只需作一级映射,描述符的最高12或8位存放的是段基址;

[1:0]=01b时,是页映射,此时虚拟地址转换为物理地址需要经历二级映射,描述符的最高22位存放的是二级页表的物理地址;

第[18]位决定段映射的粒度:

[18]=0b时,映射粒度为1M,描述符的最高12位存放段基址;

[18]=1b时,映射粒度为16M,描述符的最高8位存放段基址;

当映射方式为页映射时,我们用到二级页表,二级页表的入口描述符(second-level descriptor)格式如下:

第[1:0]位决定页映射的映射粒度:

[1:0]=10b或11b时,映射粒度为4KB,描述符的最高20位为页基址;

[1:0]=01b时,映射粒度为64KB,描述符的最高16位为页基址;

下面分4种情况对地址映射过程做详细描述:

1)段映射,映射粒度为1M

2)段映射,映射粒度为16M

3)页映射,映射粒度为4K

4)页映射,映射粒度为64K

1.1段映射,映射粒度为1M

当映射方式为段映射,且映射粒度为1M时,映射图如下:

虚拟地址到物理地址的映射过程如下:

  1. 虚拟地址的[31:20]位存放一级页表的入口index,[19:0]位存放段偏移;

  2. 从TTBR(translation table base register,协处理器CP15中的一个寄存器,用于存放一级页表的基址)寄存器中获取一级页表的基址;

  3. 一级页表基址+ VA[31:20] = 该虚拟地址对应的页表描述符的入口地址;

  4. 页表描述符的[31:20]位为该虚拟地址对应的物理段基址;

  5. 物理段基址+ VA[19:0]段偏移= 物理地址

由映射图可知,一个虚拟地址可以索引2^12个一级页表入口,每个入口映射2^20大小的内存,故虚拟地址可以映射的最大物理内存为:2^12 * 2^20,即4G。

1.2 段映射,映射粒度为16M

当映射方式为段映射,且映射粒度为16M时,映射图如下:

虚拟地址到物理地址的映射过程如下:

  1. 虚拟地址的[31:24]位存放一级页表的入口index,[23:0]位存放段偏移;

  2. 从TTBR(translation table base register,协处理器CP15中的一个寄存器,用于存放一级页表的基址)寄存器中获取一级页表的基址;

  3. 一级页表基址+ VA[31:24] = 该虚拟地址对应的页表描述符的入口地址;

  4. 页表描述符的[31:24]位为该虚拟地址对应的物理段基址;

  5. 物理段基址+ VA[23:0]段偏移= 物理地址

由映射图可知,一个虚拟地址可以索引2^8个一级页表入口,每个入口映射2^24大小的内存,故虚拟地址可以映射的最大物理内存为:2^8 * 2^24,即4G。

1.3 页映射,映射粒度为4K

当映射方式为页映射,且映射粒度为4K时,映射图如下:

虚拟地址到物理地址的映射过程如下:

  1. 虚拟地址的[31:20]位存放一级页表的入口index,[19:12]位存放二级页表的入口index,[11:0]位存放页偏移;

  2. 从TTBR(translation table base register,协处理器CP15中的一个寄存器,用于存放一级页表的基址)寄存器中获取一级页表的基址;

  3. 一级页表基址+ VA[31:20] = 一级页表描述符的入口地址;

  4. 一级页表描述符的[31:10]位存放二级页表的基址;

  5. 二级页表基址+ VA[19:12] = 二级页表描述符的入口地址;

  6. 二级页表描述符的[31:12]位存放该虚拟地址在内存中的物理页基址;

  7. 物理页基址+ VA[11:0]页偏移= 物理地址

由映射图可知,一个虚拟地址可以索引2^12个一级页表入口,每个一级页表入口指向的二级页表最大可以有2^8个二级页表入口,每个二级页表入口映射2^12大小的内存,故虚拟地址可以映射的最大物理内存为:2^12 * 2^8 * 2^12 ,即4G。

1.4 页映射,映射粒度为64K

当映射方式为页映射,且映射粒度为64K时,映射图如下:

虚拟地址到物理地址的映射过程如下:

  1. 虚拟地址的[31:20]位存放一级页表的入口index,[19:16]位存放二级页表的入口index,[15:0]位存放页偏移;

  2. 从TTBR(translation table base register,协处理器CP15中的一个寄存器,用于存放一级页表的基址)寄存器中获取一级页表的基址;

  3. 一级页表基址+ VA[31:20] = 一级页表描述符的入口地址;

  4. 一级页表描述符的[31:10]位存放二级页表的基址;

  5. 二级页表基址+ VA[19:16] = 二级页表描述符的入口地址;

  6. 二级页表描述符的[31:16]位存放该虚拟地址在内存中的物理页基址;

  7. 物理页基址+ VA[15:0]页偏移= 物理地址  

由映射图可知,一个虚拟地址可以索引2^12个一级页表入口,每个一级页表入口指向的二级页表最大可以有2^4个二级页表入口,每个二级页表入口映射2^16大小的内存,故虚拟地址可以映射的最大物理内存为:2^12 * 2^4 * 2^16 ,即4G。

1.5 地址映射总图

《ARM1176 JZF-S Technical Reference Manual》中有一张对上述四种映射情况的汇总图:

2. 关于一级页表基址

参考《ARM1176 JZF-S Technical Reference Manual》6.12 MMU descriptors

ARMv6中有两个协处理器寄存器用来存放一级页表基地址,TTBR0和TTBR1。操作系统把虚拟内存划分为内核空间和用户空间,TTBR0存放用户空间的一级页表基址,TTBR1存放内核空间的一级页表基址。

In this model, the virtual address space is divided into two regions:
• 0x0 -> 1<<(32-N) that TTBR0 controls
• 1<<(32-N) -> 4GB that TTBR1 controls.

N的大小由TTBCR寄存器决定。0x0 -> 1<<(32-N)为用户空间,由TTBR0控制,1<<(32-N) -> 4GB为内核空间,由TTBR1控制。

N的大小与一级页表大小的关系图如下:

操作系统为用户空间的每个进程分配各自的页表,即每个进程的一级页表基址是不一样的,故当发生进程上下文切换时,TTBR0需要被存放当前进程的一级页表基址;TTBR1中存放的是内核空间的一级页表基址,内核空间的一级页表基址是固定的,故TTBR1中的基址值不需要改变。

2.u-bootMMU初始化代码分析

2.1 start.s中mmu使能

enable_mmu:
    /* enable domain access */
    ldr    r5, =0x0000ffff
    mcr    p15, 0, r5, c3, c0, 0        @load domain access register

    /* Set the TTB register */
    ldr    r0, _mmu_table_base
    ldr    r1, =CFG_PHY_UBOOT_BASE
    ldr    r2, =0xfff00000
    bic    r0, r0, r2
    orr    r1, r0, r1
    mcr    p15, 0, r1, c2, c0, 0

    /* Enable the MMU */
mmu_on:
    mrc    p15, 0, r0, c1, c0, 0
    orr    r0, r0, #1
    mcr    p15, 0, r0, c1, c0, 0
    nop
    nop
    nop
    nop

2.2 lowlevlel_init.s中映射表初始化

.macro FL_SECTION_ENTRY base,ap,d,c,b
    .word (\base << 20) | (\ap << 10) | \
          (\d << 5) | (1<<4) | (\c << 3) | (\b << 2) | (1<<1)
.endm

.macro FL_SECTION_ENTRY base,ap,d,c,b /*.macro指令是汇编中宏定义的意思,此带参宏将FL_SECTION_ENTRY base,ap,d,c,b定义成一个word大小的特定值*/,

.word (\base << 20) | (\ap << 10) | \ /*这个特定值就是转换表的填充量,其中,参数base是映射出来的段地址的基地址,从第20位开始。*/

(\d << 5) | (1<<4) | (\c << 3) | (\b << 2) | (1<<1)/*20位的大小正好是1MB,由此可知转换表中未保留前20位,映射出来的地址之间间隔为1MB*/

/*故这里采用的是段式映射;继续来分析参数,ap是访问控制位,从第10位开始。d、c、b都是一些权限位*/

.endm /*.endm,即结束宏定义*/

注:该宏的用途就是定义一个.word的字段

/*这里开始设置虚拟映射转换表,这里使用的是段式映射模式,即以段(1MB)为单位进行映射*/

/*因此表中的一个单元只能管1MB,整个4G内存需要创建4096个表单元,所以后面采用了循环的方法来创建*/

.section .mmudata, "a"
    .align 14
    // the following alignment creates the mmu table at address 0x4000.
    .globl mmu_table

mmu_table:
    .set __base,0                                    //虚拟地址0开始
    // Access for iRAM
    .rept 0x100                                           //循环定义0x100次,定义0x100个  .word .word .word......,
    FL_SECTION_ENTRY __base,3,0,0,0  //.word字段中 高12位位物理基地址
    .set __base,__base+1                //地址加1
    .endr

此处是定义了0x100个.word 表单元,每个表单元对应的虚拟地址和物理地址一致 0x00000000-0x10000000~0x10000000

    // Not Allowed
    .rept 0x200 - 0x100
    .word 0x00000000
    .endr

此处循环定义0x100个 0x00000000,即物理地址为0,即虚拟地址 0x10000000-0x20000000无法访问

    .set __base,0x200               //物理基地址为0x20000000
    // should be accessed
    .rept 0x600 - 0x200             //循环0x400次 
    FL_SECTION_ENTRY __base,3,0,1,1  //定义页表单元,高12位物理地址为base
    .set __base,__base+1
    .endr

此处实现的映射关系为 虚拟地址0x20000000-0x60000000 对应的物理地址为 0x20000000-0x60000000

.rept 0x800 - 0x600
    .word 0x00000000
    .endr

虚拟地址 0x60000000-0x80000000空间无法访问

    .set __base,0x800
    // should be accessed
    .rept 0xb00 - 0x800
    FL_SECTION_ENTRY __base,3,0,0,0
    .set __base,__base+1
    .endr

平行映射, 虚拟地址0x80000000-0xb0000000 对应的物理地址为 0x80000000-0xb0000000

    .set __base,0xB00
    .rept 0xc00 - 0xb00
    FL_SECTION_ENTRY __base,3,0,0,0
    .set __base,__base+1
    .endr

平行映射, 虚拟地址0x80000000-0xb0000000 对应的物理地址为 0x80000000-0xb0000000


    .set __base,0xB00
    .rept 0xc00 - 0xb00
    FL_SECTION_ENTRY __base,3,0,0,0
    .set __base,__base+1
    .endr

    .set __base,0x200
    // 256MB for SDRAM with cacheable
    .rept 0xD00 - 0xC00
    FL_SECTION_ENTRY __base,3,0,1,1
    .set __base,__base+1
    .endr

此处实现映射  虚拟地址0xc0000000-0xd0000000 物理地址 0x20000000-0x30000000

VA                                             PA                                                                length

0-10000000                       0-10000000                                                       256MB

10000000-20000000        0                                                                          256MB

20000000-60000000        20000000-60000000                                         1GB        512-1.5G

60000000-80000000        0                                                                              512MB      1.5G-2G

80000000-b0000000        80000000-b0000000                                         768MB        2G-2.75G

b0000000-c0000000        b0000000-c0000000                                        256MB        2.75G-3G

c0000000-d0000000       20000000-30000000                                          256MB        3G-3.25G

转自:https://www.cnblogs.com/tanghuimin0713/p/3917178.html

猜你喜欢

转载自blog.csdn.net/coolperl/article/details/82502988