本文最后更新于:2020年6月30日 晚上
* 为了给之后的虚拟地址映射总结作准备,本篇先来看看什么是实地址模式、什么是保护模式。。。→_→ *
Intel的CPU发展也是经过技术不断地迭代更新,才有了今天的成就(但依旧逃不掉牙膏厂的美誉。。→_→)。所以在不同的技术时期,其CPU也采用了不同的寻址方式
实地址模式
在80286之前都采用这种寻址重点内容模式。比如在8086中虽然有20位地址总线,但CPU中的ALU的宽度却只有16位。于是为了解决寻址问题,采用了“分段”的方法。在8086 CPU中设置了四个段寄存器“CS、DS、SS、ES”,每个段寄存器都是16位的,对应于地址总线的高16位。每条指令中的逻辑地址也是16位的,所以地址要被送上地址总线之前,其高12位要与对应的段寄存器相加,而低4位不变,即
实际地址 = (段寄存器的值 << 4)+ 逻辑地址
实地址模式也称为实模式,在实模式中没有相应的地址空间保护机制,通过段寄存器可以访问从此开始的64K连续地址空间。而且更改段寄存器的指令没有“特权要求”,所以一个进程可以访问任何一个内存单元
保护模式(Protected Mode)
为了解决实地址模式中的安全问题而设计的一种寻址机制。从80286开始实现了部分保护模式,80386开始完全实现了保护模式与实模式的转化。80386是32位CPU,为了与之前的系列保持一致,保留了16位的段寄存器,增加了两个段寄存器FS、GS。
为了实现保护模式,设计使段寄存器从单纯的基地址变成一个数据结构指针,当一条指令访问内存地址时的步骤如下
根据指令的性质确定使用哪一个段寄存器
根据段寄存器的内容,找到相应的地址段描结构
从地址段描述结构中得到基地址
将指令要访问的地址作为位移,与段描述结构中规定的段长度比较,检查是否越界
根据指令的性质和段描述结构中的访问权限确定是否越权
将指令要访问的内存地址作为位移,与基地址相加得到实际的物理地址
具体实现
在80386中增设两个寄存器:全局性段描述表寄存器GDTR(Global Descriptor Table Register )和局部性段描述表寄存器LDTR(Local Descriptor Table Register )。其用来指向一个存储在内存的段描述结构数组(段描述表)而且访问这两个寄存器的指令是特权指令,这样做是为了防止没有权限的进程修改段寄存器或段描述结构等非法访问操作
图中解释段寄存器的字段含义,根据TI字段选择使用哪一种段描述表寄存器,段寄存器给出的下标和GDTR和LDTR中的基地址相结合,得到段描述表项的基地址
图中解释段描述符表项的字段含义,每个段描述表项为8字节
图中解释段描述符表项的TYPE字段含义
段描述表项的伪代码
- 80386中**四个特权级别,0级最高,3级最低**。每一条指令都有其适用级别,**通常用户程序都是3级,一般程序的运行级别由代码段的局部描述项DPL字段决定,这是由0级状态下的的内核设定的**。当**改变一个寄存器内容时,CPU对权限进行检查,确保该程序的执行权限和段寄存器所制定要求的权限RPL所要访问的内存的权限DPL**typedef struct { unsigned int base24_31:8; /*基地址的高8位 */ unsigned int g:1; /* granularity,表段的长度单位,0表示字节,1表示 4KB */ unsigned int d_b:1; /* default operation size ,存取方式,0表示16位,1表示32位 */ unsigned int unused:1; /*固定设置成0 */ unsigned int avl:1; /* avalaible,可供系统软件使用*/ unsigned int seg_limit_16_19:4; /* 段长度的高4位 */ unsigned int p:1; /* segment present,为0时表示该段不在内存中*/ unsigned int dpl:2; /* Descriptor privilege level,访问本段所需的权限 */ unsigned int s:1; /* 描述项类型,1表示系统,0表示代码或数据 */ unsigned int type:4; /* 段的类型,与S标志位一起使用*/ unsigned int base_0_23:24; /* 基地址的低24位 */ unsigned int seg_limit_0_15:16; /* 段长度的低16位 */ };
* 本篇的内容其实很杂,开始写的时候很纠结如何一篇就说清楚虚拟地址映射,发现比较难。。。所以就先把一些重要的点总结出来。。。→_→ *
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!