3.1 MMU介绍

3.1.1 MMU 特性

  内存管理单元(Memory Management Unit)简称MMU,它负责虚拟地址到物理地址的映射,并提供硬件机制的内存访问权限检查。现在的多用户多进程操作系统通过 MMU 使得各个用户进程都拥有自己独立的地址空间。

  地址映射功能使得各进程拥有“看起来”一样的地址空间,内存访问权限的检查可以保护每个进程所用的内存不会被其他进程破坏。

  S3C2440/2410 有如下特性:

  • 与 ARM V4 兼容的映射长度、域、访问权限检查机制
  • 4种映射长度:段(1MB)、大页(64KB)、小页(4KB)、极小页(1KB)
  • 对每段都可以设置访问权限
  • 大页、小页的每个子页(sub-page,即被映射页的 1/4)都可以单独设置访问权限
  • 硬件实现的 16 个域
  • 指令 TLB(含 64 个条目)、数据TLB(含64个条目)
  • 硬件访问页表(地址映射、权限检查由硬件自动进行)
  • TLB 中条目的替换采用 round-robin 算法(也称 cyclic 算法)
  • 可以使无效整个 TLB
  • 可以单独使无效某个 TLB 条目
  • 可以在 TLB 中锁定某个条目,指令 TLB、数据TLB 相互独立  

  一个程序在运行之前,没由必要全部装入内存,而仅需要将那些当前要运行的部分先装入内存,其余部分在用到的时候再从磁盘调入,而当内存耗光时再将暂时不用的部分调出到磁盘。

  再 32 位的CPU系统中,虚拟内存地址范围位 0~ 0xFFFFFFFF,这个地址范围称为虚拟地址空间,其中的某个地址称为虚拟地址。

  与虚拟地址空间、虚拟地址对应的使物理地址空间、物理地址,他们对应实际的内存

  虚拟地址最终需要转换为物理地址才能读写实际的数据,这通过将虚拟地址空间、物理地址空间划分为同样大小的一块块小空间(称为段或页),然后为这两类小空间建立映射关系。由于虚拟地址空间远大于物理空间,有可能多块虚拟地址空间映射到同一块物理地址空间,或者有些虚拟地址空间没有映射到具体的物理地址空间上去(可以在使用到时再映射)。

  • ARM CPU 上的地址转换过程的三个概念

    • VA:Virtual Address,虚拟地址
    • MVA:Modified Virtual Address,变换后的虚拟地址
    • PA:Physical Address,物理地址

  未启动 MMU 时,CPU核、cache、MMU、外设等所有部件使用的都使物理地址

  启动MMU后,CPU核对外发出虚拟地址VA;VA被转换为MVA供cache、MMU使用,再这里 MVA 被转换为 PA;最后使用PA读写实际设备:

  1. CPU核看到的、用到的只是虚拟地址 VA,至于 VA如何最终落实到物理地址 PA 上,CPU核使不理会的
  2. caches 和 MMU 也是看不见 VA 的,他们利用由 MVA 转换得到 PA
  3. 实际设备看不到 VA、MVA,读写它们时使用的是物理地址PA

  MVA 是除 CPU 核外的其他部分看见的虚拟地址

  

3.1.2 地址映射过程

  

  将一个虚拟地址转换为物理地址,由两个办法,用一个确定的数学公式进行转换或用表格存储虚拟地址对应的物理地址。这类表格称为页表(Page table),页面由一个个条目(Entry)组成;每个条目存储了一段虚拟地址对应的物理地址及其访问权限,或者下一级页表的地址。ARM CPU 中使用的是表格。

  S3C2440/2410 最多用到两级页表:以段(Section,1MB)的方式进行转换时只用到一级页表,以页(Page)的方式进行转换时用到两级页表。

  页的大小由 3 种,大页(64KB)、小页(4KB)、极小页(1KB)。

  条目也称为”描述符“(Descriptor),有段描述符、大页描述符、小页描述符、极小页描述符,主要是用来保存相应的段或页的起始物理地址;粗页描述符、细页描述符用来保存二级页表的物理地址。

  转换过程为:

  1. 根据给定的虚拟地址找到一级页表中的条目
  2. 如果此条目是段描述符,则返回物理地址,转换结束
  3. 否则如果此条目是二级页表描述符,继续利用虚拟地址在此二级页表中找到下一个条目
  4. 如果这第二个条目是页描述符,则返回物理地址,转换结束
  5. 其他情况出错

  

  TTB base 代表一级页表的地址,将它写入协处理器 CP15 的寄存器 C2(称为页表基址寄存器)即可。

  

  

