1. Linux系统的启动流程

    一、系统启动流程:

    关于Linux系统的启动流程我们可以按步骤进行划分为以下几个步骤:

POST加电自检 ==》BIOS(Boot Sequence) ==》 加载对应引导设备上的MBR中的bootloader程序==》主引导设置加载其BootLoader ==》  Kernel初始化==》 initrd==》/etc/init进程加载/etc/inittab.

其进程流程图如下:

二、剖析详细启动流程

(1)、POST开机自检

电脑主机打开电源的时候,随后会听到滴的一声,系统启动开始了开机自检(POST-Power On SelfTest),这个过程中主要是检测计算机硬件设备比如:CPU,内存,主板,显卡,CMOS等设备是否有故障存在,如果有硬件故障的话将按两种情况处理:

对于严重故障(致命性故障)则停机,此时由于各种初始化操作还没完成,不能给出任何提示或信号;

对于非严重故障则给出提示或声音报警信号,等待用户处理;

如果没有故障,POST完成自己的接力任务,将尾部工作交接给BIOS处理。

(2)、BIOS

计算机加电自检完成后第一个读取的地方就是BIOS(Basic Input Output System,基础输入输出系统),BIOS里面记录了主机板的芯片集与相关设置,如CPU与接口设备的通信频率、启动设备的搜索顺序、硬盘的大小与类型、系统时间、外部总线、各种接口设备的I/O地址、以及与CPU通信的IRQ中断信息。所以,启动如果要顺利启动,首先要读取BIOS设置。但是如果BIOS找不到任何的可引导设备那么启动将会失败。

(3)、安装BIOS所设定的系统启动流程

安装BIOS所设定的系统启动流程,如果检测通过,则根据引导次序(Boot Sequence)开始在第一台设备上支持启动程序,我们的启动设备主要包括硬盘、USB、SD等,我们一般用的是硬盘,然后进行读取的第一个设备就是硬盘,第一个要读取的就是该硬盘的主引导记录MBR(Master Boot Record),然后系统可以根据启动区安装的引导加载程序(Boot Loader)开始执行核心识别的工作。【MBR一共是512字节,其中前446字节存放的bootloader程序,由它确定选择的操作系统内核及传递给内核的参数和initrd的存放位置。】

(4)、Boot Loader加载Grub程序

在这个过程中主要靠Grub的引导开始的,Grub分为3个阶段:

stage1:主要是Boot Loader,位于MBR中,它的存在是为了引导stage2;

stage1.5:位于boot分区(基本磁盘分区),为识别内核文件系统提供文件系统识别扩展。

stage2:也是位于boot分区(基本磁盘分区),Grub的引导程序;

[root@localhost ~]# cd /boot/grub/
[root@localhost grub]# ls
abc.xpm.gz    fat_stage1_5  iso9660_stage1_5  menu.lstbak        splash.xpm.gz  ufs2_stage1_5
device.map     ffs_stage1_5  jfs_stage1_5      minix_stage1_5     stage1         vstafs_stage1_5
e2fs_stage1_5  grub.conf    menu.lst         reiserfs_stage1_5  stage2         xfs_stage1_5
[root@localhost grub]#

在/boot/grub/下面我们看到了熟悉的stage1,stage2及grub工具的配置文件grub.conf,那么grub.conf内都定义了什么呢?

首先我们先了解一下grub的功能有哪些:

Grub的功能

  1. 选择要启动的内核或系统;

    如果系统有多个内核并存时我们可以通过在系统启动倒计时我们按任意键进入选择需要用的内核或系统,但是我的系统只有一个操作系统,所以它默认时间一到就进入当前的系统了。

    当系统启动到此时,我们可以输入e键进入交互式界面:

  2. 交互式接口

如图所示,可以按照上面的说明进入交互模式;


  1. 基于密码保护。

    在了解了grub的功能后我们再来看一下grub.conf的配置文件都配置了些什么。如下:

