全网最硬核解读计算机启动原理( 二 )


我们看到,内存被各种外设瓜分了,即映射在了内存中 。BIOS 更狠,不但其空间被映射到了内存 0xC0000 - 0xFFFFF 位置,其里面的程序还占用了开头的一些区域,比如把中断向量表写在了内存开始的位置,真所谓先到先得啊 。
四、怎么就从 BIOS 里的程序开始执行了好了,现在我们知道 BIOS 里的信息被映射到了内存 0xC0000 - 0xFFFFF 位置,其中最为关键的系统 BIOS 被映射到了 0xF0000 - 0xFFFFF 位置 。假如我现在说,CPU 开机就是执行了这块区域的代码,然后巴拉巴拉一顿操作就开机了,你肯定要喷我了,为什么就执行到这了呢,那咋不从头开始执行?
这就自然有了一种猜想,我们要用到另一个前置知识了,就是 CPU 从内存的哪个位置取出执行并执行呢?是 PC 寄存器中的地址值 。BIOS 程序的入口地址也就是开始地址是 0xFFFF0(人家就那么写的),也就是开机键一按下,一定有一个神奇的力量,将 pc 寄存器中的值变成 0xFFFF0,然后 CPU 就开始马不停蹄地跑了起来 。没错,接下来这句话,可能就是你找了很久的答案,请做好准备:
在你开机的一瞬间,CPU 的 PC 寄存器被强制初始化为 0xFFFF0 。如果再说具体些,CPU 将段基址寄存器 cs 初始化为 0xF000,将偏移地址寄存器 IP 初始化为 0xFFF0,根据实模式下的最终地址计算规则,将段基址左移 4 位,加上偏移地址,得到最终的物理地址也就是抽象出来的 PC 寄存器地址为 0xFFFF0 。
当我在学习这段知识时,看到这句话才让将我心里积压了很久的疑惑解开,多么简单粗暴的道理啊 。写到这里我也是长舒了一口气,因为剩下的过程,就几乎只是流水账一样的正推了 。
至于怎么强制初始化的,我觉得就越过了前置知识的边界了,况且各个厂商的硬件实现也不一定相同,有很多办法,也很简单 。讨论起来意义就不大了 。
五、BIOS 里到底写了什么程序好了,我们现在知道了 BIOS 被映射到了内存的某个位置,并且开机一瞬间 CPU 强制将自己的 pc 寄存器初始化为 BIOS 程序的入口地址,从这里开始 CPU 马不停蹄地向前跑了起来 。那接下来的问题似乎也非常自然地就问出来了,那就是 BIOS 程序里到底写了啥?
把 BIOS 程序里的二进制信息全贴出来也不合适,我们分析一些主要的 。我们首先还是来猜测,你看入口地址是 0xFFFF0,说明程序是从这执行的 。实模式下内存的下边界就是 0xFFFFF,也就是只剩下 16 个字节的空间可以写代码了,这够干啥的呢?如果你有心的话应该能猜出,入口地址处可能是个跳转指令,跳到一个更大范围的空间去执行自己的任务 。没错就是这样,0xFFFF0 处存储的机器指令,翻译成汇编语言是:
jmp far f000:e05b意思是跳转到物理地址 0xfe05b 处开始执行(回忆下前面说的实模式下的地址计算方式) 。
地址 0xfe05b 处开始,便是 BIOS 真正发挥作用的代码了,这块代码会检测一些外设信息,并初始化好硬件,建立中断向量表并填写中断例程 。这里的部分不要展开,这只是一段写死的程序而已,而且对理解开机启动过程无帮助,我们看后面精彩的部分,也就是 BIOS 的最后一项工作:加载启动区 。
六、0x7c00 是啥该较真的地方就是要较真,我绝对不会让加载这种魔幻的词出现在这里,我们现在就来把它拆解成人话 。
其实这个词也并不魔幻,加载在计算机领域就是指,把某设备上(比如硬盘)的程序复制到内存中的过程 。那加载启动区这个过程,翻译过来就是,BIOS 程序把启动区的内容复制到了内存中的某个区域 。好了,问题又自然出来了,启动区是哪里?被复制到了内存的哪个位置?然后呢?我们一个个来回答 。
什么是启动区呢?即使你不知道,你也应该能够猜到,一定是符合某种特征的一块区域,于是人们把它就叫做启动区了,那要符合什么特征呢?先不急,不知道你有没有过设置 BIOS 启动顺序的经历,通常有 U 盘启动、硬盘启动、软盘启动、光盘启动等等,BIOS 会按照顺序,读取这些启动盘中位于 0 盘 0 道 1 扇区的内容 。
至于磁盘格式的划分,本篇就不做讲解了,总之对于内存,我们给出一个数字地址就能获取到该地址的数据,而对于磁盘,我们需要给出磁头、柱面、扇区这三个信息才能定位某个位置的数据,都是描述位置的一种方式而已 。
接着说,这 0 盘 0 道 1 扇区的内容一共有 512 个字节,如果末尾的两个字节分别是 0x55 和 0xaa,那么 BIOS 就会认为它是个启动区 。如果不是,那么按顺序继续向下个设备中寻找位于 0 盘 0 道 1 扇区的内容 。如果最后发现都没找到符合条件的,那直接报出一个无启动区的错误 。


推荐阅读