收藏 分享(赏)

80386 32位段式寻址方式.doc

上传人:天天快乐 文档编号:1143739 上传时间:2018-06-15 格式:DOC 页数:4 大小:169.50KB
下载 相关 举报
80386  32位段式寻址方式.doc_第1页
第1页 / 共4页
80386  32位段式寻址方式.doc_第2页
第2页 / 共4页
80386  32位段式寻址方式.doc_第3页
第3页 / 共4页
80386  32位段式寻址方式.doc_第4页
第4页 / 共4页
亲,该文档总共4页,全部预览完了,如果喜欢就下载吧!
资源描述

1、80386 32 位段式寻址方式80386 是个 32 位 CPU,也就是说它的 ALU 数据总线是 32 位的。我们在前面说过,最自然的地址总线宽度是与数据线一致。当地址总线宽度达到 32 位时,其寻址能力达到了 4G(4 千兆) ,对于内存来说似乎是足够了。所以,如果新设计一个 32 位 CPU 的话,其结构应该是可以做到很简洁、很自然的。但是,80386 却无法做到这一点。作为一个产品系列中的一员,80386 必须维持那些段寄存器,还必须支持实地址模式,在此同时又要能支持保护模式。而保护模式是完全另搞一套,还是建立在段寄存器的基础上以保持风格上的一致,而且还能节约 CPU 内部的资源呢?

2、这对于 Intel 的设计人员无疑又是一次挑战。Intel 选择了在段寄存器的基础上构筑保护模式的构思,并且保留段寄存器为 16 位(这样可以利用原有的四个段寄存器) ,但是却又添加了两个段寄存器 FS 和 GS。为了实现保护模式,光是用段寄存器来确定一个基地址是不够的,至少还得要有一个地址段的长度,并且还需要一些其他的信息,如访问权限之类。所以,这里需要的是一个数据结构,而并非一个单纯的基地址。对此,Intel 设计人员的基本思路是:在保护模式下改变段寄存器的功能,使其从一个单纯的基地址(变相的基地址)变成指向这样一个数据结构的指针。这样,当一条内存指令发出一个内存地址时,CPU 就可以这样

3、来归纳出实际上应该放上数据总线的地址:1. 根据指令的性质来确定应该使用哪一个段寄存器,例如转移指令中的地址在代码段,而取数据指令中的地址在数据段。这一点与实地址模式相同。2. 根据段寄存器的内容,找到相应的“地址段描述结构” 。3. 从地址段描述结构中得到基地址。4. 将指令发出的地址作为位移,与段描述结构中规定的段长度相比,看看是否越界。5. 根据指令的性质和段描述符中的访问权限来确定是否越权。6. 将指令中发出的地址作为位移,与基地址相加而得出实际的“物理地址” 。虽然段描述结构存储在内存中,在实际使用时却将其装载入 CPU 中的一组“影子”结构,而 CPU 在运行时则使用其在 CPU

4、中的 “影子” 。从“保护”的角度考虑,在由(指令给出的)内部地址(或者说“逻辑地址” )转换成物理地址的过程中,必须要在某个环节上对访问权限进行比对,以防止不具备特权的用户程序通过玩弄某些诡计(例如修改段寄存器的内容,修改段描述符的内容等) ,得以非法访问其他进程的空间或系统空间。明白了这个思路,80386 的段式内存管理机制就比较容易理解了(还是很复杂) 。下面就是此机制的实际实现。首先,在 80386 CPU 中增设了两个寄存器:一个是全局性的段描述表寄存器GDTR(global descriptor table register) ,另一个是局部性的段描述表寄存器 LDTR(local

5、 descriptor table register) ,分别可以用来指向存储在内存中的一个段描述结构数组,或者称为段描述表。由于这两个寄存器是新增设的,不存在与原有的指令是否兼容的问题,访问这两个寄存器的专用指令便设计成“特权指令” 。在此基础上,段寄存器的高 13 位(低 3 位另作他用)用作访问段描述表中具体描述结构的下标(index ) ,如图下图所示:GDTR 或 LDTR 中的段描述表指针和段寄存器中给出的下标结合在一起,才决定了具体的段描述表项在内存中的什么地方,也可以理解成,将段寄存器内容的低 3 位屏蔽掉以后与 GDTR 和 LDTR 中的基地址相加得到描述表项的起始地址。因