# grub.conf generated by anaconda
#
# Note that you do not have to rerun grubafter making changes to this file
# NOTICE: You have a /boot partition.  Thismeans that
#         all kernel and initrd paths are relative to /boot/, eg.
#         root (hd0,0)
#         kernel /vmlinuz-version ro root=/dev/mapper/MyGroup-rootfs
#         initrd /initrd-[generic-]version.img
#boot=/dev/sda
default=0                           #默认选择的启动内核(数字对应下方的title编号)
timeout=5                #->选择内核文件超时时间
splashp_w_picpath=(hd0,0)/grub/splash.xpm.gz         #->界面下的系统启动背景图片。
hiddenmenu                    #菜单隐藏。
title CentOS 6 (2.6.32-504.el6.x86_64)                  #->grub标题
       root (hd0,0)                                #->设定内核文件所在的分区为grub的根
       kernel /vmlinuz-2.6.32-504.el6.x86_64 ro root=/dev/mapper/MyGroup-rootfsrd_LVM_LV=MyGroup/rootfs rd_NO_LUKS.UTF-8 rd_LVM_LV=MyGroup/myswaprd_NO_MD SYSFONT=latarcyrheb-sun16 crashkernel=auto  KEYBOARDTYPE=pc KEYTABLE=us rd_NO_DM rhgbquiet                    #->定义要使用的内核文件,后面可附加传递给内核的启动参数
initrd /initramfs-2.6.32-504.el6.x86_64.img                 #->指定为内核提供额外驱动等功能
#的ra’m disk或ram fs文件

通过该文件我们可以知道了它的配置语法,grub.conf文件的语法如下:

#grub.conf配置文件语法:
default=# #→指定默认启动的内核或OS;
timeout=# #→等待用户选择要启动的内核或OS的时长,单位为秒;
splashp_w_picpath=/path/to/splashp_w_picpath_file #→指定使用的背景图片
hiddenmenu #→隐藏菜单
title
    root (hd0,0)(Device, Part) #→Device表示方式: 在grub中,统统以hd开头,并紧跟一个数字做各磁盘设备的标记,从0开始编号; Part表示方式:代表分区,从0开始编号
    kernel #→指定内核文件及传递给内核的参数
    参数 #→ro root=/path/to/DEVICE quiet
    initrd文件 #→通常为cpio归档,并使用gzip压缩;通常以.img作为文件名后缀;

(5)、Kernel

根据Grub文件内的定义,grub读取完毕后就把下面的工作交给内核了。kernel主要是完成系统硬件探测及硬件驱动的初始化,并且以读写的方式挂载根文件系统(根切换),那么这里就出现了一个那么这里就出现了一个"先有鸡还是先有蛋的问题了",具体是什么呢?

要想访问真正的根文件系统(rootfs)的话,就必须加载根文件系统中的设备,这时根文件系统又没有挂载,要挂载根文件系统又得加载根文件系统中的驱动程序,那怎么办呢?为了解决这个问题,这是就用到了initrd文件了。

再来说下kernel初始化所要工作的内容做下简单总结:

探测硬件à加载驱动(initrd)à挂载根文件系统àrootfs (/sbin/init)

这里要需要做一下说明:initrd和initramfs的区别,首先initrd是系统加载驱动时将内存模拟为磁盘设备,需要再次在内核中缓存,而initramfs却将内存直接模拟为文件系统,这样它就比起initrd显得更加的优越。所以在CentOS5上面的initrd在CentOStage6中改成了initramfs。

(6)、到此为止内核空间的相关工作已经完成,内核空间的任务开始向用户空间转移,内核空间通过了一个间接的initrd(微型Linux)向用户空间的/sbin/init过渡,所以grub开始引导内核转向initrd。initrd:一个虚拟的文件系统,里面有lib、bin、sbin、usr、proc、sys、var、dev、boot、等一些目录,其实你会发现里面的目录和实际的文件系统中的目录树结构相似,所以我们称之为虚拟的根文件系统,作用就是将kernel和真的根文件系统建立关联关系,让kernel去initrd中加载根文件系统所需要的驱动程序,并以读写的方式挂载根文件系统,并执行用户空间当中的第一个进程init

