MBR及linux下grub执行原理浅析

前几天,手痒痒把系统搞坏了,但正如那句话说的:塞翁失马,怎知不是福?查找了很多资料,接触到了很多新知识,发现大牛们要么不出手,出手的文章必定深入浅出,风趣幽默,还穿插了很多从技术中悟出的人生哲理,让人回味无穷。今天就把我这几天学习到的知识理出一条线,尝试模仿大牛们的方法跟大家分享,希望不会是邯郸学步。


首先让我们要讲一下MBR这个东东。它的英文全称是Master Boot Record,中文名叫“主引导记录”。每块硬盘都有且只有一个这个东东。(注意我说的是“硬盘”,不要顺眼一晃就看成来是C盘/D盘这个文件系统概念了)它指的是硬盘的第一个扇区中的前446字节。一个扇区共512字节,剩下另外的64个字节用于存储“硬盘分区表”DPT(Disk Partition Table),最后两个字节“55,AA”是分区表结束的标志。这个整体构成了硬盘的主引导扇区。


好吧,说到这,我们还得提议下关于硬盘的分区的概念:主分区/活动分区/拓展分区/逻辑分区。首先,一块硬盘最多只能划分4个主分区。如果你想要更多的分区(比如说在linux下,根目录/, 用户文档目录/home , 用户安装的程序目录/opt , 用户自己编译安装程序的目录/usr ,我都想单独的存储在一个分区,以便将来我手痒痒又把系统弄坏的时候,这些文件都可以丢失或不须要重新安装),那么就应该将未被划分为主分区的硬盘弄成拓展分区,这样在拓展分区下就可以任意划分多个逻辑分区了。要注意,拓展分区只是一个概念,以区别于主分区,在硬盘上并没有某个位置对应拓展分区(一般认为只要将某个分区设置成逻辑分区,那么该硬盘上也就自动有了拓展分区)。所以,你在linux下查看你的硬盘分区,一定不会看到sda1,sda2 ... sda7 ...这样连续不间断的分区号,因为最多只能有4个主分区,所以整块硬盘你只划分成主分区,那么也就只有sda1~sda4,没有后续了。如果你划分了逻辑分区,那么就肯定没有4个主分区了,所以最多你也只能是sda1,sda2,sda3,sda5....注意,sda4这个编号会被跳过(如果你只划分出一个主分区,那么sda2,sda3,sda4都会被跳过,直接跳到sda5)。而活动分区这个概念主要是存在于Windows下,linux则没有这个概念。因为window要将一个主分区设置为活动分区,然后将系统安装在这个被标记为活动分区的主分区上,这样windows的引导程序——ntldr才能判断windows系统被装在哪里了,然后再跳到该分区上引导系统。


