您的位置:首页 > 其它

MMU内存管理单元

2017-02-21 22:55 302 查看
1、MMU(memory management unit)功能解析

将虚拟地址转化为物理地址

//在p1.c
#include<stdio.h>
int a = 1;
void main()
{
while(1)
{
printf("&a = %p,a = %d",&a,a);
sleep(3);
}
}




//在p2.c
#include<stdio.h>
int b= 2;
void main()
{
while(1)
{
printf("&b = %p,b = %d",&b,b);
sleep(3);
}
}




从上面的运行结果来看,两个不同的程序,在相同的地址处,读取的数据不一样。

因为这个地址是虚拟地址,不是实际的物理地址,MMU的功能是对于不同的进程的地址(可能是相同的虚拟地址)进行不同的解析,在实际的内存中给相应的变量分配相应的实际物理地址。

在前面的讲解中,我已将mmu关闭了,在后续要将mmu打开,进行地址的转化。除此之外,mmu还有“访问权限管理”的作用,即控制相应地址的空间是可读还是可写的。

2、深入剖析地址转化

段转换方式(当一级转换列表的最后两位是:10):

虚拟地址的高12位(31:20)作为Translatation table的基地址索引,在这个基地址索引处,它的高12位为段的物理基地址,(0:19)位保存了偏移地址

粗页转换方式(…:01)

细页转换方式 (…:11)

错误(…:00)

引用> http://blog.sina.com.cn/s/blog_63ac1cef0100vd95.html



3、MMU的配置与使用

前面点亮一个LED,是采用物理地址的方式,本节采用MMU虚拟地址的方式来点亮LED。

(虚拟地址空间—–》物理地址空间—(GPIO寄存器等)—》led)

首先MMU要去查一级页表(由工程师建立),并将表的基地址(2440:0x30000000 6410:0x50000000)写到CP15的C2寄存器(需要用的时候在从里面读取),再打开MMU。

所以配置MMU有三项工作:

(1)建立一级页表

(2)写入TTB(Translation Table Base)

(3)使能MMU:由CP15的C1寄存器的第0位(置1)来实现的(通过C嵌入汇编来实现)。

根据段转化的方式,来建立一级页表:



【31:20】为实际物理地址的高12位。



代码如下:

#define GPBCON (volatile unsigned long*)0xA0000010   //使用虚拟地址,真正的物理地址是0x56000010
#define GPBDAT (volatile unsigned long*)0xA0000014

/*
* 用于段描述符的一些宏定义
*/
#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)

void create_page_table(void)
{
unsigned long *ttb = (unsigned long *)0x30000000;  //页表的基地址
unsigned long vaddr, paddr;

vaddr = 0xA0000000;
paddr = 0x56000000;
*(ttb + (vaddr >> 20)) = (paddr & 0xFFF00000) | MMU_SECDESC;

//建立内存的映射,因为程序是存储在内存中的,也需要通过虚拟地址的方式来访问
vaddr = 0x30000000;
paddr = 0x30000000;
while (vaddr < 0x34000000)
{
*(ttb + (vaddr >> 20)) = (paddr & 0xFFF00000) | MMU_SECDESC_WB;//相对于GPIO增加了对缓存cache和write buffer的使用
vaddr += 0x100000; // + 1M
paddr += 0x100000;
}
}

void mmu_init()
{
__asm__(

/*设置TTB,将页表的基地址写到CP15的C2寄存器*/
"ldr    r0, =0x30000000\n"
"mcr    p15, 0, r0, c2, c0, 0\n"

/*不进行权限检查*/
"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 gboot_main()
{
create_page_table();
mmu_init();
//采用虚拟地址方式点亮LED
*(GPBCON) = 0x400;
*(GPBDAT) = 0x0;

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  内存管理