0%

Linux系统启动过程

  Linux系统的启动,从计算机开机通电自检开始,一直到登陆系统,总共经历如下几个过程:

  1. 服务器加电,加载 BIOS 信息,BIOS 进行系统检测。依照 BIOS 设定,找到第一个可以启动的设备(一般是硬盘);
  2. 读取第一个启动设备的 MBR (主引导记录),加载 MBR 中的 Boot Loader(启动引导程序,最为常见的是 GRUB)。
  3. 依据 Boot Loader 的设置加载内核,内核会再进行一遍系统检测。系统一般会采用内核检测硬件的信息,而不一定采用 Bios 的自检信息。内核在检测硬件的同时,还会通过加载动态模块的形式加载硬件的驱动。
  4. 内核启动系统的第一个进程,也就是 /sbin/init。
  5. 由 /sbin/init 进程调用/etc目录下的init程序 ,来配置计算机的初始环境、确定系统的默认运行级别。
  6. 确定默认运行级别后,调用 /etc/init/rc.conf 配置文件初始化系统,然后执行 /etc/rc.d/rc.local 中的程序。
  7. 如果是终端界面启动,就可以看到登录界面了。如果是图形界面启动,就会调用相应的 X Window 接口。

  总的来说Linux启动过程大致分为五个过程:BIOS启动->内核引导过程->运行init(初始化配置文件)->系统初始化->建立终端或载入用户登陆系统

# 硬件启动与引导

# BISO启动

  BIOS 全称 Basic Input/Output System,中文可译为基本输入/输出系统。它是固化在主板上一个 ROM(只读存储器)芯片上的程序,主要保存计算机的基本输入/输出信息、系统设置信息、开机自检程和系统自启动程序,用来为 计算机提供最底层和最直接的硬件设置与控制。BIOS 的初始化主要完成以下 几 项工作:

  1. 当 BIOS 一启动,就会检查计算机硬件和外围设备(例如 CPU、内存、风扇灯),整个自检过程也被称为 POST(Power On Self Test)自检。
  2. 如果自检没有问题,BIOS 开始对硬件进行初始化,并规定当前可启动设备的先后顺序,选择由那个设备来开机。
  3. 选择好开启设备后,就会从该设备的 MBR(主引导目录)中读取 Boot Loader(启动引导程序)并执行。启动引导程序用于引导操作系统启动,Linux系统中默认使用的启动引导程序是 GRUB。
  4. 当 MBR 被加载到 RAM 之后,BIOS 就会将控制权交给 MBR,进入系统引导的第二阶段。

# 读取MBR

  MBR 也就是主引导记录,最主要的功能就是存储启动引导程序。MBR位于硬盘的 0 磁道、0 柱面、1 扇区中,主要记录了启动引导程序和磁盘的分区表。MBR 共占用了一个扇区,也就是 512 Byte。其中 446 Byte 安装了启动引导程序,其后 64 Byte 描述分区表,最后的 2 Byte 是结束标记。

MBR结构图:

MDR结构图

  之所以每块硬盘只能划分四个分区,原因就是在 MBR 中描述分区表的空间只有 64 Byte。其中每个分区必须占用 16 Byte,那么 64 Byte 就只能划分 4 个主分区。每个分区的 16 字节的规划如表 :

存储字节 数据内容及含义
第 1 字节 引导标志
第 2 字节 本分区的起始磁道号
第 3 字节 本分区的起始扇区号
第 4 字节 本分区的起始柱面号
第 5 字节 分区类型,可以识别主分区和扩展分区
第 6 字节 本分区的结束磁道号
第 7 字节 本分区的结束扇区号
第 8 字节 本分区的结束柱面号
第 9~12 字节 本分区之前已经占用的扇区数
第 13~16 字节 本分区的总扇区数

