当我们说一个CPU是16位或32位时,指的是处理器中算术逻辑单元ALU的宽度;
系统总线中的数据线部分,称为数据总线通常与ALU宽度相同(有例外);
地址总线的宽度,最自然的是和数据总线一致;
从程序设计角度,一个地址-指针,最好与一个整数的长度一致;
出于现实考虑,地址空间太小,导致CPU内部结构的不均匀性。(8位CPU,16位地址)
Intel的16位CPU-8086采用1M的内存地址空间,地址总线的宽度20位;
虽然地址总线的宽度是20位,但CPU中ALU的宽度却只有16位...
Intel设计了一种不失巧妙的方法:
段寄存器基地址<<4 + 内部偏移地址 = 20位总线地址(实地址模式)
但是,通过改变段寄存器的内容,一个进程可以访问内存中的任何一个单元;
不能对一个进程的内存访问加以限制,谈不上对其他进程以及系统本身的保护;
一个CPU如果缺乏对内存访问的限制及保护,就谈不上什么内存管理,也就谈不上什么现代意义的CPU;
Intel-80286开始实现"保护模式",能从实地址模式转入保护模式,逆向却不行;
Intel-32位的80386实现了到现代32位CPU的飞跃;
Intel设计人员的基本思路是:
在保护模式下改变段寄存器的功能,使其从一个单纯的基地址变成一个数据结构(地址段描述结构)的指针,
* 根据指令的性质来确定应该使用哪一个段寄存器,这一点与实地址模式相同
* 根据段寄存器的内容,找到相应的"地址段描述结构"
* 从地址段描述结构中得到基地址
* 将指令中发出的地址作为位移,与段描述结构中规定的段长度相比,看看是否越界
* 根据指令的性质和段描述符中的访问权限来确定是否越权
* 将指令中发出的地址作为位移,与基地址相加得出实际的"物理地址"
从保护的角度看:
在由(指令给出的)内部地址(及逻辑地址)转换成物理地址的过程中,必须要在某个环节上对访问权限进行对比;
80386的段式内存管理机制实现:
* 新增加了2个寄存器,访问它们的专用指令设计成"特权指令":
全局性的段描述表寄存器GDTR(global descriptor table register)
局部性的段描述表寄存器LDTR(local descriptor table register)
分别可以用来指向存储在内存中的一个段描述结构数组(段描述表)
* 无法通过修改描述表项的内容修改内存,起到保护作用
* 每个段描述表项的大小8字节
[ B31 - B24 ] [G][D][A][][L19-L16]
[P][DPL][S][type] [ B23 - B16 ]
[ B15 - B0 ]
[ L15 - L0 ]
B31~B24 : 基地址的 bit16~bit23
B23~B16 : 基地址的 bit24~bit31
L19~L16 : 段长度limit的 bit0~bit15
L15~L0 : 段长度limit的 bit16~bit19
DPL : 2位位段 本段特权
P : 0描述项无定义 1段包含有效基地址和界限
S : 0系统描述相 1代码或数据段描述项
type : 4位位段[E][ED/C][RW][A]
E = 0 数据段
ED 0向上伸展(数据段) 1向下伸展(堆栈段)
W 0不可写入 1可写入
E = 1 代码段
C 0忽视特权级 1遵循特权级
R 0不可读 1可读
段描述结构:
typedef struct {
unsigned int base_24_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 //avaliable,可供系统软件使用
unsigned int seg_limit_16_19:4; //段长度的最高4位
unsigned int p:1; //segment present, [0]该段的内容不在内存中
unsigned int dp1: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位
}descriptor;
?? 如此奇怪 ?? 基地址的高8位和低24位为什么要拆开来 ??
Intel起先打算使用24位地址空间,后来又修修补补~~~~ 2^24 = 2^16 * 4K