逝者如斯,不舍昼夜

尘世中一个迷途小书童,读书太少,想得太多
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

(五)Linux引导流程解析

Posted on 2015-04-15 12:40  SteveWang  阅读(998)  评论(0编辑  收藏  举报

  目录

 

Linux引导流程

 

  Linux系统引导流程如下图:

  

 

  固件(Firmware)就是写入EROM或EEPROM(可编程只读存储器)中的程序,一般来说,担任着一个数码产品最基础、最底层工作的软件才可以称之为固件,比如计算机主板上的基本输入/输出系统BIOS(Basic Input/output System),在以前其实更多的专业人士叫它固件。

  通常这些硬件内所保存的程序是无法被用户直接读出或修改的。在以前,一般情况下是没有必要对固件进行升级操作的,即使在固件内发现了严重的Bug也必须由专业人员带着写好程序的芯片把原来机器上的更换下来。随着技术的不断发展,修改固件以适应不断更新的硬件环境成了用户们的迫切要求,所以,可重复写入的可编程可擦除只读存储器EPROM(Erasable Programmable ROM),EEPROM和flash出现了,这些芯片是可以重复刷写的,让固件得以修改和升级。

  常用固件设置有:安全设置、可引导介质列表、可引导介质搜索顺序、电源管理、启动细节显示等

  

  接通微机的电源,系统将执行一个自我检查的例行程序,对系统的几乎所有的硬件进行检测。这是固件BIOS最重要的功能,通常称为POST——加电自检(Power On Self Test)

  


 

关于系统时间和硬件时钟:  

  查看当前系统时间(软件时钟): date   查看硬件时钟: hwclock   

  

  

  如上图我的系统时间和硬件时钟基本相同且准确,如果两个当中有一个不准确则需要参照另一个时钟进行同步,用 hwclock --help 命令查看hwclock常用选项的帮助信息,可以看到--hctosys选项是根据硬件时钟设置系统时间,--systohc选项是根据当前系统时间设置硬件时钟

  

 

  如果系统时间和硬件时钟都不准确,我们需要重新设置,对于系统时间,我们用 man date 看看它的帮助文档,可以看到设置系统时间的格式为 date 月月日日时时分分年年年年.秒秒 ,例如设置当前系统时间为2015年04月15日14时25分30秒的命令为 date 041514252015.30 

  

 

  同理我们用 man hwclock 查看hwclock的帮助文档可以知道,设置硬件时钟为2015年04月15日14时25分30秒的命令为 hwclock --set --date="4/15/2015 14:25:30" ,当然也可以根据当前系统时间设置硬件时钟

 


 

  固件在加电自检没有问题之后会读取位于硬盘0柱面、0磁头、1扇区(主引导扇区)的MBR(主引导记录Master Boot Record)。MBR由三个部分组成,自举程序(BootLoader)硬盘分区表DPT(Disk Partition table)和分区有效标志(magic number)。在总共512字节的主引导扇区里自举程序(BootLoader)占446个字节,第二部分是硬盘分区表DPT,占64个字节,硬盘中分区有多少以及每一分区的大小都记在其中。第三部分是分区有效标志(magic number),占2个字节,固定为55AA。

  

 

  GRUB是在Linux中广泛应用的BootLoader,它的配置文件是/etc/grub.conf。(windows xp/windows server 2003中广泛应用的BootLoader是NT Loader,即ntldr;而Windows Vista/Windows 7/win8(.1)中取而代之的是Boot Manager,即bootmgr

  输入命令 vi /etc/grub.conf 可以编辑GRUB的配置文件。无论哪种系统它的自举程序最重要的功能就是载入操作系统内核,如下图GRUB配置文件中选中部分 kernel /vmlinuz-2.6.18-194.e15 就是用来指定内核所在的位置,所以如果我们在进行内核编译生成新的内核后要重新编辑一下GRUB的配置文件。/vmlinuz-2.6.18-194.e15是一个可执行的Linux内核文件,z表示他是一个解压缩文件,2.6.18是内核的版本号,其中2是主版本号,6是次版本号,次版本号若为奇数表示这是一个测试版内核,这里次版本号为偶数6表示这是一个正式版内核,18是末版本号。

  

 

  如下图编译好的Linux内核位于/boot/vmlinuz-2.6.18-194.e15,他就是一个二进制可执行文件;而没有编译的Linux内核源文件一般默认位于/usr/src/linux文件夹下,是一堆源代码文件

  

 

  在引导流程里载入内核Kernel后内核只做两件事情:

    一是驱动硬件。所有操作系统内核中保存最多的就是硬件驱动程序,所以想把一个操作系统放在一个小型硬件设备中裁剪内核时只需要保留这个小型硬件设备所需要的驱动。内核驱动硬件和固件进行加点自检是不同的,加电自检是在物理的层面上检测硬件可不可用,比如硬件有没有连接好,线有没有插错等;而内核驱动硬件是在操作系统(软件)的层次上识别和调用硬件。

    二是启动init进程,init进程启动后会读取/etc/inittab配置文件,执行缺省运行级别,从而继续引导过程。在类UNIX系统中,init是第一个可以存在的进程,它的pid(Process Identification)恒为1,但它也必须向一个更高级的功能负责:pid为0的内核调度器(Kernel scheduler),用来分配CPU时间片以及进行进程间切换。Linux是一个分时的多任务操作系统,所谓分时就是把CPU循环周期分成小的时间片让任务排队处理,在一个CPU循环周期里会尽量给每一个任务分配一个时间片,如果任务在本次CPU循环周期中没有执行完,则在下一个CPU循环周期中还会给任务分配时间片。

    输入进程管理命令 ps -le | more 查看当前进程如下图,可以看到init进程的PID为1,PPID(Parent Process Identification)为0。

  

  

  如果父进程中止而子进程仍然存在,则这个子进程被称为孤儿进程,在Linux系统中不允许有孤儿进程的存在,所以当系统检测到孤儿进程会自动将它的父进程指向为init,所以init进程理论上讲是系统中所有进程的父进程。

  如果子进程中止而父进程不知道,还在尝试保持与子进程之间的联系,这个子进程被称为僵尸进程(Z),当然在Linux系统中僵尸进程也是不允许存在的。

 

 

Linux运行级别

 

  输入命令 vi /etc/inittab 进入配置文件inittab,可以看到下图选中部分为Linux系统(RedHat系列)默认的运行级别(runlevel)

  

 

  0 — halt  关机,类似于shutdown,括号中警告不要把缺省的运行级别设置成这个

  1 — Single user mode  单用户模式,只有Root可以登录,类似于Windows的安全模式,但它没有图形界面

  2 — Multiuser mode  多用户模式,没有NFS(Network File System)服务

  3 — Full multiuser mode  完整的多用户模式,具有NFS服务,可以进行类Unix操作系统之间的文件共享(由于NFS的安全性较差,不推荐使用NFS进行文件共享,所以3比2并没有优势)

2和3都是没有图形界面的,是应用最多的服务器运行模式

  4 — unused  没有被使用的运行级别,可以由用户自定义

  5 — X11  系统缺省的运行级别,是图形化的多用户模式(比3多个图形界面)。X即图形环境X-window,11是其版本号

  6 — reboot  重启,同样不要把缺省的运行级别设置成这个

 

关于运行级别的命令:

  输入 runlevel 可以查看当前的运行级别,输入 init 运行级别 或 telinit 运行级别 可以切换当前的运行级别(telinit是init的软链接文件,所以这两个实际上是同一命令)

  

 

 

inittab文件剖析

 

  输入 man inittab 可以查看配置文件inittab的帮助文档如下:

  

 

  从中可以看出,在配置文件inittab中所有条目采取此格式: id:runlevels:action:process 

  id:脚本/命令标识符,一般由两位字母或数字组成

  runlevels:指定脚本/命令的运行级别,表示可在此运行级别下执行,可以指定多个,若不指定则表示在所有运行级别下均可执行

  action:指定脚本/命令的运行状态

  process:指定要运行的脚本/命令,前面三项皆为此项的修饰

 

  输入 grep -v "^#" /etc/inittab | more 分页浏览配置文件inittab中非注释内容如下:

  

 

  action常用取值如下:

  initdefault:指定系统启动时缺省的运行级别,如上图inittab中的第一行 id:5:initdefault:   指定系统启动时缺省的运行级别为5

  sysinit:该状态下系统启动就会执行process中指定的命令,如上图inittab中的第二行 si::sysinit:/etc/rc.d/rc.sysinit 只要系统启动就会执行一次Shell脚本文件/etc/rc.d/rc.sysinit(不论在哪个运行级别下),完成系统服务程序启动,如系统环境变量设置、设置系统时钟、加载字体、检查加载文件系统、生成系统启动信息日志文件等。

  wait:执行process中指定的命令,并等其结束再运行其他命令

  once:执行process中指定的命令,不等待其结束

  ctrlaltdel:按下Ctrl+Alt+Del时执行process指定的命令

  powerfail:当出现电源错误时执行process指定的命令,不等待其结束

  powerokwait:当电源恢复时执行process指定的命令

  respawn:一旦process指定的命令中止,便重新运行该命令

 

  上图inittab中的三到九行如下:

l0:0:wait:/etc/rc.d/rc 0
l1:1:wait:/etc/rc.d/rc 1
l2:2:wait:/etc/rc.d/rc 2
l3:3:wait:/etc/rc.d/rc 3
l4:4:wait:/etc/rc.d/rc 4
l5:5:wait:/etc/rc.d/rc 5
l6:6:wait:/etc/rc.d/rc 6

  脚本/etc/rc.d/rc的作用是启动对应运行级别下的服务,上述七行设置段分别对应了七个不同的运行级别,因为第一行设置的缺省运行级别是5,所以会执行 l5:5:wait:/etc/rc.d/rc 5 这一行,调用/etc/rc.d/rc脚本,执行运行级别5目录(/etc/rc.d/rc5.d)下的服务程序,完成运行级别5的初始化设置

  /etc/rc.d/rc[0123456].d目录下分别存放了对应于运行级别的服务程序脚本的符号链接(文件名分三部分,第一部分分两种:S开头意为Start,表示此运行级别下启动这个服务;K开头意为Kill,表示此运行级别下关闭这个服务。第二部分数字表示脚本的启动顺序,理论上数字越小越优先启动,数字相同则按照脚本创建的顺序依次启动。第三部分是脚本名称),链接到/etc/rc.d/init.d目录下的相应脚本,缺省运行级别5目录(/etc/rc.d/rc5.d)下服务程序脚本的符号链接如下:

  

 

  如要取消某运行级别下某服务的开启与关闭,只需到该运行级别目录下改变该服务程序脚本的符号链接名,如取消运行级别5下sendmail服务的启动只需到/etc/rc.d/rc5.d目录下输入 mv S80sendmail s80sendmail 把S改成小写s,则在下次初始化运行级别5时则不启动sendmail服务(如要恢复只需把s改回S)

 

  /etc/rc.d/rc[0123456].d目录下存放的仅是服务程序脚本的符号链接,所链接到的服务程序脚本位于/etc/rc.d/init.d目录下,如下图所示: