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