[root@192 ~]# mkdir /p_w_picpath    #->新建目录/p_w_picpath
[root@192 ~]# cp/boot/initramfs-2.6.32-504.el6.i686.img /p_w_picpath/    #->赋值initramfs至/p_w_picpath目录下
[root@192 ~]# cd /p_w_picpath/
[root@192 p_w_picpath]# zcatinitramfs-2.6.32-504.el6.i686.img | cpio -id  #->将它解压到当前目录
80684 blocks
[root@192 p_w_picpath]# ls
bin                                mount
cmdline                            netroot
dev                                pre-mount
dracut-004-356.el6                 pre-pivot
emergency                          pre-trigger
etc                                pre-udev
init                               proc
initqueue                          sbin
initqueue-finished                 sys
initqueue-settled                  sysroot
initqueue-timeout                  tmp
initramfs-2.6.32-504.el6.i686.img  usr
lib                                var
[root@192 p_w_picpath]#看到了initramfs这个映像文件所包含的文件bin,etc,dev,init,dev,lib,sbin,sys,sysroot、proc等,
  1. 挂载:将initrd中的proc、sysfs挂载到当前的主分区中的相应目录;

# mount someimportant things
[root@192 p_w_picpath]# mount -t proc proc /proc>/dev/null 2>&1
[root@192 p_w_picpath]# mount -t sysfs sysfs /sys>/dev/null 2>&1

2.通过mknod完成block的创建

[root@192 p_w_picpath]# mknod -m 0666 /dev/null c1 3
[root@192 p_w_picpath]# mknod -m 0666 /dev/ptmx c5 2
[root@192 p_w_picpath]# mknod -m 0600/dev.console c 5 1
[root@192 p_w_picpath]# mknod -m 0660 /dev/kmsg c1 11

3.    创建系统需要的目录并设定权限:

[root@192 p_w_picpath]# mkdir /dev/shm
[root@192 p_w_picpath]# mkdir /dev/pts
[root@192 p_w_picpath]# mount -t devpts -ogid=5,mode=620 devpts /dev/pts >/dev/null 2>&1

4. 尝试挂载根文件系统

wKioL1Xnf5fgq1JaAAB3Ga4Ce8k584.jpg

5.最后完成根切换

wKioL1XngADQHpswAAAYSAaiNJQ605.jpg

6.init执行完毕以后会启动系统内的/etc/inittab文件,来完成系统的初始化工作。现在来分析一下inittab这个配置文件内的详细内容:

wKioL1XngGvTqfISAAHr3EjPv5w210.jpg

上面6行英文注释主要是告诉我们一些工作室在哪些配置文件里面去配置的,各个级别的定义:

0:halt  #→系统关机状态
1: single user mode #→单用户维护状态
2:multi user mode, without NFS #→多用户状态,不支持NFS功能
3: multi user mode, textmode     #→完整多用户模式、字符界面
4:reserved   #→系统保留,一般不使用

