首页 > 代码库 > Linux系统启动流程

Linux系统启动流程

Linux系统机动流程详解

以PC为例,OS为Linux

第一部分:运行级别及grub

·POST(Power On Self Testing):加电自检

    我们计算机的CPU其实自己什么工作都不会做,它要做的工作只是执行我们用户事先编排好的指令,CPU所要执行的指令是从我们的内存中去提取的,所以对一台计算机来讲最为重要的部件就是CPU和内存,但是在我们计算机刚开机的那一刻内存中是什么指令都没有的,所以我们的系统在这个时候必须要完成一个自举的过程,那就意味着我们的计算机必须得有一个硬件,这个硬件里面有一些固化的指令来帮助我们将系统运行起来,所以在计算机的设计之初,就可以使得我们的计算机在开机的时候,在CPU的指挥下将该硬件中的指令装载进内存,这些指令不需要任何的额外配置,是我们的硬件自己内置的,而这个过程实质上就是将我们系统开机的时候的自检所需要的指令装载进内存中去,其实就是将bios的程序映射进我们CPU可以查找到的物理地址空间中去,bios这段程序存在于我们计算机上主板上的一块ROM存储芯片中。

    计算机上的内存设备我们称之为RAM,还有另外一种存储设备我们叫做ROM(只读型存储器),ROM设备不需要额外的加电就可以完成数据的保存,CPU在刚开机的时候,能够实现将这个ROM设备中的某些程序映射进RAM设备中的低地址空间中去,或者也可以理解为是将RAM和ROM设备拼接起来,使得可以同时找到ROM中程序的内存空间,由此我们的CPU就可以读取到ROM设备里面配置好的那些指令信息了,这些指令信息的第一段就是用来实现我们系统当中硬件的健康状况检查的,比如说有没有显卡、显卡是否正常、有没有内存设备、内存设备是否正常以及CPU的风扇是否能够运转等等,当硬件检查通过时,系统才可以正常启动,于是我们就可以根据bios中的配置信息来完成我们系统的启动了。

·Boot Sequence

    bios中定义的配置信息主要是我们系统中设备的启动次序(Boot Sequence),启动次序设定我们外部I/O设备或者是存储设备哪一个作为我们查找操作系统所在位置的设备

·MBR(bootloader)

    之后查找设备的MBR信息,MBR中有一段程序叫做bootloader,这段程序的大小是446个字节,它主要的功能是根据MBR中的分区表查找活动分区,即我们的操作系统所在的那个分区,并加载那个分区上的操作系统上的内核,因此当我们的bios找到bootloader的时候,此时所有的空间权限全部会交给bootloader,如果bios中的第一个设备中没有MBR,或者是MBR中没有bootloader,那么bios就会继续查找第二个设备中是否存在,如果第一个设备中有bootloader,但是bootloader损坏了,无法正常的启动的话,那么bios就不会再去查找第二个设备,但凡我们的bios读取了一个设备中的MBR中的bootloader,那么它就不会再去下一个设备中查找,由于bootloader的空间特别小,只有446个字节,所以说这些程序很有可能是压缩存放的,所以说当bios将bootloader载入到内存当中的时候有可能还要进行解压缩,当bootloader获得控制权之后,bios基本上就可以退出了,这个时候bootloader就会加载用户所选定的设备分区上的操作系统的内核,内核文件一般来讲也是压缩存放的,此时bootloader会将内核加载到内存中,在内存中完成解压缩,此时bootloader就会将控制权限转交给内核,这个时候我们的内核就取得了计算机整体硬件的控制权,此时bootloader就退出了,内核此时获得了整个系统的控制权

