前言
本文内容只集中在操作系统启动原理的讲解上,不涉及启动的技术细节,因为这些细节都可以通过网络或者相关代码了解。只有了解了启动原理,才能在分析和解决有关启动的问题时具有针对性,不会有无从下手的感觉。限于作者经验的原因,本文内容只涉及关于Windows和Linux系统的启动过程。
启动过程简介
操作系统的启动简单来说,就是将操作系统的内核从外存储加载到内存中,并使其运行的完整过程。可是现在的操作系统实在太复杂了,要将这么复杂的系统启动起来,也不是一件简单的事情。大家都知道软件的大小是随着功能多少而变化的;同理,随着操作系统越来越复杂,启动过程也变得更加复杂,但MBR(硬盘第一个扇区)的空间有限(512Bytes),不可能将所有的启动代码全部塞到里面,但MBR又是操作系统启动的第一个环节,BIOS从硬盘启动时只加载MBR一个扇区。MBR有两个非常重要的作用:存放第一阶段的启动代码和保存分区记录。
那怎么办呢?聪明的程序员想出了一个办法:链式启动,一环扣着一环,先用小程序(功能极其简单,主要功能就是加载其他程序)加载一个较大的程序(功能稍微复杂些,比如可以搜索文件系统等等),然后这个较大的程序再加载更大的程序(功能全面,负责加载系统内核等),不断重复这个过程,直到把完整的bootloader(启动加载器)都加载到内存中。当bootloader完全加载到内存后,它才开始执行操作系统内核加载启动等工作。在x86平台上,Windows和Linux操作系统的启动程序一般是由三个部分组成的,每一部分都完成链式启动过程中一个阶段的启动任务。
Windows系统启动过程
在一个只装有Windows系统的硬盘中,MBR中存放着微软提供的第一部分的启动代码,虽然随着Windows版本的不同,这段代码也略有变化,但是其主要功能并没有改变。在存放这段代码的MBR扇区被加载到内存后,它首先查找保存在这个扇区(MBR整个扇区已被加载到内存中,实际是在内存固定位置处查找)中的分区记录,在其中找到活动标志值为0x80(表示该分区是活动的)的那条分区记录,依照记录中的分区开始位置,将这个分区的第一个扇区加载到内存中并执行。如果在这个过程中出现错误,比如报告“没有活动分区”之类的,都是由这部分代码产生的。
由Windows操作系统格式化的分区,不管文件系统类型是FAT16/32还是NTFS,在分区开始的若干个扇区内,都存放着Windows系统启动的第二部分代码。这部分代码分为两小段:第一段是第一个扇区的自加载部分,第二段是后面扇区的启动功能部分。第一段的这个扇区由MBR的启动代码加载到内存并执行,这个扇区的主要功能是将第二段代码全部加载到内存中;而第二段代码的主要功能是解析文件系统,将保存在文件系统中的最后一个阶段的启动代码文件(ntldr)加载到内存中,由于有文件系统的解析功能,因此第二部分的启动代码随文件系统类型而有所不同。像“ntldr is missing”这样的错误信息都是由这部分代码报告的。
Windows启动过程中第三部分的代码存在于系统分区的文件系统中,文件名通常是ntldr(win2k及其后的Windows系统),这段代码并没有覆盖第二部分的代码,因为还要用到它的文件系统解析功能。这部分代码分析boot.ini文件,提供给用户启动选项等功能,在用户作出选择后,加载操作系统内核文件,并将控制权交给系统内核,至此,bootloader的使命就完成了,接下来的系统初始化等功能都是由Windows操作系统内核来完成的。
Linux系统启动过程
Linux系统是开源操作系统,针对同一个功能开源社区里总是存在着多种选择,就连bootloader也不例外,早期的Linux一般使用Lilo,现在的Linux系统一般使用GRUB作为bootloader。两者的功能是相同的,只不过GRUB提供的功能更加丰富。GRUB和Windows系统的启动程序在功能划分上基本一致,都分为三个部分,分别是stage1, stage1.5和stage2。
stage1是GRUB第一部分的启动代码,和Windows系统第一部分的启动代码的功能相似,但也有很大的不同:
驻留位置,stage1可以驻留到MBR或者分区的第一个扇区中;
加载方式,stage1在MBR中时,并不通过查看分区表来获得下一阶段的启动代码的位置,而是在Linux安装好后,由Linux安装程序在stage1内部的特定位置上写好了下一阶段启动代码的开始位置(硬盘扇区的绝对偏移);
由于第二点的不同,因此它既可以加载stage1.5也可以直接加载stage2;
stage1.5和Windows系统第二部分启动代码的功能相同,它通过解析启动分区的文件系统,将stage2加载到内存中。stage1.5一般驻留在启动分区的开始部分。其加载方式也和Windows系统一样,由stage1先将stage1.5的第一个扇区加载到内存中,然后由此扇区中的代码将其余部分也加载到内存中。stage1.5代码因为与解析文件系统有关,本身又不能太大,因此和Windows系统一样,针对每个Linux文件系统都有对应的stage1.5的代码,一些Linux安装可以让用户选择启动分区的文件系统类型,所以相应的stage1.5会被使用。
stage2功能和Windows系统第三部分启动代码的功能相同,它可以显示一个启动列表,让用户选择启动,然后加载相应的Linux内核文件和ramdisk文件到内存并解压,最后将控制权交给Linux内核。至此,GRUB的使命就完成了,接下来的系统初始化等功能都是由Linux内核来完成的。
GRUB不同于Windows启动程序的地方是:虽然GRUB提供了stage1.5用于解析文件系统和加载stage2,但是在流行的Linux发行版中,安装程序并不使用stage1.5,而是跳过stage1.5,直接由stage1加载stage2,具体原因有以下几点:
某些Linux文件系统在设计时,分区开始出并没有留出足够的空间存放stage1.5;
某些Linux文件系统出现时间较晚,没有对应的stage1.5;
虽然stage1.5具有启动时的灵活性,但是也付出了增加复杂度的代价;
基于以上几个原因,例如Redhat,Suse等Linux发行版在安装时并没有使用stage1.5,而是简单地让stage1直接加载stage2。因此,stage2在设计上也和stage1.5相似,分为两段,第一段代码是stage2的第一个扇区,用于加载第二段代码,而第二段代码完成stage2的主要功能。因此,stage2的加载方式有两种:一是由stage1.5通过解析文件系统加载同内存中;二是由stage1只加载stage2的第一个扇区,由此扇区将stage2其余部分加载到内存中。
多系统安装实战
想必在一块硬盘上安装过Windows和Linux双系统的网友都有个这种经历:一旦Linux出了问题,不能进入GRUB的启动界面的话,那么连Windows也启动不了了,不得已,只能完全重装所有的系统。其实这都是Linux发行版中GRUB安装方式惹的祸。为什么这么说呢?还要从GRUB的安装方式讲起。
上面已经谈到,流行的Linux发行版在安装过程中对GRUB安装的默认方式方式是将stage1安装在MBR中,然后让stage1直接加载Linux分区中的stage2,如果在Linux安装之前存在有Windows系统,那么GRUB会在启动配置中添加一个启动项,使用户可以启动Windows系统。
这个启动项背后的故事是:如果用户选择了这个启动项,stage2依照这个启动项提供的分区位置,加载该分区的第一个扇区,然后将控制权转给该扇区。也就是说这个启动Windows的过程相当于从Linux启动第三个阶段跳转到Windows启动的第二个阶段。如果在这个启动过程中Linux系统出了问题导致GRUB工作不正常的话,自然连带的Windows也无法启动了。
所以,相比较来说,Windows的启动程序加载的方式是比较灵活的,不像Linux,将其他系统的启动也纳入到自己的管理之中,一旦Linux系统的启动出了问题,也会危及到其他系统的启动。
一个比较好的多系统安装方法如下:
首先安装一个Windows系统,其目的就是要将Windows启动的第一部分代码写入到MBR中。随后的步骤和你想要安装的操作系统有关,可以分为三个类型,多Windows系统,多Linux系统,混合性系统,下面分别讨论:
多Windows系统:
在安装新的Windows系统前,通过控制面板->计算机管理->磁盘管理,将你想安装新的Windows系统的分区设为活动的,这是会出现警告信息,点击确认通过。然后重启系统,插入安装光盘,设定光盘启动,就会从光盘启动安装程序,安装程序默认会将系统安装在活动分区上。按照这种方式,在主分区上最多可以安装4个WindowsXP系统,2个Windows Vista/7系统(因为占用2个分区)
平常使用时,如果想切换到另一个系统,使用控制面板->计算机管理->磁盘管理将你想切换到的系统设为活动即可,重启后,即可进入新的系统,返回同理。
多Linux系统:
如果硬盘分区打算全部安装Linux系统,第一个Linux系统必须装在Windows系统所在的分区上,而且最多安装2个Linux系统(每个Linux分区占用2个分区)。在Linux系统安装的过程中,有一步是指定grub的安装位置,默认是MBR,改为分区(因为Linux发行版的不同,指定方式也有所不同),其他默认。后续Linux的安装遵循多Windows系统安装的方式,首先改变活动分区(Linux中使用fdisk工具),在重启系统安装新的Linux。
平常使用时,使用fdisk改变活动分区,即可切换到不同的Linux系统。
混合性系统,当你充分理解了上面两个例子的安装原理后,我相信混合系统对你来说,应该是非常容易的意见事情了。
题外话:
1早期的启动代码,不管Windows还是Linux,都存在对硬盘前7.8G空间的寻址限制,这是因为硬盘的CHS寻址机制造成的,随着LBA寻址方式的出现,现在的启动代码不再有这个限制了,意味着你可以将系统分区安排在硬盘空间7.8G之后的位置了,不过如果硬盘上还有dos系统,就应该注意了。