# 启动引导程序的作用

  BIOS 的作用就是自检,然后从 MBR 中读取出启动引导程序,所以,启动引导程序最主要的作用就是加载操作系统的内核。由于每种操作系统的文件格式不同,因此每种操作系统的启动引导程序也不一样。不同的操作系统只有使用自己的启动引导程序才能加载自己的内核。如果服务器中安装了多个操作系统,而 MBR 只有一 个,那么明显是不够用的。

  然而每块硬盘只能有一个 MBR 是不能更改的,所以不可能増加 MBR 的数量。系统只能在每个文件系统(可以看成分区)中单独划分出一个扇区,称作引导扇区(Boot Sector)。每个分区的引导扇区中也能安装启动引导程序,也就是说,在 MBR 和每个单独分区的引导扇区中都可以安装启动引导程序。这样多个操作系统才能安装在同一台服务器中(每个操作系统要安装在不同的分区中),而且每个操作系统都是可以启动的。

  但是BIOS 只能找到 MBR 中的启动引导程序,而找不到在分区的引导扇区中的启动引导程序。如果要想完成多系统启动,那么就要増加启动引导程序的功能,让安装到 MBR 中的启动引导程序(GRUB)来调用在分区的引导扇区中的其他启动引导程序。

因此,启动引导程序拥有以下功能:

  1. 加载操作系统的内核。这是启动引导程序最主要的功能。
  2. 拥有一个可以让用户选择的菜单,来选择到底启动哪个系统。大家如果在服务器上安装过双 Windows 系统,就应该见过类似的选择菜单,不过这个选择菜单是由 Windows 的启动引导程序提供的,而不是 GRUB。
  3. 可以调用其他的启动引导程序,这是多系统启动的关键。不过需要注意的是,Windows 的启动引导程序不能调用 Linux的启动引导程序,所以我们一般建议先安装 Windows,后安装 Linux,是为了将 Linux 的启动引导程序安装到 MBR 中,覆盖 Windows 的启动引导程序。

启动引导程序的作用示意图:

MBR的作用

# Linux内核模块加载

  GRUB 加载了内核之后,内核首先会再进行二次系统的自检,而不一定使用 BIOS 检测的硬件信息。这时内核终于开始替代 BIOS 接管 Linux的启动过程了。

  内核再次系统自检后,就会开始动态加载每个硬件的模块,这个动态模块大家可以想象成硬件的驱动[1]。Linux 的内核存放在 /boot 的启动目录中。

/boot目录
1
2
3
4
5
6
7
8
9
[root@localhost ~]#ls /boot/
config-2.6.32-279.el6.i686 #内核的配置文件,内核编译时选择的功能与模块
efi #可扩展固件接口,为英特尔为全新PC固件的体系结构、接口和服务提出的建议标准
grub #启动引导程GTUB的数据目录
initramfe-2.6.32-279.el6.i686.img #虚拟文件系统(CentOS 6.x 中用initramfs替代了initrd,但功能是一样的)
lost+found # boot分区的备份目录
symvers-2_6.32-279.el6.i686.gz #模块符号信息
System.map-2.6.32-279.el6.i686 #内核功能和内存地址的对应列表
vmlinuz-2.6.32-279.el6.i686 #用于启动的Linux内核。这个文件是一个压缩的内核镜像

  Linux 为了保证了内核不会过大,会把不重要的功能编译成内核模块,在需要时再调用。在多数 Linux 中,都会把硬件的驱动程序编译为模块, 这些模块保存在 /lib/modules 目录中。常见的 USB、SATA 和 SCSI 等硬盘设备的驱动,还有一些特殊的文件系统(如 LVM、RAID 等)的驱动,都是以模块的方式来保存的。

  如果 Linux 安装在 IDE 硬盘之上,并且采用的是默认的 ext3/4 文件系统,那么内核启动后加载根分区和模块的加载都没有什么问题。如果要将 Linux 安装在 SCSI 硬盘之上,或者采用的是 LVM 文件系统,那么内核(内核载入内存是启动引导程序 GRUB 调用的,并不存在硬盘驱动不识别的问题)在加载根目录之前是需要加载 SCSI 硬盘或 LVM 文件系统的驱动的。而SCSI 硬盘和 LVM 文件系统的驱动都放在硬盘的 /lib/modules 目录中,内核没有办法识别 ,因此Linux 采用了 initramfs 这个虚拟文件系统来处理这个问题。

# initramfe虚拟文件系统

  CentOS 6.x 中使用 initramfs 虚拟文件系统取代了 CentOS 5.x 中的 initrd RAM Disk。它们的作用类似,可以通过 initramfs 虚拟文件系统在内存中模拟出一个根目录,然后在这个模拟根目录中加载 SCSI 等硬件的驱动,就可以加载真正的根目录了,之后才能调用 Linux 的第一个进程 /sbin/init。

