GRUB——系统的引导程序简单介绍

时间:2024-02-20 16:21:20

这几天对于操作系统是如何引导启动的特征的感兴趣,已经到了不能自拔的状态了,所以索性好好了解一下;

前面已经说过了,MBR对于系统启动的重要性,这是不多啰嗦;  现在介绍一个 grub ,启动管理器,它可以用于引导不同的系统;

 

grub 是一个怎么样的引导原理?

通过我的实验,我得到的结论就是: 整个grub启动管理器其实也算是有点大的,引导扇区里是放不开的;  所以,grub会往引导扇区(可以是MBR, 也可以是每一个分区里面的引导扇区)里面写入部分内容,对于剩余的部分,它会写入到我们的硬盘分区里面的;在启动时,首先运行引导扇区里的程序, 然后在运行硬盘分区里的程序,最后引导操作系统;

对于引导扇区里的程序是如何找到硬盘分区里的程序与配置的,这个就是细节方面的问题了,我们可以忽略;不过我也是一个好学习的人,我也查了查相关的资料,有的解释如下:

来自:作者:js li
链接:https://www.zhihu.com/question/27652991/answer/37500373
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

grub的话,肯定是要在mbr里写东西的,但446字节的机器码也干不了太多东西,只是负责把后续的内容加载到内存在执行而已。这个写到mbr的是stage1,它加载的是写在mbr之后62个扇区中的stage1.5(因为过去磁盘是按磁道还划分分区的,一个碰道63个扇区,因为mbr占据了第一个磁道的第一个扇区,所以第一个分区只能从第二个磁道开始,这样在mbr和第一个分区之间就留下了62个扇区的空间,62*512byte=31KB)。

mbr之前说了容量太小没法放下识别文件系统的代码,只能以计算扇区绝对偏移的方法加载stage1.5,但31KB的stage1.5就足够了(但基本也只够一种类型的文件系统,所以stage1.5是有好几个,分别对应ext4,xfs等等,在grub安装时根据需要写入,随便一提,正是因为GPT分区表占用了后62个扇区的相当一部分位置,导致空间不够写下stage1.5,所以需要额外分出一个非常小的分区来存放)。 (我的备注:我在写grub时,没有设置是ext4,还是xfs, 应该是它自动识别的吧)

stage1.5可以识别文件系统,然后根据安装时硬写到里面的系统路径(hexdump可以看到)找到stage2,然后这个stage2才是真正负责干活的,它会读取grub.cfg并生成启动菜单,然后根据你的选择加载内核并把执行权限转过去,完成启动。

 

实验部分:

先跟着实验走一遍,然后就会更容易明白grub是如何引导的,来,先折腾起来:

我使用的grub版本分别为 grub-0.97 和 grub-2.02;

 

grub-0.97 的使用:

第一步:我们下载 grub-0.97这个工具,并安装到 linux系统上      

(注意:这里说的安装是指的 把这个 grub-0.97 工具安装到 linux 上,而不是把 grub-0.97的启动管理器安装到 硬盘分区上;我们需要使用grub-0.97 这个工具来安装 grub-0.97 启动管理器)

方法1:在 linux 上 使用 apt-get install grub 下载下来的为就是 grub-0.97版本的,所以直接 apt-get install grub 就下载下来了;

