Linux系统启动流程(Linux如何被启动)
一个Linux系统的组成部分
Linux系统组成部分:内核+根文件系统;理解这个概念非常重要,简单来说,系统启动就是为了启动内核,让内核加载根文件系统,最后执行初始化程序。
Linux开机启动流程
首先简要概括下Linux系统的启动流程
从按下电源键开始,Linux的启动流程大概如下
1.POST自检
2.按顺序寻找引导程序
3.启动内核
4.内核加载根文件系统
5.启动init程序
下面来详细说明下各启动阶段都做了什么
一、POST自检
POST自检主要对硬件设备的检查设备的运行状态,POST自检也是一个程序,安装在主板的的ROM上,读取CMOS中的信息,以了解部分硬件的信息,比如硬件自检(post)、硬件上的时间、硬盘大小和型号等。包括,手动进入bios界面看到的信息,都是在这一阶段获取到的,如下图。
设置引导顺序
当硬件扫描完成后,开始读取第一个设备的MBR,如果第一个设备没有MBR,则会读取第二个。
二、寻找引导程序
硬盘的第一个扇区:MBR(Master Boot Record) 主引导记录
引导程序为了加载内核而存在,当POST自检没问题后,计算机会按照用户所给定的存储设备顺序来读取MBR,为什么读取MBR,因为MBR保存了引导程序,但引导程序不一定安装在MBR上,本文这个步骤只针对MBR,但无论哪种启动方式都好,目的都是一样的,为了加载引导程序!
MBR也称:主引导记录,位于磁盘的第一个扇区,和分区无关,和操作系统无关,注意,MBR位于磁盘的第一个扇区,因此一个硬盘只有一个MBR;
MBR由512 Byte组成
446 Byte:存放引导程序(bootloader);
64 Byte:存放磁盘的分区表;
最后2 Byte:用于标识MBR是否有效,如果BIOS读取时,发现MBR最后2个字节的数值不是0x55AA,则认为这个MBR是没用的,会去读取下一个设备。
这里需要注意的是,不要把MBR和bootloader的概念混在一起,2个是不同的东西,一定要区分开,bootloader存放在MBR中;MBR不单单存放bootloader还有存放分区信息呢。
引导程序
引导程序是为了加载内核而存在,引导程序是有很多的,其中,就有grub一个,很多的Linux发行版使用grub这个程序作为它的引导程序,它有两个版本。
grub 0.X:Linux5、6使用
grub 1.X:Centos7使用
本文只针对grub 0.X引导程序来说明,grub 0.X也称为grub lagecy,有三部分组成,也称为三个阶段。stage1,stage1.5,stage2。分别安装在不同的位置上
stage1: 安装在MBR的前446个字节中
stage1.5: 安装在MBR后面,第一个分区前的间隙中
stage2: 放在磁盘某个分区中
为什么要划分为三个阶段?
因为引导程序grub实在太大了(相比起MBR只有446字节来说)上面三个阶段中,stage2才是gurb的核心程序,它是向我们提供菜单的提供者,它的代码量大小,远超446字节,是不能直接存放在MBR中。stage1只是为了加载stage2,但前面说了stage2是存放在磁盘分区中的,磁盘分区要想保存文件,必须拥有文件系统。而要读取这个文件系统上的文件,是需要驱动的,而现在文件系统格式这么多(如ext2,3,4、ntfs、xfs...)而stage1只有446Byte存放引导程序,明显是不够的,所以引入了stage1.5,stage1.5保存了文件系统驱动,用于提供文件系统驱动协助stage1加载stage2,当stage1有文件驱动的支持后,才能读取磁盘分区上的数据,从而能加载stage2
stage1_5的目的之一是识别文件系统,但文件系统的类型有很多,所以对应的stage1_5也有很多种,如下图:
stage1.5的文件驱动
这些文件通常存放在/boot/grub目录下,satge2程序也存放在该目录下,在安装系统的时候,通常情况下,很多人的做法是把boot分区单独分区,而且分区格式一般都是比较常见的,这是为什么呢?
原因也很简单,如上图,stage1.5所支持的文件系统不多,某些特殊或比较少见的文件系统是不支持的,而现在也有很多人喜欢把根文件系统挂载到LVM之类的逻辑文件系统,而grub没有这类文件系统的驱动。如果把boot目录挂载在grub不能识别的文件系统上,引导就没办法进行。所以一般boot单独分区就是因为这个。
顺利启动stage2之后,屏幕应当显示一个菜单,让用户选择要启动的系统或内核。这个菜单是通过配置文件定义的,配置文件在根目录下的grub目录,引导程序的根目录和内核的根目录是两回事,迄今,内核还没启动,还没去找文件系统呢,所以别混肴。
用户在菜单中选定了某一功能后,在背后就会按照配置文件的定义来启动内核,grub legacy的配置文件很有意思,我会对grub legacy的配置文件作详细说明,请查看我的其他文章。
grub会按照配置文件所给定的参数来启动内核。
三、启动内核
内核存放在哪里?grub如何启动内核?
第一个问题:内核存放在哪里?
内核文件通常存放在/boot目录下,通常该目录也是grub程序的根目录,内核是以bzimage压缩存放在该目录中,并且名称一般都是以vmlinuz-后跟版本号。这样的方式来命名
内核文件位置
第二个问题:如何启动内核
很简单,通过配置文件,该配置文件通常存放在/boot/grub目录中,名字通常为:grub.conf
grub.conf
配置文件定义了各种菜单,每个一般都对应一个内核,以及传递一些运行参数给内核,
grub.conf文件
如上图,开头的几个选项是一些通用配置,只要定义默认菜单、超时时间和背景图的一些选项。重点是用红色框和绿色框的内容。
每个title对应一个菜单,如下图,title后面的字符串就是菜单所显示的内容。
每个title对应一个菜单
每个菜单,基本上都定义了三个类内容:root、kernel、initrd
第一个选项:root
指定grub以哪个硬盘分区作为根目录(hd0,0)是指第一个磁盘第一个分区的意思,它的索引从0开始算起。
这里说明一下,hd0,0一般挂载在/boot目录下,如也就是说,hd0,0,其实对应sda1(sda1也是第一个磁盘第一个分区的意思嘛)然后sda1又挂在/boot目录下,所以指定root=hd0,0;其实也就是root=/boot的意思。虽然有点绕,但是最好还是理解一下。
第二个选项:kernel
kernel:后面指定压缩好的内核文件存放路径,前面已经说了内核文件一般存放在/boot目录下,然后上一个root选项指定了hd0,0作为根目录,相当于grub的根就是/boot,所以kernel 后面指定的/vmlinuz-4.14.341其实说的就是/boot/vmlinuz-4.14.341这个文件。
指定好linux内核位置之后,还需要传递参数给内核,如linux的根文件系统在哪里,这是必须给出的。
指定linux根文件系统位置
绿框的是位置,因为我的根文件系统存放在LVM逻辑卷上,所以看上去可能不太好理解。
第三个选项:initrd
理解这个之前,先来说明下,内核启动后,主要的工作就是加载根文件系统,然后启动init初始化程序(通常就是/sbin/init),随后的所有用户空间的工作全部由init完成,内核不关心用户空间的程序。
内核为了加载init程序,需要加载根文件系统,因为init程序就是存放在根文件系统的/sbin目录下,而加载根文件系统是必须要有文件系统的驱动。而文件系统的驱动又在哪里呢?答案是在磁盘某个分区上,内核加载磁盘需要磁盘驱动,而驱动又存放在磁盘上,这就有了先有鸡还是先有蛋的问题,那么如何解决呢?
解决方法一:把根文件系统的驱动以模块方式嵌入到内核中,但文件系统又太多,都嵌入到内核明显是不合适的
解决方法二:跟grub那样,在加载真正的根文件系统之前,先加载这个临时的根文件系统,然后再去加载真正的根文件系统。这个临时的根文件系统,这个临时的文件系统是安装操作系统之后产生的,不是默认提供的,在安装系统时候,我们创建好了根文件系统,这个initramdisk就能根据我们的根文件系统来嵌入对应的文件系统驱动,而不用嵌入其他的驱动。如图
系统安装完成后,会自动创建initramfs
initramdisk存放着根文件系统的驱动生成的initramdisk文件存放在和内核一起的目录。
在Centos5之前,这个文件名叫:initrd-VERSION-RELEASE.img
在Centos6、7,这个文件名叫:initramfs-VERSION-RELEASE.img
两者区别在于
Linux特性之一:通过使用缓冲/缓存来达到加速对磁盘上文件的访问的目的,而ramdisk是加载到内存并模拟成磁盘来使用的,所以Linux就会为内存中的“磁盘”再使用一层缓冲/缓存
CentOS 5系列以及之前版本是存在此问题。
而为了解决一问题,CentOS 6/7系列版本就将其改为initramfs-VERSION-RELEASE.img,使用文件系统的方式就可以避免双缓冲/缓存了,我们可以说这是一种提速机制。
而且这两类的临时根系统有各自的特点,在其他文章中再说明
以上三个选项内容指定好后,grub程序把内核和临时根文件系统从磁盘中加载到内存中并解压运行。内核通过临时根加载到真正的根文件系统后,切换到真正的根文件系统中运行初始化程序init。
Centos5根6和7的临时根文件系统有区别,在Centos5中,使用initrd.xxx来作为临时根,内核通过内核线程来先挂载真正的根文件系统,然后再运行Init程序。而Centos6和7使用initramfs.xxx作为临时根,在initramfs中,内核直接就执行init程序了,挂载真正的根文件系统是由init程序来完成。
五、启动init程序
接下来就是用户空间init程序的介绍,Centos 5 6 7 中init程序都不一样。
Centos5使用sysV作为init程序
Centos6使用upstart作为init程序
Centos7使用systemd作为init程序
各init程序的区别我用其他文章做说明。
其实init程序启动之后,Linux的启动已经完成了
init的工作无非就是把初始化环境,启动开机启动程序,打印登陆提示符给用户。