实地址模式
当我们说CPU是16位或者32位的,是指处理器中ALU的宽度。系统总线中数据线部分,称为“数据总线”,通常与ALU具有相同的宽度。那么地址总线的宽度最自然的是和数据总线一致,但是,从CPU的寻址能力上来说是不现实的,8位的CPU,如果这样设计,只能访问2的8次方,256个不同的地址单元。所以一般8位CPU的地址总线是16位的,寻址空间为64K。
INTEL 8086的ALU宽度为16位,即数据总线16位,但是地址总线20为,可以寻址空间达到1G,如何设计?
INTEL在8086中设置来四个段寄存器:CS,DS,SS,ES,分别表示指令段,数据段,堆栈段和其他段,每个段寄存器都是16位的。每条“访内”指令中的地址都是16位的,在送入地址总线之前,在CPU内部自动的于某个段寄存器中的内容相加,形成一个20位的地址。
对于每一个由段寄存器内容确定的基地址,一个进程总是能够访问由此开始的64K内容空间,无法加以限制,通过修改段寄存器中的值,一个进程可以访问内存中的任何位置,不受限制。
保护模式
为了实现保护模式,光是用段寄存器来实现基地址是不现实的,至少还要有地址段的长度和一些其他信息,如访问权限等。所以,这里需要一个数据结构,而并非一个单纯的基地址。
- 根据指令的性质来确定应该使用哪个段寄存器,例如转移指令中的地址在代码段,而取数指令中的地址在数据段。
- 根据段寄存器的内容,找到相应的“地址段描述结构”。
- 从地址段描述结构中得到基地址。
- 将指令中发出的地址作为位移,于段描述结构中规定的段长度相比,是否越界。
- 根据指令的性质和段描述符中的访问权限来确定是否越权。
- 将指令中发出的地址作为位移,于基地址相见得到实际的物理地址。
虽然段描述结构存在内存中,在实际使用的时候却将其装载入CPU的一组“影子”结构,而CPU在运行时则使用其在CPU中的影子。从“保护”的角度考虑,在由(指令给出的)内部地址(或者说,逻辑地址)转换成物理地址的过程中,必须要在某个环节上对访问权限进行比对,防止用户程序访问其他进程的空间。
首先要在80386 CPU中增设了两个寄存器:一个全局段描述表寄存器GDTR(global descriptor table register),另一个局部的段描述表寄存器LDTR,分别用来只想存储在内存中的段描述结构数组,或者称为段描述表。
在此基础上,段寄存器的高13位用作访问段描述表中具体描述结构的下表,低3位另作他用。
GDTR或LDTR中的段描述表指针和段寄存器中给出的下表结合在一起,才决定了具体的段描述表项在内存中的位置。每个段描述表项的大小是8个字节,每个描述表项含有段的基地址和段大小,加上一些其他信息。
结构中的B31-B24和B23-B16分别为基地址的bit16~bit23和bit24~bit31,而L19-L16和L15-L0则为段长度的bit0~bit15和bit16~bit19,DPL是个2位的位段,而type是一个4位的位段。
每当一个段寄存器的内容改变(通过MOV,POP等指令或中断事件),CPU就把由这段寄存器的新内容所决定的段描述项装入CPU内部的一个影子描述项。这样,CPU中有几个段寄存器就有几个影子描述项。