博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
linux开机引导和启动过程(详细)(含配置文件解读)
阅读量:3898 次
发布时间:2019-05-23

本文共 8607 字,大约阅读时间需要 28 分钟。

过程概述

BIOS开机加电自检

BIOS(基本输入输出系统),该系统存储于主板的ROM芯片上,计算机在开机时,会最先读取该系统,然后会有一个加电自检过程。这个过程其实就是检查CPU和内存,计算机最基本的组成单元(控制器、运算器和存储器),还会检查其他硬件,若没有异常就开始加载BIOS程序到内存当中。BIOS的功能大概可以分为3个部分:

  1. 用于电脑刚接通电源时对硬件部分的检测,也叫做加电自检(Power On Self Test,简称POST)。功能是检查电脑是否良好,通常完整的POST自检将包括对CPU,640K基本内存,1M以上的扩展内存,ROM,主板,CMOS存储器,串并口,显示卡,软硬盘子系统及键盘进行测试,一旦在自检中发现问题,系统将给出提示信息或鸣笛警告。自检中如发现有错误,将按两种情况处理:

    • 对于严重故障(致命性故障)则停机,此时由于各种初始化操作还没完成,不能给出任何提示或信号;
    • 对于非严重故障则给出提示或声音报警信号,等待用户处理。
  2. 初始化硬件(这个玩过开发板的应该都很清楚)。包括创建中断向量、设置寄存器、对一些外部设备进行初始化和检测等,其中很重要的一部分是BIOS设置,主要是对硬件设置的一些参数,当电脑启动时会读取这些参数,并和实际硬件设置进行比较,如果不符合,会影响系统的启动。

  3. 引导操作系统程序BIOS会按照硬盘的引导记录去查找第一个磁盘头的MBR信息,并加载和执行MBR中的Bootloader程序,若第一个磁盘不存在MBR,则会继续查找第二个磁盘(启动顺序可以在BIOS的界面中进行设置),一旦BootLoader程序被检测并加载内存中,BIOS就将控制权交接给了BootLoader程序(控制权交接其实就是指CPU跳转到Bootloader程序的内存位置执行)

加载MBR中的BootLoader

MBR(Master Boot Record)主引导记录,MBR存储于磁盘的头部,大小为512 bytes,组成为:[446 bytes(存储BootLoader程序)+64 bytes(存储分区表信息)+2 bytes(用于MBR的有效性检查)]。

这个部分就需要分为3个阶段来执行了:

Stage_1

BIOS加载它找到的第一个引导记录(MBR)中到内存中,并开始执行此代码。Bootloader必须非常小,因为它必须连同分区表放到硬盘的第一个 512 字节的扇区中。 在传统的常规 MBR 中,引导代码实际所占用的空间大小为 446 字节。这个MBR中这个 446 字节的文件通常被叫做引导镜像(boot.img),其中不包含设备的分区信息,分区是一般单独添加到引导记录中。

Stage_1.5

由于boot.img必须做的非常小,所以基本不可能有太多复杂的功能,他唯一能做的就是加载Stage_1.5中的存储的代码,也就是core.img( 25389 25389 25389字节)。该文件通常位于MBR与第一个分区之间,也就是 0 ∼ 63 0\sim63 063扇区之间(未包括 63 63 63),总大小为 62 ∗ 512 = 31744 62*512=31744 62512=31744字节。这个文件,存放了一些通用的文件系统驱动程序,如标准的 EXT 和其它的 Linux 文件系统,如 FATNTFS 等。所以这阶段就是负责执行Stage_1.5中存放的驱动程序,并加载相关的驱动程序。

Grub2core.img 远比老一版的 Grub1 更复杂且更强大。这意味着 Grub2core.img 能够放在标准的EXT 文件系统内,但是不能放在逻辑卷内。故在Grub2中,Stage_1.5中的文件可以存放于 /boot 文件系统中,一般在 /boot/grub2 目录下。

Stage_2

进入Stage_2时,所有的文件(内核、initrd等)都已存放于/boot目录及其几个子目录之下。同时,该阶段还可以从 /boot/grub2/i386-pc 目录下加载一些内核运行时模块。所以Stage_2的主要功能是定位和加载 Linux 内核和initrd到内存中,并转移控制权。

关于Grub2

linux启动时按下C即可进入Grub2的命令行模式,这里你可以自己手动引导内核和initrd的加载。关于手动引导的相关操作,可以自行百度。这里我们重点来看下配置文件/boot/grub2/grub.cfg,这里有篇文章已经说得很详细,这里就直接与大家分享了:

