i386 CPU的内存管理机制

1. Intel X86 cpu-8086和8088(16位处理器)

CPU算术逻辑单元ALU宽度为16位(一次能处理16位的数据)。数据总线宽度——16位(一次能传输16位的数据)。地址总线宽度——20位(用20位表示一个地址,一共能表示220个地址,即能直接寻址/确定内存地址的大小为1M)。

问题:16位CPU一次处理的内存指针长度为16位,但地址是20位的,怎么能用16位的数据表示20位才能表示的内存地址?

解决:在CPU内设置四个‘段寄存器’‘:CS、DS、SS和ES,分别指向内存中的’执行指令‘、’数据‘、’堆栈‘、其他。段寄存器16位。用访问内存指令中的16位’内部地址‘ + 16位段寄存器,表示20位的实际地址。

段寄存器16位对应20位实际地址中的高16位,在寻址前,指令中16位内部地址高12位与段寄存器中的16位地址相加,得到20位地址中的高16位;16位内部地址中剩下的低4位保持不变,和前面得到的高16位,一起拼成20位。

段寄存器16位确定一个内存段(64K)的起始地址,内部地址中低4位相当于是段内的偏移量。

2. 80386CPU(实地址 + 保护模式)/(段式内存管理)

ALU和数据总线是32位的。地址总线宽度32位。

虽然32位直接寻址很方便,但之前的CPU不是32位的,Interl的产品得向下兼容啊,不能轻易改变指令集。所以。。。

Interl在段寄存器的基础上构建保护模式。在保留原有四个16位段寄存器的同时,新增了两个16位段寄存器FS和GS。段寄存器不再用于拼凑实际地址,而是存储指向一个特殊数据结构(地址段描述结构)的指针。地址段描述结构中包括内存实际地址、访问权限等信息。


保护模式下的寻址方式

Step1: 根据指令性质,确定该用的段寄存器。内存如:转移指令中的地址在代码段CS,取数指令中的地址在数据段DS。

Step2: 取段寄存器的内容,找到相应的地址段描述结构(8个字节)。

Step3: 从地址段描述结构中得到内存基址

Step4: 安全检查——指令中的地址是段内位移,根据地址段描述结构中段长度,检查是否越界;根据地址段描述结构的访问权限,检查指令是否越权。

Step5: 指令中的段内位移 + 地址段描述结构中内存基址 == 实际物理地址
在这里插入图片描述

每个段寄存器都对应一个地址段描述结构,(本来存在内容中的)地址段描述结构在段寄存器内容变化时加载到CPU,进行寻址。

为了防止通过修改段寄存器内容、修改地址段描述结构内容等,访问其他进程内存空间或系统内存空间,

80386增设了两个寄存器:全局性的段描述表寄存器GDTR(Global Descriptor Table Register)、局部性的段描述表寄存器LDTR(Local Descriptor Table Register),分别指向存在内存中的地址段描述结构数组/段描述表

Step2: 段寄存器的高13位 + GDTR/LDTR中的基地址 == 地址段描述结构的起始地址。

段寄存器的低3位表示使用的是GDTR还是LDTR(1位),以及权限级别(2位)。

GDTR/LDTR的载人和存储指令是“特权指令”,只能在系统状态(操作系统内核)使用,一般用户不能读写GDTR/LDTR,提高了安全性。

引出问题——划分系统状态和用户状态,以及状态切换?

解决:不划分系统状态和用户状态,而是划分4个权限级别,0级最高,3级最低(对应段寄存器低3位中权限级别(2位))。程序的权限级别有其代码段的局部描述结构(由段寄存器CS所指向的局部段描述项)中的dpl字段决定。即:对比段寄存器中的权限和段描述结构中的权限。


平面(Flat)地址:

在上述段式内存管理基础上,如果把所有段寄存器都指向同一个地址段描段从0到232的内存地址空间。基址为0,所以物理地址逻辑地址CPU指令中的地址。

3. i386的页式内存管理机制

段式内存管理机制——指令中的地址 + 段寄存器逻辑地址映射 == 物理地址。

保护模式的实现与段式存储密不可分。

80386的页式内存管理建立在段式管理的基础上,即:页式内存管理是在段式内存管理形成的地址上再加一层地址映射。段式内存管理奖指令中的地址映射成**‘线性地址’**,页式内存管理将线性地址映射成物理地址。

线性地址结构

typedef struct{

	unsigned int dir:10; //页面表目录中的下标,指向一个页面表

	unsigned int page:10; //页面表中的下标,指向一个物理页面

	unsigned int offset:12; //在4k字节物理页面内的偏移量

} 线性地址;

新增寄存器CR3,指向当前页面目录。

从线性地址到物理地址的映射过程

  1. 从***CR3***取***页面目录的基址***;
  2. 以线性地址中***dir位段***为下标,在页面目录中取得相应的***页面表的基地址***;
  3. 以线性地址中***page位段***为下标,在所得页面表中取得相应的***页面描述项***;
  4. 将页面描述项中给出的***页面基址***和线性地址中的***offset位段***相加,得到***物理地址***。
    在这里插入图片描述

目录项中有指向一个页面表的指针,页面项中有指向一个页面起始地址的指针。页面表和页面起始地址总是在4k字节(一个页面4k)的边界上,这些指针的低12位永远为0。因此,在目录项和页面项中,20位用于指针,剩下12位用于控制等。

当页面目录项中ps (page size)位为0时,指向的页面大小为4k字节。从奔腾处理器开始,Intel引入了PSE页面大小扩充机制,当ps位为1时,页面大小为4M字节,而页面表不再使用了。线性地址中低22位全部用作在4M字节页面中的位移。

i386 CPU中还有个寄存器CR0,其最高位PG是页式映射机制的总开关,值为1时开启页式存储的映射机制。

Pentium Pro CPU扩充了物理地址的宽度。在另一个控制寄存器CR4中,增加了一位PAE(Physical Address Extension),值为1时,地址总线宽度为36位(增加了4位)。

From:《Linux内核源代码情景分析》

发布了3 篇原创文章 · 获赞 0 · 访问量 189
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览