s3c6410的MMU使用(用段的方式转化…

1.mmu的介绍
mmu,即Memory Management Unit,内存管理单元。在处理器中,放在cpu和内存之间,有两个作用
(1)转换虚拟内存
(2)设置程序对内存的访问(在裸机阶段,对于处在不同域domain的虚拟地址,可设置不同的权限)

2.s3c6410中的mmu
s3c6410的MMU使用(用段的方式转化)
在6410中,mmu的虚拟地址到物理地址的转化如图,可采用3种方式
按照虚拟地址的[31:20]位的最后两位,当为0b00时,表示这个虚拟地址是无效的
      当为0b01时,表示这个虚拟地址要按粗页(coarse page)的方式转化
      当为0b10时(且18位为0),表示这个虚拟地址要按段(section)的方式转化
      当为0b10时(且18位为1),表示徐哲虚拟地址按supersection的方式转化

今天,我先采用段的方式来设置虚拟地址
s3c6410的MMU使用(用段的方式转化)
当采用段的转化方式时,过程如图所示
首先,我们从一个叫Translation table base(TTB)的地方取高18位,加上虚拟地址的高12位,最后加上00;但是我看到一些其他人的代码,都是TTB的地址直接加上虚拟地址的高12位,最后没有00,我试了之后发现确实是这样,具体为什么,我也不清楚,就先按照这样来。
1.首先,我们要访问一个虚拟地址va(virtual address),然后我们预先设好一个TTB
2.我们把TTB的高20位,加上va的高12位,构成一级描述符地址(First-level descriptor address)
3.通过一级描述符的地址,得知这个虚拟地址对应物理地址的一些特性,在First-level descriptor里面的各个域,我们可以得知一些特性
4.mmu根据一级描述符进行配置后,把一级描述符的高12位加上虚拟地址的[19:0]位得到物理地址

这些过程都是mmu完成的,而我们要做的就是把这个TTB写好

3.采用段的转换方式使用虚拟内存
那要通过一个虚拟地址,实现对LED的控制
首先,我们要制作一个TTB,然后把这个TTB写到cp15协处理器中,告知cp15协处理器,我们的TTB在哪一个位置,当要进行虚拟地址转换时要去哪里找TTB

假设我们写好了TTB,则需要把我们存放TTB的地址告诉cp15协处理器(因为mmu由它管),然后使能mmu
设置TTB地址
s3c6410的MMU使用(用段的方式转化)
我们使用TTB0,内存起始地址为0x50000000,把TTB放在这个地方,则
ldr r0, =0x50000000
mcr p15, 0, r0, c2, c0, 0
然后设置域的访问控制,不进行权限检查
mvn     r0, #0
mcr     p15, 0, r0, c3, c0, 0
最后打开MMU,对c1寄存器的第0位进行配置
s3c6410的MMU使用(用段的方式转化)
mrc p15, 0, r0, c1, c0, 0
orr r0, r0, #0b1
mcr p15, 0, r0, c1, c0, 0
然后回过头来编写者个TTB表
在6410里面,GPIO的地址在外设区,即在0x7f******的位置,加入我们把这一块区域的物理地址的虚拟地址设为0xa0******,则根据一级描述符,我们需要写好一级描述符的内容,即里面的几个域
s3c6410的MMU使用(用段的方式转化)
根据这张表,每一个mmu的域可以控制1MB,其中的各个位如图
首先最后两位为10
[2]表示是否使用缓冲。在MMU和内存之间,为了协调高速cpu和低速内存,则加入了buffer缓冲,这里可以设置,也可以不设置
[3]表示是否使用cache。使用cache可以提高cpu取值得速度,这里可以使用,也可以不使用。
[4]这里写着SBZ(0),但是我实际操作过,写成0会无法完成转化,要写成1.
[8:5]表示对于这部分虚拟地址,要使用那个域,6410一共有16个域可以使用,我们用第0个域
[11:10][9]这几位表示访问权限
s3c6410的MMU使用(用段的方式转化)
我们要设置成可读可写的,则使用APX=0,AP=0b11
[14:12]根据C,B两位来设置
s3c6410的MMU使用(用段的方式转化)
这里设置成0b000

把所有的外设地址都转换成虚拟地址
#define SECTION 0b10
#define BUFFER 0b1<<2
#define CACHE 0b1<<3
#define XN 0b1<<4
#define DOMAIN 0b0<<5
#define AP 0b11<<10

va = 0xa0000000;
pa = 0x7f000000;
while(pa <= 0x7fffffff)
{
*(ttb + (va>>20)) = (pa&0xfff00000) | SECTION | BUFFER | CACHE | XN | DOMAIN | AP;
va += 0x100000;
pa += 0x100000;
}

然后还有一点值得注意的是,我们还要去转化内存所在的地址为虚拟地址,为什么呢?因为我们的程序是要在内存当中运行的,然而我们所运行的程序访问的又是物理地址,所以我们要把内存的地址映射到相同的虚拟地址去
va = 0x50000000;
pa = 0x50000000;
while(pa < 0x54000000)
{
*(ttb + (va>>20)) = (pa&0xfff00000) | SECTION | BUFFER | CACHE | XN | DOMAIN | AP;
va += 0x100000;
pa += 0x100000;
}

而在主程序中,我们就直接使用虚拟地址来配置点亮LED了
#define GPMCON *((unsigned long volatile *)0xa0008820)
#define GPMDAT *((unsigned long volatile *)0xa0008824)

void main()
{
mmu_init();
GPMCON = 0x1111;
GPMDAT = 0x39;
}

下面贴上初始化MMU的代码
#define SECTION 0b10
#define BUFFER 0b1<<2
#define CACHE 0b1<<3
#define XN 0b1<<4
#define DOMAIN 0b0<<5
#define AP 0b11<<10

void creat_TTB()
{
unsigned long *ttb = (unsigned long *)0x50000000;
unsigned long va, pa;
va = 0xa0000000;
pa = 0x7f000000;
while(pa <= 0x7fffffff)
{
*(ttb + (va>>20)) = (pa&0xfff00000) | SECTION | BUFFER | CACHE | XN | DOMAIN | AP;
va += 0x100000;
pa += 0x100000;
}
va = 0x50000000;
pa = 0x50000000;
while(pa < 0x54000000)
{
*(ttb + (va>>20)) = (pa&0xfff00000) | SECTION | BUFFER | CACHE | XN | DOMAIN | AP;
va += 0x100000;
pa += 0x100000;
}
}

void mmu_enable()
{
__asm__(
"ldr r0, =0x50000000\n"
"mcr p15, 0, r0, c2, c0, 0\n"
"mvn r0, #0\n"
"mcr p15, 0, r0, c3, c0, 0\n"
"mrc p15, 0, r0, c1, c0, 0\n"
"orr r0, r0, #0b1\n"
"mcr p15, 0, r0, c1, c0, 0\n"
:
:
);
}

void mmu_init()
{
creat_TTB();
mmu_enable();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值