mmu内存管理单元

主要功能
虚拟地址(VA)到物理地址(PA)映射
内存保护

概述
一个程序在运行前,没有必要全部装入内存,而仅需要将那些当前需要运行的部分先装入内存,其余部分在用到时再从磁盘读入。当内存耗光时,再将暂时不用的部分调出到磁盘。虚拟存储器从逻辑上对物理内存进行了扩充,对于32位的CPU而言,其虚拟内存为4G,这里以CortexA7内核为例。
MMU的开启是由用户通过配置CP15协处理器实现的,后面会说到。在没有开启MMU之前,内核发出的地址都是物理地址,通过总线传输到DDR控制器以及外设控制器上,实现对物理地址的读写操作,而对于开启了MMU的处理器而言,CPU和发出的地址都是虚拟地址,需要经过MMU的控制转换为实际的物理地址,再传送到DDR控制器实现对物理内存的读写以及对外设控制器等的操作。

地址转换过程

虚拟地址到物理地址的转换是通过地址映射表实现的,系统在初始化内存时,会通过一些指令在内存中填写地址映射表,开启MMU,告诉MMU映射表的位置(基地址,地址映射表的基地址保存在CP15协处理器的C2寄存器中),对于虚拟到物理的转换,MMU通过读取地址映射表来实现最终的转换。
地址映射表又名页表,页表由多级条目(描述符)组成,描述符是32bit的数据组成的,保存物理地址或下一级页表的基地址。对于地址的转换,有段转换方式,页转换方式

段转换

段式转换用到一级页表,也就是存放在内存中的地址映射表有一个。对于32位的CPU,页表中存放了4096个条目(描述符:32bit的数据),也就是这个表格将虚拟内存分为了4096份(4096*1MB=4GB),每份保存一个描述符,每个条目对应1MB的内存地址
在这里插入图片描述
此图为一级页表描述符组成格式,由图可知当bit[1][0]为0b10时,使用的是段转换方式,在段转换方式下

  • bit[1:0] 转换方式位

  • bit[2] 是否使用write buffer

  • bit[3] 表示一段内存是否可以被Cache,即使能后的Cache是否有效

  • bit[8:5] 域选择位,内存保护,决定是否对某块内存进行权限检查

  • bit[15,11:10] AP内存保护,如何对某块内存进行权限检查

  • bit[31:20] 保存物理地址PA的bit[31][20],与VA的bit[19:0]组成转换后的物理地址PA

    以虚拟地址 VA = 0x87800000为例,地址转换的大致过程:

  • 内核发出地址0x8700000,传输到MMU

  • MMU读取CP15协处理器的C2寄存器bit[31:14]得到页表基地址(16K对齐)

  • 取读取到的虚拟地址0x87800000 bit[31:20],得到地址偏移0x878*4

  • 读取一级页表地址(页表基地址+0x878*4)的内容,此内容保存的是段描述符

  • PA = 段描述符bit[31:20] + VA bit[19:0]
    所以最终的物理地址就是PA。

    以段进行映射时,通过VA的bit[31:20]结合页起始地址,得到一段1MB的起始物理地址,通过VA的bit[19:0]在段中寻址

页转换

页转换最少需要用到两级页表,如上图所示,当一级页表描述符bit[1:0]为0b01时,实现的是页转换方式。在该讲解中,没有划分粗页表,细页表,默认的二级页表含有1024个条目,页表的大小有大页(64KB)小页(4KB)之分。因为一级页表一个条目代表1MB的内存空间,所以所以一个二级页表将1MB的内存空间划分为了1024个条目,每个条目为1KB,即每个描述符保存了1KB的物理内存起始地址。
当以页方式转换时,一级页表条目bit[31:10]保存二级页表物理基地址部分位,它和VA的bit[19:12]组成低两位为0的二级页表物理地址,据此可以找到二级页表描述符
在这里插入图片描述
此图为二级页表描述符组成格式,通过bit[1:0]选择大页,小页。大页为64KB,小页为4KB

  • 大页bit[1:0] = 0b01
    因为大页单位是64KB,二级页表每个条目1KB,所以每64个描述符的值相同,表示该64KB的起始地址,bit[31:16]保存PA的bit[31:16],它与VA的bit[15:0]组成最终的32bit物理地址
  • 小页bit[1:0] = 0b10
    因为小页单位是4KB,二级页表每个条目1KB,所以每4个描述符的值相同,表示该4KB的起始地址,bit[31:12]保存PA的bit[31:12],它与VA的bit[11:0]组成最终的32bit物理地址