Initramfs 虚拟文件系统主要有以下优点:

  • initramfs 随着其中数据的増减自动増减容量。
  • 在 initramfs 和页面缓存之间没有重复数据。
  • initramfs 重复利用了 Linux caching 的代码,因此几乎没有増加内核尺寸,而 caching 的代码已经经过良好测试,所以 initramfs 的代码质量也有保证。
  • 不需要额外的文件系统驱动
initramfe虚拟文件系统

  内核启动后,首先会去解析grub的配置文件/boot/grub/grub.conf,然后加载内核镜像到内存中,并将控制权转交给内核。而内核会立即初始化系统中各设备并做相关的配置工作,其中包括CPU、I/O、存储设备等。在内核加载完毕,系统开始运行第一个进程。

# 第一个进程:init

  在内核加载完毕,并完成硬件检测与驱动程序加载后,此时主机硬件已经准备完毕,内核会主动呼叫第一个进程,也就是 /sbin/init,此配置文件最主要的功能就是准备软件执行的环境,包括系统的主机名、网络设定、语言、文件系统格式及其他服务的启动等。

  由于Linux内核的不断发展,各个发行版、各个版本的操作系统,采用的init程序配置系统完全不同。基本上是由 /sbin/init 进程来 配置计算机的初始环境确定系统的默认运行级别

  例如在 CentOS 6.x 系统中,由于用 Upstart 启动服务来替换以前的 init,所以在 /etc/inittab 配置文件中只能定义系统的默认运行级别,而其他的功能是靠 /etc/init/ 目录中的其他配置文件实现的。