3.1.3 权限管理 

  MMU对段和页面进行保护,对段和页面进行保护是由几个因素造成的。它由域的访问控制字段和一级描述符或二级描述符中的 AP 字段,以及 C1 寄存器的 S(表示system),R(表示rom)控制位来共同决定的。
  MMU中的域是指的一些段,大页或者小页的集合。ARM支持最多16个域,每个域的访问控制特性由 CP15 中的寄存器 C3 中的两位来控制。CP15 中的寄存器 C3 的格式如下:

  

   其中每两位控制一个域的访问控制特性,其编码及对应的含义如下:

  

  • 当控制位为00时,此域是没有访问权限的;
  • 当控制位为01时,此时域的属性为“用户”域;
    • 当其域为“用户”域时,存储访问权限控制由AP,S,R来决定。
  • 当控制位为11时,此时域的属性为“系统”域。
    • 当其域为“系统”域时,AP,S,R 的值将会忽略,CPU(无论cpu运行在用户级还是在特权级)可以直接访问存储内容,将不进行存储权限检查。

  当域为“用户”域时,AP,S,R控制访问权限的具体规则如下:

  

  当域为“用户”域时,当CPU运行在“特权级”或“用户级”时,AP,S,R 控制段或页的存储访问权限;

  比如:

  当域为“用户”域时,当CPU运行在“用户级”时,AP=00,S=1,R=0,查表可知,这时CPU没有访问权限;

  当域为“用户”域时,当CPU运行在“特权级”时,AP=00,S=1,R=0,这里CPU只能读存储内容,但不能写,如果写的话将产生错误;

  注意:AP,S,R的决定访问权限的作用只用是在其域为“用户”域的状态。