以虚拟地址 VA = 0x87800001为例,大页地址转换的大致过程如下:

  • 内核发出地址0x8700001,传输到MMU

  • MMU读取CP15协处理器的C2寄存器bit[31:14]得到页表基地址(16K对齐)

  • 取读取到的虚拟地址0x87800001 bit[31:20],得到地址偏移,0x878*4

  • 读取一级页表地址(页表基地址+0x878*4)的内容,此内容保存的是页描述符,假设为0x80000000

  • 一级页表描述符bit[31:10]和VA的bit[19:12]组成低两位为0的二级页表物理地址=0x80000000

  • 根据二级列表物理地址,读取二级列表描述符,假设为0x65511000

  • PA=VA bit[15:0] | 二级列表描述符bit[31:16] = 0x65510001

内存保护

内存保护是MMU的主要功能之一,它决定了一块内存的读写权限。CP15协处理器的c3寄存器(域访问控制)+描述符的域(Domain)+描述符的AP决定了内存的访问权限

  • c3寄存器(域访问控制)
    每两个位决定一个域,一共有16个域,从0~15 ;含义如下

  • Domain

    描述符的Domain位(4bit)对应查找C3寄存器的指定域,如Domain(0b0001),则访问域1,如果域1的值为0b00,则会产生异常;如果值为0b11,如果是段描述符,则通过描述符的AP位进行权限检查,如果是页描述符,则通过二级页表描述符AP位进行权限检查

  • AP
    在这里插入图片描述
    在这里插入图片描述
    更多精彩内容,请关注公众号“LLP学嵌入式”,相互学习!
    在这里插入图片描述

