电脑CPU开机上电后的第一条指令
结合上面的文章,CPU上电后第一条指令是通过CS:IP来指定的,CPU厂家会给其初始值,对于386处理器来说,CPU第一条指令地址是
0xFFFFFFF0
这里会有一个问题,CPU怎么能一上来就去0xFFFFFFF0取指令呢?因为此时的内存都没有初始化呢,内存中什么都没有,第一条指令毫无疑问肯定在BIOS中,现在用来烧写BIOS的Flash芯片一般也就256KB、1MB、4MB,都是非常小的,怎么也没有0xFFFFFFF0这个地址的。
这里就需要说一下x86的地址编码方式了,我们平时说的内存,主存是指RAM,但是这里会有些问题,因为RAM是从0开始的一个地址范围,而ROM也是从0开始的一个地址范围,当我们要访问一个地址,比如0x100,此时到底是去RAM里找还是去ROM里找呢?
x86解决这个问题的方法是“统一编码”,也可以叫做地址映射,也就是在CPU眼里,它只看到一块打的空间,对于32位CPU,从0开始,4G结束,64位的CPU最大范围就更大了,CPU才不懂什么叫RAM,什么叫ROM,什么叫硬盘的,地址映射的概念就是给地址分段,不同位置是有不同的作用的,大部分是用来给程序运行的RAM的,但还有部分是映射给ROM,IO或者其他设备,下图是一种典型的地址映射关系:
那么问题又来了,上面不是说CPU上电后会去0xFFFFFFF0处取第一条指令,这条指令肯定是在BIOS中,但是上图中BIOS的映射地址时0xF0000,这个就有点懵了,到底是为什么呢?那么BIOS代码到底映射在什么位置呢?
答案是--两个地址都有,BIOS的代码肯定是存在EPROM中的,CPU中的硬件回把EPROM芯片映射到2个地方,一个是从0xFFFFFFFF(4G)处向下扩展,一个是从0xFFFFF(1MB)处向下扩展,第一个映射是因为第一条指令在0xFFFFFFF0处,所以EPROM必须在哪个位置,第二个映射是为了兼容,在16位时代就有了,另外地址映射是占据地址空间,总是你的PC机只有2G内存也没关系,因为病没有使用内存,使用的只是地址空间,所到底对于CPU来说,它才不知道哪是哪,它只知道服从硬件安排,上面的所有所有地址映射,都是给程序员看的,不是给CPU看的,CPU只认各种“门”电路。
那么第一条指令的内容是什么呢?
这是比较容易产生混淆的地方,多数人说第一条指令是个长跳转(long jmp),跳转到0~0xFFFFF(0-1MB)这一段,然后再执行BIOS剩余的指令,但是intel手册中却又这么一段话:
简单的说,就是不让有长跳转动作,其实这两种都对,intel手册上说的是让BIOS在高地址空间运行,器件一直修改CS寄存器,也就是一直使用Base+EIP的方式生成地址,这种新式方法应该是UEFI的,那种刚开始就长跳转的属于老式做法。
假设有一块1M的flash芯片,第一条指令一般都是在0xFFFF0的这个位置,这样的原因,我们可以很简单的想到,这是为了把这1M空间方便的映射到4G地址中最高的1M中吧,可能看起来比较对齐吧。
BIOS也就是ROM的地址空间通过CPU的硬件自动映射到了高地址1M,但是我们平时看到的都是低于1M的BIOS,因为在高地址的时候,CPU实际上是在访问ROM,这段时间内,基本的操作就是硬件初始化,最重要的肯定是RAM等重要硬件的初始化,初始化完成后,CPU根据BIOS中的“搬家”代码,回将ROM的所有内容拷贝到RAM中(整体拷贝比较方便,如果是想着把前面执行过的剔除掉,得不偿失),当然这个位置肯定就是低1M的地址空间,比如上图中,从0xF0000开始的那64Kb空间(放心,一般的BIOS不会超过64KB),拷贝完成后,CPU会执行一条长跳转,这会引起CS寄存器的改变,也就会控制CPU指向RAM进行执行程序了,这样带来2个好处,第一肯定是RAM比ROM更快,第二是这样重新满足了实模式下寻址范围是1M的这一特点,当然CPU寻址方式回重新回归到CS左移4位+IP的模式。
到这里还有一些疑问:我们一般会认为第一条紫菱本身就是一条长跳转指令,那么CPU是怎么完成内存初始化后,并将BIOS相关数据拷贝到1M以下地址空间呢?这里有几种可能(方便说服内心的猜测),第一是这条指令并不是真正的长跳转,而是先进行一些基本的初始化,才跳转,第二是ROM到地址空间的映射并不是简单的映射到搞地质的1M,而是有着更复杂的映射方式,使得长跳转后时间上CPU还是在访问ROM,第三就是CPU一旦上电,就自动的由硬件将BIOS内容复制到对应的RAM中,这一点在ARM9的工作模式可以验证。