方法2:当然也可以下载源码,自己编译(下载地址:ftp://alpha.gnu.org/gnu/grub/):别忘了给 root 权限:

// 假设应该下载完毕,,位置目录 grub 下:

tar xzvf grub-0.97.tar,gz
./configure --prefix=/usr                 // prefix 指定了安装的位置,当然也可以放在其它地方,不过需要添加一下环境变量,
                                                 // 如果不过添加环境变量,就到安装的目录下去运行也可以;
make
make install

 

第二步:安装grub 引导管理器到硬盘分区:

方法1:是通过命令一步步的安装,输入 grub 会出来 grub的交互窗口如下图,这时可以输入命令进行安装; 至于命令吧,我没有研究啊,用第二个方法方便;

image

方法2: 用自带的 grub-install 脚本安装: 这个脚本其实也是调用 grub 的命令进行安装的:

首先 使用help 来看看grub的用法,输入 grub-install –help:

image

所以,我们知道了 grub-install 的用法啦.我们仅仅使用下面的命令格式就可以了,其它的就不用管了: 

sudo grub-install --root-directory=DIR install_device 

// DIR指的是grub的安装到硬盘的那一部分的目录位置;其实这个不重要,写到哪里都可以,反正 grub 的第一部分都可以找到的;只要你记住就可以了,因为可以在里面加入配置文件的;
                                                                  // 不过有一点要求:那就是把交叉硬盘,即不能把grub的第一部分与第二部分写在不同的硬盘上,我试过,会报错的;
// install_device 表示了安装到引导扇区的那一部分的到底的安装到哪一个引导扇区;
          // 例如:一块硬盘为sda, 如果 install_device 为 /dev/sda,则表示安装到了这个硬盘的MBR上;
                 //                     如果 install_device 为 /dev/sda1,则表示安装到了这个硬盘的第一个主分区的引导扇区上;
                 // 当然如果安装到第MBR上, grub启动管理器可以正常运行,如果安装到分区的引导扇区上,则需要使用到 chainloader(下面会说到)

安装完成以后,我们在 sdb1的分区下面应有了一个 /boot/grub/ 目录了;里面有相关的内容;

 

举个两个例子:

我给虚拟机加了一块硬盘sdb,并且已经分区、格式化完成了,如下:

image

例子1:把 grub的 引导程序的第一部分写到硬盘的MBR上, 至于grub的剩余部分安装到哪,都行,我就安装到第一个分区里吧,过程如下:(我要先创建一个空目录 sdb1,然后把硬盘的第一个分区挂载到上面)

image

这时,开机把启动项选择从硬盘 sdb启动, 就会出现  grub> 窗口了,如下:(由于sdb硬盘上 grub,并没有配置信息: menu.lst,所以它自己找不到sda硬盘上的系统上,所以需要进行手动引导,见下面)

image

 

例子2:把 grub的 引导程序的第一部分写到硬盘第一分区的引导扇区上, 至于grub的剩余部分同样的安装到哪,都行,我就安装到第一个分区里吧,过程如下:(我要先创建一个空目录 sdb1,然后把硬盘的第一个分区挂载到上面)

方法与上面相同:只需要把sdb 改为 sdb1就可以了;

image

 

补充:(这一小段来自:http://blog.csdn.net/zzqhost/article/details/5935317

    grub-install 是一个脚本,它完成以下任务:                     
    * 调用 grub-mkdevicemap 创建设备映像文件 /boot/grub/device.map
    * 复制 *.mod *.lst *.img 文件到 /boot/grub/
    * 调用 grub-probe 自动侦测文件系统类型
    * 调用 grub-mkimage 生成grub2内核文件 /boot/grub/core.img
    * 调用 grub-setup 安装引导记录到mbr或分区-

 

第三步:grub> 命令窗口下如何手动启动 linux 系统:

由于sdb硬盘上 grub,并没有配置信息: menu.lst,所以它自己找不到sda硬盘上的系统上,所以进行手动引导:

说明: 1.在 grub-0.97中,会把硬盘识别为 hd0,hd1,hd2, ……; 分区也是从0标志开始的,如第一分区(hd0,0), 第二分区(hd0,1),……; 

        2. grub 会把启动盘作为 hd0盘,其它盘为hd1, hd2等;

        3. 记得用 tab 补全;

命令如下:

image

解释: 1. 第一行 root (hd1,0),  表示设置一个 linux 系统的 /boot 目录的分区,在这个 /boot 目录下有 内核文件与启动的镜像文件;又由于 这个分区是 grub 看到的,所以用grub的格式表示,那为什么为(dh1,0)呢??因为现在的启动盘为 sdb,而linux的系统在sda的第一个分区上,所以为(dh1,0);  如果省略这个 root (hd1,0) 也可以,后面找内核与镜像文件时再指明也行,只是会麻烦一些;

       2.  第二行的命令是加核 linux 的内核文件,  对于后面的 root=/dev/sda1是什么?? 它指明了 linux 系统的  /  目录所在的分区,因为需要把很多东西mount到  / 目录下的目录名字下; 这个分区的路径是 linux 系统看到的,所以为 /dev/sda1;

      3. 加载映像文件;(什么是initrd.img,百度或google)

      4. 启动;

第四步: 配置 grub-0.97的配置文件,让它自动引导:

在 grub-0.97的 配置文件名字为:menu.lst 文件;至于配置文件的内容的书写方式,不多说,网上有很多,再说 现在都用grub2了,它的配置文件变了,所以研究也没有用了;我怎么做的呢?我先用 linux 上的grub-0.97 来自动自成一下 配置文件(命令:udpdate-grub),然后把它复制到 sdb1下的 /boot/grub/ 目录下(这个是我们上面生成的), 然后修改一下:  添加了一行命令: root  (hd1,0)  :

修改前:

image

修改后:

image

此时,我们重新从 硬盘 sdb里启动电脑,就可以启动了:

image

image

完成;

 

grub-2.02 的使用:

整个过程与grub-0.97 是相同的,说说不一样的地方 :

1. grub-2.02 可以在这里下载:ftp://ftp.gnu.org/gnu/grub/ftp://alpha.gnu.org/gnu/grub/

    或者: ap-get install grub2-common;

2. grub-2.02支持更多的命令;

3. grub-2.02的 grub-install 的参数不一样了,同样可以通过 grub-install –help查看,部分如下:

image

在使用时,这么用:

sudo grub-install --boot-directory=DIR install_device 

// 例如: sudo grub-install --boot-directory=/sdb1/ /dev/sdb
 // 它指的是 boot的目录 , 而不是root的目录了;

4.  在 grub-2.02中,会把硬盘识别为 hd0,hd1,hd2, ……; 而分区也是从msdos1标志开始的,如第一分区(hd0,msdos1), 第二分区(hd0,msdos2),……; 

5. 在grub-2.02中的配置文件变成了 grub.cfg;

6. 当我把 grub-2.02安装到 sdb的MBR时, 把 linux系统下的 grub.cfg 文件复制到 sdb1分区上的 /grub/ 目录下时, 修改如下:

把 grub.cfg 里面的 hd0 全部替换为 hd1;  最后,在sdb硬盘启动时, sda上的 linux 系统启动成功;

7. 我发现使用在grub-2.02里,使用grub-install 写入到分区的引导记录时,会出问题,而使用grub-0.97则不会再现问题;

8.grub-2.02的命令有所不同:

set root=(hd1,msdos1)
linux /boot/ vm**** boot=/dev/sda1
initrd /boot/initrd.img***
boot

 

当把grub 没有安装到硬盘的 MBR里面,而是安装到了 第一分区,或第二分区时,怎么办?

使用 chainloader 命令( 它属于 grub的命令),它可以调用另一个启动器,如:在grub中,输入命令例如:

root (hd0, 0)             // 为安装grub 的分区,这是为第一分区;

chainloader +1          // 将指定的文件作为一个链式装载程序载入。为了获取在一个指定分区第一 扇区内的文件,使用+1作为文件名。

boot

这时,就会从硬盘的第一分区进行启动了;

 

完;

另外:可以看看相关的:GRUB(简体中文)