?
Loop.c的代码是:
Loop.c的代码是:
最后两个程序的运行结果:
我们看到两个程序里的地址是一样的。这是怎么回事呢!?
这就是我们今天的重点:MMU内存管理单元。
?
?
?
?
?
MMU的作用:两个
上面是虚拟地址和物理地址的转化。
在上面的两个程序中,输出的都是虚拟地址,MMU会将虚拟地址转化为对应的物理地址。上面的两个虚拟地址是相同的。为什么转化后会变成不同的物理地址呢?这是因为我们的MMU对于不同的进程,他是有不同的转化和映射关系的。如上图。
?
?
?
?
?
?
?
?
?
?
深入剖析地址转化
?
- 段式转化分析
?
?
?
?
4.细页转化:
?
配置与使用MMU
在上节课中,我们知道我们的MMU能够把我们的虚拟地址映射成我们的物理的地址:
- 段
- 粗页
- 细页
我们以段的方式为例子:
?
高20~31,取出作为表的偏移,TTB,加上后20的虚拟偏移,就是物理地址。
我们要让我们的MMU工作:
- 建立一级页表。
- 写入TTB
- 打开MMU
?
段式映射的20~31位保存的是段的物理基地址的高十二位。12~19位固定是为0的。10-11位AP控制访问权限和domain一起工作的。9位固定为0。第4位固定为1.第三位表示我们访问这段物理区域的时候是否使用cache,B位表示我们是否使用write buffer的。最后两位10是表示段式映射。
AP-10~11位11的时候,都是可读可写的。页表象的位置是物理基地址加上虚拟地址的高12位。
Cp15的c3寄存器是用来控制域的访问权限的:
从最后一行知道,我们可以设置这两位为11,表示当我们去访问物理区间的时候,不用去理他的访问权限。这是简单的设置方法:
Mmu.c的代码:
上面就是我们的mmu.c,然后在Makefile加mmu.o,执行make后就可以烧写测试了。
测试是可行的。
?
Mmu.c的代码:
#define GPKCON (volatile unsigned long*)0xA0008820
#define GPKDAT (volatile unsigned long*)0xA0008824
?
/*
* 用于段描述符的一些宏定义
*/
#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 *)0x50000000;
unsigned long vaddr, paddr;
?
vaddr = 0xA0000000;
paddr = 0x7f000000;
*(ttb + (vaddr >> 20)) = (paddr & 0xFFF00000) | MMU_SECDESC;
?
vaddr = 0x50000000;
paddr = 0x50000000;
while (vaddr < 0x54000000)
{
*(ttb + (vaddr >> 20)) = (paddr & 0xFFF00000) | MMU_SECDESC_WB;
vaddr += 0x100000;
paddr += 0x100000;
}
?
}
?
?
void mmu_init()
{
__asm__(
?
/*设置TTB*/
"ldr r0, =0x50000000\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();
?
*(GPKCON) = 0x1111;
*(GPKDAT) = 0xe;
?
return 0;
}
?
?