grub2配置原理分析

2 篇文章 0 订阅
1 篇文章 0 订阅

综述

BootLoader(引导程序)是系统启动之后第一个运行的程序。它的主要作用是加载操作系统并转入操作系统的入口,接下来的系统将由操作系统接管。随着技术发展,计算机系统的部署越来越复杂。从硬件角度,计算机引入了许多新的技术用以提供系统的性能,如SAS接口磁盘、NVMe接口磁盘、APIC等等,从软件角度,系统可能会安装在不同的文件系统上,甚至需要支持RAID、逻辑卷等底层的数据组织架构。复杂的环境对BootLoad有的设计带来了很大的挑战。BootLoad需要设计能够应对各种硬件的驱动程序,而且需要能够识别越来越复杂的数据存储结构。引导程序逐渐成为了一个在操作系统之前的操作系统。
Grub是一个可以被广泛应用的引导程序。他即能支持多种多样的硬件平台,也能够与包括Linux、windows在内的多种操作系统进行对接,它甚至可以能够引导安装在软RAID上的操作系统1。当采用Grub进行引导时,你即可以用他的图形界面选择启动项,也可以通过它提供的命令行在启动之前对启动项的各项进行编辑。而且,对于我们经常进行内核开发的场景来说,Grub提供的命令操作是非常有用的。
2002年始,Grub的维护者 Yoshinori K. Okuji开始重写Grub的相关程序,在架构上对其进行了重构,引入了模块化、基于Shell的配置文件生成机制、类脚本的编程的配置文件格式等新的设计思想,彻底的解决了Grub原有设计上的一些限制。业界将重构版的Grub称做Grub2,以区分原有的Grub。自2007年始,Grub2逐渐被各大发行版所接受,代替原有的引导程序。
与原有的grub相比,有很多新的不同点。在其用户手册中,主要总结了如下几点:
* 采用grub.cfg作为配置文件名字。采用新的配置文件语法
* grub.cfg可以通过grub-mkconfig进行自动生成。围绕grub-mkconfig,Grub2提供许多自动生成脚本,包括linux启动项自动搜索、适于Xen的配置项及内存检测配置项等。你可以在/etc/grub.d中找到他们。
* 分区编号开始从1开始
* 配置文件支持脚本化编写,支持变量、条件、循环
* 提供环境块机制用以保存少量的启动过程信息(操作系统加载之前的)
* 能够支持多盘引导,可以通过磁盘标签、磁盘的UUID确定磁盘
* 支持更多的系统,包括PC BIOS、PC EFI等等
* 提供图形化的终端
* 支持更多的文件系统
* 支持LVM、RAID等机制
* 重新组织引导镜像,不再使用Stage 1, Stage 1.5, and Stage 2作为引导阶段
* 支持动态模块加载,可以根据需要加载不同的驱动

如果有兴趣或者必要,可以对上述的区别进行详累的分析。
假设我们编译一个新内核,以期在现有的系统进行引导,需要做的动作如下:

  1. 将对应的内核镜像和initramf复制到/boot目录
  2. 复制内核模块到/usr/lib/modules目录
  3. 调用grub-mkconfig这个命令重新生成一下配置文件。

前两步由内核的编译程序可以帮你完成。后面一步是grub提供的程序完成的。这一步会重新检索/boot目录,将识别到可引导的操作系统引导项加入到grub.cfg中。
第三步我们可以手动操作。从配置文件中复制一项以munuentry开头的命令项,将内核及initcramfs替换成新的项就可以。之所以可以这做手动操作,是因为,Grub启动引导时只与grub.cfg这一个配置文件有关。与/etc/grub.d中的所有配置都是无关的。

grub.cfg基本语法

前面已经提到,grub.cfg是脚本化的,语法类似于Shell的语法。但是要注意,它不是一个Shell脚本,我们不能使用在本Shell所能使用的指令去编写这个脚本(比如,做一些字符处理什么的)。脚本里面的命令均是Grub的内置命令,其执行机理与操作系统Shell无一点关系。在这个脚本执行时,我们的操作系统内核还没有引导起来。下面,我们摘一些段落进行分析。

