X86在段式管理方式下地址形成的机制以及BIOS初始化过程对这种机制的利用Word文档下载推荐.docx
- 文档编号:15747928
- 上传时间:2022-11-15
- 格式:DOCX
- 页数:13
- 大小:106.60KB
X86在段式管理方式下地址形成的机制以及BIOS初始化过程对这种机制的利用Word文档下载推荐.docx
《X86在段式管理方式下地址形成的机制以及BIOS初始化过程对这种机制的利用Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《X86在段式管理方式下地址形成的机制以及BIOS初始化过程对这种机制的利用Word文档下载推荐.docx(13页珍藏版)》请在冰豆网上搜索。
一、x86的地址翻译机制(知识准备)
由于历史原因,在存储管理上,80x86系列的所有cpu都支持段式管理方式(分段方式),并且分段是地址翻译的必经阶段(后面提到的分页是可选的)。
我们把段式地址翻译之前所使用的“段基址:
偏移量”的地址形式,也就是程序员使用的地址形式称为虚拟地址,很显然虚拟地址是二维的。
而虚拟地址经过段翻译后得到的地址称为线性地址,这时的线性地址已经变成平坦的一维的形式了。
如果不分页,这个线性地址就是实际的物理内存地址(简称物理地址)了。
如果启用分页机制,再由分页地址翻译机制将线性地址译成物理内存地址。
最后形成的物理地址显然也是一维的。
整个地址翻译过程可以用下图来表示:
二、关于神秘的A20(知识准备)
上面只提供了一个地址形成机制的理论框架。
接下来我们来看看单就实模式而言,由一个虚拟地址得到相应的物理地址的具体过程是怎样的。
我们知道,8086cpu比较单纯,cpu内部的段寄存器和其它的寄存器宽度都是16位的,只有20根地址线(A0-A19),并且没有什么保护模式和分页一说。
它的段翻译机制使用如下方法将虚拟地址翻译成线性地址:
将16位的段寄存器的值左移4个二进制位(也就是乘以16),再加上16位的偏移地址,形成一个20位的线性地址,由于没有分页机制,所以形成的线性地址也就是实际的物理内存地址了。
但有一个细节,我们不能忽略,那就是8086的20根地址线只能访问1M(220)的地址空间,也就是00000h~FFFFFh。
但8086的这种地址翻译机制却很明显允许我们使用一个段地址是FFFFh偏移地址也是FFFFh的虚拟地址:
FFFFh:
FFFFh。
这个虚拟地址形成的物理地址为FFFF0h+FFFFh=10FFEFh,但这个地址已经超出了1M(它比1M多64K-16字节),由于地址宽度有限,截掉高位的进位,最后形成的物理地址实际上是:
0FFEFh,这种地址循环的地址翻译方式我们称之为wrap-around。
也就是说,程序员访问100000h~10FFEFh之间的内存时,会被处理器自动wrap-around去访问00000h~0FFEFh的内存空间。
这也是后来出现一根特殊的A20地址线的历史根源。
80286出现以后,地址线增加到24根,可以访问到最大16M(224)的物理内存空间,并且有了保护模式,情况变得复杂起来。
Intel在设计80286时提出的目标是,在实模式下,系统所表现的行为应该和8086/8088所表现的完全一样,也就是说,在实模式下,80286以及后续系列,应该和8086/8088完全兼容。
但最终,80286芯片却存在一个BUG:
如果程序员访问100000H-10FFEFH之间的内存,系统将实际访问这块内存,而不是象过去一样重新从0开始。
为了解决上述问题,IBM使用键盘控制器上剩余的一些输出线来管理第21根地址线(从0开始数是第20根,被称为A20Gate)。
如果A20Gate被打开,则当程序员给出100000H-10FFEFH之间的地址的时候,系统将真正访问这块内存区域;
如果A20Gate被禁止,则当程序员给出100000H-10FFEFH之间的地址的时候,系统仍然使用8086/8088的方式。
绝大多数IBMPC兼容机默认的A20Gate是被禁止的。
由于在当时没有更好的方法来解决这个问题,所以IBM使用了键盘控制器来操作A20Gate,但这只是一种黑客行为,毕竟A20Gate和键盘操作没有任何关系。
在许多新型PC上存在着一种通过芯片来直接控制A20Gate的BIOS功能。
从性能上,这种方法比通过键盘控制器来控制A20Gate要稍微高一点。
我们也不难发现,在实模式下即使打开了A20,也只能访问到最大1024K+64K–16Byte的地址空间。
这是由其地址翻译机制的先天因素所决定的。
这正好又给我们展示出一个值得关注的地方。
那就是:
在实模式下,由它的物理地址形成机制(段地址左移4位加偏移)最多只需要21根地址线(原来的20根地址线再加上A20)就能解决寻址问题,但保护模式下可以访问的空间要比这大得多,肯定还需要使用A20以上的地址线,但如果此时A20却关闭了,那会带来什么样的后果呢?
也就是说在进入保护模式时,不打开A20,会出现什么样的情况呢?
首先我们必须明白关闭A20和打开A20是什么样一个意思。
所谓关闭就是将A20恒置0,也就是通过地址翻译机制得到的物理地址对该位不会有影响;
所谓打开就是允许按实际的地址翻译机制得到的物理地址去设置该位。
对于关闭A20的情况,我们只要仔细分析一下地址字,将其第21位恒置0,于是可以得到地址线宽度所决定的地址空间范围内任意的奇数兆段的地址,如1M(00000h~FFFFFh),3M(200000h~2FFFFFh),5M(400000h~4FFFFFh),但却得不到偶数兆段的地址。
所以我们进保护模式之前都要习惯性的开启A20,A20的相关电路虽然不是在CPU内部,但与CPU关系密切,所以就多说了几句。
三、x86处理器在保护模式下的地址翻译(这里主要阐述分段部分的翻译过程,并且主要是为了引入shadowregister,为下面的文章作铺垫)(知识准备)
由于80286只是一个过渡产品,生存时间也很短,不具有很强的代表性,不作为重点讲述,我将重点放在386及其以后的32位处理器(统称为80x86或x86)的寻址上。
32位的x86处理机有了实模式,保护模式和V86模式等三种工作模式,由于启动部分不涉及V86模式,所以对该部分也不作重点讲述。
另外在这里我不详细阐述x86的整个存储系统支持,相关的内容可以在手册上和其它的一些书籍上找到。
我们来看32位保护模式的寻址机制。
为了以最小的篇幅介绍相关的知识点并尽早切入重点问题,我先给出一幅x86保护模式下的地址翻译图:
该地址翻译过程分为两部分,即Segmentation部分(分段部分)和Paging部分(分页部分),其中Paging部分是可选的。
Segmentation部分是必须的,该部分的翻译过程如下:
首先从指定的段寄存器中取出选择子(selector),然后根据selector中的TI位确定是要检索GDT(全局描述符表)还是LDT(局部描述符表)中的描述符,不妨假设是要检索GDT中的描述符,然后再根据GDTR寄存器所指示的GDT的基址以及selector中的index字段所指示的描述符的索引号在GDT中找到相应的描述符,将描述符中的特权级字段DPL与selector的RPL字段进行比较,看是否有越权访问发生,另外还要检查虚拟地址中的偏移量是否超过了描述符中的limit字段所定义的段长限,这些检查都通过后,再将描述符中的段基址Base与虚拟地址中的偏移量offset相加形成线性地址。
为了便于理解,下面提供了selector和段描述符的格式:
上面只是理论上的情况,在实际的实现中对于每个段寄存器都增加了一个相应的shadowregister(称着段描述符高速缓冲寄存器或者影子寄存器),每个shadowregister都用来存一个完整的描述符,这个描述符是与之相关的那个段寄存器所装的selector所指示的描述符,shadowregister的格式如下:
有了shadowregister,就只需要在将选择子载入段寄存器时到描述符表中读一次段描述符,并将其存入shadowregister中,以后只要段寄存器中的选择子不改变,就再也不需要到描述符表中去索引描述符了,而直接使用shadowregister中的描述符形成线性地址,效率大大提高。
但还有一个地方不是很明确,那就是intel似乎从来没有在手册上说过shadowregister的limit字段是32bit的。
实际上,在描述符中的limit字段只有20bit,而是通过一个粒度字段G来说明每个单位是1Byte还是4K,从而达到指示1Mlimit或4Glimit的目的。
那么这个shadowregister中的limit是不是也是20bit,然后由Attribute字段中的粒度位来指示它的单位呢?
也就是说shadowregister中的字段和描述符中的字段是不是完全一样呢?
这还存在一些争议。
不过我个人认为,把shadowregister的limit字段设计成32bit更合理一点,因为在指令执行时需要用到limit的时候非常多,如果每次都从shadowregister中取出20位,然后再取出粒度位计算出一个32bit的limit,这显然在做高频率的重复劳动,还不如直接把shadowregister的limit域设计成32bit,这样只需要在将描述符装入时计算一次,得到一个32bit的limit,以后直接使用就行了。
不过这可能会带来一些兼容性问题,例如在64位处理器的情况下,又会怎么样呢?
需要进一步的分析和研究。
四、x8632位处理器对实模式地址形成机制的模拟(关键)
这些shadowregister对我们很重要。
这种重要性不单单来自效率方面。
如果情况真像我下面所说的那样,那么我们不得不改变原来所固化在脑子里的很多对实模式地址翻译机制的理解。
我们都知道在8086的实模式下是将16位段地址左移4个二进制位再加上16位偏移地址形成20位的物理地址。
而80286及其后续产品在保护模式下是这样形成物理地址的:
理论上是通过虚拟地址中的选择子索引到描述符表中的描述符,再将描述符中的基地址加上虚拟地址中的偏移量形成32位的线性地址(暂不考虑64位的情况),如果不分页,这个线性地址就是物理地址了;
实际情况是,直接使用cpu内部的shadowregister中的描述符而得到线性地址,而不是每次都去访问内存中的描述符表。
那么现在的问题是,这种具有了保护模式的cpu在实模式下是不是也按照8086的方式来形成物理地址呢?
或是自己采用另外一套方案,只是模拟出8086的效果来呢?
很多迹象表明,它选择的是后者。
其中一个最有力的证据就是可以在具有保护模式的x86cpu(286一般先不考虑)的实模式上,不使用任何内存扩展程序的前提下可以访问到4GB的物理内存空间,并且我已经亲手做成了这个实验。
这是怎么回事呢?
难免让人糊涂。
按理说如果保持向前完全兼容的话实模式下是只能访问1M物理内存空间的,就算打开A20,也就再多加64K-16Byte而已,所以说x86cpu对8086在实模式下的行为只是一种模拟,而不是完全相同的。
下面我来谈谈这些具有保护模式的x86cpu是怎样模拟8086的实模式的。
首先从我的实验说起。
我事先构建了一个具有三个描述符的描述符表GDT,其中第一个是NULL描述符,这对x86cpu来说是必须的(至于原因我就不再这里多说了)。
第二个是一个数据段描述符,它的Base被设成0,limit被设成4GB。
第三个是一个代码段描述符,Base被设成准备在保护模式下执行的代码的入口点,limit被设置成64K。
因为我准备切换到保护模式,所以先打开A20,否则不能访问到所有内存地址,这在前面有详细的阐述。
当CR0中的保护模式允许位被打开后,我用一个长跳转(该长跳转后面带的虚拟地址的选择
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- X86 段式 管理 方式 地址 形成 机制 以及 BIOS 初始化 过程 这种 利用
链接地址:https://www.bdocx.com/doc/15747928.html