美文网首页嵌入式单片机学习程序员
uboot step 11 内存一下子变大了 ----MMU的配

uboot step 11 内存一下子变大了 ----MMU的配

作者: 2625K | 来源:发表于2016-08-12 22:20 被阅读642次

uboot step 11 内存一下子变大了 ----MMU的配置与使用

本文结构如下:

在前面初始化的过程中,由于MMU与Cache会影响我们进行初始化的工作,因此关闭了MMU与Cache,在那篇文章中已经说过了MMU的作用,这里再重新说下:

  • 1.完成虚拟地址到物理地址的转换
  • 2.对内存的访问权限进行控制

首先还是先来简要说下相关与MMU相关的寄存器,先有个大概印象,后面用到了再去详细的看:


mmu3.png
名称 描述 简写
Translation Table Base Register 0 保存一级转换表的物理地址 TTBR0
Translation Table Base Register 1 保存一级转换表的物理地址 TTBR1
Translation Table Base Control Register 一级转换表控制相关 TTBCR
Domain Access Control Register 域访问权限控制
C1 Control Register MMU和cache使能

MMU使能

mmu enable.png
  • 1.编程所有相关的CP15寄存器正确的值
  • 2.编程建立所要求的一级页表,二级页表
  • 3.关闭I-cache
  • 4.使能MMU

MMU 内存访问权限控制

  • Domains 域控制
    一个域被联系到一些内存区域,在页表描述符中有个Domain域来标识此区域内存属于哪一个域Domian来控制,ARM1176 支持16个Domains,域访问权限控制是由C3来设定的,如下图:


    c3.png

    每个域由两位来控制,32位寄存器,总共16个域

    • 00 无权限,任何访问都会产生domain fault
    • 01 Client 检查TLB页表描述符的权限位是否允许访问
    • 10 保留,产生domain fault
    • 11 Manager 不检查访问权限,不会产生权限错误
  • 访问权限控制
    在域控制中,提到会检查TLB页表描述符的权限位,这个权限位就是APX,AP位,在页表描述符中有这几个域


    ap.png
  • 可执行区域XN位


    XN.png
    • 如果含有可执行区域,XN=0
    • XN=1时,在此内存区域任何试图去执行指令的行为会产生权限错误

MMU 页表描述

为了支持段和页的映射方式,MMU使用两级页表描述符,一级页表描述符决定访问的是一个分段还是一个分页式的表,如果访问的是一个分页式的页表,处理器MMU决定页表类型是大页还是小页并找到二级页表。

一级页表描述符地址

ARM1176 包含 两个转换表基地址寄存器TTBR0和TTBR1,一个转换表基地址控制寄存器,当一个TLB未命中时,虚拟地址最高位决定使用的基地址寄存器是哪一个,采用两个转换表基地址期望去减少OS上下文切换的花费,每个独立的任务或进程,有他自己的页表而不用消耗大量内存。整个虚拟内存空间被分为两个部分,用户空间和内核空间

 0x0 -> 1<<(32-N) that TTBR0 controls
  1<<(32-N) -> 4GB that TTBR1 controls.

N的值在TTBCR寄存器中进行设定,N的大小决定了内核空间和用户空间的分界线,当N=0时,表示只使用了TTBR0寄存器


N1.png
n2.png
一级页表描述符格式分析
mmu1.png

如上图所示:

  • bit[1:0]: 映射类型,分段式还是分页式。
    • 00 忽略
    • 11 无效,返回Translation fault
    • 10 分段式
    • 01 分页式
  • nG : 0 转换表被标记为全局的; 1 转换表属于特定进程
  • S : 共享位,0 非共享; 1 共享内存
  • XN: 0 包含可执行代码; 1 不包含可执行代码
  • APX,AP位: 权限访问控制位
  • Doman : 域标识,属于哪个域
  • P: ECC校验
  • TEX,C,B: 此区域是否采用缓冲buffer,cache,还是直接访问,一般外设采用无缓冲,内存采用缓冲方式(个人理解)
  • NS:No-Secure 属性
二级页表描述符格式分析
mmu2.png

如上图所示,和一级页表描述符格式相似,相应的位的功能是一样的。不同的是最后两位代表了两种不同的分页类型。

  • bit[1:0] : 01 时,采用粗粒度大页64K进行映射 1X时,采用小(细)页4K进行映射

虚拟地址到物理地址的转化

MMU对于刚接触的人可能会感觉到有些不知所措,因为它有那么多相关的寄存器,还有什么TLB,一级页表,二级页表,粗细粒度,等等,完全一个大写的懵,认为MMU的使用是个很难的过程,当你从了解地址转化流程开始入手学习,慢慢了解了之后,便会觉得其实还是蛮简单的,下面来看下S3c6410中MMU的地址转化流程:

  • TLB:Translation Lookaside Buffer,可以称为快表,当要进行虚拟地址到物理地址转化的时候,MMU便会去查询这个表来确定虚拟地址所对应的物理地址是多少,而这个表也被我们保存在了内存的某个地址,这个地址称为转换表基地址,我们需要将这个基地址写到转换表基地址寄存器中。