加载内核并初始化initrd

由于Linux内核是很精简的,只保留必要的驱动程序,而现实中的设备种类繁多,例如:根文件系统可以存储在包括IDE、SCSI、USB在内的多种介质上,如果将这些设备的驱动都编译进内核那该多么臃肿,所以就干脆将设备特有的驱动与内核分离,单独形成initrd(一般自己编译的系统不需要,发行版需要兼容所以会需要)。需要哪种驱动就提取到initrd中,待启动时提前加载即可。所以内核启动一般分两步:

初始化initrd

linux内核启动前, bootloader会将存储介质中的 initrd 文件加载到内存,内核启动时会在访问真正的根文件系统前先访问该内存中的 initrd 文件系统,这个过程将会完成相关驱动模块的加载,最主要就是加载根文件系统存储介质的驱动模块等,这样内核就可以正常识别设备和真正的根文件系统了。

initrd( boot loader initialized RAM disk),就是由 bootloader 初始化的内存盘,算是一个很mini版的文件系统。

启动内核

之后,内核会以只读方式挂载根文件系统,当根文件系统被挂载后,开始装载第一个进程(用户空间的进程),执行/sbin/init,之后就将控制权交接给了init程序。如果是使用systemd的话,则是加载systemd进程到内存中。

初始化系统

这一节呢,我们分为两个init系统来叙述:

Sysvinit系统

sysvinit 就是 System V 风格的 init 系统,顾名思义,它源于 System V 系列的 UNIX。最初的 linux 发行版几乎都是采用 sysvinit 作为 init 系统。sysvinit 用术语 runlevel 来定义 “预订的运行模式”。比如

  • runlevel 3 是命令行模式,
  • runlevel 5 是图形界面模式,
  • runlevel 0 是关机,
  • runlevel 6 是重启。

这个初始化系统的涉及到的配置文件如下(按init进程读先后顺序):

/etc/inittab

####省去多余注释##########表示当前缺省运行级别为5(initdefault),即默认以图形界面启动id:5:initdefault:###启动时自动执行/etc/rc.d/rc.sysinit脚本(sysinit)# 这一项表示在系统启动时执行/etc/rc.d/rc.sysinit程序si::sysinit:/etc/rc.d/rc.sysinitl0:0:wait:/etc/rc.d/rc 0l1:1:wait:/etc/rc.d/rc 1l2:2:wait:/etc/rc.d/rc 2# 当切换到runlevel3(命令行模式时),执行一下/etc/rc.d/rc这个程序,并传递参数3l3:3:wait:/etc/rc.d/rc 3l4:4:wait:/etc/rc.d/rc 4###当运行级别为5时,以5为参数运行/etc/rc.d/rc脚本,init将等待其返回(wait)l5:5:wait:/etc/rc.d/rc 5#这个就是同时匹配多个runlevell6:23456:wait:/etc/rc.d/rc 6

每个配置项格式如下:

i d : r u n l e v e l : a c t i o n : p r o c e s s id:runlevel:action:process id:runlevel:action:process

各项含义如下:

  1. id

    id是指入口标识符,它是一个字符串,对于getty或mingetty等其他login程序项,要求id与tty的编号相同,否则getty程序将不能正常工作。

  2. runlevel

    runlevel是init所处于的运行级别的标识.runlevel可以是并列的多个值,以匹配多个运行级别,对大多数action来说,仅当runlevel与当前运行级别匹配成功才会执行

    • 0:表示关机
    • 1:表示单用户模式,在这个模式中,用户登录不需要密码,默认网卡驱动是不被加载,一些服务不能用。
    • 2:表示多用户模式,NFS服务不开启
    • 3:表示命令行模式
    • 4:这个模式保留未用
    • 5:表示图形用户模式
    • 6:表示重启系统
  3. action

    • respawn:当process终止后马上启动一个新的
    • wait:当进入指定的runlevels后process才会启动一次,并且到离开这个runlevels终止
    • initdefault:设定默认的运行级别,即我们开机之后默认进入的运行级别,不能是0,6,你懂的
    • sysinit:系统初始化,只有系统开机或重新启动的时候,这个process才会被执行一次
    • powerwait:当init接收到电源失败信号的时候执行相应的process,并且如果init有进程在运行,会等待这个进程完成之后,再执行相应的process
    • powerfail:当init接收到电源失败信号的时候执行相应的process,并且如果init有进程在运行,不会等待这个进程完成,它会直接执行相应的process
    • powerokwait:电源已经故障,但是在等待执行对应操作的时候突然来电了就执行对应的process
    • powerfailnow:当电源故障并且init被通知UPS电源已经快耗尽执行相对应的process
    • ctrlaltdel:当用户按下ctrl+alt+del这个组合键的时候执行对应的process
    • boot:只有在引导过程中,才执行该进程,但不等待该进程的结束;当该进程死亡时,也不重新启动该进程
    • bootwait:只有在引导过程中,才执行该进程,并等待进程的结束;当该进程死亡时,也不重新启动该进程
    • off:如果process正在运行,那么就发出一个警告信号,等待20秒后,再通过杀死信号强行终止该process。如果process并不存在那么就忽略该登记项
    • once:启动相应的进程,但不等待该进程结束便继续处理/etc/inittab文件中的下一个登记项;当该进程死亡时,init也不重新启动该进程
  4. process

    表示启动哪个程序或脚本或执行哪个命令

