Linux中CPU是如何访问到内存的?--MMU最基本原理(转)

什么是MMU?

摘自维基百科:
   内存管理单元(英语:memory management unit,缩写为MMU),有时称作分页内存管理单元(英语:paged memory management unit,缩写为PMMU)。它是一种负责处理中央处理器(CPU)的内存访问请求的计算机硬件。它的功能包括虚拟地址到物理地址的转换(即虚拟内存管理)[1]、内存保护、中央处理器高速缓存的控制,在较为简单的计算机体系结构中,负责总线的仲裁以及存储体切换(bank switching,尤其是在8位的系统上)。
   在开始之前,希望读者简略读过我之前写的一篇文章:

操作系统总结之内存管理(除虚拟内存管理)

以下论述,皆以32位为例

首先,假设页表只有一级:

对于一个有MMU的CPU而言,MMU开启后,CPU是这样寻址的:CPU任何时候,一切时候,发出的地址都是虚拟地址,这个虚拟地址发给MMU后,MMU通过页表来在页表里面查出来这个虚拟地址对应的物理地址是什么,从而去访问外面的内存条。MMU里面的页表地址寄存器,记录了页表本身的存放位置。
在这里插入图片描述
分页存储管理将一个进程的逻辑地址空间(就是虚拟地址空间)分成若干个大小相等的片,称为页面或页,相应地,把内存空间分成与页面相同大小的若干个存储块,称为(物理)块或者页框

现在我们假设每一页的大小是4KB(意思就是将虚拟地址空间和物理地址空间均分为小块(4KB)),如下所示:
在这里插入图片描述
而且假设页表只有一级,这个页表长成下面这个样子,页表的每一行是32个bit 
在这里插入图片描述
当CPU访问虚拟地址0的时候,MMU会去查上面页表的第0行,发现第0行没有命中,于是无论以何种形式(R读,W写,X执行)访问,MMU都会给CPU发出page fault,CPU自动跳到fault的代码去处理fault

CPU访问虚拟地址4KB的时候,MMU会去查上面页表的第1行(4KB/4KB=1),发现第1行命中,(为什么是第一行,在我上一篇文章中有讲到.不过我下面也会提到,先不用着急)如果这个时候

  • 用户是执行读或者执行,则MMU去访问内存条的6MB这个地址,因为页表里面记录该页的权限是RX

  • 用户是去写4KB,由于页表里面第1行记录的权限是RX,没有记录你有写的权限,MMU会给CPU发出page fault,CPU自动跳到fault的代码去处理fault。

当CPU访问虚拟地址8KB+16的时候,MMU会去查上面页表的第2行(8KB/4KB=2),发现第2行命中了物理地址8M,这个时候,MMU会访问内存条的8MB+16这个物理地址。当然,权限检查也是需要的。

当CPU访问虚拟地址3GB的时候,MMU会去查上面页表的第3GB/4KB行,表中记录命中了,查到虚拟地址3GB对应的物理地址是0,于是MMU去访问内存条上的地址0。但是,这个访问分成2种情况:

  • CPU在执行用户态程序的时候,去访问3GB,由于页表里面记录的U+K权限只有K,所以U是没权限的,MMU会给CPU发出page fault,CPU自动跳到fault的代码去处理fault;

  • CPU在执行内核态程序的时候,去访问3GB,由于页表里面记录的U+K权限只有K,所以K是有权限的,MMU不会给CPU发出page fault,程序正常执行。

那么页表究竟是多大呐?

如果页表只有1级,每4KB的虚拟地址空间就需要页表里面的一行(32bit),那么CPU要覆盖到整个4GB的虚拟内存,就需要这个页表的大小是:

4GB/4KB *4 = 4MB

注意:页表是无缝全覆盖虚拟内存!!!你页表不覆盖全,CPU访问虚拟地址的时候,MMU都不知道查哪里了…

也就是说页表的大小取决于虚拟内存的大小,他是根据虚拟内存计算出来的大小.但是物理内存又很小,所以就会导致大部分是空闲的,真正映射的区域几乎是汪洋大海中的小岛