1/*start.S,代码入口*/
  2.global _start
  3_start:
  4    mrs r0,cpsr
  5    bic r0,r0,#0xf1
  6    orr r0,r0,#0x13
  7    msr cpsr,r0 /*工作在SVC模式*/
  8    ldr sp,=0x86000000 /分配栈空间/
  9    b main
 10
 11/*MMU.lds链接脚本*/
 12SECTIONS{
 13    . = 0x87800000;
 14    .text :
 15    {
 16        start.o
 17        main.o
 18        *(.text)
 19    }
 20    .rodata ALIGN(4) : {*(.rodata*)}
 21    .data ALIGN(4) : { *(.data) }
 22    _bss_start = .;
 23    .bss ALIGN(4) :{ *(.bss) *(COMMON)}
 24    _bss_end = .;
 25}
 26
 27/*main.c*/
 28static void create_tlb(unsigned int *ttb,unsigned int va,unsigned pa,unsigned char WB)
 29{
 30    if(WB==1)
 31    {
 32        *(ttb+(va>>20))=(pa&0xfff00000)|MMU_SECDESC_WB;
 33    }
 34    else
 35    {
 36        *(ttb+(va>>20))=(pa&0xfff00000)|MMU_SECDESC;
 37    }
 38}
 39
 40void create_page_table(void) /*创建页表*/
 41{
 42    /*512M DDR MAP*/
 43    unsigned int *ttb = (unsigned int *)0x80000000;
 44    unsigned int va = 0x80000000;
 45    unsigned int pa = 0x80000000;
 46    /*DDR映射的虚拟地址,物理地址不变,512MB*/
 47    for(;va<0xA0000000;va+=0x100000,pa+=0x100000)
 48    {
 49        create_tlb(ttb,va,pa,1);/*Cache ,write buffer有效*/
 50    }
 51    /*register map*/
 52    /*只映射了1MB的物理内存,包含了时钟使能,GPIO控制寄存器地址*/
 53    create_tlb(ttb,0x02100000,0x02000000,0);
 54}
 55
 56static void mmu_init(void)
 57{
 58    __asm__(
 59        "ldr r0,=0x80000000\n"
 60        "mcr p15,0,r0,c2,c0,0\n"  /*设置页表基址寄存器*/        
 61        "ldr r0,=0xffffffff\n"
 62        "mcr p15,0,r0,c3,c0,0\n"  /*域访问控制寄存器为0xffffffff,不进行权限检查,允许任何访问*/
 63        "mrc p15,0,r0,c1,c0,0\n"  /*读取控制寄存器的值*/
 64        "orr r0,r0,#0x0004\n"    /*开启Dcache*/
 65        "orr r0,r0,#0x1000\n"    /*开启Icache*/
 66        "orr r0,r0,#0x0001\n"    /*使能MMU*/
 67        "mcr p15,0,r0,c1,c0,0\n" /*写入c1,使之有效*/ 
 68    );
 69}
 70
 71void delay_short(volatile unsigned int n)
 72{
 73    while(n--){}
 74}
 75
 76void delay(volatile unsigned int ms)
 77{
 78    while(ms--)
 79    {
 80        delay_short(0x7ff*20);
 81    }
 82}
 83
 84void clk_enable(void)
 85{
 86   *((volatile unsigned int *) VA_CCM_CCGR0) = 0xffffffff;
 87   *((volatile unsigned int *) VA_CCM_CCGR1) = 0xffffffff;
 88   *((volatile unsigned int *) VA_CCM_CCGR2) = 0xffffffff;
 89   *((volatile unsigned int *) VA_CCM_CCGR3) = 0xffffffff;
 90   *((volatile unsigned int *) VA_CCM_CCGR4) = 0xffffffff;
 91   *((volatile unsigned int *) VA_CCM_CCGR5) = 0xffffffff;
 92   *((volatile unsigned int *) VA_CCM_CCGR6) = 0xffffffff;
 93}
 94
 95void led_init(void)
 96{
 97   *((volatile unsigned int *)VA_SW_MUX_GPIO1_IO03) = 0x5;
 98   *((volatile unsigned int *)VA_SW_PAD_GPIO1_IO03) = 0x10B0;
 99   *((volatile unsigned int *)VA_GPIO1_GDIR) = 0x0000008;
100   *((volatile unsigned int *)VA_GPIO1_DR)|= (1<<3);//关闭LED
101}
102void led_off()
103{
104   *((volatile unsigned int *)VA_GPIO1_DR)  |= (1<<3);//关闭LED
105}
106void led_on()
107{
108   *((volatile unsigned int *)VA_GPIO1_DR)  &= ~(1<<3);//打开LED
109}
110
111int main(void)
112{
113    create_page_table();/*创建页表*/
114    mmu_init();         /*MMU使能*/
115    clk_enable();       /*操作虚拟地址,使能时钟*/ 
116    led_init();         /*led_init 打开led*/
117    while(1)
118    {
119        led_off();
120         delay(1000);
121        led_on();
122        delay(1000);
123    }
124    return 0;
125}
126
127
128
129/*宏定义*/
130#define CCM_CCGR0           0X020C4068
131#define CCM_CCGR1           0X020C406C
132#define CCM_CCGR2           0X020C4070
133#define CCM_CCGR3           0X020C4074
134#define CCM_CCGR4           0X020C4078
135#define CCM_CCGR5           0X020C407C
136#define CCM_CCGR6           0X020C4080
137
138#define SW_MUX_GPIO1_IO03   0X020E0068
139#define SW_PAD_GPIO1_IO03   0X020E02F4
140
141#define GPIO1_DR                0X0209C000
142#define GPIO1_GDIR            0X0209C004
143#define GPIO1_PSR              0X0209C008
144#define GPIO1_ICR1            0X0209C00C
145#define GPIO1_ICR2            0X0209C010
146#define GPIO1_IMR              0X0209C014
147#define GPIO1_ISR              0X0209C018
148#define GPIO1_EDGE_SEL    0X0209C01C
149
150
151#define VA_CCM_CCGR0           (0X020C4068+0x100000)
152#define VA_CCM_CCGR1           (0X020C406C+0x100000)
153#define VA_CCM_CCGR2           (0X020C4070+0x100000)
154#define VA_CCM_CCGR3           (0X020C4074+0x100000)
155#define VA_CCM_CCGR4           (0X020C4078+0x100000)
156#define VA_CCM_CCGR5           (0X020C407C+0x100000)
157#define VA_CCM_CCGR6           (0X020C4080+0x100000)
158
159#define VA_SW_MUX_GPIO1_IO03   (0X020E0068+0x100000)
160#define VA_SW_PAD_GPIO1_IO03   (0X020E02F4+0x100000)
161
162#define VA_GPIO1_DR                  (0X0209C000+0x100000)
163#define VA_GPIO1_GDIR              (0X0209C004+0x100000)
164#define VA_GPIO1_PSR                (0X0209C008+0x100000)
165#define VA_GPIO1_ICR1              (0X0209C00C+0x100000)
166#define VA_GPIO1_ICR2              (0X0209C010+0x100000)
167#define VA_GPIO1_IMR                (0X0209C014+0x100000)
168#define VA_GPIO1_ISR                (0X0209C018+0x100000)
169#define VA_GPIO1_EDGE_SEL      (0X0209C01C+0x100000)
170
171#define MMU_SECTION_AP                      (0x3<<10)   /*访问权限*/
172#define MMU_SECTION_DOMAIN              (0<<5)      /*属于哪个域*/
173#define MMU_SECTION_SPECIAL            (1<<4)      /*必须是1,决定该区域是否可以执行*/ 
174#define MMU_SECTION_CACHEEABLE      (1<<3)      /*cacheable*/ 
175#define MMU_SECTION_BUFFERABLE      (1<<2)      /*bufferable*/
176#define MMU_SECTION_SECTION            (2)         /*段映射*/ 
177#define MMU_SECDESC    (MMU_SECTION_AP|MMU_SECTION_DOMAIN|MMU_SECTION_SPECIAL|MMU_SECTION_SECTION)
178#define MMU_SECDESC_WB (MMU_SECTION_AP|MMU_SECTION_DOMAIN|MMU_SECTION_SPECIAL|MMU_SECTION_SECTION| \
179                        MMU_SECTION_CACHEEABLE|MMU_SECTION_BUFFERABLE)
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值