/etc/inittab文件的格式及语法(CentOS5

wKiom1XnftDAl9H4AAXS6v6aoGM204.jpg

/etc/inittab文件语法格式:

         [选项]:[runlevel]:[动作]:[操作]

行为:

initdefault:设置默认运行级别,无需定义操作

sysinit   代表系统初始化操作选项;

ctalaltdel:定义组合键CtrlAltDel被按下时的动作;

wait:等待系统切换至此级别时运行一次;

respawn:当指定操作进程被关闭时立即再启动一次;

命令选项:

以下命令,不过通常都是脚本;

 

下面说下inittab内定义的初始化脚本:/etc/rc.d/rc.sysinit,系统根据运行级别运行相关的服务脚本:/etc/rc.d/init.d/脚本和/etc/rc.d/rc$d


wKiom1Xnf03gY__vAAEUNMX8XYQ439.jpg

再来看一下rc0-rc6目录中的文件,以rc3.d为例:

wKioL1XngbjBEbkkAANCj8CW3v0952.jpg这些文件都是链接文件,它们链接到了/etc/init.d/*目录下的各个程序的,例如ntpd这个脚本:

wKioL1XnggeR2SFFAACMFf113Tw969.jpgK74或者$##开头的那些又是什么意思呢?

         其实K代表的是该服务下次启动将会是关闭的,不代表当前这服务就是关闭的,定义的只是下次冲洗系统后是关闭与否;

         S代表就是该服务下次启动将会是随系统启动而一起启动的,但是不代表当前它就是关闭的,定义的只是下次重启系统后是否开启;

         后面的数字是众多服务在开机程序中的优先级别,它们的取值是0-99,数字越小,优先级越高;那我们怎么设置某一服务下次重启系统后是该关闭或者开启呢?可以使用chkconfig命令实现:

checkconfig
命令格式:
chkconfig [options] Service_Name [on|off]
    Options:
         --add              #→添加程序服务
         --list             #→列出当前系统上所有的服务对应的级别是关闭还是启动
         --del              #→删除某个服务(只是删除链接文件,不删除原文件)
         --level [on|off]   #→指定某个服务对应哪些级别是on或off

例如:

查看至此那个服务的运行信息:0-6级别都是关闭的:

[root@Gmq ~]# chkconfig --list ntpd
ntpd       0:off  1:off   2:off    3:off   4:off    5:off    6:off

我们将该服务打开:

[root@Gmq ~]# chkconfig ntpd on
[root@Gmq ~]# chkconfig --list ntpd
ntpd  0:off 1:off  2:on  3:on  4:on  5:on 6:off23452345;chkconfig:
[root@Gmq ~]# vim /etc/init.d/ntpd
.......................
.......................
# chkconfig: - 58 74
# description: ntpd is the NTPv4 daemon. \
.......................

我们就看这两行信息就行啦,其他都是程序自己的一些信息了;

Chkconfig: - 58 74

 其中“-”表示的是运行级别,默认就代表2345(难怪上面的那个操作默认就开启2345级别了)

    "58" 代表指定启动时的优先级;“74”代表指定关闭时的优先级

    Description:代表的对这个脚本的一个描述
用户自定义开机启动程序,可以根据自己的需求将一些执行命令或是写到脚本/etc/rc.d/rc.local.当开机时就可以自动加载啦!

三、总结:

Linux系统启动大概步骤总结如下:

1、  加载BIOS硬件信息,并获取第一个启动设备的代号;

2、  读取第一个启动设备的mbr到物理内存,物理内存的内容就是Boot Loader了;

3、  运行Boot Loader(如grublilo等),初始化硬件设备,建立内存空间映射图。

4、  根据Boot Loader设定的内核映像路径,系统读取内存映像,解压内核,尝试驱动所有硬件设备。

5、  运行第一个程序/sbin/init

6、  执行第一个/etc/rc.d/rc.sysinit脚本程序。

7、  依据/etc/modules.conf装载内核模块。

8、  执行不同运行级别的脚本程序

9、  执行/etc/rc.d/rc.local脚本程序;

10、             执行/bin/login,进入等待用户登录状态。

 

系统初始化的大致内容总结如下:

1、  硬件的初始化,图像界面启动的初始化(如果设置了默认启动脚本)

2、  主机RAID的设置初始化,devicemapper及相关的初始化,

3、  检测根文件系统,以只读方式挂载

4、  激活udevselinux

5、  设置内核参数/etc/sysctl.conf

6、  设置系统时钟

7、  启用交换分区,设置主机名

8、  加载键盘映射

9、  激活RAIDLVM逻辑卷

10、             挂载额外的文件系统/etc/fstab

等等….

 

最后根据mingetty程序调用login让用户登录à用户登录(系统完成启动)

在完成启动过程中主要的脚本和目录有哪些呢?

boot 目录

/grub目录

/boot/grub/grub.conf脚本

/boot/initrd+内核版本 文件

/initrd文件中的init文件

/initrd文件中的/proc/         /sys/                  /dev/目录的挂载及根的切换

/etc/inittab 脚本

/etc/rc.d/rc.sysinit 脚本

 

还有其他重要的目录和文件、脚本等,此处不再一一列举。

不足之处等我学得透彻之后,再来改善!