x86寻址

看linux内核之前有些i86的基础知识,开始的内存管理就是很不清楚,于是总结一下。主要是看的毛德操的书。

从8088到80386是Intel处理器的一个跨越,后面的各种很牛的处理器虽然性能比386要好的多,但是由于在内存管理上延续了386的方式,所以在这个方面只要看懂386就可以了。其中286是一个过渡的阶段,他实现了实模式到保护模式的转变。

通 常所说的cpu为16位,32位都是说的cpu内部ALU的宽度。同时对于系统总线包括的数据总线很明显要与ALU宽度相同(他要想ALU传数据,那么最 好是相同,否则就复杂了),而地址总线对应了cpu的外部寻址能力,如果和ALU相同,固然是很好实现与操作,但是当cpu是8位的时候就不能满足要求 (只有256个可寻址单元)。也就是说,地址总线与ALU相同保护满足需求,使得采用其他方式来扩大寻址能力。

Intel在此选择了分段的 方式,286前在cpu中增加四个段寄存器(cs,ds,ss,es ),就是我们通常很熟悉的代码段寄存器,数据段寄存器,堆栈段寄存器和扩展段寄存 器。内部的16位地址的高12位与其相对应的段寄存器相加,在将原有的低4位保留,得到了一个20位的寻址能力的地址。这就是286中实模式的方式。显 然,可以通过改变段寄存器的方式访问内存的任一位置,那么对内核的安全将不能保护(这也是保护模式的名称来源)。于是在286以后就采用了一定的方式来避 免内核的得不到保护。

虽然我们可以看到,在386的32总线上,我们可以实现4G访问能力,但是Intel为了节省开发时间,继续使用以前的4个寄存器,就想到了在实模式的基础上实现保护模型的构想,也就使得我们今天学习段式内存管理的根本原因。

从 前面的经验,为什么不能实现保护模式,一个是对基址没有要求,一个对段长度也没有限制,那么想实现就要解决这两个问题。于是在新的方式中,段寄存器不能单 单是个基址,应该是个指向一个数据结构的指针,在指针的位置,说明了基址,说明了段长度,还应该有访问权限,这样就达到了内存保护的目的。实现是在386 中,增加了两个段寄存器:fs和gs。六个段寄存器指向的内存单元作为段指针的“影子”结构,装载在cpu内。

具体实现过程:

增 加两个寄存器:GDTR和LDTR,称为全局段描述表寄存器(glabl descriptor table register)和局部段描述表寄存器,分别指向内存中一个段描述结构数组,称为段描述表。访问这两个寄存器需要特权指令。原有的16位的六个段寄存 器,分为低3位和高13位(8192种选择)。高13位作为描述表结构的下标。下标加指向段描述表的指针决定描述表在内存中的位置。

而段描述表有8个字节,其中规定了段的基址和段长以及其他信息。

每当段寄存器内容发生改变的时候,cpu将对应的六个影子结构也装载到里面。影子结构是对段寄存器的扩充。程序可见的是段寄存器,而影子结构是不可见的。

可 以知道这样的实现是很复杂的,但是如果我们使用一个特例的话将是很方便。将所有段寄存器的都指向同一个描述表,将描述表中的基址变为0,段长度位32的最 大,那么cpu内部地址就是地址总线的地址,这也与开始的想法是一致的。值得说明的是,linux正是使用的这种平坦结构。

更多细节,请参看毛的书!

 

你可能感兴趣的:(linux学习,x86,descriptor,linux内核,数据结构,table,linux)