3.2 编程地址映射

  CPU核只关心 发出地址、读写数据,至于是否是虚拟地址还是物理地址,CPU不关心,至于是什么地址,是后面的设备关心的

  写程序的时候的链接地址,也是没有物理地址和虚拟地址之分,只是单纯的地址,链接地址是CPU看到的

  • MMU 操作:

    • 建立地址映射表格,即建立虚拟地址到物理地址的映射
    • 把表格地址告诉 MMU,即把内存地址告诉 MMU
    • 启动MMU

  mmu.lds

 SECTIONS {
   firtst    0x00000000 : { head.o init.o }
   second    ) { leds.o }
 } 

  head.S

 @*************************************************************************
 @ File:head.S
 @ 功能:设置SDRAM,将第二部分代码复制到SDRAM,设置页表,启动MMU,
 @       然后跳到SDRAM继续执行
 @*************************************************************************       

 .text
 .global _start
 _start:
     ldr sp, =                       @ 设置栈指针,以下都是C函数,调用前需要设好栈,指向 SRAM 的顶端
     bl  disable_watch_dog               @ 关闭WATCHDOG,否则CPU会不断重启
     bl  memsetup                        @ 设置存储控制器以使用SDRAM
     bl  copy_2th_to_sdram               @ 将第二部分代码复制到SDRAM
     bl  create_page_table               @ 设置页表
     bl  mmu_init                        @ 启动MMU
     ldr sp, =0xB4000000                 @ 重设栈指针,指向SDRAM顶端(使用虚拟地址)
     ldr pc, =0xB0004000                 @ 跳到SDRAM中继续执行第二部分代码
 halt_loop:
     b   halt_loop

  init.c

 /*
  * init.c: 进行一些初始化,在Steppingstone中运行
  * 它和head.S同属第一部分程序,此时MMU未开启,使用物理地址
  */ 

 /* WATCHDOG寄存器 */
 #define WTCON           (*(volatile unsigned long *)0x53000000)
 /* 存储控制器的寄存器起始地址 */
 #define MEM_CTL_BASE    0x48000000

 /*
  * 关闭WATCHDOG,否则CPU会不断重启
  */
 void disable_watch_dog(void)
 {
     WTCON = ;  // 关闭WATCHDOG很简单,往这个寄存器写0即可
 }

 /*
  * 设置存储控制器以使用SDRAM
  */
 void memsetup(void)
 {
     /* SDRAM 13个寄存器的值 */
     unsigned long  const    mem_cfg_val[]={ 0x22011110,     //BWSCON
                                             0x00000700,     //BANKCON0
                                             0x00000700,     //BANKCON1
                                             0x00000700,     //BANKCON2
                                             0x00000700,     //BANKCON3
                                             0x00000700,     //BANKCON4
                                             0x00000700,     //BANKCON5
                                             0x00018005,     //BANKCON6
                                             0x00018005,     //BANKCON7
                                             0x008C07A3,     //REFRESH
                                             0x000000B1,     //BANKSIZE
                                             0x00000030,     //MRSRB6
                                             0x00000030,     //MRSRB7
                                     };
     ;
     volatile unsigned long *p = (volatile unsigned long *)MEM_CTL_BASE;
     ; i++)
         p[i] = mem_cfg_val[i];    //32位CPU中,指针移动一次是4个字节
 }

 /*
  * 将第二部分代码复制到SDRAM
  */
 void copy_2th_to_sdram(void)
 {
     unsigned ;      //链接脚本中指定了 led.o 的存放的地址为 2048
     unsigned int *pdwDest = (unsigned int *)0x30004000;  // led.o 存放在 SDRAM 中的地址 

     )
     {
         *pdwDest = *pdwSrc;
         pdwDest++;
         pdwSrc++;
     }
 }

 /*
  * 设置页表
  */
 void create_page_table(void)
 {

 /*
  * 用于段描述符的一些宏定义
  */
 #define MMU_FULL_ACCESS     (3 << 10)   /* 访问权限 */
 #define MMU_DOMAIN          (0 << 5)    /* 属于哪个域 */
 #define MMU_SPECIAL         (1 << 4)    /* 必须是1 */
 #define MMU_CACHEABLE       (1 << 3)    /* cacheable */
 #define MMU_BUFFERABLE      (1 << 2)    /* bufferable */
 #define MMU_SECTION         (2)         /* 表示这是段描述符 */
 #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)
 #define MMU_SECTION_SIZE    0x00100000

     unsigned long virtuladdr, physicaladdr;
     unsigned long *mmu_tlb_base = (unsigned long *)0x30000000;

     /*
      * Steppingstone的起始物理地址为0,第一部分程序的起始运行地址也是0,
      * 为了在开启MMU后仍能运行第一部分的程序,
      * 将0~1M的虚拟地址映射到同样的物理地址
      */
     virtuladdr = ;
     physicaladdr = ;
     *(mmu_tlb_base + (virtuladdr >> )) = (physicaladdr & 0xFFF00000) | \
                                             MMU_SECDESC_WB;

     /*
      * 0x56000000是GPIO寄存器的起始物理地址,
      * GPBCON和GPBDAT这两个寄存器的物理地址0x56000050、0x56000054,
      * 为了在第二部分程序中能以地址0xA0000050、0xA0000054来操作GPFCON、GPFDAT,
      * 把从0xA0000000开始的1M虚拟地址空间映射到从0x56000000开始的1M物理地址空间
      */
     virtuladdr = 0xA0000000;
     physicaladdr = 0x56000000;
     *(mmu_tlb_base + (virtuladdr >> )) = (physicaladdr & 0xFFF00000) | \
                                             MMU_SECDESC;

     /*
      * SDRAM的物理地址范围是0x30000000~0x33FFFFFF,
      * 将虚拟地址0xB0000000~0xB3FFFFFF映射到物理地址0x30000000~0x33FFFFFF上,
      * 总共64M,涉及64个段描述符
      */
     virtuladdr = 0xB0000000;
     physicaladdr = 0x30000000;
     while (virtuladdr < 0xB4000000)
     {
         *(mmu_tlb_base + (virtuladdr >> )) = (physicaladdr & 0xFFF00000) | \
                                                 MMU_SECDESC_WB;
         virtuladdr += 0x100000;
         physicaladdr += 0x100000;
     }
 }

 /*
  * 启动MMU
  */
 void mmu_init(void)
 {
     unsigned long ttb = 0x30000000;

 __asm__(
     "mov    r0, #0\n"
     "mcr    p15, 0, r0, c7, c7, 0\n"    /* 使无效ICaches和DCaches */

     "mcr    p15, 0, r0, c7, c10, 4\n"   /* drain write buffer on v4 */
     "mcr    p15, 0, r0, c8, c7, 0\n"    /* 使无效指令、数据TLB */

     "mov    r4, %0\n"                   /* r4 = 页表基址 */
     "mcr    p15, 0, r4, c2, c0, 0\n"    /* 设置页表基址寄存器 */

     "mvn    r0, #0\n"
     "mcr    p15, 0, r0, c3, c0, 0\n"    /* 域访问控制寄存器设为0xFFFFFFFF,
                                          * 不进行权限检查
                                          */
     /*
      * 对于控制寄存器,先读出其值,在这基础上修改感兴趣的位,
      * 然后再写入
      */
     "mrc    p15, 0, r0, c1, c0, 0\n"    /* 读出控制寄存器的值 */

     /* 控制寄存器的低16位含义为:.RVI ..RS B... .CAM
      * R : 表示换出Cache中的条目时使用的算法,
      *     0 = Random replacement;1 = Round robin replacement
      * V : 表示异常向量表所在的位置,
      *     0 = Low addresses = 0x00000000;1 = High addresses = 0xFFFF0000
      * I : 0 = 关闭ICaches;1 = 开启ICaches
      * R、S : 用来与页表中的描述符一起确定内存的访问权限
      * B : 0 = CPU为小字节序;1 = CPU为大字节序
      * C : 0 = 关闭DCaches;1 = 开启DCaches
      * A : 0 = 数据访问时不进行地址对齐检查;1 = 数据访问时进行地址对齐检查
      * M : 0 = 关闭MMU;1 = 开启MMU
      */

     /*
      * 先清除不需要的位,往下若需要则重新设置它们
      */
                                         /* .RVI ..RS B... .CAM */
     "bic    r0, r0, #0x3000\n"          /* ..11 .... .... .... 清除V、I位 */
     "bic    r0, r0, #0x0300\n"          /* .... ..11 .... .... 清除R、S位 */
     "bic    r0, r0, #0x0087\n"          /* .... .... 1... .111 清除B/C/A/M */

     /*
      * 设置需要的位
      */
     "orr    r0, r0, #0x0002\n"          /* .... .... .... ..1. 开启对齐检查 */
     "orr    r0, r0, #0x0004\n"          /* .... .... .... .1.. 开启DCaches */
     "orr    r0, r0, #0x1000\n"          /* ...1 .... .... .... 开启ICaches */
     "orr    r0, r0, #0x0001\n"          /* .... .... .... ...1 使能MMU */

     "mcr    p15, 0, r0, c1, c0, 0\n"    /* 将修改的值写入控制寄存器 */
     : /* 无输出 */
     : "r" (ttb) );
 }

