Linux系统启动过程
BIOS/UEFI
我们使用的电脑,在主板上面会有一段固化代码,我们称之为板载启动程序(固件)
,早期是BIOS,近几年已经迭代为UEFI。
注:BIOS/UEFI也是可以刷写的,不过需要特别小心哟,不然电脑就起不来啦!
GRUB
GRUB(GRand Unified Bootloader)是一个来自GNU项目的多操作系统启动程序,其角色和嵌入式领域的U-Boot是类似的,负责硬件初始化(如内存、硬盘)和加载内核。
系统启动过程
电脑按下开机键后,系统引导分3个阶段:
-
初始准备阶段:加载BootLoader
BIOS自检通过后,会根据设置的boot order寻找第一个可以引导的设备(boot device)。如果第一个boot device是硬盘/U盘,BIOS会读取它的第一个扇区(MBR所在扇区)加载到内存0x07c00地址处,并跳转到该地址执行。
MBR只有446字节,不可能实现复杂功能,它用于存放GRUB2 boot.img,它的主要任务(或者说boot.img的主要任务)是读取GRUB2 core.img的第一个扇区到内存,并执行该扇区的代码。
注1:GRUB2编译出的boot.img恰好是512字节,GRUB安装时会将boot.img写入MBR。
注2:MBR空间有限,不可能实现复杂功能,不支持通过文件系统读取GRUB2 core.img,只能按扇区去读core.img。
那么,core.img又存储在哪里呢?
一般来说,在MBR扇区和硬盘第一个分区之间,还有一块空闲区域(MBR gap,又称保留扇区),MBR gap有62个扇区(即31744字节)。GRUB2的core.img就是从MBR gap的第一个扇区开始依次存储,这也意味着core.img大小不能超过31744字节!(注:GRUB2里的很多功能模块是以module的形式存在,不会编译进core.img,从而控制core image的size)
GRUB安装时,会将MBR gap第一个扇区的地址硬编码到MBR,MBR会从该位置读取第一个扇区内容(即core.img的开头512字节)到内存并执行,此扇区代码会将core.img剩余部分读入内存。
core.img功能强大,可以按需加载功能模块(比如文件系统驱动),可以识别文件系统,挂载分区和访问文件。
扩展:引导扇区的结构
-
前446字节是MBR(Master Boot Record,主引导记录);
-
接下来的64字节是分区表;
-
末尾2字节是结束标志(0xaa55);
-
-
内核启动前的配置和管理阶段
GRUB core.img执行后,会出现GRUB2启动菜单,按上、下方向键选择启动项(按E键可以编辑启动项)。
同时,在此阶段,也可以按C键进入GRUB Shell。
-
加载内核阶段
在选择完启动项后,GRUB2会加载指定的内核文件(grub.cfg的每个menuentry都会指定kernel和initrd的位置)到内存0x100000处,然后跳转到内核指令开始执行。
-
Kernel引导阶段:
内核自解压
内核初始化
内核启动时,会再次检测硬件并初始化。
-
准备过渡阶段的root文件系统
为了兼容不同类型的存储设备和文件系统,同时不增大kernel size,CentOS、Ubuntu等发行版都会先启动一个临时的root文件系统作为过渡系统,在过渡系统内加载需要的驱动模块,并挂载真正的root文件系统。
这个“临时的root文件系统”就是initramfs,一般存放在/boot/目录下。在系统引导阶段,GRUB加载
/boot/initrd.img-$(uname -r)
到内存,然后内核将其解压到所创建的tmpfs中,而tmpfs在创建时就被挂载到根目录。然后,kernel会调用initramfs中的
/init
程序,从此进入用户空间,init程序会继续启动各个系统服务,最后运行agetty程序,显示登录界面。 -
跳转到真正的root文件系统
此小节未完待续。请思考:“过渡root文件系统”是怎么切换到“真正的root文件系统”? (switch-root服务?)
GRUB内部窥探
GRUB的运行模式:
模式 | 说明 |
---|---|
Normal | 常规模式,包括菜单和控制台,是GRUB默认模式 |
Rescue | 受限模式,比如GRUB未找到root设备,会进入该模式 |
注:在 normal 模式下输入rescue
即可进入 rescue 模式;在 rescue 模式下输入normal
即可进入 normal 模式。
GRUB Rescue mode
如果GRUB未能成功加载内核,就会进入Rescue模式。在Rescue模式下,只有很少的命令可用:
命令 | 说明 |
---|---|
set | 查看环境变量(主要是root 和prefix 变量) |
unset | |
ls | 查看设备 |
insmod | 加载模块 |
参考: