MMU地址空间映射

MMU地址空间映射

虚拟地址-物理地址

虚拟地址,和芯片位数相关,对于32位芯片,一个指针的大小为4字节,寻址范围为【0x0000,0000 ~ 0xFFFF,FFFF】,寻址范围为4G,也就是说最多能够访问到4G的内存空间。但是实际情况下缺很尴尬,在早期,内存的真实物理容量都很小,通常只有几百兆,在这种情况下,如何让用户拥有4G的寻址空间呢?虽然这是一个假象。可以通过内存映射的方式,为每一个进程都营造出可以访问到4G内存空间的假象。
为什么要使用虚拟地址呢?在单片机上,没有MMU单元,我们都是直接访问的内存物理地址,这样会存在一些问题:

  • 所有程序的资源都是共享的,如果有一个程序崩溃,会造成整个系统崩溃。
  • 用户可以违法使用非法地址,来破坏系统,在有MPU的单片机上,可以做一些内存保护操作
  • 所有程序都必须在不同的地址上运行,这在编译链接时就必须确定好,如果你的操作系统有成千上万的用户,那你还要为他们分配不同的地址,那工作量简直惨不忍睹,我们希望每个应用程序都可以从0开始链接,而且各自的资源相互独立,不能相互访问,只能通过操作系统提供的接口来提供IPC进程间通信的接口

基于如上,我们需要一套机制来实现内存映射机制,在ARM9上引入了MMU,这是实现内存映射的基本硬件单元。

MMU

MMU为内存管理单元,他提供2个功能可以帮助我们实现内存映射

  • 虚拟地址转换到物理地址
  • 地址空间的权限控制

当我们开启MMU后,CPU读取虚拟地址后,经过MMU单元,会硬件自动转换成物理地址,最后访问内存。注意,这是硬件自动完成的,你只需要设置好TTB的基地址就可以了。
映射流程:

  1. cpu获取虚拟地址VA
  2. 读取CP15中的C13将不同进程的相同虚拟地址转换成MVA,修正后的虚拟地址
  3. 读取CP15寄存器的C2寄存器,得到TTB的基地址,注意TTB是存放在物理地址中,在编译链接时确定。
  4. 通过查找页表,最后得到真实的物理地址

前提:
在映射之前,我们首先要做好映射工作,不然MMU根本无法进行地址转换

  • 根据需要映射的空间地址,设置好页表映射
  • 开启MMU

L1级映射

前提:
我们首先要确定我们要怎么映射。
比如说,我的物理地址是从0x5000,0000开始
我们想把虚拟地址4G空间里的高端内存1G空间规定为内核空间,低端3G空间作为用户空间。
我们先进行内核空间映射,我们想把虚拟地址0xC000,00000xFFFF,FFFF,映射到物理地址0x5000,00000x8FFF,FFFF
我们在编译链接时,就指定内核空间的代码和数据段到0xC000,0000开始

映射规则分为两种:

  • 分段
  • 分页

L1级映射为分段映射,映射规则很简单,把4G空间分为4096个段,每一个段大小为1M。
我们定义页表为:

int page_table[4096];

MVA = 0xC000,0000

index_L1 = MVA >> 20;
得到一级页表描述索引
index_L1 = 0xC00
进而得到一级页表描述地址为

PGD = page_table[index_L1];

PGD结构
在这里插入图片描述

低两位为[1:0],表示直接段映射
映射的真实物理地址为:

// 先右移动再左移动,清除低20位
Phy_addr = base + offset = ((PGD>>20)<<20) + MVA[19:0]

物理地址为0x50000000,右移20位得到0x500;
AP,domain,C,B属性不设置,最终得到一级描述符位:0x12
pgd = ((0x500>>20)<<20)+0x12 = 0x5000,0012
我们将pgd的值写入到page_table[0xC00]里去

若低两位为[0:1],表示还有二级映射,也叫粗页表,PGD的高22位[31:10]表示二级页表的基地址

// 地址为32为,需要把低10位清零
PTE_addr = ((PGD>>10)<<10);

L2级映射

二级页表为256个页,一般二级映射的单元为小页,大小为4K,
我们设置二级页表为:

page_table_L2 = PTE_addr

PTE_addr指向一个page_table_L2

index_L2 = MVA[19:12];

得到二级页表描述地址为

PTE = page_table_L2[index_L2];

PTE结构
在这里插入图片描述

低两位一般为[1:XN],表示页面大小为small page为4K
高20位表示base addr
最中的物理地址为:

base = (PTE>>20)<<20
// 先右移动再左移动,清除低12位
Phy_addr = base + offset = ((PTE>>20)<<20) + MVA[11:0]

要实现0xC000,0000 到 0x5000,0000的映射,那么

pte = (0x5000,0000>>20)<<20 + 0x12 = 0x5000,0012
我们将pte的值写入到page_table_L2[index_L2]里去

映射流程

在这里插入图片描述

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值