Intel X86 CPU系列寻址方式

  Intel所谓的X86体系,是指Intel从16位微处理器8086开始的整个CPU芯片系列,系列中的每种型号都保持与以前的各种型号兼容,主要有8086,8088,80186,80286,80386,80486以及以后各种型号的Pentium芯片。该篇文章主要是结合Linux内核的储存管理对其寻址方式做一些简要的说明。

  在X86体系中,8086和8088是16位的处理器,而从80386开始为32位处理器,80286是从8088到80386,也就是从16位处理器过渡到32位的一个中间过程。80286虽然还是16位的处理器,但是从寻址方式上开始了从“实地址模式”到“保护地址模式”的过渡。

  知识小解:

  1. 当我们说CPU是“16位”或“32位”时,指的是什么?

      指的是处理器中“算术逻辑单元”(ALU全称:Arithmetic Logic Unit)的宽度。系统总线中的数据线部分,称为“数据总线”通常和ALU有着相同的宽度。同样的最自然的地址总线也是与数据总线一致。但是实际中有可能不同。

  2.MMU:内存管理单元,也称为“地址翻译器”,全称为 Memory Manage Unit。

  实地址模式历史发展:

   起初,先从8位CPU的寻址能力的角度来看,这样一个8位的地址只能用来寻访256个不同的地址单元,这显然太小了,实际上也就是不现实的,所以在那个年代就设置成了8位CPU16位的地址总线,这也造成了内部结构不对称的问题。

  后来,当CPU的技术从8位发展到16位之后,本来地址总线的宽度和数据总线的宽度可以一致了,但是现实和历史总是惊人的相似,人们觉得16位的地址总线,也就是寻址范围(64K)还是太小了。那么该增加多少呢???但是结合微型机的应用前景和储存器芯片的价格,Itel决定采用1M(20位),当时已经很大了。

  Itel决定了其16位CPU,即8086中采用1M字节的内存地址空间,地址总线的宽度即为20位,但是我们的CPU的ALU却只有16位!如何解决这个问题呢???

  Itel当时结合MMU,设计了一种“分段”的技术。Itel在8086 CPU中设置了四个“段寄存器”: CS DS SS ES(指令,数据,堆栈,其他),每个段寄存器都是16位的,对于地址总线的高16位。则每条访问指令中的“内部地址”都是高16位这样就实现了从16位的内部地址到20位的实际地址的转换(也称为“映射”

  这种模式的内存管理最大的缺陷就是:没有地址空间的保护机制。对于每一个由段寄存器的内容确定的“基地址”,一个进程总是能够访问从此开始的64K字节的连续地址空间,而无法进行相应的控制。同时可以用来改变段寄存器内容的指令也不是什么“特权指令”,也就是说可以通过改变段寄存器的内容,任何一个进程便可以随心所欲的访问内存中的任何一个单元,而丝毫不受限制。

  不能对一个进程的内存访问加以限制,也就谈不上什么内存管理。于是“保护地址模式”出现了。Intel从80286开始实现了其“保护地址模式”,但是早期的80286只能从实地址模式转入到保护地址模式,却不能从保护地址模式转回实地址模式。随着后来的发展,下面将以80386为例子进行介绍保护地址模式。

  保护地址模式的发展:

   80386是个32位CPU,也就是其ALU数据总线是32位的,当他的地址总线宽度和数据总线一致,即寻址范围到达了4G,它的内存来说似乎已经足够了,那么是否可以重新设计一个32位的CPU呢???答案是肯定的,不能!!!。作为该系列产品中的一员,80386必须维持那些段寄存器,还必须支持实地址模式,与此同时还能支持保护地址模式。这该怎么做呢???

  思路分析:Intel选择了在段寄存器的基础上构建保护模式的构思,并且保留段寄存器为16位(这样才能利用原来的四个段寄存器)同时又添加了两个段寄存器FS和GS。为实现保护模式,光利用一个段寄存器来确定它的基地址是不是够的,至少还得要一个地址段的长度,以及其它的一些权限等信息。所以这里需要设计一个数据结构,而并非一个单纯的基地址。

  解决办法:在保护模式下改变段寄存器的功能,使其从一个单纯的基地址变成指向这样的一个数据结构。这样当一条内存指令发出一个内存地址时,CPU就可以这样来归纳出实际上应该放上数据总线的地址:

① 根据指令的性质,确定使用哪个段寄存器。

② 根据段寄存器的内容,找到相应的地址段描述结构

③ 从地址段描述结构中得到基地址。

④ 将指令中发出的地址作为地址偏移量,与段描述结构中规定的段长度相比,看看是否越界。

⑤ 根据指令的性质和段描述符中的访问权限来确定是否越权。

⑥ 将指令中发出的地址作为偏移,与基地址相加得到相应的物理地址。

  80386的段式内存管理机制

  比较容易理解了。首先,在80386 CPU中增设了两个寄存器:一个全局性的段描述表寄存器GDTR(global descriptortable register),另一个是局部性的段描述表寄存器LDTR(local descriptor table register),分别用来指向储存在内存中的一个段描述结构,称之为“段描述表”,并且访问这两个段寄存器的指令都设置为了“特权指令”。

  在此基础上,段寄存器的高13位用作访问段描述表中具体描述结构的下标(index),如下图:

 

所以:将段寄存器内容的低3位屏蔽掉以后与GDTR或LDTR中的基地址相加得到的描述表象的起始地址。每个段描述表项的大小是8个字节:包含 段的基地址和段的大小,再加上一些其他的信息,如下图:详细介绍(http://www.javashuo.com/article/p-bqqvsfqt-cu.html