MMU内存管理单元
2017-02-21 22:55
302 查看
1、MMU(memory management unit)功能解析
将虚拟地址转化为物理地址
从上面的运行结果来看,两个不同的程序,在相同的地址处,读取的数据不一样。
因为这个地址是虚拟地址,不是实际的物理地址,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位。
代码如下:
将虚拟地址转化为物理地址
//在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; }
相关文章推荐
- 内存管理单元 MMU
- 自己学驱动13——内存管理单元MMU(虚拟地址和物理地址)
- 内存管理单元--MMU
- 4, 嵌入式Linux之内存管理单元MMU
- 自己学驱动14——内存管理单元MMU(内存访问权限检查和TLB)
- JZ2440的MMU内存管理单元
- 内存管理单元MMU概述
- MMU内存管理单元
- OK6410(s3c6410)存储之MMU(内存管理单元)
- ARM920T内存管理单元MMU
- 04.ARM-mini2440-内存管理单元(MMU)
- MMU内存管理单元相关知识点总结
- 内存管理单元 MMU
- Mini2440内存管理单元MMU
- OK6410MMU内存管理单元
- s3c2440 内存管理单元MMU学习笔记
- 三、内存管理单元---MMU
- DRAM内存原理(五)内存管理单元MMU
- 嵌入式 linux 第四课 内存管理单元MMU
- ARM4412的MMU内存管理单元