CPU的寻址方式(Linux内核情景分析)

来源:互联网 发布:有没有自学java成功的 编辑:程序博客网 时间:2024/06/05 06:46
Intel在8086 CPU中设置了四个“段寄存器”:CS、DS、SS和ES,分别用于可执行代码即指令、数据、堆栈和其他。
每个段寄存器都是16位的,对应于地址总线中的高16位。
每条“访内”指令中的“内部地址”都是16位的,但是在送上地址总线之前都在CPU内部自动地与某个段寄存器中的内容相加,形成一个20位的实际地址。(映射)
段寄存器中的内容对应于20位地址总线中的高16位;
相加时拿内部地址中的高12位与段寄存器中的16位相加;
对于每一个由段寄存器的内容确定的“基地址”,一个进程总是能够访问从此开始的64K字节的连续地址空间,而无法加以限制。(没有地址空间的保护机制)
通过改变段寄存器的内容,一个进程可以随意访问内存中的任何一个单元。
8086的这种内存寻址方式缺乏对内存空间的保护,就称为“实地址模式”。


i386系列的保护模式
同一种系统结构中的改进与加强。
支持实地址模式,又要能支持保护模式。
Intel设计人员的基本思路是:在保护模式下改变段寄存器的功能,使其从一个单纯的基地址变成指向一个数据结构的指针。
(1)根据指令的性质来确定应该使用哪个段寄存器;
(2)根据段寄存器的内容,找到相应的“地址段描述结构”;
(3)从地址段描述结构中的到基地址;
(4)将指令中发出的地址作为位移,与段描述结构中规定的段长度相比,看看是否越界;
(5)根据指令的性质和段描述符中的访问权限来确定是否越权;
(6)将指令中发出的地址作为位移,与基地址相加得到实际的“物理地址”。


段描述结构在实际使用时将其装载入CPU中的一组“影子”结构。


80386CPU中增设了两个寄存器:全局性的段描述表寄存器GDTR(global descriptor table register)和局部性的LDTR(local descriptor table register)。
用来指向存储在内存中的段描述表。
访问这两个寄存器的专用指令设计为“特权指令”。

段寄存器的高13位用作访问段描述表中具体描述结构的下标(index);
TI = 0时使用GDTR, = 1时使用LDTR;
RPL == 00最高级, 11 = 最低级。


GDTR或LDTR中的段描述表指针和段寄存器中给出的下标结合在一起,才决定了具体的段描述表项在内存中的什么地方。


每个段描述表项的大小是8个字节,含有段的基地址和段的大小,再加上其它一些信息。


每当一个段寄存器的内容改变时(通过MOV、POP等指令或发生中断等事件),CPU就把由这段寄存器的新内容所决定的段描述项装入CPU内部的一个“影子”描述项。
CPU中有几个段寄存器就有几个影子描述项。


在80386的段式内存管理基础上,如果把每个段寄存器都指向同一个描述项,而在该描述项中将基地址设为0,并将段长度设成最大,这样便形成了一个从0开始覆盖整个32位地址空间的一个整段。
由于基地址为0,此时的物理地址与逻辑地址相同,CPU放到地址总线上的地址就是指令中给出的地址。


用来装入和存储GDTR和LDTR的指令LGDT/LLDT和SGDT/SLDT等都是特权指令。
用户程序不但不能改变GDTR和LDTR的内容,还无法确知其段描述表在内存中的位置,也无法访问其空间,从而无法通过修改段描述项来打破系统的保护机制。


80386如何分隔系统状态和用户状态
80386划分成四个特权级别,0级为最高,3级为最低,每一条指令都有其适用级别。
LGDT特权指令中有在0级下才能使用,一般的输入/输出指令(IN,OUT)则规定为0级或1级。用户的应用程序都是3级。


一般程序的当前运行级别由其代码段的局部描述项中的dpl字段(descriptor privilege level)决定。
每个描述项中的dpl字段都是在0级状态下由内核设定。


全局段描述的dpl字段表示所需的级别。


i386 CPU中还有中断向量表指针寄存器IDTR、与进程有关的寄存器TR以及描述任务状态的“任务状态段”TSS等。


0 0