/etc/rc.d/rc.sysinit

所有的运行级别下,init依赖/etc/rc.d/rc.sysinit这个脚本对系统进行初始化。按照下面的顺序按部就班的初始化系统:

  • 激活 udev 和 selinux
  • 设置定义在 /etc/sysctl.conf中的内核参数
  • 设置系统时钟
  • 加载 keymaps
  • 启用交换分区
  • 设置主机名(hostname)
  • 根分区检查和 remount
  • 激活 RAID 和 LVM 设备
  • 开启磁盘配额
  • 检查并挂载所有文件系统
  • 清除过期的 locks 和 PID 文件
  • 最后找到指定 runlevel 下的脚本并执行,其实就是启动服务。

/etc/rc.d/rc

这个程序就是根据传入的参数,调用/etc/rc.d/rc0.d~rc6.d中的相应的脚本程序,来完成相应的初始化工作和启动相应的服务,最后调用/etc/rc.d/rc.local,这个文件里面可以放一些用户自定义的启动脚本等等

Systemd系统

systemd 是 linux 系统中最新的初始化系统(init),它主要的设计目标是克服 sysvinit 固有的缺点,提高系统的启动速度。

在开始看Systemd进程做的事情之前,请先了解一下开机启动脚本的编写和选项含义,这里直接推荐一篇不错的文章:。新旧系统运行等级映射关系如下:

SystemV 运行级别 systemd 目标态 systemd 目标态别名 描述
halt.target 停止系统运行但不切断电源。
0 poweroff.target runlevel0.target 停止系统运行并切断电源.
S emergency.target 单用户模式,没有服务进程运行,文件系统也没挂载。这是一个最基本的运行级别,仅在主控制台上提供一个 shell 用于用户与系统进行交互。
1 rescue.target runlevel1.target 挂载了文件系统,仅运行了最基本的服务进程的基本系统,并在主控制台启动了一个 shell 访问入口用于诊断。
2 runlevel2.target 多用户,没有挂载 NFS 文件系统,但是所有的非图形界面的服务进程已经运行。
3 multi-user.target runlevel3.target 所有服务都已运行,但只支持命令行接口访问。
4 runlevel4.target 未使用。
5 graphical.target runlevel5.target 多用户,且支持图形界面接口。
6 reboot.target runlevel6.target 重启。
default.target 这个目标态target是总是 multi-user.targetgraphical.target 的一个符号链接的别名。systemd 总是通过 default.target 启动系统。default.target 绝不应该指向halt.targetpoweroff.targetreboot.target。

Systemd进程在被加载到内后,将依次执行五个目标:

  1. /usr/lib/systemd/system/default.target,这个文件链接到当前目录的graphical.target
[Unit]Description=Graphical InterfaceDocumentation=man:systemd.special(7)Requires=multi-user.targetWants=display-manager.serviceConflicts=rescue.service rescue.targetAfter=multi-user.target rescue.service rescue.target display-manager.serviceAllowIsolate=yes
  1. 根据上一步中可以看到default.target强依赖于multi-user.target,所以接下来这步就要执行如下两个目录中的目标了:
  • /etc/systemd/system/multi-user.target.wants/
  • /usr/lib/systemd/system/multi-user.target.wants/

大部分的用户程序的目标都在这两个目录下有配置,在这步就一并启动了

