CPU执行第一条指令时情形

CPU执行第一条指令时情形

 

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编址在系统可寻址空间的最后(如32x86机的话,这段地址就位于4GB的最后一个64K内),在系统复位时,CPU进入实模式,并将CS寄存器设置成F000h,而将它的shadow registerBase设置成FFFF0000h(理论上正常情况下CSF000h的话,其shadow registerBase应该设置成000F0000h,但intel有意识的将高12位触发成1了,除了这样他也没有什么好办法让机器一启动就跑道4GB那么高的地址上去执行),而偏移量EIP置成0000FFF0h,所以机器执行的第一条指令的固件安排的物理地址显然就变成了FFFFFFF0hBIOS代码和以前还是要兼容的,也就是说此时从FFFFFFF0h处取出的还是一条远跳转指令jmpF000 : XXXX(我跟踪调试过好几款BIOS,这里的XXXX似乎都是E05B),问题随之而来。这个远跳转指令是要更新CS寄存器和它的shadowregister的,也就是说执行这条jmp F000 : E05B之后(也就是CPU执行第一条指令之后),CS将被更新成F000,其实CS原来就是这个值,这里说不上是更新,但CSshadowregister就不一样了,它被真正的更新了,它的Base域被更新成000F0000h了(高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的初始化和memorysizing。按理说这个时候CPU还处在实模式下,BIOS还没有办法去确定超过1M的内存量。另外还有一件事就是代码和数据拷贝,因为映射到1M以内来的BIOSROM容量有限,事实上还有很大一部分没有映射过来,以压缩的形式存放在高端的ROM中了,BIOS1M以内执行初始化时难免需要将高端的那些内容拷过来使用,这也是不容易做到的。但不要忘了,我们可以使用前面说的将段break4G的方法来做成这几件事。当然,似乎还存在着这样一种可能性,那就是切换到保护模式,这些事情就都可以做了,并且好像没有必要再切换回实模式。情况没有想象中那么简单,从我前面的那个实验看,我切换到保护模式之后只执行了几行非常必要的将段break4G的代码,其他的事情一律不做,因为保护模式下有非常严格的特权检查,并且需要设置GDTIDTLDT等一系列的表格,一般的代码是不容易在保护模式下跑起来的,所以想在保护模式下完成整个BIOS的初始化,工程过于浩大,几乎等于写一套小型的保护模式操作系统了(FreeBios可能就是这么干的)。

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

 

---------------------------------------

 

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

                   陈英豪  中科院计算所

 

 

 

对于BIOS的一些质疑解答:

 

1.      而这里之后我开始不明白了。JMP要跳转到的位置是在高地址(4G末端)Flash Rom BIOS中还是在低地址(1M末端)的shadow BIOS呢?

2.位于低地址(1M处)的(BIOS shadow)是从Flash BIOS拷贝而来呢,还是没有任何拷贝过程仅仅利用地址映射到原Flash BIOS中的呢?

3  无论是拷贝还是映射,内存地址空间上ROM BIOS映射区只有 0xF0000~0x100000之间的64KB。而ROM本身有可能大于2M。那映射的应该是原BIOS程序的一部分,那么是哪一部分呢?

 

对这些问题的回答需要阐明机关概念:

1.     机器加电时,内存控制器还没有初时化,内存是不可用。(李皓:这是对的)

2.  机器加电时,对CPU的指令的解码不是北桥,CPU发出的地址被传递到南桥并由FHW (Firmware Hub)解码到BIOS ROM芯片(Flash)。在加电时一直到引导进程初,BIOSE(0xE0000~0xEFFFF)F(0xF0000~0xFFFFF)4G内存顶端的对应段0xFFFE0000 ~0xFFFEFFFF0xFFFF0000 ~0xFFFFFFFF都被FWH解码到BIOSROM芯片的两个64区域。即在启动阶段访问0xE0000~0xEFFFF0xFFFE0000~0xFFFEFFFF是同一个BIOS区域,访问0xF0000~0xFFFFF0xFFFF0000~0xFFFFFFFF是同一个BIOS区域。

3.     机器加电时,CS段寄存器值为0xF000,EIP值为0x0000FFF0,但CPU的取的地址是段寄存器不可见的部分(影子寄存器)加上偏移部分,此时影子寄存器的值为0xFFFFFFF0。所以CPU执行的第一条指令是0xFFFFFFF0(复位向量),通常在BIOS ROM对应的指令是一个跳转指令JMP F000:E05B,当取出跳转完成后,由于CS段的影子寄存器刷新并重新加载,下一条指令地址是0xFE05B。不过这条指令仍然从BIOS ROM里取得。

4.     关于shadow BIOSBIOS程序通常是压缩的,在系统初始化阶段,BIOS会解压BIOS ImageRAM中,然后编程北桥控制器对0xE0000~0xFFFFF置为write only,这样对该区域的写被传递到DRAM里,然后把解压的BIOS拷贝到E段和F段。最后重新编程北桥控制器对0xE0000~0xFFFFF置为read only。对于PCI ROM BIOSBIOS会把每个卡上的ROM拷贝到0xC0000~0xDFFFF然后执行他们的初时化代码。

5.     BIOS ROM可以很大,但不都是可执行的,如含有ACPI Table等,开始解压到0xE0000~0xFFFFF只是其中一部分,在启动过程中还需要从BIOS ROM解压代码到RAM中,并覆盖其中不需要的代码。这个就好像BIOS ROM是硬盘(不过可用直接访问),真正执行的代码在RAM中一样。硬盘可以很大但RAM小,这也就是程序的局部性原理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页
评论
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值