(具体的实验代码,请参看https://github.com/elvinsys/arm_tq2440/tree/master/1_uboot/1-11.mmu)
一、 MMU的功能解析作用
1. 将虚拟地址转化为物理地址
2. 访问权限的管理
二、 关于MMU的地址转换
1. 地址转化的原理和转换过程(可参看ARM920T手册 Memory Management Unit一节)
三、 MMU的配置与使用
1. 以使用段式转换为例,可将步骤分解为:
1.1 建立一级列表
1.2 写入TTB
1.3 打开MMU
(因为使用了MMU,一级列表存放在0x3000 0000,因此,链接脚本地址改为0x3000 8000,代码搬移地址同样改为0x3000 8000)重要!!!
四、 实验代码(以下代码作用是把GPIO物理地址(0x5600 0000)映射到虚拟地址(0xA000 0000)上)
/* 描述符的宏定义 */
#define pGPBCON (volatile unsigned long *)0xA0000010
#define pGPBDAT (volatile unsigned long *)0xA0000014
#define MMU_FULL_ACCESS (3 << 10) /* 访问权限 */
#define MMU_DOMAIN (0 << 5) /* 属于哪个域 */
#define MMU_CACHEABLE (1 << 3) /* Cacheable */
#define MMU_BUFFERABLE (1 << 2) /* Bufferable */
#define MMU_SPECIAL (1 << 4) /* 必须是1 */
#define MMU_SECTION (2 << 0) /* 段描述符 */
#define MMU_SECDESC (MMU_FULL_ACCESS | MMU_DOMAIN | MMU_SPECIAL | MMU_SECTION)
#define MMU_SECDESC_WB (MMU_FULL_ACCESS | MMU_DOMAIN | MMU_SPECIAL | MMU_SECTION|MMU_CACHEABLE | MMU_BUFFERABLE)
void create_page_table()
{
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;
vaddr = vaddr + 0x100000;
paddr = paddr + 0x100000;
}
}
void mmu_init()
{
__asm__(
/* 设置TTB */
"ldr r0, =0x30000000\n"
"mcr p15, 0, r0, c2, c0, 0\n"
"mvn r0, #0x0\n" /* 不进行权限检查 */
"mcr p15, 0, r0, c3, c0, 0\n"
"mrc p15, 0, r0, c1, c0, 0\n" /* 使能MMU */
"orr r0, r0, #0x0001\n"
"mcr p15, 0, r0, c1, c0, 0\n"
:
:
);
}
int gboot_main()
{
create_page_table();
mmu_init();
*pGPBCON = 0x1540;
*pGPBDAT = 0x75f;
return 0;
}