从最早的8086 PC机开始,操作系统的引导是在CPU的实地址模式下进行的。具体说来,BIOS将启动盘的第一个扇区内容读到0000:7C00这个地址开始的512字节内存中,然后检查最后两字节是否为0x55 0xAA,若是则跳转到0000:7C00执行。BIOS是Basic Input Output System的缩写,原意是基本输入输出系统,为PC软件提供了基本的硬件接口服务——通过一系列软中断调用。例如INT 10h的显示服务,INT 13h的磁盘服务。DOS (Disk Operating System)就必须依赖BIOS的服务才能工作,比如读取磁盘上的文件操作,关系到访问磁盘上扇区的内容,就需要通过BIOS的调用来完成,因为DOS自己没有磁盘的驱动程序代码。BIOS的代码是放在PC上的ROM中的,机器上电启动时,CPU首先执行的是BIOS所在的ROM地址空间的POST(Power-On Self-Test)程序,进行硬件检测。我猜显示卡上也有一块ROM是属于BIOS的部分。早期PC ROM还包含了BASIC语言解释器,可以在引导操作系统失败的时候使用,我觉得BASIC ROM不能算作BIOS.
博主认为,BIOS有两层含义,一层是指实模式下INT 1x代表的那些中断调用服务,另一层是指固化在ROM中刚启动时执行的程序。随着DOS退出历史舞台,前一层含义已经弱化了,甚至在新的一些电脑上,无法启动DOS——说原因是“没有BIOS了”也不完全错。但是,PC不可能没有ROM固化的程序,它依然被叫做BIOS:
重点在于,目前流行的PC引导(启动)操作系统方式并不是像古老的PC那样在实模式下进行,而是直接在保护模式下引导。实模式的地址访问能力只有1M字节,都不能胜任复杂的BIOS POST程序、SETUP程序的工作,而现代的操作系统没有对实模式的需求,于是硬件厂商推出了EFI (Extended Firmware Interface)规范,摈弃了老的引导方式。于是,在近些年的PC setup界面上,可以看到EFI或者UEFI的字样,表示这种新的引导操作系统的方式。
说白了,就是用新的保护模式下的API来实现操作系统引导。我所了解的优点有:(1)支持GPT磁盘分区格式,支持2TB以上硬盘。(2)直接访问分区内的文件系统,加载启动文件,也就是文件copy过去就能用来启动,不用特殊扇区存放启动代码。(3)软件接口的许多调用支持,比如支持secure boot.
不过EFI引导就和老的引导完全不兼容了。刚开始BIOS提供了两种引导模式供选择(比如有的PC可以在自检时按F12调出引导选择菜单,选择可以用的启动项),后来的默认是UEFI模式,将老的模式称为传统(legacy)模式。比如我现在这台机器BIOS里面要开启CSM(Compatibility Support Module)才有老的引导模式。目前最新的PC已经见到很多完全取消了传统引导模式,只能EFI启动了。
EFI模式下,BIOS会搜寻磁盘分区的 /EFI/boot/bootx64.efi 这个文件(传说中早期有32位EFI的时候,找的是bootia32.efi),找到就进行引导,怎么使用这个文件的细节就远比传统模式复杂了。因为现在PC主流CPU是x86_64架构,EFI引导是64位模式下执行程序的。那么问题一:能否返回到实模式?问题二:能否切换到32位模式?这关系到能否引导16位和32位操作系统的问题。
关于第二个问题,我实验过用grub2引导32位和64位的Linux kernel,在比较老的机器上,32位kernel是可以引导的,最新的机器好象都失败了,也不能肯定是否是其它问题。EFI的一个麻烦是显示模式不是VGA字符模式,Linux支持的VGA text console没法用,只能用EFI framebuffer, 若EFI framebuffer驱动没有加载,就看不到任何kernel输出信息了。