csdnyasin 2019-12-12
CentOS系统启动流程介绍
本章我们将学习 Linux 启动流程和内核模块管理相关的内容。通过本章我们将学习如下内容:
在学习本章内容之前,需要对之前学习的操作系统知识做一个简单梳理总结,目的是了解 Linux 系统在启动时面临了哪些问题,怎么去解决这些问题。这样我们才能知道为什么启动流程是”这样”。
123456789 | --------------| 库调用接口 |---------------| 系统调用接口 |-------------------------------| 操 作 系 统 |-------------------------------| 底 层 硬 件 |------------------------------- |
在一个已经开机的计算机上,操作系统位于底层硬件之上,通过加载硬件的驱动程序从而能够管理各种硬件设备。操作系统通过系统调用,将管理底层硬件的接口暴露给各应用程序。应用程序在需要时发起系统调用即可完成对底层硬件的驱动。系统调用接口比较简陋,不便于程序员进行编程,因此在系统调用基础上有各种库,方便程序员进行编程。
操作系统=内核+根文件系统,Linux 中一切皆文件,Linux 的所有设备都表现为根文件系统上的某个文件。因此内核必需首先要加载底层磁盘设备的驱动程序,然后加载该磁盘设备上特定的文件系统,最后挂载根文件系统。
但是在系统启动之前,操作系统和各种驱动程序都是存放在硬盘上的。这样就会出现以下问题:
因此开机启动,必需要解决上述两个问题。
本节,我们开始学习 Centos 系统的启动流程,本章开篇我们了解到,开机过程中存在两个问题:
本节核心就是讲解如何解决上述两个问题,并在此基础上介绍 Linux 系统的启动。本节将包括以下内容:
Linux 主要由内核+根文件系统组成,一个运行中的Linux,可以看作是运行在内核之上,由内核负责完成底层硬件管理,从而将硬件接口抽象为系统接口以后,让根文件系统工作为文件系统的一个底层虚拟机。运行中的OS可以分为内核空间和用户空间两个部分,应用程序运行在用户空间,通常表现为一个进程或线程;而内核空间主要运行内核代码,执行特权操作,通过系统调用向用户空间输出接口。用户空间通过发起系统调用执行特权操作。
Linux 需要实现的功能包括:
内核设计有两种流派
Linux 虽然为单内核设计但是充分吸收了微内核的特点,支持模块化(.ko (kernel object)),支持模块运行时动态装载或卸载。
首先我们来解决开机启动的第二个问题。
内核加载根文件系统需要加载驱动程序,而驱动程序就在根之上。因此我们不能依赖根文件系统上的驱动程序,内核必须自带驱动程序。
一种方法是将设备的驱动程序编译进内核,对于个人用户自编译的系统没有有问题,因为只需要将其特定的驱动程序编译进内核即可,然后对于操作系统发行商而然,它面对的是各种用户的不同驱动设备,如果都将这些驱动程序编译进内核,内核将庞大无比,而每个用户又只会用到其中一个。
另一种方法是借助于中间临时根文件系统,中间临时根文件系统包含了加载根文件系统所在设备的驱动程序,而中间根文件系统放置在一个基于内存的磁盘设备中,内核无须加载其他驱动程序即可访问该设备。内核启动后,先访问基本设备挂载中间的临时根文件系统,并从中装载设备驱动程序,在真正的根文件系统准备完成之后,从临时根切换到真正的根。
用于系统初始化的基于内存的磁盘设备通常称为 ramdisk,内核在启动过程中需要将 ranmdisk 装载进内存 ,并将其识别为一个根文件系统。ramdisk 并不是发行商预先生成,而是在系统安装过程中针对当前设备临时生成了,因此其仅需包含当前设备的驱动程序即可。
因此从编译完成后的视角,Linux 系统由如下部分组成:
/boot/initrd-VERSION-release.img
# 基于 ram 的磁盘/boot/initramfs-VERSION-release.img
# 基于 ram 的文件系统/lib/modules/VERSION-release
1234567891011121314151617181920大专栏 13.1 CentOS系统启动流程介绍class="line">212223242526272829303132333435363738394041424344 | > uname -r # 内核版本4.9.86-30.el7.x86_64> ls /boot/|grep vmvmlinuz-4.9.86-30.el7.x86_64> ls /lib/modules/$(uname -r)/kernelarch crypto drivers fs lib mm net sound virt> tree -L 2 /lib/modules/$(uname -r)/lib/modules/4.9.86-30.el7.x86_64├── build -> ../../../usr/src/kernels/4.9.86-30.el7.x86_64├── extra├── kernel│?? ├── arch│?? ├── crypto│?? ├── drivers│?? ├── fs│?? ├── lib│?? ├── mm│?? ├── net│?? ├── sound│?? └── virt├── modules.alias├── modules.alias.bin├── modules.block├── modules.builtin├── modules.builtin.bin├── modules.dep├── modules.dep.bin├── modules.devname├── modules.drm├── modules.modesetting├── modules.networking├── modules.order├── modules.softdep├── modules.symbols├── modules.symbols.bin├── source -> build├── updates├── vdso│?? ├── vdso32.so│?? └── vdso64.so└── weak-updates |
接下来我们来解决第一个问题,在没有根文件系统的前提下将内核加载进内存。
可引导设备的第一个分区叫MBR,MBR 中包含了开机引导程序 BootLoader。开机启动时会先加载 MBR内的BootLoader,由BootLoader 将内核加载到内存。有人可能会问,开机时是如何读取到MBR的,BootLoader又是如何读取到内核文件的。BIOS 通过硬件的 INT 13 中断功能来读取 MBR,也就是说,只要 BIOS 能够侦测的到你的磁盘 (不论磁盘是 SATA 还是 SAS ),那他就有办法通过 INT 13 这条信道来读取该磁盘的第一个扇区内的 MBR 软件,这样 boot loader 也就能够被执行。boot loader 能够识别操作系统的文件格式,也就能加载核心文件。其他分区的第一个扇区叫做 boot sector,也可以安装BootLoader,这样可以实现多系统安装。
有了上述阐述,我们就可以开始讲解开机启动流程了。
启动流程:
/sbin/init
/etc/inittab
/etc/inittab
: 为向前兼容,基本没哟使用/etc/init/*.conf
/usr/lib/systemd/system/
/etc/systemd/system/
mkinitrd
dracut, mkinitrd
/sbin/init
需要说明的是无论是下述的 ramdisk 还是 BootLoader 都是在安装操作系统时针对当前硬件生成的。所以 BootLoader 是能够识别当前主机的硬盘设备的。但是需要注意的是BootLoader 是需要和磁盘分区打交道的,而BootLoader 本身一般是无法驱动那些软设备,逻辑设备(LVM),也无法驱动RAID这些复杂的逻辑结构,因此内核只能放在基本的磁盘分区上。