任何一个虚拟地址都是下面的这个样子:
在这里插入图片描述

  • 地址的高20位,作为页表这个表的行号去读对应的页表项.
  • 0~11位为页内偏移,2^12 == 4KB .

上面整个过程,都由MMU硬件自动完成。

现在我们假设在Linux里面有2个进程,一个是QQ,一个是Firefox,他们的页表分别如下:
在这里插入图片描述
在这里插入图片描述
当CPU在执行QQ的时候,Linux会把QQ的页表的物理地址255MB,填入MMU的页表地址寄存器,于是这个时候,QQ的页表生效。根据页表内容,CPU如果访问4KB这个虚拟地址的话,MMU访问内存条的6MB物理地址;CPU如果访问8KB这个虚拟地址的话,MMU访问内存条的8MB物理地址;CPU如果访问3GB这个虚拟地址的话,MMU访问内存条的0MB物理地址;

当CPU在执行Firefox的时候,Linux会把Firefox的页表的物理地址280MB,填入MMU的页表地址寄存器,于是这个时候,Firefox的页表生效,QQ的页表淡出江湖。根据页表内容,CPU如果访问4KB这个虚拟地址的话,MMU访问内存条的100MB物理地址;CPU如果访问8KB这个虚拟地址的话,MMU访问内存条的200MB物理地址;CPU如果访问3GB这个虚拟地址的话,MMU访问内存条的0MB物理地址。

上面我们发现一个共同点,QQ和Firefox去访问3GB虚拟地址的时候,最终MMU访问的都是0MB这个物理地址,具体原因非常简单,QQ和Firefox,这2张页表里面,3GB/4KB这一行,里面填的是完全一样的东东。

为什么3GB的虚拟地址对应的物理地址是是0?

在Linux下为0的低端内存都会直接往3GB线性映射.其余系统看硬件

多级页表

上面我们发现,如果采用一级页表的话,每个进程都需要1个4MB的页表,这个空间浪费还是很大,而且要求连续,这显然是不现实的.于是我们可以采用二级或者三级页表。举例如下,假设我们用地址的高10位作为一级页表的索引,中间10位作为2级页表的索引。CPU访问虚拟地址16,这个地址如果分解为10/10/12位的话,就是这个样子:

在这里插入图片描述

那么MMU会用0这个下标去访问一级页表(一级页表的地址填入MMU的页表地址寄存器)的第0行,第0行的内容写的是2MB(此处不再是最终的物理地址,而是二级页表的物理地址),证明二级页表的地址在2MB,于是MMU自动去以中间的10位作为下标,去查询位置在2MB的二级页表,在2级页表里面,最终查到第0页(地址范围0x00000000~0x00000FFF)这个虚拟地址的物理地址是1GB(这是自己定义的,没有来源),于是MMU去访问内存条的1GB+16这个物理地址。

在这里插入图片描述
据以上分析,1级页表占据的内存是2的10次方,再乘以4,即4KB。而每个二级页表,也是2的10次方,再乘以4,即4KB。分级机制的主要好处是,二级页表不是一定存在了,比如一级页表的第2行不命中,也即如下地址都无效的话:

在这里插入图片描述
那么这一行对应的二级页表,就整个都不需要了,于是就省掉了这段区间4KB二级页表的内存占用。页表当然还有是三级甚至更多(LInux中采用三级页表)。

至于有多级页表的时候,其实MMU也只需要知道一级页表的基地址即可。

每次切换进程的时候,把一级页表的地址重新填入MMU,把新的进程的各个页表激活即可。

一些概念:

  • 虚拟地址:就是逻辑地址,又叫虚地址
  • 分页存储管理将一个进程的逻辑地址空间分成若干个大小相等的片,称为页面或页,相应地,把内存空间分成与页面相同大小的若干个存储块,称为(物理)块或者页框
  • 每个进程一个页表,存放在物理内存.页表的起始地址在进程未执行时,页表的始址和页表长度存放在本进程的PCB中;进程执行时将两个数据装入页表寄存器 。MMU访问它直接通过该页表寄存器(物理地址)访问

转载自:Linux阅码场

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值