init程序的类型举例:

  • SysV: init, CentOS 5之前, 配置文件: /etc/inittab。

  • Upstart: init,CentOS 6, 配置文件:/etc/inittab,/etc/init/*.conf。

  • Systemd: systemd, CentOS 7,配置文件:/usr/lib/systemd/system/etc/systemd/system

关于init系统的介绍,可以阅读以下文章:

# 配置计算机的初始环境

  以centos 6采用的Upstart系统举例, /sbin/init 进程通过 /etc/init/rcS.conf 配置文件,分别找到 /etc/rc.d/rc.sysinit 配置文件和 /etc/inittab 配置文件,前者用于初始化系统,配置计算机的初始环境;后者用于确定系统的默认运行级别。用 Vim 查看 /etc/rc.d/rc.sysinit 配置文件,就会发现这个这个配置文件主要进行了以下几项工作:

  • 获得网络环境和主机类型;
  • 测试设备:除了挂载内存设备 /proc 之外,还会主动侦测系统上是否具有 usb 设备,如果有,则会主动加载 usb 的驱动程序,并尝试挂载 usb 文件系统;
  • 开机启动画面 Plymouth(代替了以往的 RHGB);
  • 判断是否启用 SELinux;
  • 显示开机过程中的欢迎画面;
  • 初始化硬件;
  • 用户自定义模块的加载,用户可以在/etc/sysconfig/modules/*.modules 加入自订的模块,则此时会被加载到系统当中;
  • 配置内核的参数,系统会主动去读取/etc/sysctl.conf这个文件的配置参数,使内核的功能成为我们想要的样子。
  • 设置主机名。
  • 同步存储器。
  • 设备映射器及相关的初始化。
  • 初始化软件磁盘阵列 (RAID)。
  • 初始化 LVM 的文件系统功能。
  • 检验磁盘文件系统 (fsck)。
  • 设置磁盘配额 (quota)。
  • 重新以可读写模式挂载系统磁盘。
  • 更新 quota (非必要)。
  • 启动系统虚拟随机数生成器。
  • 配置机器(非必要)。
  • 清除开机过程中的临时文件。
  • 创建 ICE 目录。
  • 启动交换分区(swap)。
  • 将开机信息写入/var/log/dmesg 文件中。

  /etc/rc.d/rc.sysinit配置文件已经将基本的系统配置数据都写好了,我们可以查询 /var/log/dmesg文件或使用 dmesg 命令查看系统在启动时到底发生了什么。当然,我们也可以通过这个命令来看看 Linux 服务器的硬件信息。

# 配置运行级别

  在 CentOS 6.x 中,/etc/inittab 配置文件只能用来设置系统的默认运行级别。而在systemd 系统中,采用目标(target)替代了运行级别的概念,这里展示了Sysvinit 运行级别和 systemd 目标的对应表。

Sysvinit 运行级别 Systemd 目标 备注
0 runlevel0.target, poweroff.target 关闭系统。
1, s, single runlevel1.target, rescue.target 单用户模式。可以想象为 Windows 的安全模式,主要用于系统修复
2, 4 runlevel2.target, runlevel4.target, multi-user.target 用户定义,不含 NFS 服务/域特定运行级别。默认等同于 3。
3 runlevel3.target, multi-user.target 多用户,非图形化。用户可以通过多个控制台或网络登录。
5 runlevel5.target, graphical.target 多用户,图形化。通常为所有运行级别 3 的服务外加图形化登录。
6 runlevel6.target, reboot.target 重启
emergency emergency.target 紧急 Shell

在 Linux 系统中可以使用 runlevel 命令来查看系统的运行级别,命令如下:

1
[root@localhost ~]# runlevel

# 系统初始化

  以centos6 为例子,在init的配置文件中有这么一行:si::sysinit:/etc/rc.d/rc.sysinit 它调用执行了/etc/rc.d/rc.sysinit,而rc.sysinit是一个bash shell的脚本,是每一个运行级别都要首先运行的重要脚本。在其中会有类似这样的代码:

1
l5:5:wait:/etc/rc.d/rc 5

  其中数字5就是我们要运行的运行级别,这一行表示以5为参数运行/etc/rc.d/rc/etc/rc.d/rc是一个Shell脚本,它接受5作为参数,去执行 /etc/rc.d/rc5.d/目录下的所有的rc启动脚本,/etc/rc.d/rc5.d/目录中的这些启动脚本实际上都是一些连接文件,而不是真正的rc启动脚本,真正的rc启动脚本实际上都是放在/etc/rc.d/init.d/目录下。这些rc启动脚本有着类似的用法,它们一般能接受start、stop、restart、status等参数。

  /etc/rc.d/rc5.d/中的rc启动脚本通常是K或S开头的连接文件,对于以 S 开头的启动脚本,将以start参数来运行。而如果发现存在相应的脚本也存在K打头的连接,而且已经处于运行态了(以/var/lock/subsys/下的文件作为标志),则将首先以stop为参数停止这些已经启动了的守护进程,然后再重新运行。这样做是为了保证是当init改变运行级别时,所有相关的守护进程都将重启。

  在每个运行级中将运行哪些守护进程,用户可以通过chkconfig或setup中的"System Services"来自行设定。

# 载入自定义配置

  在/etc/rc.d/rc[0-6].d 目录中的程序启动之后,系统的启动就已经完成。不过,我们总有一些程序是需要在系统启动之后随着系统一起启动的。这时我们并不需要自己把需要启动的服务链接到 /etc/rc3.d/ 目录中,因为系统给我们准备了 /etc/rc.d/rc.local 配置文件。

  这个配置文件会在用户登陆之前读取,这个文件中写入了什么命令,在每次系统启动时都会执行一次。也就是说,如果有任何需要在系统启动时运行的工作,则只需写入 /etc/rc.d/rc.local 配置文件即可。这个文件的内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
[root@localhost ~]# ll /etc/rc.local
Irwxrwxrwx. 1 root root 13 4月10 21:46 /etc/rc.local -> rc.d/rc.local
#有一个链接文件,两个文件修改哪一个都可以
[root@localhost ~]#vi /etc/rc.d/rc.local
#!/bin/sh
#
#This script will be executed *after* all the other init scripts.
#You can put your own initialization stuff in here if you don't
#want to do the full Sys V style init stuff.
touch /var/lock/subsys/local
#默认会touch这个文件,每次系统启动时都会touch这个文件,这个文件的修改时间就是系统的启动时间
/etc/rc.d/init.d/httpd start
#如果写入RPM包安装的apache服务的启动命令,apache服务就会在开机时自动启动

# 建立终端和用户登录系统

# 建立终端

  在启动过程中还有一个配置文件会生效,就是 /etc/init/start-ttys.conf,这个文件主要定义了 Linux 支持的 1~6 个本地终端(tty[1-6])。

  在inittab中的以下6行定义了6个终端:

1
2
3
4
5
6
1:2345:respawn:/sbin/mingetty tty1
2:2345:respawn:/sbin/mingetty tty2
3:2345:respawn:/sbin/mingetty tty3
4:2345:respawn:/sbin/mingetty tty4
5:2345:respawn:/sbin/mingetty tty5
6:2345:respawn:/sbin/mingetty tty6

  从上面可以看出在2、3、4、5的运行级别中都将以respawn方式运行mingetty程序,mingetty程序能打开终端、设置模式。同时它会显示一个文本登录界面,这个界面就是我们经常看到的登录界面,当我们看到mingetty的登录界面时,我们就可以输入用户名和密码来登录系统了。

# 用户登陆系统

一般来说,用户的登录方式有三种:

  • 命令行登录
  • ssh登录
  • 图形界面登录

  对于运行级别为5的图形方式用户来说,他们的登录是通过一个图形化的登录界面。登录成功后可以直接进入 KDE、Gnome 等窗口管理器。

  当通过mingetty登录时,Linux 的账号验证程序是 login,login 会接收 mingetty 传来的用户名作为用户名参数,然后对用户名进行分析:如果用户名不是 root,且存在 /etc/nologin 文件,login 将输出 nologin 文件的内容,然后退出。这通常用来系统维护时防止非root用户登录。只有/etc/securetty中登记了的终端才允许 root 用户登录,如果不存在这个文件,则 root 用户可以在任何终端上登录。/etc/usertty文件用于对用户作出附加访问限制,如果不存在这个文件,则没有其他限制。

# 图形模式与文字模式的切换方式

  Linux预设提供了六个命令窗口终端机让我们来登录。

  默认我们登录的就是第一个窗口,也就是tty1,这个六个窗口分别为tty1,tty2 … tty6,你可以按下Ctrl + Alt + F1 ~ F6 来切换它们。

  如果你安装了图形界面,默认情况下是进入图形界面的,此时你就可以按Ctrl + Alt + F1 ~ F6来进入其中一个命令窗口界面。当你进入命令窗口界面后再返回图形界面只要按下Ctrl + Alt + F7 就回来了。

  如果你用的vmware 虚拟机,命令窗口切换的快捷键为 Alt + Space + F1~F6. 如果你在图形界面下请按Alt + Shift + Ctrl + F1~F6 切换至命令窗口。


至此Linux启动完成,流程图如下

Linux启动过程

# Linux 关机

  在linux领域内大多用在服务器上,很少遇到关机的操作。毕竟服务器上跑一个服务是永无止境的,除非特殊情况下,不得已才会关机。

  正确的关机流程为:sync > shutdown > reboot > halt

  关机指令为:shutdown ,你可以man shutdown 来看一下帮助文档。例如你可以运行如下命令关机:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
sync 将数据由内存同步到硬盘中。

shutdown 关机指令,你可以man shutdown 来看一下帮助文档。例如你可以运行如下命令关机:

shutdown –h 10 ‘This server will shutdown after 10 mins’ 这个命令告诉大家,计算机将在10分钟后关机,并且会显示在登陆用户的当前屏幕中。

shutdown –h now 立马关机

shutdown –h 20:25 系统会在今天20:25关机

shutdown –h +10 十分钟后关机

shutdown –r now 系统立马重启

shutdown –r +10 系统十分钟后重启

reboot 就是重启,等同于 shutdown –r now

halt 关闭系统,等同于shutdown –h now 和 poweroff

  最后总结一下,不管是重启系统还是关闭系统,首先要运行 sync 命令,把内存中的数据写到磁盘中。

  关机的命令有 shutdown –h now halt poweroffinit 0 , 重启系统的命令有 shutdown –r now reboot init 6

参考文档地址:

IBM Develope:https://www.ibm.com/developerworks/cn/linux/l-linuxboot/index.html

C语言中文网:http://c.biancheng.net/view/1014.html

菜鸟教程:https://www.runoob.com/linux/linux-system-boot.html


  1. 默认 Linux 硬件的驱动是不需要手工安装的,如果是重要的功能,则会直接编译到内核当中;如果是非重要的功能,比如硬件驱动会编译为模块,则在需要时由内核调用。不过,如果没有被内核硬件,要想驱动,就需要手工安装个硬件的硬块了。