(图片来源:http://hi.baidu.com/waybq/item/a4490f026f9859d21ef046a4

好了,讲到这我们可以把前面的开机过程串一下:按下电源开关后,BIOS检查设备,可以听到“滴”的一声就说明设备正常。然后就是我们装系统时需要专注的时刻——按F2或者DEL进如启动顺序的设置:如你可以选择从光盘,U盘,或者默认的硬盘启动。假如你有两块硬盘,一个U盘都装了系统,还有启动光盘你也给他插到电脑上,那么你就至少有4个可以选择的系统,这个时候,按下F2或DEL然后在BOOT菜单中选择这些硬件的启动顺序,就是要告诉BIOS你要启动那个系统。这个过程结束后,BIOS就把启动过程的控制权给到了引导程序(Boot Loader)。


什么是Boot Loader?——嗯,这个是我们这篇文章的主角。Boot Loader是一个很小但非常重要的可执行文件(程序),不同的操作系统都有其对应的boot loadr,如windows 的叫ntldr,linux的就有很多了,有grub grub2,Syslinux等,更具体的待会再讨论。先关注一下这个Boot Loader住哪?啊哈,就安装在硬盘的MBR上。大家学过微机原理的都知道“指针”这么个概念,它对应的就是物理地址,再说白一点,就是你的硬盘上的某个位置。BIOS完成任务后,把指针指向了MBR,实际是怎么执行的呢?就是CPU到该指针所指向的地址读取下一条指令(就是程序代码)。该MBR就是你在BIOS的BOOT启动顺序所选择的安装了操作系统的那个设备的MBR。


说到这大家应该有疑问了吧?什么,没有?!唉,你真是中国好同学。但不能我说什么就是什么,很有可能我说错了,对吧。至少我有两个问题:BIOS怎么知道MBR的地址?如何知道我的硬盘/U盘/光盘上有没有安装操作系统?第一个问题: 有一个硬件中断INT13会告诉BIOS外设的MBR地址。看看,看看!软件并不是万能的,它不能解决所有问题,软硬件结合才能最好的完成任务。同样一个人也不能什么都干,因该是找一个人尽其才的团队,这样才能有所作为,SuperMan就让他在电影里飞着就好了,从屏幕里飞出来是要摔死的。第二个问题:这个问题比较复杂,我们来慢慢讲。首先,对于windows,之前我们讲到它要求一个主分区设置为活动分区,并把windows操作系统安装在该主分区。这个时候,windows的引导程序ntldr就会寻找到活动分区,并加载系统文件到内存。那要是linux系统呢,它可是个跟洪七公一样的大侠,居无定所,住哪都行的。要处理这样一个棘手的问题,就要隆重请出本文的主角啦——grub2. grub2现在是Ubuntu linux 默认的引导程序(boot loader)。如果你的一块硬盘里有两个操作系统,一个是linux,一个是windows.那么如果是windows的引导程序ntldr安装在了MBR上,除非使用像easyBCD这样的配置工具进行额外配置,它是只能够启动windows的,因为它不会把控制权交到别个系统的boot loader手上。而如果MBR上安装的是grub2,那么它就默认提供3大功能:
A.提供一块硬盘上所有安装的系统的选择菜单;
B.载入操作linux系统内核,移交控制权给内核;
C.将控制权移交给其他系统的boot loader

也就是说在grub2启动,在屏幕上呈现出操作系统的选择菜单,如果你并没有选择linux,而是选择了windows那么grub2就会把控制权交给ntldr,进而启动windows操作系统。


boot loader 最主要的作用就是识别自己的操作系统文件,并将它载入到内存。好问题又来了:一块硬盘只有一个MBR,那么你装上了grub2之后,就不能再装windows的ntldr了,如果没有ntldr就载入不了windows的系统文件,启动不了系统。但现在我们很多人的电脑上都有双系统,那是怎么做到的呢?答案是这样的:大家看上边的图,每个分区都有一个引导扇区(boot sector)。那么当你把系统安装在某个分区时,它同时也会在该分区的boot sector上安装它自己的boot loader。因为一个分区只能装一个系统(注意是分区,不是一块硬盘),这样该分区上的系统就可以被该分区的boot sector上的boot loader引导了,不会有其他系统的loader来抢占这个位置。但windowns除了在自己所在分区的boot sector上安装自己的boot loader,它还会在硬盘的MBR上也装上一份(linux的brub2不会这样)。所以,如果你先安装了linux,再装windows,那么最后MBR上就是ntldr,它是不会将控制权转交给别个系统的loader的,所以你也就启动不了linux。如下图所示:

(图片来源---鸟哥的博客http://linux.vbird.org/linux_basic/0510osloader.php#startup



我在安装linux的时候,还遇到了以下几个特别搞的情况:
1.在安装系统的过程中,为linux的根“/", "/boot"都分配了各自的分区,但却在最后的“安装启动引导器的设备”一栏选择 /dev/sda 而不是/boot. 这导致了个什么结果呢?就目前我所分析的,结果应该是这样:MBR上装上了grub2,系统装在了/里(/boot目录里包括原本想安装在/boot分区的内容),而/boot分区里什么也没有,也没有被系统给mount起来,grub.cfg也没有关于/boot的内容。也就是说/boot分区完全成为了“路人甲”。但系统运行没有任何问题。

2.之前的linux被弄坏了,且MBR上安装的是grub2.那么重装linux,"/" "/home"跟之前的都一样,但/boot选则了别的分区,在“安装启动引导器的设备”一栏选择/boot.结果是系统正确安装了,但并没有重写MBR,其上还是原来的那个grub2,所以它还是到原来旧的/boot读取其配置文件,造成系统启动不了。解决的办法就是从光盘启动,将/boot分区挂载到/的/boot目录下,然后执行指令 sudo grub-install /dev/sda 将grub2重新安装到MBR上,这个新的grub2默认读取配置文件是在这个新的/boot分区了。这个现象说明了一个问题:linux重装系统并不会在硬盘的MBR上安装它的boot loader(除非你指定让它安装在/dev/sda上)。【疑问:会不会是重装系统并不会覆盖MBR上已存在的与该系统配套的boot loader?】


情况2的显示形式:


接下来请转到鸟哥的博客(http://linux.vbird.org/linux_basic/0510osloader.php#startup)里阅读vmlinuz和initrd.img的作用。


那么你现在是否该有疑问了:由于MBR的容量太小,只能安装grub2代码,它的配置文件都是放在硬盘上的,要读取它们需要分区的驱动。但分区的驱动要在内核vmlinuz和initrd.img载入后才能找到而这两个东西又是依靠grub.cfg才能找到的,并且选择内核的菜单都是在该文件中配置的,这不是矛盾了吗?哈哈,这就是刚才没有认真读鸟哥的博客啦吧,不是说了有些分区格式,如ext2,是不需要驱动也能被内核找到的吗。而/boot一般都选取为ext2格式,grub.cfg也存储在那,所以正好解决了这个矛盾。(目前我认为MBR上的grub2代码有一条应该是指向了/boot分区的,这样他就可以绕过内核,直接读取配置文件。这也恰好解决了“特别搞情况2 所描述旧grub2还是指向旧的/boot而没有刷新到新的/boot的原因。因为是代码存储在MBR,而MBR的grub2又没有被重新安装)
好,讲到这,我们就来分析一下grub.cfg文件。
menuentry 'Ubuntu, with Linux 3.2.0-57-generic' --class ubuntu --class gnu-linux --class gnu --class os {
 recordfail
 gfxmode $linux_gfx_mode
 insmod gzio
 insmod part_msdos
 insmod ext2
 set root='(hd0,msdos10)'
 search --no-floppy --fs-uuid --set=root 6f887a61-a153-47bb-9631-4554472a1d6c
 linux /vmlinuz-3.2.0-57-generic root=UUID=e5f51b57-91c9-4ca8-8245-971ddee22269 ro quiet splash $vt_handoff
 initrd /initrd.img-3.2.0-57-generic

}

 前几行都是在这条启动命令之前定义的函数,用于设置背景,文字的干活。set语句和search语句目的一样,都是为了设置root变量的值,这样做保险,因为UUID更为稳定,其实root变量都是以最后设置的为准,所以前边set一句基本是废话。之前我以为这个root是告诉grub2去那找grub.cfg文件的,这不可能:第一,既然grub2都已经读取到了这个配置文件,还需要你告诉它去哪找这个文件吗?另一个是因为我目前认为每个grub2有一条特定代码告诉它去哪(地址)找到与它配对的配置文件。所以这个root是用于确定 /vimlinz 和/initrd.img文件是相对谁(root)的路径。  linux 这条载入内存指令中的 root==UUID=.....是指定系统文件所在的根目录,也就是系统运行时的那个"/"分区。(从鸟哥的博客里知道内核还要载入系统文件,而系统文件是在/上的,所以要在linux载入内核指令里指定你系统文件的根目录的UUID。)这样set和search语句设定/boot分区的UUID为 vmlinuz和initrd.img的root,并在linux载入内核指令中指定系统根目录/分区的UUID,这样就把分开成两个分区的/boot和/联系到一块了。

如果不是linux和initrd语句的错误,而是其他配置语句有问题,如找不到,就会有如下提示,但不要紧,有可能是你输入有错误,认真接查拼写就好了,不影响系统启动。


如果/boot与根/是独立的两个分区,但在linux载入内核指令中,root=UUID=...还是写的/boot的UUID,那么就找不到系统文件,但内核已经载入,所以出现如下提示:


耶,终于基本写完了。!!!(花了3天啦) 总结一下grub2的开机过程: BIOS自检->选择硬盘启动顺序->跳转到第一顺序硬盘上的MBR读取boot loader(grub2)->到硬盘特定的位置读取配置文件->显示操作系统菜单->加载linux内核mlinuz和虚拟文件系统initr.img->内核到/目录下加载系统文件->启动init进程初始化系统->等待用户登录使用。
进入系统后,就是挂载硬盘的过程了,如果你的/etc/fstab文件关于挂载分区的UUID有问题,那么就会出现如下现象:



如果/boot和根/挂载正确,并不影响使用。进入后修改fstab文件就可以了。
===========================华丽的分割线==========================

前边讲到的都是/boot与/是两个独立分区的情况。那么如果没有划分独立的/boot,应该是怎么样的情况呢?当你将分区与挂载点连接在一起之后,就得选择“安装启动引导器的设备”,有两种情况,一是你选择了/的分区;二是选择了/dev/sda,装在MBR上,覆盖掉原来装在MBR上的boot loader。


情况一:你将boot loader只是装在了/分区上,但MBR上还是原来旧的boot loader。如果原来的是ntldr,那么你就找不到你的linux系统了,要进入windows后用easyBCD等配置工具添加对linux启动的引导。由于我不喜欢ntldr的黑白引导界面,所以我很讨厌这样做。好,加入原来的是grub2,那么好了,由于原来的/或者/boot没有了,那么grub2到特定地方找不到配置文件,那么就会进入grub rescue界面,可以手动引导它找到新的配置文件位置。这样进入linux后,因为配置文件上的分区都是正确的,所以只要sudo grub-install /dev/sda将grub2安装到MBR覆盖旧的就解决了。还有一种特别绝的情况,就是既进入不了windows也到不了grub rescue,就是MBR上的boot loader坏掉了。这种情况下就没有办法了,MBR坏掉了,该硬盘上的系统肯定是启动不了了,但不妨碍其他硬盘或者光盘的系统启动呀。以linux启动光盘为例,进入BIOS的boot选项,设置启动顺序,选择DVD优先。进入启动界面,选择试用Ubuntu。因为这个时候系统是光盘上的系统,分区什么的信息都是相对于光盘而言的,它的配置文件对于硬盘上的Ubuntu来说都是不正确的。所以我们得移花接木,利用挂载mount指令,将当前的系统的挂载分区换成跟硬盘上的系统一致的。首先如果你有/boot分区,就要将该分区挂载到当前系统的/boot目录下。最绝的一点,我们可以把当前系统的根目录替换为硬盘系统的跟目录(当然这个要求你光盘系统跟硬盘系统是一样的,包括版本号和系统位数,不然恐怕要出错)。这样移花接木之后,当前的系统其实就相当与硬盘上的系统启动后的状态,配置信息什么的都是一致的。所以这时候执行指令sudo grub-install /dev/sda就可以把硬盘上的MBR给修复成硬盘系统的boot loader了。


情况二:如果你选择将boot loader装在了/dev/sda上,那么恭喜你,系统一定可以正常使用,它会同时在你挂载的根目录/分区的boot sector和硬盘的MBR上同时安装grub2。但如果这时你单独有一个/boot分区,那对不起,系统也只是将内核和initrd.img安装在/分区下的/boot目录里,不会安装在你的那个/boot相当于/boot被忽略,没有被使用到。

如果遇到了grub rescue的问题,不要着急,其实很easy,参考http://www.2cto.com/os/201111/112327.html,很有效的解决该问题。

参考资料:
大牛详述linux文件系统  http://forum.ubuntu.org.cn/viewtopic.php?t=257333
硬盘MBR详述  http://blog.csdn.net/sallay/article/details/3668614
鸟哥linux私房菜  http://linux.vbird.org/linux_basic/0510osloader.php#startup

grub2 详细介绍  https://wiki.archlinux.org/index.php/GRUB_(%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87)


本文是笔者的实验性探索总结,紧供技术交流讨论。奈何道行太浅,肯定有说错的地方,请大家批评指正。

感谢大牛们的无私分享,此致敬礼!


  
  
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值