0x51000000为真实的物理内存地址
上面确定了,猎户座4412想使用异常向量表,只能打开mmu。
-
#include <common.h>
-
#include <mmu.h>
-
-
void mmu_enable(void)
-
{
-
__asm__ __volatile__(
-
"mrc p15, 0, r0, c1, c0, 0\n"
-
"orr r0, r0, #1\n"
-
"mcr p15, 0, r0, c1, c0, 0\n"
-
:::"r0"
-
);
-
}
-
-
void mmu_disable(void)
-
{
-
__asm__ __volatile__(
-
"mrc p15, 0, r0, c1, c0, 0\n"
-
"bic r0, r0, #1\n"
-
"mcr p15, 0, r0, c1, c0, 0\n"
-
:::"r0"
-
);
-
}
-
/*eg:虚拟地址0x123456789想要访问物理地址,则用c2+0x123找到页表对应的条目,取出高12位(&0xfff00000)+0x56789=真实物理地址*/
-
void my_mmap(unsigned int *ttb, unsigned int va, unsigned int pa)
-
{
-
/*页表条目基地址[偏移] = 页表内容,也就是物理地址的高12位 | 2,或2,表示此条目是段映射*/
/*用虚拟地址的前3位来寻找条目的原因:一个条目可以寻址1M,那么3位hex,2^12是4k,4K*1M=4G*/
-
ttb[va >> 20] = (pa & 0xfff00000) | 2;
-
}
-
-
void ttb_init(unsigned int *ttb)
-
{
-
int va, pa;
-
/*va从0开始的原因:就是bootlader起来之后开启MMU想把全部虚拟地址=物理地址*/
/*va每次+0x100000的原因:条目只保存物理地址的高12位,也就是低20位都补0x0~0xfffff(2^20=1M)*/
-
for(va = 0; va < 0x80000000; va += 0x100000){
-
pa = va;
-
my_mmap(ttb, va, pa);
-
}
-
-
__asm__ __volatile__(
-
"mcr p15, 0, %0, c2, c0, 0\n"
-
"mvn r0, #0\n"
-
/*c3寄存器表示虚拟地址的访问权限(读?写?之类),c3寄存器每2位表示一个权限(00,01,10,11)总过有16个,如果段页表条目的5-8位是3,那么就去c3寄存器的第4个去查看相应的权限。*/
-
"mcr p15, 0, r0, c3, c0, 0\n"
-
:
-
:"r"(ttb)
-
:"r0"
-
);
-
}
以下代码是小页映射
-
#include <common.h>
-
#include <mmu.h>
-
-
void mmu_enable(void)
-
{
-
__asm__ __volatile__(
-
"mrc p15, 0, r0, c1, c0, 0\n"
-
"orr r0, r0, #1\n"
-
"mcr p15, 0, r0, c1, c0, 0\n"
-
:::"r0"
-
);
-
}
-
-
void mmu_disable(void)
-
{
-
__asm__ __volatile__(
-
"mrc p15, 0, r0, c1, c0, 0\n"
-
"bic r0, r0, #1\n"
-
"mcr p15, 0, r0, c1, c0, 0\n"
-
:::"r0"
-
);
-
}
-
-
//运行一次映射4K内存
-
//my_mmap(sssss, aaaa, 0x12345000, 0x56789000);
-
void my_mmap(unsigned int *ttb1, unsigned int *ttb2, unsigned int va, unsigned int pa)
-
{
-
ttb1[va >> 20] = ((unsigned int)ttb2 & (~0x3ff)) | 1;
-
ttb2[(va >> 12) & 0xff] = (pa & (~0xfff)) | 2;
-
}
-
-
void ttb_init(unsigned int *ttb1, unsigned int *ttb2)
-
{
-
int va, pa;
-
int va1;
-
/*va从0开始,每次加0x100000和段映射一样,表示0-2G的内容全部映射。而且物理地址和虚拟地址一样*/
-
for(va = 0; va < 0x80000000; va += 0x100000){
-
//0----1M,ttb1[va>>20]就是把0x100000*0-0x100000*0x800>>20位,右移后相当于i=0;ttb1[i++]
-
//figure10-3表明一级页表的内容为二级页表的基地址的高22位|表明是页映射
-
ttb1[va >> 20] = ((unsigned int)ttb2 & (~0x3ff)) | 1;
-
//0-4K 4K-8K 8K-12K 1M
-
/*va1=va是因为外循环一次就映射了1M的物理内存,而pa=va1主要是为了得到正确的物理内存偏移值;va1
-
for(va1 = va; va1 < va + 0x100000; va1 += 0x1000){
-
pa = va1;
-
//求得虚拟地址的中间8位 = 物理地址的高20位
-
ttb2[(va1 >> 12) & 0xff] = (pa & (~0xfff)) | 2;
-
}
-
ttb2 += 0x100;//二级页表每执行一次需要移动256个条目=1k=256*4
-
}
-
-
__asm__ __volatile__(
-
"mcr p15, 0, %0, c2, c0, 0\n"
-
"mvn r0, #0\n"
-
"mcr p15, 0, r0, c3, c0, 0\n"
-
:
-
:"r"(ttb1)
-
:"r0"
-
);
-
}
-
关于对这张表格的理解:
一级页表基地址(Translation table base address)高18位 + 虚拟地址(Vlrtual Address)高12位,查找到一级页表对应的条目,为什么这么说呢?4G空间全部映射为虚拟地址,需要多少个一级页表条目呢(每一个条目代表1M空间)?4G :x个一级条目 = 1M : 1个一级条目。那么x = 1024 *4M/1M = 4096个。也就是说只需要4096=2^12个一级条目就可以表示了4G空间了,而虚拟地址的高12位正好可以寻址,这就对上了。你可能疑惑那一级页表的物理地址的第0和第1位为什么不用呢,这是因为一个条目占用4个字节,地址最后俩位不填,表示4字节对齐。
我们根据虚拟地址和一级页表基地址找到了一级页表中对应的条目,那这个条目里放的是什么东西呢?如上图,放的是二级页表的高22位物理地址,然后用这22位地址 + 虚拟地址的12到19位(8bit)就可以找到二级页表对应的物理地址了。这里的虚拟地址8个bit也是表示偏移,表示每一个一级条目对应2^8=256个二级条目,每一个二级条目表示真实的4K空间大小。然后用二级条目的12到31位 + 虚拟地址的低12位,找到了真实的虚拟地址对应的物理地址,可以精确到每一个字节。
TLB:Translation lookaside buffer,即旁路转换缓冲,或称为缓冲
TTB:Translation Table Base
阅读(4418) | 评论(0) | 转发(0) |