MMU也属于操作系统核心部分,主要功能:
a) 通过内存管理单元对每个进程进行不同的物理地址映射,实现了各进程间的相同虚拟地址到独立物理地址空间访问,是操作系统支持多进程的基本,相对多线程操作系统更安全;
b) 当物理内存不够时可以虚拟到外部存储设备,即使当物理内存不够时也能正常运行程序,当然需要足够的外部存储空间,如nand,nor,harddisk等这些外部存储器容量比内存大的多;
c) ARM的中断向量表需要在0地址,一般情况bank0为nor flash,当程序从内存运行时,需要开启MMU,映射中断向量表到0地址,否则中断时程序可能跑飞;
1.设置MMU的页表,页表本身存储在内存中(此示例为:0x32000000):
/*
* 设置页表
*/
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 (0 << 3) /* cacheable */
#define MMU_BUFFERABLE (0 << 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;
volatile unsigned long *mmu_tlb_base = (unsigned long *)0x32000000;
/*
* Steppingstone的起始物理地址为0,第一部分程序的起始运行地址也是0,
* 为了在开启MMU后仍能运行第一部分的程序,
* 将0~1M的虚拟地址映射到同样的物理地址
*/
#if 0
virtuladdr = 0;
physicaladdr = 0;
*(mmu_tlb_base + (virtuladdr >> 20)) = (physicaladdr & 0xFFF00000) | /
MMU_SECDESC_WB;
#endif
/*
* 0x56000000是GPIO寄存器的起始物理地址,
* GPBCON和GPBDAT这两个寄存器的物理地址0x56000010、0x56000014,
* 为了在第二部分程序中能以地址0xA0000010、0xA0000014来操作GPBCON、GPBDAT,
* 把从0xA0000000开始的1M虚拟地址空间映射到从0x56000000开始的1M物理地址空间
*/
virtuladdr = 0x56000000;//0xA0000000;
physicaladdr = 0x56000000;
*(mmu_tlb_base + (virtuladdr >> 20)) = (physicaladdr & 0xFFF00000) | /
MMU_SECDESC;
/*
* SDRAM的物理地址范围是0x30000000~0x33FFFFFF,
* 将虚拟地址0xB0000000~0xB3FFFFFF映射到物理地址0x30000000~0x33FFFFFF上,
* 总共64M,涉及64个段描述符
*/
virtuladdr = 0;//0xB0000000;
physicaladdr = 0x30000000;
while (virtuladdr < 0x04000000) //0xB4000000
{
*(mmu_tlb_base + (virtuladdr >> 20)) = (physicaladdr & 0xFFF00000) | /
MMU_SECDESC_WB;
virtuladdr += 0x100000;
physicaladdr += 0x100000;
}
virtuladdr = 0x30000000;//0xB0000000;
physicaladdr = 0x30000000; //映射到相同物理地址,保证MMU开启后能正确取下条指令,否则跑飞
while (virtuladdr < 0xFF000000) //0xB4000000
{
*(mmu_tlb_base + (virtuladdr >> 20)) = (physicaladdr & 0xFFF00000) | /
MMU_SECDESC_WB;
virtuladdr += 0x100000;
physicaladdr += 0x100000;
}
}
2.ARM通过协处理器p15访问MMU:
MMU_INIT
stmfd sp!,{r0-r4,lr}
mov r0, #0x32000000 ;页表基址
mcr p15, 0, r0, c2, c0, 0
mov r0, #0x00000001 ;开启MMU,注意开启MMU后地址发生变化,为保证CPU能正确取下以条指令,将虚拟地址0x30000000映射到相同的物理地址0x30000000上,否则程序跑飞。
mcr p15,0,r0,c1,c0,0
ldmfd sp!,{r0-r4,pc}
END
3.init.s:
bl create_page_table
bl MMU_INIT
; bl LED_ON
bl Main