内存管理寄存器
处理器提供了四个内存管理寄存器(GDTR、LDTR、IDTR、TR),用于指定分段内存管理所使用的系统表的基地址。
1 全局描述符表寄存器GDTR
GDTR寄存器用于 存放全局描述符表GDT的32位线性基地址和16位表长度。基地址指定GDT表中字节0在线性地址空间中的地址。
表的长度指明GDT表的字节长度值。 在保护模式初始化的时候,必须给该寄存器加载一个新值。
2 中断描述符寄存器 IDTR
与全局描述符寄存器类似,IDTR存储中断描述符表的IDT的32位基地址,长度表示中描述符表的长度值。
3 局部描述符表寄存器 LDTR
LDTR用于存储局部描述符表LDT的32位线性基地址,16位段限长以及 描述符属性值。
4 任务寄存器 TR
TR寄存器用于存储当前任务TSS段的16位段选择符、32位基地址、16位段长度和描述符属性值。
5 为了进行内存寻址,8086使用了一种称为段 的寻址方式,这种技术把内存分成了一个一个的段,从而要访问内存中的数据,就需要知道段的起始地址和
段内偏移地址。段地址部分使用使用16位的段选择符来表示。段偏移地址使用32位的值来指定,因此段内地址可以使0 - 4G 。程序中使用一个48位的地址或长指针
成为一个逻辑地址。它唯一的确定一个内存对象的段地址和段内偏移地址。
二 地址变换
1 8086的地址变换方式
第一阶段,使用分段机制把程序的逻辑地址变换到处理器可寻址的内存空间(线性地址空间)
第二阶段,使用分页机制把线性地址变为物理地址 。 物理地址: 处理器在其地址总线上能够产生的地址范围。
2 分段提供了隔绝各个代码、数据和堆栈区域的机制,因此多个程序可以运行在同一个处理器上而不会相互干扰。
为了定位指定段中的一个字节,程序必须提供一个逻辑地址。逻辑地址包括一个段选择符和一个偏移量。段选择符是一个
段的唯一标示。
另外段选择符提供了段描述符表中的一个数据结构的偏移量。每个段都有一个段描述符, 段描述符指定段的大小、
访问权限和段的特权级、段类型以及段的第一个字节所在线性地址空间中的位置。逻辑地址的偏移量部分加到段的基地址上就可
以定位段中某个字节的位置。
3 分页机制
分页机制主要目的就是为了,采用虚拟化的技术。
分页和分段都使用了两种不同的地址变换机制,它们对整个地址变换操作提供了独立的处理阶段。
两种机制使用了存储在内存中的变换表,但所用的表结构不同。 实际上段表存储在线性地址空间
,而页表存储在物理地址空间。
三 保护
1 任务之间的保护
8086采用的方法是把每个任务放置在不同的虚拟地址空间中,并给予每个任务不同的逻辑地址到物理地址的变换映射。
每个任务间的地址变换功能被定义成一个任务中的逻辑地址映射到物理地址空间中的一部分区域,而另一个任务映射到物理地址空间
中的另一部分区域 。 每个任务都有各自独立的映射表,当处理器切换去执行一个新任务时,任务切换的关键部分就是切换到新任务的变换表。
2 特权级保护
特权级用数字0 到3 表示,0是最高特权级,3是最低特权级。
四 分段机制
1 每个段由三个参数定义:
(1) 段基地址 ,指定段在线性地址空间中的开始地址。
(2) 段限长 , 虚拟地址空间中段内最大可用偏移位置。
(3) 段属性 , 指定段的属性。 例如该段是否可以读或者写是否可以作为一个程序执行,段的特权级。
上述三个字段存储在段描述符结构项中。 段描述符存储在段描述符表中。段描述符表是包含段描述符的一个数组,
段选择符则是指定表中一个段描述符的位置来指定相应的段。
2 段描述符表
该表是段描述符的一个数组,且有两种描述符表,全局GDT 和 局部 LDT 两种。
3 段选择符
段选择符并不是直接的指向段,而是指向段描述符表中的段描述符。
![](http://www.cppblog.com/images/cppblog_com/jake1036/segment_selector.jpg)
上图为段选择符的结构 。 在编程过程中 , cs ss , ds ,fs , gs ,es等段寄存器存储段选择符。
若要访问某个段的程序,必须已经把段选择符加载到一个段寄存器中。因此,尽管一个系统能够定义很多的段
但是同时只能有6个段可供立即访问。
4 段描述符
每个段描述符是段描述符表的一个数据结构,用于向处理器提供一个段的位置和大小信息以及访问状态的信息。每个段选择符是8个字节。含有
三个主要字段,段基地址、断限长度和段属性。下图为段描述符的一般结构图。8个字节大小
![](http://www.cppblog.com/images/cppblog_com/jake1036/1_200904092346053aWm8.jpg)
4.1 代码段和数据段描述符类型
TYPE字段是不同的。
关于代码段的一致性和非一致性
所谓的“一致代码段”,目的是为了共享,比如该一致代码段的特权级是2,那么即使是特权级是3的代码,也可以访问该一致代码。也就是允许低权限的代码访问 高权限的代码,而成功访问之后,当前的特权级并不是目标代码的特权级,而是原来代码的特权级,也就是说,跳转之后,CPL不变。要注意的是,一致代码段的 DPL的定义,它定义的是允许访问改一致代码段的最高权限,也就是说,如果一个权限比一致代码段中DPL的权限还要高的话,是不允许访问该一致代码段的。
总结:一致代码段的DPL规定了成功访问它的最高权限,高于这个权限的代码不能成功访问它。成功访问一致代码段后,CPL并不会改变,还是保持为原来的权限。这样的设置主要是为了共享,比如一些函数库之类的,而不用受到权限的限制.
对于非一致代码段,要求CPL=DPL,RPL<=DPL.
对于非一致代码段,只允许同特权级的转移
原因:
1.低特权级下不能调用高特权级的代码,即保护高特权级的代码.
2.高特权级下不能调用低特权级的代码,为了避免低特权级代码获得高特权级从而能执行某些系统指令.
1.
一致代码段的转移,转移后的CPL不变
对于非一致代码段的转移与通过调用门转移,转移后的CPL就是段的DPL.
5 分页机制
处理器分页机制将会把 线性地址 转变成 物理地址 。 根据CR0寄存器的PG位,来判断使用分页机制。
一个页面的大小事12位,所以线性地址空间的低12位可以直接作为页内偏移量,即物理地址。分页机制执行的重定位功能可以看做
是把线性地址的高20位,转换到物理地址空间的高20位。
5.1 页表结构
分页功能由驻留在内存中的表来描述,该表称为页表,存放在物理内存空间中。线性到物理地址的映射功能可以看做是进行数组查找,
线性地址空间的高20位构成这个数组的索引值,用于选择对应页面的物理基地址。这就意味着高20位的页面基地址和12位偏移量组合在一起
就能得到对应的物理地址。
5.1.1 两级页表项结构
页表含有2 的20次方个表项,每项占用4字节,要是作为一个表来存放的话,那就占用了4M内存。为了减少内存的使用,8086使用了2 级表。
由此,高20位线性地址地址到物理地址的转换就被分成了两步来进行,每步转换使用其中的10位。
![](http://www.cppblog.com/images/cppblog_com/jake1036/6.jpg)
第一级页表称为页目录表,它存放在1页4KB的页面中,这些表项指向对应的二级表,线性地址空间的最高10位用作一级表中的索引值来选择1024 个二级表。
第二级表项中,存储的是物理地址的高20位。 二级页表使用线性地址空间的中间10位来索引二级页表。二级页表中的20位页面物理基地址再加上最后12位基地址,就构成了最终的物理地址。
其中
CR3指定的页目录表的物理基地址。
页目录表中也有一个属性来决定是否存在对应得二级页表项。也就是说二级页表不一定存在内存中,当需要的时候可以再加入内存。
5.1.2页表项格式
5.1.3 虚拟内存
页表项的一些字段为虚拟内存提供了便利条件,诸如 已访问标志和已修改标志和存在位。