什么是GRUB
GRUB(GRand Unified Bootloader简称“GRUB”)是一个来自GNU项目的多操作系统启动程序。
Linux的启动过程
详细可参照阮一峰的计算机是如何启动的?。
1. BIOS
BIOS在自检无误后,会根据启动顺序,把控制权转交给排在第一位的储存设备。
计算机读取该设备的第一个扇区,也就是读取最前面的512个字节(为啥是512个字节)。
如果这512个字节的最后两个字节是0x55和0xAA,表明这个设备可以用于启动。
这512个字节的主要作用是,告诉计算机到储存设备的哪一个位置去找操作系统。
2. GRUB
在计算机读取第一个扇区512个字节(stage1)后,找到了GRUB,由用户选择启动哪一个操作系统。
3. Linux
GRUB在用户选择后,会启动选择的操作系统的kernel,然后运行init进程。
GRUB怎么用
详细可参照官方手册
boot分区下的文件
- vmlinuz 内核
- initramfs 虚拟文件系统
在linux内核启动前,GRUB会将虚拟文件系统加载到内存。内核启动时,会在访问真正的根文件系统前,先访问该内存中的虚拟文件系统。
虚拟文件系统的目的是为访问真正的根文件系统扫清一切障碍,最主要的是加载根文件系统存储介质的驱动模块。
GRUB常用脚本
安装GRUB
grub2-install /dev/sda
这样的安装方式,默认会将文件放入到/boot目录下
生成配置文件
grub2的默认配置文件为/boot/grub2/grub.cfg,该配置文件的写法弹性非常大,但绝大多数需要修改该配置文件时,都只需修改其中一小部分内容就可以达成目标。grub2-mkconfig -o /boot/grub2/grub.cfg
可用来生成符合绝大多数情况的grub.cfg文件
GRUB常用命令
详情见官方手册
命令 | 描述 | 示例 |
---|---|---|
insmod | 插入模块 | # insmod ntfs |
lsmod | 显示已经加载的模块 | # lsmode |
set | 设置环境变量 root-设置根目录 default-设置默认菜单 timeout-设置超时 |
# set root=(hd0,msdos1) # set default=0 # set timeout=5 # set prefix=(hd0,msdos1)/EFI/grub |
linux | 加载linux内核 | # linux /vmlinux |
initrd | 加载初始化RAM数据模块 | # initrd /initrd.img |
boot | 启动 |
如何自定义GRUB命令
万事始于HelloWorld!
1 | GRUB_MOD_LICENSE ("GPLv3+"); |
使用grub_register_extcmd()注册你自己的命令就是那么简单。
编写过程中的注意点
- 因为是grub中跑,所以不能用系统的函数,得用grub的函数,比如grub_printf(printf)、grub_malloc(malloc)以此类推。
- 自定义的命令需要与其他文件一起编的时候,得在Makefile.core.def中写明,比如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41module = {
name = normal;
common = normal/main.c;
common = normal/cmdline.c;
common = normal/dyncmd.c;
common = normal/auth.c;
common = normal/autofs.c;
common = normal/color.c;
common = normal/completion.c;
common = normal/datetime.c;
common = normal/menu.c;
common = normal/menu_entry.c;
common = normal/menu_text.c;
common = normal/misc.c;
common = normal/crypto.c;
common = normal/term.c;
common = normal/context.c;
common = normal/charset.c;
common = lib/getline.c;
common = script/main.c;
common = script/script.c;
common = script/execute.c;
common = script/function.c;
common = script/lexer.c;
common = script/argv.c;
common = commands/menuentry.c;
common = unidata.c;
common_nodist = grub_script.tab.c;
common_nodist = grub_script.yy.c;
common_nodist = grub_script.tab.h;
common_nodist = grub_script.yy.h;
extra_dist = script/yylex.l;
extra_dist = script/parser.y;
cflags = '$(CFLAGS_POSIX) -Wno-redundant-decls';
cppflags = '$(CPPFLAGS_POSIX)';
}; - 在grub中有一些库是没有的,比如
math.h
,需要自己实现。 - 在grub中只能读文件,没有实现写文件的功能,需要自己写。也可以借助save_env存到
/boot/grub2/grubenv
。 - 每次重新安装grub的rpm包后要重新
grub2-install
安装模块,保险起见grub2-mkconfig
重新生成菜单文件。
总结
GRUB的模块开发挺有意思的,其代码量也不是很多,有时间可以通读一下,我觉得可以加深我对磁盘以及文件系统的理解。