6、此就无法通过修改描述表项的内容来玩弄诡计,从而起到保护的作用。每个段描述表项的大小是 8个字节,每个描述表项含有段的基地址和段的大小,再加上其他一些信息,其结构下图所示:结构中的 B31B24 和 B23B16 分别是基地址的 bit24bit31 和 bit16bit23 。而L19L16 和 L15L0 则为长度( limit)的 bit16bit19 和 bit0bit15 。其中 DPL 是个 2位的位段,而 type 是一个 4 位的位段。它们所在的整个字节分解下图所示。上面有一个标志位没有提到是 G:解释如下:G:颗粒度(Granularity):指定了限长字段值代表的单元含义。当

7、为 0 时,限长单元值为 1 字节;当该位为 1 时,限长的单元值为 4KB 字节。我们也可以用一段“伪代码”来说明整个段描述结构:typedef structunsigned int base24_31:8; /* 基地址的最高 8 位 */unsigned int g:1; /* granularity,表段的长度单位,0 表示字节,1 表示 4KB */unsigned int d_b:1; /* default operation size,存取方式,016 位,1 32 位 */unsigned int unused:1; /* 固定设置为 0 */unsigned int avl:

8、1; /* avalable,可供系统软件使用 */unsigned int seg_limit_16_19:4; /* 段长度的最高 4 位 */unsigned int p:1; /* segment present,为 0 表示该段的内容不在内存中 */unsigned int dpl:2; /* Descriptor privilege level,访问本段所需权限 */unsigned int s:1; /* 描述项类型,1 表示系统,0 表示代码或数据 */unsigned int type:4; /* 段的类型,与上面的 S 标志位一起使用 */unsigned int base

9、_0_23:24; /* 基地址的低 24 位 */unsigned int seg_limit_0_15:16; /* 段长度的低 16 位 */段描述项;以这里的位段 type 为例, “:4”表示其宽度为 4 位。整个数据结构的大小为 64 位,即 8 个字节。读者一定会问:为什么把段描述项定义成这样一种奇怪的结构?例如,为什么基地址的高 8 位和低 24 位不连在一起?最自然也最合理的解释就是:开始时 Intel 的意图是 24 位地址空间,后来又改成了 32 位地址空间。这也可以从段长度字段也是拆成两节得到印证:当 g 标志位为 1 时,长度的单位为 4KB,而段长度的 16 位的容

10、量是64K,所以一个段的最大可能长度为 64K4K256M,而这正是 24 位地址空间的大小。所以,可以看出,Intel 起先意欲使用 24 位地址空间,不久又意识到应该使用 32 位,但是 80286 已经发售出去了,于是只好修修补补。当时的 Intel 确实给人一种“小脚女人走路”的感觉。每当一个段寄存器的内容改变时(通过 MOV、POP 等指令或发生中断等事件) ,CPU 就把由这段寄存器的新内容决定的段描述项装入 CPU 内部的一个内部的一个 “影子影子 ”描述项描述项 。这样,CPU 中有几个段寄存器就有几个影子描述项,所以也可以看作是对段寄存器的扩充。扩充后的段寄存器分成两部分,一

11、部分是可见的(对程序而言) ,还与原先的段寄存器一样;另一部分是不可见的,就是用来存放影子描述项的空间,这一部分是专供 CPU 内部使用的。在 80386 的段式内存管理的基础上,如果把每个段寄存器都指向同一个描述项,而在该描述项中将基地址设成 0,并将段长度设成最大,这样便形成一个从 0 开始覆盖整个 32 位地址空间的一个整段。由于基地址为 0,此时的物理地址与逻辑地址相同,CPU 放到地址总线上去的地址就是在指令中给出的地址。这样的地址有别于由“段寄存器/ 位移量 ”构成的“层次式 ”地址,所以 Intel 称其为“平面(Flat)地址” 。Linux内核的源代码(更确切地应该说是 gcc)采用平面地址。这里要指出, 平面地址的使用平面地址的使用并不意味着绕过了段描述表、段寄存器这一整套内存管理机制,而只是段式内存管理并不意味着绕过了段描述表、段寄存器这一整套内存管理机制,而只是段式内存管理的一种使用特例的一种使用特例 。

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 企业管理 > 经营企划

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报