·bootloader

    bootloader是一个程序,对于不同的操作系统来讲它是不一样的,这个程序通常是由操作系统的安装程序提供的,bootloader在MBR当中存在着,但是MBR它不属于任何操作系统,MBR是全硬盘级别的,Linux中常用的bootloader通常有三种:

    1,LILO(LInux LOader)

        这是早期一个用来引导Linux启动过程的一个bootloader,但是该bootloader不支持引导1024柱面上之后的分区上的内核,也就是不支持大硬盘

    2,GRUB(GRand Unified Bootloader)

        红帽5和红帽6上所使用的grub是不一样的,grub本身也是一个程序,它需要装载到MBR中的bootloader的位置上去引导操作系统的,不过MBR上bootloader所占的空间太小了,只有446个字节,没有办法完全展现grub的丰富特性,因此我们的gurb实际上是一个两阶段的程序:分别为Stage1和Stage2

        Stage1->第一阶段的程序被放入了MBR中的bootloader的位置中去,它存在的主要目的就是为了引导第二阶段的程序,而不是为了引导操作系统,第二阶段的程序才是用来引导操作系统的

        Stage2->第二阶段的程序和我们的内核文件在同一个目录下,一般在/boot/grub/stage2,名字就叫做stage2

        技术分享

        在第二阶段的程序之前还有一个过渡阶段的程序,被称为stage1_5,这种文件是为了帮助我们的MBR去识别不同的操作系统的,因为我们MBR中的第一阶段的程序要引导的第二阶段的程序是存在于文件系统上的,从而帮助我们的MBR中的第一段grub去访问到我们的文件系统上的第二段grub

        grub作为一个程序,它也是由自己的配置文件的,一般在/boot/grub/目录下的名为grub.conf这个文件,它的软链接文件是/etc/grub.conf

        技术分享

        技术分享

        该配置文件中的default段到hiddenmenu段全都是grub配置文件的全局属性定义,接下来的title段表示的是,每一个title指定一个操作系统或者是一个内核,Linux同一个系统下可以提供多个不同版本的内核,我们要启动不同内核的情况下,每一个内核都得给它一个title,每一个title是用来定义当前系统的不同版本的内核或者是当前主机上不同的操作系统,这是title的两个功能:

    ->default=0表示默认启动0号title对应的操作系统或内核,即下面第一个定义的title就是0号title,default是用来设定默认的title的,从而设定默认启动的内核或系统,设定默认启动的title编号,title是从0开始编号的

    ->timeout=5表示虽然我们有默认启动的title,但是系统也会给用户时间,使得用户自己来选择用户想要启动的title,这就是等待用户选择title的超时时长,单位是秒钟

    ->splashimage=(hd0,0)/grub/splash.xpm.gz

        这一行用来指定启动系统时的背景图片,即grub的背景图片

    ->hiddenmenu

        表示隐藏菜单

    -> title Red Hat Enterprise Linux (2.6.32-431.el6.x86_64)

        每一个title后面的字符串可以自由修改,该字符窜表示我们要引导的操作系统或内核的标题

    ->root (hd0,0)

        这一行用来指定内核文件所在的设备

        grub识别硬件和内核识别硬件的模式是不一样的,对于grub来说,无论是什么类型的硬盘都会被识别为hd类型,hd#中的#表示第#块磁盘设备,0就表示第一块磁盘,而(hd#,@)中的@表示对应磁盘上的分区

    ->kernel /vmlinuz-2.6.32-431.el6.x86_64 ro root=UUID=77b4e8c0-e932-4990-a594-2d5e619f2a70 rd_NO_LUKS rd_NO_LVM LANG=en_US.UTF-8 rd_NO_MD SYSFO    NT=latarcyrheb-sun16 crashkernel=auto  KEYBOARDTYPE=pc KEYTABLE=us rd_NO_DM rhgb quiet

        这一行用来指定内核文件的路径以及传递给内核的参数,/proc目录下的cmdline文件里面的内容就是我们内核文件的路径:

        技术分享

        我们知道我们的内核文件是在/boot目录下的,为什么这里显示的是在/目录下呢?因为在当前系统上我们的/boot目录是单独挂载在一个分区上的,当我们的grub在访问磁盘设备的时候,我们系统上的根文件系统还没有被装载,故此时grub是直接访问我们/boot目录所在的分区的,它把该分区当做我们的根分区来处理了,所以才会如此显示,如果我们的/boot目录没有独立挂载出去,而是就在我们的根分区中,那么就会显示正常的内核文件的路径

    ->initrd /initramfs-2.6.32-431.el6.x86_64.img

        这一行是我们的ramdisk文件的路径,ramdisk文件的版本号和内核的版本号是一致的,这是一个镜像文件,该文件是安装操作系统的最后一步生成的,该文件是一个完整意义上的Linux系统



