Linux内存寻址之二:逻辑地址到虚拟地址的转换
1.段选择符和分段寄存器 一个逻辑地址包括两部分:段标识符 和 段内相对偏移地址。段标识符是一个被叫做段选择符(selector)的16比特的域,而偏移地址是一个32比特的域。 为了方便快速检索段选择符,处理器提供了6个分段寄存器(segmentation register)来缓存段选择符,它们是:cs,ss,ds,es,fs和gs. 虽然只有这6
1.段选择符和分段寄存器
一个逻辑地址包括两部分:段标识符 和 段内相对偏移地址。段标识符是一个被叫做段选择符(selector)的16比特的域,而偏移地址是一个32比特的域。
为了方便快速检索段选择符,处理器提供了6个分段寄存器(segmentation register)来缓存段选择符,它们是:cs,ss,ds,es,fs和gs. 虽然只有这6个寄存器,但程序可以复用同一个寄存器来实现不同的目的,只需要把该寄存器的内容保存到内存中,在随后需要的时候可以恢复它的内容。需要注意的是,cs、ss、ds有专门的用途。请看下面介绍:
cs-----内存段寄存器,指向含有代码指令的段;cs寄存器还有一个重要的功能:用于区分用户模式和内核模式,它包含一个指定当前优先级别(CPL, current priviledge level)的的2比特的域。如果该域的值为0,表明优先级最高;如果该值为3,表明最低的优先级。 Linux只使用了0和3,用以区分内核模式和用户模式。
ss-----堆栈段寄存器,指向包含当前程序栈的段;
ds-----数据段寄存器,指向包含静态和全局数据的段。
其它三个,即es,fs和gs,都是通用分段寄存器,可以指向任意类型的段。
2.段描述符
每一个段都由一个8字节的段描述符来表示,它描述了段的特征。段描述符要么存储在全局描述符表(GDT)里,要么存储在本地描述符表(LDT)里.
通常只定义了一个GDT。然而,每个进程都允许有自己的LDT,如果进程需要额外创建除了GDT里描述的之外的段。主存里GDT的地址和大小都包含在gdtr控制寄存器中,而当前正在使用的LDT的地址和大小则包含在ldtr控制寄存器中。
BASE:段的第一个字节的线性地址。
G:如果为0,则段的大小用字节表示。
Limit:保存了段中最后一个存储单元的偏移值,因此与segment的长度、大小是绑定在一起的。如果G为0,则LIMIT的大小范围为1字节~1MB;反之, LIMIT大小范围为4KB~4GB.
S:如果为0,表示为一个系统段(system segment);反之,为一个普通的数据段或代码段。系统段里保存了关键的数据结构,如LDT.
Type:描述segment的类型。
DPL:描述符优先级别。主要用于对segment的访问进行限制。
P:描述段是否在内存中存在的标记。
3.对段描述符的快速访问的实现
我们知道,逻辑地址由一个16比特的段选择符和一个32比特的偏移地址组成。同时,我们也知道,分段寄存器里只存储了段选择符。
我们先接着第一节继续对段选择符进行分析。它的格式如下所示:
Index:标记了GDT或LDT中段描述符的入口。由于段寄存器有8个字节长,它在GDT或LDT中的相对地址是这样来计算的:13个bit之长(如上图,比特3-15位)的index域值乘以8. 假设GDT位于0x00020000 (该值存放在gdtr控制寄存器中) 并且 段选择符的index域值为2,那么相应的段描述符的地址是这么来计算的:
0x00020000 +(2 x8),即0x00020010.
TI: table indicator。TI=0,表示段描述符位于GDT中;TI=1,表示段描述符位于LDT中。
RPL:Requestor Previlige Level请求者优先级。
为了加快逻辑地址到线性地址的转换过程,80x86增加了一个不可编程的寄存器。
每当一个段选择符被加载到分段寄存器中时,相应的段描述符也被从内存里加载到那个匹配的不可编程的CPU寄存器中。这样,逻辑地址的转换就不再需要访问主内存中的GDT和LDT,而只需要访问那个包含段描述符的不可编程的寄存器。只有在分段寄存器内容改变时,才需要访问LDT或GDT。
3.分段单元实现逻辑地址到线性地址的转换
我们知道,内存管理单元(MMU)可通过一个叫做分段单元(segmentation unit)的硬件电路,将逻辑地址转换成线性地址;接着,通过一个叫做分页单元(paging unit)的电路,再将线性地址转换成物理地址。如下图所示:
那么,这个分段单元是按照什么样的流程完成自己的职责所在呢?
首先,它会检查段选择符的TI域,进而知道是哪个描述表存放了相应的段描述符。如果段描述符位于GDT,则分段单元从gdtr寄存器中读取GDT的线性基地址;否则,分段单元从ldtr读取LDT的线性基地址。
其次,根据上一步得到的线性基地址和段选择符的index域,计算出段描述符的地址。计算方法可参考上节。
通过以上两步,我们就可以定位到我们需要的段描述符。
最后,把逻辑地址的偏移与前面定位到的段描述符的线性地址BASE域相加,得到线性地址。这样,整个逻辑地址到线性地址的转换过程就成了
地址转换的过程如下图所示:
注意,本文中的线性地址跟虚拟地址是一个概念。如有不懂,请参阅我的上一篇文章。
Smith先生翻译版权所有,如需转载,请注明出处:http://blog.csdn.net/acs713/article/details/7950622
更多推荐
所有评论(0)