内存位置访问无效_CPU是如何访问到内存的?

本文深入探讨了ARM架构Linux下的内存管理单元(MMU)工作原理,详细解释了虚拟地址如何通过页表转换为物理地址。内容涵盖了单级页表和多级页表的机制,以及在进程切换中页表的作用,强调了权限检查和空间优化的重要性。同时,通过QQ和Firefox进程的例子说明了不同进程间的地址空间隔离和页表的使用。
摘要由CSDN通过智能技术生成

讨论的重点

我们知道CPU有地址总线,数据总线和控制总线

数据总线(Data Bus):在CPU与RAM之间来回传送需要处理或是需要储存的数据。

地址总线(Address Bus):用来指定在RAM(Random Access Memory)之中储存的数据的地址。

数据总线是用来传输数据的,假设内存上有一个篮球,这个篮球存放的地址是0x2345,CPU想拿到这个篮球的方法就是通过地址总线发送0x2345告诉内存,内存再通过数据总线把篮球运到CPU里面。

我们这篇文章只讨论ARM架构 Linux下的MMU,不讨论段式寻址,也不讨论有些特殊的芯片直接寻址,技术高明的同学不要抬杠哈。

假设页表只有一级

对于一个有MMU的CPU而言,MMU开启后,CPU是这样寻址的「CPU任何时候,一切时候,发出的地址都是虚拟地址,这个虚拟地址发给MMU后,MMU通过页表来在页表里面查出来这个虚拟地址对应的物理地址是什么,从而去访问外面的内存条。」MMU里面的页表地址寄存器,记录了页表本身的存放位置。c940aba00ddb09aec6a2bc1d07149f7e.png

现在我们假设每一页的大小是4KB,而且假设页表只有一级,这个页表长成下面这个样子,页表的每一行是32个bit。

0552adad43b6d5f385b58341ab37ac8d.png

当CPU访问虚拟地址0的时候,MMU会去查上面页表的第0行,发现第0行没有命中「第0行没有映射物理内存」,于是无论以何种形式(R读,W写,X执行)访问,MMU都会给CPU发出page fault,CPU自动跳到fault的代码去处理fault「这就是我们很多书里面提到的缺页异常处理」。

当CPU访问虚拟地址4KB的时候,MMU会去查上面页表的第1行(4KB/4KB=1),发现第1行命中,如果这个时候

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

2、用户是去写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种情况「用户空间和内核空间访问内核地址」:

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

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

04c76afe07d3958f14bd33d588c64954.png

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

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

所以,这个页表的大小是4MB,覆盖了整个0-4GB的虚拟地址空间,任何一个虚拟地址,都可以用地址的高20位「由于一页是4KB,低12位就是ye内偏移了」,作为页表这个表的行号去读对应的页表项。

这个查水表的过程,由MMU硬件自动完成。现在我们假设在Linux里面有2个进程,一个是QQ,一个是Firefox,他们的页表分别如下:2a6913301b3a0033752999f46cc42f17.png19d805dcbf1037ba549af6df156bdc58.png当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这一行,里面填的是完全一样的东东。

多级页表:真实的存在

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

9bbd84a688098ba07822bce8e36cbe19.png

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

997799b6a43a5c4bd9f7d06738da8c4a.png

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

6c48607316f49fd33e42293c060607e6.png

那么这一行对应的二级页表,就整个都不需要了,于是就省掉了这段区间4KB二级页表的内存占用。页表有一级页表,二级页表甚至三级页表或者更多。至于有多级页表的时候,其实MMU也只需要知道一级页表的基地址即可。每次切换进程的时候,把一级页表的地址重新填入MMU,把新的进程的页表激活即可。

fa966f1cf0e5316d69e69bdc6e2210d3.png

876bd13431164395a020a41cc1b75be2.png

d794238012df55bba98605bdd6431581.png

扫码或长按关注

回复「 加群 」进入技术群聊

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值