·Kernel

    内核取得了我们整个系统的控制权之后,它会识别每一个硬件,并且使得每一个硬件都会工作起来,能够使得硬件更好的工作起来的程序叫做硬件的驱动程序,因此当内核在内存中完成了解压之后,它会尝试着去探测每一个硬件,但是更重要的是我们的内核必须先去识别CPU和内存,内核启动起来之后的工作就是探测我们系统上的硬件,后来的功能就和管理我们的系统相关了,内核提供我们管理操作系统的功能有:

    ->提供文件系统帮助我们管理文件

    ->进程管理,实现对进程的调度

    ->内存管理

    ->网络管理

    ->安全功能的实现

    ->驱动程序

    当内核探测硬件结束之后,即将基本的硬件加载完成、把基本的外围硬件加载结束、驱动程序也加载结束以及识别完主要硬件之后,接下来的主要任务就是启动用户空间的进程了,从内核空间开始去管理用户空间,第一件事就是在用户空间去启动init进程,init这个文件在/sbin目录下,是我们用户空间的一个主导程序,所有在用户空间所启动的进程都是由init这个程序来进行管理的,因此对于用户空间的管理,我们可以全权交给init进程,除非我们要和硬件打交道,才会由用户空间切换至内核空间,但是我们的init文件是位于/sbin目录下的,也就是说是位于文件系统中的,但是我们的文件系统在此时还没有被挂载,内核是从某个磁盘分区上被装载进内存的,这个磁盘分区是由bootloader识别的,内核被装载进内存之前是由bootloader来识别内核所在的分区的,而不是MBR,MBR只是一段存储空间,这就意味着bootloader必须要能够识别内核所在的分区,从逻辑的角度来看文件系统和从物理的角度来看是不一样的,从逻辑上来看,文件系统是由层次关系的,从物理上看,文件系统在磁盘上是一个个并行的磁盘分区,我们的文件系统都是由根目录开始的,根目录下有许多一级的文件系统,比如/usr、/boot、/home等等,这是文件系统的层次结构,但是我们有很多的目录是可以单独挂载在一个磁盘分区上的,不过有些目录是一定不可以单独挂载出去的,比如/bin、/sbin,因为这些目录是和我们的根目录自身完成初始化相关的,文件系统上的所有目录都是通过根目录之后才可以被访问到,因此我们根目录所在的那个磁盘分区通常就是我们的操作系统的内核能够完成进入我们的用户空间最核心的位置,故我们的根目录所在的磁盘分区有一个特殊的名字叫做rootfs(根文件系统),根分区就是我们的内核访问系统上任何其他的存储设备的访问入口,我们的根目录挂载完成之后就要开始启动我们的操作系统了,/bin和/sbin目录下面所存储的二进制程序是我们操作系统自身启动就要用到的程序,故这些目录是不可以独立分区的,一定得存储在根分区,其他很多目录比如/usr可以单独挂载至其他分区,因为它里面的程序和我们操作系统本身的启动是没有关系的,或者和操作系统自身完成初始化是没有关系的,/usr这个路径名是一定在根分区上的,但是它里面的文件可以独立到其他分区上,根目录是我们文件系统上所有其他目录的访问入口,要想找到文件系统上的任何一个目录必须从根目录开始查找,那么我们是从哪里开始查找根目录呢?我们的根目录是自引用的,自我识别的,即它可以自己找到自己,这就意味着我们必须得有一个外力来帮助根目录完成自我识别,这个过程是由内核来完成的,意味着内核要能够装载rootfs,装载完成之后,才能够知道/sbin/init的存在,而后才可以将它启动,因此当我们的内核启动完成之后,或者说是内核初始化完成之后,接下来最关键的一步就是要去挂载根文件系统,或者说是访问根文件系统使得根文件系统建立起来,但是我们必须要告诉内核根目录在哪一个磁盘分区上,这样内核才能找到我们的根分区,我们可以使用给内核传递一个参数的方法root=...来告诉内核根目录在哪个磁盘分区上,但是我们的根目录必须要能够探测到根目录所在的那个磁盘分区才可以访问根目录,我们Linux内核的设计风格是这样的:

    Linux的内核设计风格总共有两种,

    1,被称作单内核结构

        单内核结构是将所有的功能全部做进内核的一种结构,此种结构可以由一个内核进程来控制所有的功能

    2,被称作微内核结构

        微内核结构的内核很小,只是一个核心,而其他所要实现的所有具体功能全部被做成了一个个的子系统,当需要某些功能的时候,由核心区调度相关的子系统即可

    我们Linux的内核在结构上是属于单内核结构的,而Windows的内核在结构上是属于微内核结构的,Solaris系统的内核结构也是属于微内核结构的,微内核结构的设计风格才是真正意义上支持多线程的内核结构,所以在Linux系统上的,多线程被支持的并不是很好,在Linux上线程被称为LWP(Light Weight Process->轻量级进程),内核在设计的时候采用的是模块化的设计风格,内核可以由核心和所谓的外部内核模块来组成,内核的外部模块被称为ko(kernel oject->内核对象),是内核独享的模块,这些模块是不可以被用户进程所使用的,是内核所专有的模块,所以内核是由核心和各种功能的ko组成的,内核的核心很小,但是核心上有很多的空洞,任何时候我们需要其它的ko的时候,将ko装载进核心上即可,这样可以大大缩小内核整体所占据的空间,这个过程叫做动态加载,内核的核心可以动态加载各种外围的ko,这就意味着我们的内核是由两部分组成的,核心和ko,而我们被初始化的内核只是核心本身,而ko文件在redhat系列的系统上一般是存在于/lib/modules/这个目录下中以内核版本号命名的目录中的文件:

    技术分享    而且我们在同一个系统上可以多个内核并存的,每一个内核在/lib/modules这个目录下都有一个和你内核版本号相同的一个目录,在该目录下,有对应的内核所需要的各种ko,ko彼此间可能也是有依赖关系的,但是在该目录中有一个ko依赖关系的文件,就是上图中的.dep文件,该文件会自动生成,它可以自动去识别这些依赖关系,我们的真正的核心是在/boot目录下的,内核的命名是以vmlinuz开头的,后面跟上内核的版本号:

    技术分享