三、内存管理单元---MMU的更多相关文章

  1. 转 s3c2440硬件学习----内存管理单元MMU

    本篇基本是韦东山书上的 一.内存管理单元MMU介绍 内存管理单元简称MMU,它负责虚拟地址到物理地址的映射,并提供硬件机制的内存访问权限检查.MMU使得每个用户进程拥有自己独立的地址空间,并通过内存访 ...

  2. JZ2440 裸机驱动 第7章 内存管理单元MMU

    本章目标:     了解虚拟地址和物理地址的关系:     掌握如何通过设置MMU来控制虚拟地址到物理地址的转化:     了解MMU的内存访问权限机制:     了解TLB.Cache.Write ...

  3. 第七章 内存管理单元MMU介绍

    7.1 内存管理单元MMU介绍 7.1.1 S3C2410/S3C2440 MMU特性 负责虚拟地址到物理地址的映射,并提供硬件机制的内存访问权限检查 特性: 与ARM V4兼容的映射长度.域.访问权 ...

  4. 内存管理单元--MMU

    现代操作系统普遍采用虚拟内存管理(Virtual Memory Management)机制,这需要处理器中的MMU(Memory Management Unit,内存管理单元)提供支持,本节简要介绍M ...

  5. linux内核(四)内存管理单元MMU

    1,基本概念 一个程序运行时没必要全部都同时装入内存,只需要把当前需要运行的部分装入内存即可,这样就使得一个大程序可以在较小的内存中运行,也使得内存中可以同时装入更多的程序并发执行,从用户角度看,该系 ...

  6. MMU内存管理单元

    arm-linux学习-(MMU内存管理单元) 什么是MMU MMU(Memory Management Unit)主要用来管理虚拟存储器.物理存储器的控制线路,同时也负责虚拟地址映射为物理地址,以及 ...

  7. [转帖]MMU内存管理单元

    MMU内存管理单元 https://www.cnblogs.com/alantu2018/p/9002309.html 之前对这一块一直不理解 最近学习了点 CPU time slice 以及 con ...

  8. 内存管理单元(MMU)和协处理器CP15介绍(转)

    内存管理单元(MMU)和协处理器CP15介绍内存管理单元(MMU)介绍嵌入式系统中,存储系统差别很大,可包含多种类型的存储器件,如FLASH,SRAM,SDRAM,ROM等,这些不同类型的存储器件速度 ...

  9. MMU内存管理单元相关知识点总结

    1.MMU是Memory Management Unit的缩写,中文名是内存管理单元,它是中央处理器(CPU)中用来管理虚拟存储器.物理存储器的控制线路,同时也负责虚拟地址映射为物理地址,以及提供硬件 ...