字符串

字符串是组成脚本的基本语义单元。字符串在脚本中可以表示函数名、变量等。
保留字是一类特殊的字符串,在脚本中具有特别的意义,不能表示函数名、变量等。grub.cfg定义的一些保留字如下:

! [[ ]] { }
case do done elif else esac fi for function
if in menuentry select then time until while

变量引用

和Shell脚本一样,grub.cfg用”$”表示一个变量。变量可放在大括号中,如 ${prefix},其主要目的是在与字符联接时能被完整的识别为一个变量。如表达式if [ -e ${prefix}/gfxblacklist.txt ]; then${prefix}可以正确被识别为一个变量。一般的变量的名称是以字母开头的,后面可以有0个或者多个字母。数字作为变量名表示函数中的参数。如$1表示传递给函数的第一个变量。变量$?表示近一次调用函数的状态值。这个含义也与Shell中的含义相同。
其它预定义特殊的变量。总结如下表:

变量名称含义
$1传到函数中的第一个变量,以此类推
$?近一次函数执行的状态值,可参考Shell中的状态值的含义
$@所有的参数,每个参数用”“引起来
$*没加引号的所有参数
$#参数的个数

命令

一行简单的命令就是一个表达式。他可以是一个单独的命令执行。第一个单词指定了要执行的命令。后面的字符串表示其执行所需要的参数。命令执行的返回值存放在状态值里面,在接下来最近语句中可以使用$?获取。可以在命令执行前加上”!”,使其最后的值取反。
Grub配置很多引导过程所需要的命令。这些命令在脚本中的使用方式和惯例与Shell脚本非常相似。可以说,Grub配置文件本身就是一个小的程序解释器。
官方的手册将其所支持的命令分根据应用范围和作用,分了四类:
1. 与菜单相关的命令
Grub支持menuentrysubmenu两个与启动项相关的命令。
menuentry表示生成一个GRUB的选择项,一旦用户选择这个选项后,将会执行一系列指定的命令。
submenu生成一个包括子菜单的菜单项。用户选定后,会弹出子菜单,子菜单的中的选项由menuentry指定。
2. 通用命令
通用命令是可以放在配置文件任何位置命令。
3. 可以在命令行及菜单内部使用的命令
这类命令即可以在命令行也可以在菜单项内部执行。此类命令可以分成两类理解。一类是模访Shell用于判断和字符串处理的基本命。如[catcmp等。一类是Grub所使用的命令集。如acpilinuxboot等。
Grub提供了help命令可查阅各个命令的具体使用。
4. 与网络相关指令
此类命令用于远程启动时对网络环境配置。如设置IP、设置DHCP等。

函数

形式为:

function name { command; . . . }

表示定义了一个函数名为name的函数;函数体中包含着这个函数所要执行的命令。其格式如简单命令所述。通常的写法是每一行一个命令,如果在同一行中,两个命令之间需要用分号隔开。函数定义不会改变$?中的值。即在函数定义块之前和之后,$?的值一定是相等。函数调用时,其状态值由最后一个执行的命令所决定。
以下为一个函数的示例:

function load_video {
  if [ x$feature_all_video_module = xy ]; then
    insmod all_video
  else
    insmod efi_gop
    insmod efi_uga
    insmod ieee1275_fb
    insmod vbe
    insmod vga
    insmod video_bochs
    insmod video_cirrus
  fi
}

语句控制块

可参考shell中的写法,如下表:

表达式含义
for name in word . . .; do list; done对word中的每个字符串进行遍历
if list; then list; [elif list; then list;] . . . [else list;] fi条件判断
while cond; do list; done
until cond; do list; done
循环
menuentry title [‘--class=class’ . . .] [‘--users=users’] [‘--unrestricted’]
[‘--hotkey=key’] [‘--id=id’] { command; . . . }
定义一个启动项

环境块

为了简化引导程序的实现,Grub没有实现对文件写的逻辑。因此,在操作系统运行之前,我们不能像管理配置文件那样对一些需要保存的信息进行保存的。在一些场景下,我们需要保存一些用户在Grub操作中执行的一些状态信息。例如,保存本次用户选择的启动项,以便下次启动时以此为启动项。为此,Grub引入了环境块(environment block)来解决这个问题。在启动过程中,grub.cfg调用load_env命令将其载入到内存中,在运行过程中,使用save_env命令保存修改的信息。
在ubuntu系统上,环境块存储于/boot/grub/grubenv中。我们可以使用grub-editenv编辑这个文件。ubuntu系统默认情况下,对没有保存任保变量。例用上述命令增加一个变量:

[root@ubuntu grub]# grub-editenv  /boot/grub/grubenv set foo=1

查看验证:

[root@ubuntu grub]# grub-editenv  /boot/grub/grubenv list
foo=1

取消这个已经设置的变量:

[root@ubuntu grub]# grub-editenv  /boot/grub/grubenv unset foo
[root@ubuntu grub]# grub-editenv  /boot/grub/grubenv list

grub-mkconfig利用此信息定义记录上次启动信息以便下次利用。当将设置选项2GRUB_SAVEDEFAULT设置为true后,再次生成一次配置文件,启动时,就能够将启动时选择的启动项记录到环境块的saved_entry。为使下次执行仍使用上次启动的项,还需要将GRUB_SAVEDEFAULT设置成saved

如果grub环境变量 GRUB_SAVEDEFAULT 设置为true时,表示:每当启动时,对启动项进行的调整,这个启动项将会保存起来。

生成配置文件

命令说明

Grub2运行时配置文件可以通过grub-mkconfig3进行生成。

[root@ubuntu grub]# grub-mkconfig -o /tmp/grub.cfg
Generating grub configuration file ...
Found linux image: /boot/vmlinuz-3.16.0-30-generic
Found initrd image: /boot/initrd.img-3.16.0-30-generic
Found memtest86+ image: /boot/memtest86+.elf
Found memtest86+ image: /boot/memtest86+.bin
done

grub-mkconfig检索配置项

该命令被调用时会检索/etc/grub.d目录下配置文件,按照文件排序进行调用执行,将配置文件的输出到标准输出的信息重定向到grub.cfg中。在该目录下的所有可执行的配置文件都会被调用,为确保调用顺序易理解,系统将该目录下的文件进行编号。编号的规则是:
* 所有的需要被生成命令识别的配置文件都以*‘编号’+‘-’+文件名的形式定义
* 编号00_*: 留给00_header,使其优先于所有的配置文件而被执行
* 编号10_*: 本系统的相关启动项生成脚本
* 编号20_*: 第三方应用的生成脚本

通过上述编码之后,每个配置文件名称前面的编号基本上决定了其解析顺序。这个顺与执行ls -l所获得的文件的顺序是一致的。如:unbuntu系统中的配置文件列出如下:

[root@ubuntu grub.d]# ls -l 
total 76
-rwxr-xr-x 1 root root  9791 Jul 16 22:59 00_header
-rwxr-xr-x 1 root root  6058 May  8  2014 05_debian_theme
-rwxr-xr-x 1 root root 11608 May 15  2014 10_linux
-rwxr-xr-x 1 root root 10412 May 15  2014 20_linux_xen
-rwxr-xr-x 1 root root  1992 Mar 12  2014 20_memtest86+
-rwxr-xr-x 1 root root 11692 May 15  2014 30_os-prober
-rwxr-xr-x 1 root root  1418 Jul 16 22:59 30_uefi-firmware
-rwxr-xr-x 1 root root   214 May 15  2014 40_custom
-rwxr-xr-x 1 root root   216 May 15  2014 41_custom
-rw-r--r-- 1 root root   483 May 15  2014 README

如果需要对Grub进行个性化定制,我们需要调整/etc/grub.d目录中的配置。


  1. 在软件RAID上引导Linux https://www.experts-exchange.com/questions/28555676/Centos-7-grub2-problems-putting-root-on-raid1-md-array.html
  2. /etc/default/grub 中的配置项是通过grub-mkconfig解析。为使其生效,改动后均需要重新生成grub配置文件/boot/grub/grub.cfg
  3. centos 中为了区分新一代的Grub命令需要将Grub替换成grub2
  • 1
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值