·initrd

    我们的内核在访问根分区的时候,其实还需要一个中间层的文件系统,称为虚根,内核首先访问这个虚根,然后由虚根引导着访问到我们真正的rootfs,当内核顺利的访问到我们真正的根文件系统的时候就会,系统的rootfs就会切换到真正的rootfs上来,这个过程叫做根切换,这个是完全的根切换,会将虚根文件系统上的某些目录完全搬到我们的根文件系统当中去,而不用再次在我们的根文件系统中再次生成,比如/proc内核的映射目录、/sys以及/dev目录等,我们的虚根也是一个文件,而且可以被装载进内存中,而且虚根是将内存当做了一个磁盘来使用,它可以把物理内存中的一段空间当做硬盘来使用,该虚根文件在红帽5上被称作ramdisk,在红帽5上,真正被内核装载进内存的虚根文件叫做initrd(ramdisk),而在红帽6上被称作ramfs,在红帽6上该虚根的文件名是initramfs,该虚根文件的作用是提供真正的根分区的驱动程序给我们的内核,使得内核最终可以访问真正的根分区,所以说我们的内核一般情况下是无法独自访问到init的,得依靠虚根文件的帮助

    我们可以使用chroot命令在我们系统上的一个额外的临时目录变成虚根来使用,使用格式:

    chroot NEWROOT [COMMADN...]

    NEWROOT由任意一个目录来指定,COMMAND是默认shell,可以让这个小的rootfs使用某种shell风格的命令

    技术分享

    上图中的错误是因为新的根目录下必须得有对应shell的库文件才可以完成切换,我们可以使用ldd命令来找到默认shell所需要的库文件:

    ldd命令:

        该命令可以用来显示二进制文件所依赖的库文件

        使用格式:ldd BINARY_FILE

        技术分享

    我们在要变成新根的那个目录下新建一个bin目录和一个lib目录,并且将/bin/bash复制进bin目录中,将bash的库文件也复制进新根目录的lib目录中,然后再使用chroot命令,才可以完成新根文件系统的建立:

        技术分享    但是,我不知道为什么还是不成功。。。。

    完成切换后的虚根和我们系统上真正的根文件系统是隔离开来单独运行的,切换完成后,我们还可以指令新根中所运行的命令种类,使用格式:

    chroot NEWROOT /bin/bash | /bin/ksh

    一定要给新的根文件系统一个shell,否则它无法给用户返回一个登录界面

    由以上可知,我们Linux系统的启动流程大致可以分为这么几个步骤:

        ->POST完成加电自检

        ->bios决定启动次序(Boot Sequence)

        ->MBR装载bootloader

        ->bootloader装载内核,并在内存中解压,然后将控制权交给内核

        ->kernel完成硬件探测,装载驱动程序,然后启动init

        ->initrd,kernel在initrd的帮助下找到init

        ->init,init启动之后开始控制用户进程,系统启动完成

·Linux操作系统的运行级别

    我们系统上的所有后台进程又被称为是服务进程,所谓运行级别,就是在不同的级别下系统所启动的服务不同,运行级别区别的核心就是系统在不同的运行级别下所启动的服务不同,所以级别不同,Linux的运行级别依靠数字来标识,一共分为0-6共7个级别:

    ->级别0表示halt:关机

    ->级别1表示单用户模式(single user mode):类似于Windows的安全模式,Linux默认是多用户模式的,在单用户模式下用户可以直接以管理员的身份登录系统,而且不需要登录密码

    ->级别2表示多用户模式(multi user mode):该模式下具有网络功能,但是不可启用NFS

    ->级别3表示正常的多用户模式:类似于我们平常操作计算机的模式,不过只是文本模式,只启用命令行,并不启用图形界面

    ->级别4表示Reserved,表示尚未使用的模式,保留级别,没有意义

    ->级别5表示图形多用户模式(graphic mode)

    ->级别6表示reboot,重启

    我们知道,运行级别指的是系统在不同的级别下所启用的服务不同,而服务全都是我们用户空间的进程,故我们操作系统的运行级别是由我们用户空间的进程来控制的,而我们有关系统运行级别的配置文件就是我们的/etc/inittab这个文件:

    技术分享

    技术分享

    该配置文件中的id这一行,定义了我们当前系统的运行级别,由上图知,我们当前系统默认运行在级别5,即图形多用户模式


        

本文出自 “菜鸟的技术文档” 博客,请务必保留此出处http://zhubo.blog.51cto.com/11395641/1859580

Linux系统启动流程