2007-3-11 19:11:00 cpu执行第一条指令时情形

系统 1441 0
cpu执行的第一条指令不在内存中,众所周知,内存是由ram组成的 ,而ram不断电,可以保存信息,一旦断电,ram中的信息将会丢失,所以cpu要执行的第一条指令被固化在rom中
以前8086年代,由于内存是1M的,所以rom被编址在1M的最后的64K中,所以它的段地址是0xFFFF0,这样就不至于不ram分成两个部分,就是将cs设置成0XF000,cpu执行的BIOS第一条指令的地址是:0XF000:FFF0H,这样使得固件的地址在寻址空间靠后的位置16个字节处,这是一条跳转指令,向前调转到一个地方,然后开始执行, 启动代码由 jmp F000 : XXXX 中的偏移 XXXX 来把握,如果使用得多, XXXX 就小,使用得少, XXXX 就大,这样使启动代码尽量靠后,而不浪费多余的地址空间,由于地址空间安排在最后,也不会把整个地址空间隔离成两段。
而出现80386以后,内存已经大于1M,所以

如果把冷启动固件编址在 F000h 段内,就会把整个地址空间隔离成不连续的两段,一段是 F000h 以前的地址,一段是 1M 以后的地址,这很不方便。 intel 采用的办法是,还是默认将执行启动代码的 BIOS ROM 编址在系统可寻址空间的最后(如 32 x86 机的话,这段地址就位于 4GB 的最后一个 64K 内),在系统复位时, CPU 进入实模式,并将 CS 寄存器设置成 F000h ,而将它的 shadow register Base 设置成 FFFF0000h (理论上正常情况下 CS F000h 的话,其 shadow register Base 应该设置成 000F 0000h ,但 intel 有意识的将高 12 位触发成 1 了,除了这样他也没有什么好办法让机器一启动就跑道 4GB 那么高的地址上去执行),而偏移量 EIP 置成 0000FFF0h ,所以机器执行的第一条指令的固件安排的物理地址显然就变成了 FFFFFFF0h BIOS 代码和以前还是要兼容的,也就是说此时从 FFFFFFF0h 处取出的还是一条远跳转指令 jmp F000 : XXXX (我跟踪调试过好几款 BIOS ,这里的 XXXX 似乎都是 E05B ),问题随之而来。这个远跳转指令是要更新 CS 寄存器和它的 shadow register 的,也就是说执行这条 jmp F000 : E05B 之后(也就是 CPU 执行第一条指令之后), CS 将被更新成 F000 ,其实 CS 原来就是这个值,这里说不上是更新,但 CS shadow register 就不一样了,它被真正的更新了,它的 Base 域被更新成 000F 0000h 了(高 12 不再具有触发成 1 的功能,那个功能只在机器启动到第一次更新 CS 的内容期间有效)。这个 Base 再加上虚拟地址中的偏移量 E05B ,得到物理地址 000FE05Bh ,这就是 CPU 执行的第二条指令的地址,但是这条指令的地址已经是 1M 以内了。但我们不要忘记,这时的 F000h 段内可不再是 BIOS ROM 了,这一段此时安排的事实上是我们的 RAM 空间,这一段 RAM 需不需要初始化才能使用那还另说,关键是此时此刻这个地方不应该有可以执行的代码才对啊? CPU 第二条指令就跳到这里不是自寻死路吗 ?

似乎走进了死胡同,但我翻阅了很多资料,找到了一点线索。在很久以前出现过一个叫着 Chips & Technoloqies 的公司,他设计出一组被称着 neat 的芯片组, 可以将内存高端的 BIOS ROM 映射到 1M 以内的 RAM 空间里 并且可以使这一段被映射的 RAM 空间具有与 ROM 类似的只读属性。 这个公司后来被 intel 收购。但后来这种映射似乎就成为了一种标准。由于这种映射关系我们有理由相信,机器启动的时候, 4G 的最后一个 64K 里与 1M 的最后一个 64K 里应该具有相同的东西, 所以即使从 FFFFFFF0h 用一条 jmp 跳到 000FE05Bh ,也仍然能够找到正确的代码去执行。

那么 BIOS 接下来要干一些什么事呢?它有很多事情要做,我只举几件有代表性的,其中有两件事是 DRAM 的初始化和 memory sizing 。按理说这个时候 CPU 还处在实模式下, BIOS 还没有办法去确定超过 1M 的内存量。另外还有一件事就是代码和数据拷贝,因为映射到 1M 以内来的 BIOS ROM 容量有限,事实上还有很大一部分没有映射过来,以压缩的形式存放在高端的 ROM 中了, BIOS 1M 以内执行初始化时难免需要将高端的那些内容拷过来使用,这也是不容易做到的。但不要忘了,我们可以使用前面说的将段 break 4G 的方法来做成这几件事。当然,似乎还存在着这样一种可能性,那就是 切换到保护模式 ,这些事情就都可以做了,并且好像没有必要再切换回实模式。情况没有想象中那么简单,从我前面的那个实验看,我切换到保护模式之后只执行了几行非常必要的将段 break 4G 的代码,其他的事情一律不做,因为保护模式下有非常严格的特权检查,并且需要设置 GDT IDT LDT 等一系列的表格,一般的代码是不容易在保护模式下跑起来的,所以想在保护模式下完成整个 BIOS 的初始化,工程过于浩大,几乎等于写一套小型的保护模式操作系统了( FreeBios 可能就是这么干的)。

当然我也有足够多的证据证明我们常用的 BIOS 都使用了这种 break limit 的技术,并且它们完成 break 后都是迅速切换回实模式
---------------------------------------------
                参考了

X86 CPU在段式管理下的地址形成机制以及BIOS初始化过程对这种机制的利用

                   陈英豪   中科院计算所

2007-3-11 19:11:00 cpu执行第一条指令时情形


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论