下面分四种情况对映射转化过程作下说明:

  • 分段式映射,大小1M
  • 分段式映射,大小16M
  • 分页式映射,大小64KB 粗页
  • 分页式映射,大小4KB 细页
1M分段式映射
1M.png
  • 页表基地址(TTBRx寄存器中)18bits[31:14]+虚拟地址12bits[31:20] +2[00] 构成了一级页表描述符的地址
  • 取得了一级页表描述符的地址,访问这个地址从中可以得到真实的物理段基地址[31:20]
  • 将得到的物理段基地址[31:20]加上虚拟地址中的[19:0]位偏移地址构成了真正的物理地址
    每个虚拟地址可以索引 2^12 个一级描述符地址,每个一级描述符可以包含 2^20 个物理地址,总共可以索引4G空间
16M分段映射
16M.png

与1M的段映射相似,只是有些地址线的范围发生了改变,另外一级描述符的第18位为1表示16M的段映射,0表示1M段映射

64KB分页映射
64KB.png
  • 页表基地址+虚拟地址的[31:20]位得到了一级描述符的地址
  • 一级描述符的[31:10]位为二级描述符的基地址
  • 二级描述符的基地址+虚拟地址的[19:16]位,最后几位补0构成了二级页表描述符的地址
  • 二级页表描述符的第[31:16]位为物理基地址+虚拟地址的[15:0]页内偏移地址构成了真正的物理地址
    注:上图映射是从内核手册中截取的,有些错误,二级页表描述符的Second-level tabel index 应该为96位,50位应为0
4KB分页映射
4kb.png
  • 页表基地址+虚拟地址的[31:20]位得到了一级描述符的地址
  • 一级描述符的[31:10]位为二级描述符的基地址
  • 二级描述符的基地址+虚拟地址的[19:12]位,最后几位补0构成了二级页表描述符的地址
  • 二级页表描述符的第[31:12]位为物理基地址+虚拟地址的[11:0]页内偏移地址构成了真正的物理地址

代码实现-控制led

#define GPKCON (volatile unsigned long*)0xA0008800
#define GPKDAT (volatile unsigned long*)0xA0008808


/* 
* 用于段描述符的一些宏定义
 */ 
#define MMU_FULL_ACCESS     (3 << 10)   // 访问权限  AP
#define MMU_DOMAIN          (0 << 5)    // 属于哪个域 Domain
#define MMU_SPECIAL         (1 << 4)    // 必须是1  XN 
#define MMU_CACHEABLE       (1 << 3)    // cacheable C
#define MMU_BUFFERABLE      (1 << 2)    // bufferable B
#define MMU_SECTION         (2)         // 表示这是段描述符 10
#define MMU_SECDESC         (MMU_FULL_ACCESS | MMU_DOMAIN | MMU_SPECIAL | MMU_SECTION)
#define MMU_SECDESC_WB      (MMU_FULL_ACCESS | MMU_DOMAIN | MMU_SPECIAL | MMU_CACHEABLE | MMU_BUFFERABLE | MMU_SECTION)


void create_page_table(void)
{
    unsigned long *ttb = (unsigned long *)0x50000000;
    unsigned long vaddr, paddr;

    vaddr = 0xA0000000;
    paddr = 0x7f000000;
    *(ttb + (vaddr >> 20)) = (paddr & 0xFFF00000) | MMU_SECDESC;  //将虚拟地址A000映射到led所对应的物理地址区间

    vaddr = 0x50000000;
    paddr = 0x50000000;
    while (vaddr < 0x54000000)//64M的区间地址虚拟地址与物理地址映射相同, 或者说相当于没有进行地址转化
    {
        *(ttb + (vaddr >> 20)) = (paddr & 0xFFF00000) | MMU_SECDESC_WB;
        vaddr += 0x100000;
        paddr += 0x100000;
    }

}


void mmu_init()
{
   __asm__(
    
    /*设置TTB Base addr*/
    "ldr    r0, =0x50000000\n"                  
    "mcr    p15, 0, r0, c2, c0, 0\n"    
    
    /*不进行权限检查 Domain*/
    "mvn    r0, #0\n"                   
    "mcr    p15, 0, r0, c3, c0, 0\n"    
    
    
   /*使能MMU*/
    "mrc    p15, 0, r0, c1, c0, 0\n"    
    "orr    r0, r0, #0x0001\n"          
    "mcr    p15, 0, r0, c1, c0, 0\n"    
    : 
    : 
  );
}


int main()
{
    create_page_table();
    mmu_init();

    *(GPKCON) = 0x11110000;
    *(GPKDAT) = 0xa0;

    return 0;    
}

此去经年
zhaiyk@sina.cn
August 10, 2016

相关文章

网友评论

    本文标题:uboot step 11 内存一下子变大了 ----MMU的配

    本文链接:https://www.haomeiwen.com/subject/wqyesttx.html