#/usr/lib/systemd/system/multi-user.target.wants/multi-user.target[Unit]Description=Multi-User SystemDocumentation=man:systemd.special(7)Requires=basic.targetConflicts=rescue.service rescue.targetAfter=basic.target rescue.service rescue.targetAllowIsolate=yes
  1. 接下来到了basic.target目标了,内容如下:
  • /etc/systemd/system/basic.target.wants/
  • /usr/lib/systemd/system/basic.target.wants/
#/usr/lib/systemd/system/multi-user.target.wants/basic.target[Unit]Description=Basic SystemDocumentation=man:systemd.special(7)Requires=sysinit.targetAfter=sysinit.targetWants=sockets.target timers.target paths.target slices.targetAfter=sockets.target paths.target slices.target
  1. sysinit.target会启动重要的系统服务例如系统挂载,内存交换空间和设备,内核补充选项.
  • /etc/systemd/system/sysinit.target.wants/
  • /usr/lib/systemd/system/sysinit.target.wants/
[Unit]Description=System InitializationDocumentation=man:systemd.special(7)Conflicts=emergency.service emergency.targetWants=local-fs.target swap.targetAfter=local-fs.target swap.target emergency.service emergency.target
  1. 然后是最后一个目标local-fs.target,它不会启动用户相关服务,它只处理底层核心服务,这个target会根据/etc/fstab来执行相关磁盘挂载操作

Systemd系统服务配置修改

  • /usr/lib/systemd/system/xx服务.service:官方默认配置文件,不建议修改这个位置的文件,而应该像下面这项这样操作;
  • /etc/systemd/system/xx服务.service.d/custom.conf:在 /etc/systemd/system 下面创建与配置文件相同文件名的目录,但是要加上 .d 的扩展名。然后在该目录下创建配置文件即可。另外,配置文件最好附文件名取名为 .conf。 在这个目录下的文件配置会合并到 /usr/lib/systemd/system/xx服务.service
  • /etc/systemd/system/xx服务.service.wants/*:此目录内的文件为链接文件,设置相依服务的链接。意思是启动了 xx服务.service 之后,最好再加上这目录下面建议的服务。
  • /etc/systemd/system/xx服务.service.requires/*:此目录内的文件为链接文件,设置相依服务的链接。意思是在启动 xx服务.service 之前,需要事先启动哪些服务的意思。

打开终端

sysvinit系统

在sysvinit系统中,由于/etc/inittab中的配置如下:

1:2345:respawn:/sbin/mingetty tty12:2345:respawn:/sbin/mingetty tty23:2345:respawn:/sbin/mingetty tty34:2345:respawn:/sbin/mingetty tty45:2345:respawn:/sbin/mingetty tty56:2345:respawn:/sbin/mingetty tty6# 只有我们进入5运行级别,会打开图形用户终端,并且一旦终端终止,就会再创建一个新的x:5:respawn:/etc/X11/prefdm -nodaemon

在2345运行级别下,会调用/sbin/mingetty启用6个命令行界面的终端,并且一旦终端终止,就会再创建一个新的。

Systemd系统

在上面初始化的第1步中等待了display-manager.service这个服务就是用于启动终端界面的,内容如下:

[Service]ExecStart=/usr/sbin/gdmExecStartPost=-/bin/bash -c "TERM=linux /usr/bin/clear > /dev/tty1"KillMode=mixedRestart=alwaysIgnoreSIGPIPE=noBusName=org.gnome.DisplayManagerStandardOutput=syslogStandardError=inheritEnvironmentFile=-/etc/locale.confExecReload=/bin/kill -SIGHUP $MAINPID[Install]Alias=display-manager.service

转载地址:http://xqfen.baihongyu.com/

你可能感兴趣的文章
C++之编码实现ping的功能
查看>>
C++之动态配置ip信息
查看>>
生活之工资条(薪资结构参考)
查看>>
Makefile之通用模板
查看>>
Makefile之常用函数介绍
查看>>
Makefile之自动变量介绍
查看>>
C++之位测试练习的相关代码
查看>>
C++之IPC测试单元
查看>>
C++之测试snmp的注册模块
查看>>
WebKit之WebSocket的初步源码分析2
查看>>
WebKit之Canvas的源码初步分析1
查看>>
WebKit之Canvas源码分析2
查看>>
WebKit之CSSValue的继承关系
查看>>
WebKit之ScriptWrapper继承关系图
查看>>
Perl之默认变量
查看>>
Linux之ARM/Linux与单片机开发差异
查看>>
Linux之内存泄露的检测工具
查看>>
URL之开源项目的在线网址
查看>>
工具之OpenGrok的搭建方法
查看>>
Android之NDK搭建
查看>>