1、BIOS的工作:
我们的计算机在开机之前,它是一个纯硬件的机器,但是从按下开机按钮的那一刻起,ROM上的固化程序就开始为操作系统这个重要的软件进行初始化工作,初始化工作完成以后,将操作系统内核加载到内存中,操作系统就会帮助我们管理各种硬件资源,带给了用户良好的体验。我们普通用户通常都不关心,在电脑启动时具体都做了什么,但是作为一个IT行业的从业人员或者即将作为一名IT行业的从业人员,尤其是作为一个搞技术开发的从业人员,对于计算机是如何启动的有必要了解一二。
(1)、纯硬件检测与BIOS初始化阶段:
首先,在我们按下开机按钮的时候,供电系统向计算机主板和其他硬件设备供电。刚开机时电压不太稳定(但是会快速稳定下来),所以计算机主控芯片组会向CPU发出并保持一个RESET重置信号,让CPU自动恢复到初始状态,当主控芯片组检测到稳定供电后,便撤去RESET信号,此时程序计数器初始化置为FFFF:0H(硬件芯片初始化地址,和软件没关系),CPU开始从FFFF:0H除执行指令,这个地址只有一条指令jmp START,FFFF:0H是BIOS(Basic Input Output System) ROM的起始地址,但不是有效指令开始地址,jmp指令跳转的START是真正进行BIOS程序起始地址(如图)。
(2)、BIOS进行显卡、CPU检测并设置BIOS:
系统BIOS启动后,进行一系列硬件检测与程序初始化:先检测关键设备电路,如果设备异常则发出警报并死机。然后进行显卡检测,调用显卡BIOS的代码(C000:0H处),初始化显卡,如果显卡不正常则黑屏(不正常不能显示,所以黑屏),正常则屏幕显示显卡信息,并返回系统BIOS接着进行检测其它设备是否正常。其它设备不正常则等待处理,正常则屏幕显示系统BIOS信息。接着检测CPU,如果出错则蓝屏死机,正常则进行BIOS设置检测,如果需要设置BIOS则先进行BIOS设置,然后退出BIOS设置界面进行标准硬件设备检测,如果不需要设置BIOS则直接进行标准硬件设备检测(如图)。
(3)、其它设备检测更新与CPU控制权限转交:
在完成BIOS设置之后,需要进行两步操作,①检测是否存在即插即用设备,如果存在则为即插即用设备分配资源,不存在则直接进行系统BIOS清屏;②检测是否存在硬件设备的更新,如果存在硬件更新,存放于CMOS之中的系统硬件信息就需要进行修改,进行ESCD(Extended System Configuration Data)更新(ESCD是系统BIOS与操作系统进行硬件配置信息交换的一种手段),更新完毕先要把BIOS提供的中断例程的入口地址登记在中断向量表中,然后进入指定启动项(BIOS设置中设置的优先启动顺序:软盘、硬盘、U盘或光盘)。
假设是硬盘启动,系统BIOS读取硬盘0盘面0磁道1扇区的MBR(主引导记录)到内存中指定区域(具体是BIOS提供的int 19中断例程加载MBR),设置程序计数器到指定区域,然后CPU开始执行MBR的指令(即CPU使用权交由MBR来掌控)。
(4)、MBR的工作:
MBR会先检查硬盘分区表,然后根据硬盘分区表找到硬盘上的引导分区,将引导分区的首扇区(boot loader)内容调入内存,boot loader中的ntdlr(Windows引导程序)启动mini-file system divers以便能识别NEFS和FAT32的文件系统的硬盘分区。或者grub(Linux引导程序)启动vmlinuz-version和initrd-version.img(eg:Centos5.5中的/boot/vmlinuz-2.6.18-194.el5和/boot/initrd-2.6.18-194.el5.img)。便完成MBR的引导过程。
2、MBR与boot sector的关系:
在最开始接触MBR和boot sector、boot loader、grub、ntdlr这些概念的时候,脑子是一片混乱,直到我做了一个实验(即后面要提到的的三系统引导实验)之后才彻底搞清楚:
在安装系统的一个磁盘上有多个分区,第一个分区是主分区(从1柱面开始),主分区之前有一个柱面,其第一个扇区是MBR(0面0道1扇区),之后便是各个分区,每个分区的第一个扇区都是一个boot sector(存放引导加载程序boot loader)。MBR也相当于boot sector,起码它是一个扇区(sector)存放了引导记录,只不过广义的MBR中不仅仅有引导记录。在安装Linux时如果需要为/boot分区分配一些空间,则/boot是用来存放操作系统内核的启动文件与配置文件,而grub是Linux系统的引导程序,在/boot/grub/grub.conf中记录着grub的基本配置信息。ntldr是windows上的boot loader。
总的来说:
①广义MBR(512Byte)和boot sector都是一个扇区,boot sector是每个分区的第一个扇区,而MBR是磁盘的第一个扇区。
②boot loader和狭义MBR(446Byte)是引导加载程序,负责加载系统内核、提供引导选项或转交引导权限给其它boot loader(关于这三种功能我们稍后一一会遇到)。Linux的grub和Windows的ntldr都是boot loader的具体程序。
关系如下所示(这是先装了一个Windows7再装了一个Redhat后的MBR与boot loader情况,Linux的grub改写了原本直接引导Windwos的MBR,将Linux的grub写到了MBR里,所以MBR可以直接引导Linux,当然也有可以间接通过/dev/sda3中的grub来引导):
上面已经提到了boot loader的三种情况:①直接引导kernel、②转交其它boot loader来引导,③提供菜单选项(选择1还是2,即选择双系统的Windows7还是Redhat)。如下图所示(暂时忽略Centos5.5):
我们看到MBR的选择菜单标题是GNU GRUB,这证明了后安装的Linux的grub引导程序修改了MBR(修改MBR时,自己的boot sector里也生成了grub),选择第一个则按照直接引导的方式引导Linux kernel,选择第二个则将引导权交给ntldr,由ntldr来引导Windows kernel,ntldr中不存在菜单选项和转交loader权。(如果我们把grub覆盖到ntldr的boot sector,且选每次菜单出来都选择Windwos7则会存在互相转交引导权,一直不能启动系统,后面会详细说到)。
3、Win7+Redhat6.4+Centos5.5三系统引导实例:
上面所述的过程,在MBR加载的前知识点(即BIOS检查操作)对于实际应用来说,帮助不大(CPU初始化FFFF:0H和BIOS加载MBR的部分还是有用的,只是显卡、内存等检查现在来说没有太大实际应用),但是从MBR加载之后的信息,对于我们在操作系统安装,双系统安装等方面有极大的指导作用。接着我们来看看一个有趣的实验:先安装Win7再安装Redhat6.4,最后安装Centos5.5的过程中,MBR以及磁盘分区情况是如何变化的,并且实现按自己心意来随意引导的方式。
(1)、只安装Windows7:
只安装Windows7时的磁盘情况如下所示:
安装Windows7时,安装程序将ntldr写入MBR便开机时读取MBR时正确引导Windows的Kernel,在自己的boot sector中也写入了ntldr(备份)。注意:boot sector所在的分区是分出来存放系统内核程序的,C盘是另外一块分区。空闲的分区可以做D:盘、E:盘,但是我们要安装多个系统,所以就不分非系统盘了。
(2)、安装Windows7以后安装Redhat6.4:
这一操作的结果与我们在上面区分MBR和boot sector时已经分析过了(但是分区图不太一样):原本的MBR中是Windwos的ntldr,安装Redhat时选择了用Redhat的grub覆盖Windwos在MBR上的ntldr,但是Redhat识别出了已经有一个操作系统是Windows,所以在安装grub时增加了loader的菜单选项。grub中将Redhat作为了默认引导项,不用去读自己的boot sector了。实际操作中的分区与MBR变化如下:
(3)、接着安装一个Centos5.5:
安装Centos5.5时,选择是修改MBR还是不修改,我选的是不修改,所以Centos的grub只写到了/dev/sda安装好以后,只有Redhat和Others两个选项,所以Centos无法启动。此时的文件分区情况与MBR如下(MBR没有Centos的grub信息,所以开机无法直接引导):
用fdisk -l查看磁盘分区情况:
那么Centos的grub只写在/dev/sda7的boot sector中 ,如何启动Centos?我们可以在MBR的选项菜单中直接按’c’键,进行grub编辑:
编辑如下(编辑完一行回车即可):
root (hd0,6)。其实就是挂载/dev/sda7到/boot,即指定/boot,/vmlinuz-version也就是/boot下的/vmlinuz-version而不是根(/)下的/vmlinuz-version。
kernel /vmlinuz-version root=LABEL=/,只要输入kernel /vmlinuz然后按Tab键就能自动补全版本号加上root=LABEL=/即可,下一行也一样按Tab即可
initrd /initrd-version.img
以上三行其实就是boot loader做的事情,如Redhat的引导过程如下图:(因为/dev/sda3的boot sector上存放的是redhat的boot loader,所以root (hd0,2)即挂载redhat的/boot)
这样做只能每次手动boot,如何才能一劳永逸呢?只要我们在redhat的/boot/grub/grub.conf配置文件中将以上三行加上去即可(相当于在菜单项中加了一项):
加完以后,MBR引导时菜单项中就多了一项Centos5.5,选择Centos5.5时MBR将引导全交给了Centos 的/dev/sda7的boot sector来引导,因为/dev/sda7的boot sector中本来就放的是Centos的引导程序,则Centos就能正确引导。
4、随意修改boot sector的boot loader:
接着我们做以下变化:
进入Redhat6.4中,执行grub-install /dev/sda1(注意做备份,由于我是用虚拟机做的,用快照也可以,但是用备份更方便)将redhat的grub安装到Windows7的boot sector中去,每次选择菜单中的Windows7,这样就能达到引导权互相交换的效果,修改方式如下所示(由于Linux能够识别Windows7的NTFS文件系统,所以能够做这一步,如果不能识别是不存在写权限的):
效果如下所示:
要恢复Windows7原来的引导,只需要将备份写回去即可:
类似的操作可以随意修改,只要能够识别对应文件系统,比如把centos的grub装到Windows的boot sector中,则选择Windows7是启动的是Centos的操作系统。
当然也可以在开机选择时,按‘c’进入grub编辑,如下编辑(不做演示):
grub> rootnoverify(hd0,0)
grub> chainloader +1
grub> boot
//MBR转交boot权限的便是/dev/sda1的boot loader启动Windows7grub> rootnoverify(hd0,2)
grub> chainloader +1
grub> boot
//MBR转交boot权限的便是/dev/sda3的boot loader启动Redhat6.4grub> rootnoverify(hd0,6)
grub> chainloader +1
grub> boot
//MBR转交boot权限的便是/dev/sda7的boot loader启动Centos5.5