随机推荐

  1. 好文章之——PHP系列(一)

    注:最近实习的公司是一家做电商企业,后台主要是php开发,好久不怎么接触php的我看了几篇相关文章,提高下对它的认识与理解,发现里面的学习思路还是非常好的,当然也会重新拾一下基础知识啦! 其实自己心中 ...

  2. docker资料---添加阿里docker加速镜像

    首先必须登录阿里云获得加速镜像地址: https://cr.console.aliyun.com/#/accelerator 基于centOS7 cp -n /lib/systemd/system/d ...

  3. [IOI2018]会议——分治+线段树

    题目链接: [IOI2018]meetings 题目大意:有$n$座山峰,每座山峰有一个高度,有$q$次询问,每次需要确定一个开会山峰使$[l,r]$所有山峰上的人都前往开会山峰,一个山峰的人去开会的 ...

  4. Uva821-Floyd

    计算所有页面的平均距离. 用floyd求距离,再求平均 #include <algorithm> #include <cstring> #include <ctype.h ...

  5. springmvc源码解析MvcNamespaceHandler之<mvc:view-resolvers>

    说在前面 本次主要介绍springmvc配置解析. springmvc配置解析 本次介绍MvcNamespaceHandler. 进入到这个方法org.springframework.web.serv ...

  6. JOISC 2017 自然公园

    吐槽 YMD的课件是真的毒,YYB的也很毒. 题目链接 LOJ sol 我是一个一个Subtask做的... Subtask 1 \(O(n^2)\)枚举每两个点有没有边即可. Subtask 2 链 ...

  7. 【dp专题】NOIP真题-DP专题练习

    这里学习一下DP的正确姿势. 也为了ZJOI2019去水一下做一些准备 题解就随便写写啦. 后续还是会有专题练习和综合练习的. P1005 矩阵取数游戏 给出$n \times m$矩阵每次在每一行取 ...

  8. cf757F Team Rocket Rises Again (dijkstra+支配树)

    我也想要皮卡丘 跑一遍dijkstra,可以建出一个最短路DAG(从S到任意点的路径都是最短路),然后可以在上面建支配树 并不会支配树,只能简单口胡一下在DAG上的做法 建出来的支配树中,某点的祖先集 ...

  9. UVALive - 6434 (思维题)

    题目链接:https://vjudge.net/contest/241341#problem/A 题目大意,给你n个数字,让你分成m组,每组的花费为每组的最大值-最小值,总的花费就是各组花费相加,要求 ...

  10. java.sql.SQLException: [Microsoft][ODBC Microsoft Access Driver] 不能使用 '(未知的)';文件已在使用中

    最近查看程序输入的日志时发现一个java连接Access的程序时不时的抛出: java.sql.SQLException: [Microsoft][ODBC Microsoft Access Driv ...