6.2Linux系统的引导过程Linux系统的引导和初始化过程可以分为两个阶段,如图6.3所示图6.3Linux内核启动过程示意图第1阶段:完成硬件检测、初始化和内核的引导。第2阶段:主要是init初始化进程的执行。1.BIOS自检计算机通电后,首先由BIOS进行自检,即所谓的POST(PowerOnSelfTest),对硬件进行检测,然后BIOS必须确定要使用哪个设备来引导系统,此时会根据CMOS中设置的引导顺序,搜索处于活动状态并可引导的设备(硬盘、CDROM、USB设备或软盘),当找到一个引导设备之后,从中读出引导块或MBR(MBR,MasterBootRecord)。主引导记录MBR中包含主引导加载程序。MBR是一个512B大小的扇区,位于磁盘的第一个扇区中(0道0面1扇区)。当MBR被加载到RAM中之后,BIOS会把控制权交给MBR。注意,要看MBR的内容,可以执行如下命令:#ddif=/dev/hdaof=mbr.binbs=512count=1//从/dev/hda上读取前512B的内容,将其写入mbr.bin文件中#od-xambr.bin//以十六进制和ASCII码格式打印这个二进制文件的内容MBR中的主引导加载程序是一个512B大小的映像,其中包含程序代码和一个分区表。前446B是主引导加载程序,其中包含可执行代码和错误消息文本。接下来的64B是分区表,其中包含4个分区的记录(每个记录的大小是16个字节)。MBR以两个特殊数字的字节(0xAA55)结束。这个数字会用来进行MBR的有效性检查。2.启动GRUBGRUB是引导加载程序,会引导操作系统。当机器引导它的操作系统时,BIOS会读取引导介质上最前面的512字节(MBR,MasterBootRecord)主引导加载程序(第一阶段的引导加载程序)的主要作用是查找并加载次引导加载程序,它是通过在分区表中查找一个活动分区来实现这种功能的。当找到一个活动分区时,会扫描分区表中的其它分区,以确保它们都不是活动的。当这个过程验证完成之后,就将活动分区的引导记录(第二阶段的引导加载程序)从这个设备中读到RAM中,并执行它。第二阶段的引导加载程序(次引导加载程序)可以更形象地称为内核加载程序。主要作用是将默认的内核映像和initrd映像加载到内存中。在PC环境中,第一阶段和第二阶段的引导加载程序一起称为GRandUnifiedBootloader(GRUB)。在GRUB命令行环境中(启动电脑后,在GRUB界面中按C键进入),可以使用initrd映像引导一个特定的内核,方法如下:grubkernel(hd0,2)/Possiblefilesare:lost+foundsysprocvartmpdevetcrootselinuxusrbinboothomelibmediamntoptsbinsrvmisctftpboot.autofscknetcache_dbgrubkernel(hd0,2)/boot/vmlinuz-2.6.18-128.el5[Linux-bzImage,setup=0x1e00,size=0x1bbeb4]grubinitrd(hd0,2)/boot/initrd-2.6.18-128.el5.img[Linux-initrd@0x2fd79000,0x266c72bytes]grub当内核映像被加载到内存后,内核阶段就加开始了。3.加载内核当内核映像被加载到内存中,并且阶段2的引导加载程序释放控制权之后,内核阶段就开始了。内核映像并不是一个可执行的内核,而是一个压缩过的内核映像。通常它是一个zImage(压缩映像,小于512KB)或一个bzImage(较大的压缩映像,大于512KB)。在这个内核映像前面是一个例程,它实现少量硬件设置,并对内核映像中包含的内核进行解压,然后将其放入高端内存中,如果有初始RAM磁盘映像,就会将它移动到内存中,并标明以后使用。然后该例程会调用内核,并开始启动内核引导的过程。在内核引导过程中,初始RAM磁盘(initrd)是由次引导加载程序加载到内存中的,它会被复制到RAM中并挂载到系统上。这个initrd会作为RAM中的临时根文件系统使用,并允许内核在没有挂载任何物理磁盘的情况下完整地实现引导。由于与外围设备进行交互所需要的模块可能是initrd的一部分,因此内核可以非常小,但是仍然需要支持大量可能的硬件配置。在内核引导之后,就可以正式挂载根文件系统了,此时会将initrd根文件系统卸载掉,挂载真正的根文件系统。注意:在一个没有硬盘的嵌入式环境中,initrd可以是最终的根文件系统,或者通过网络文件系统(NFS)挂载最终的根文件系统。4.执行init进程内核被载入内存,开始运行并初始化所有的设备驱动程序和数据结构等之后,内核将生成第一个进程―init(实际上依次寻找/sbin/init、/etc/init、/bin/init或/bin/sh,将执行第一个找到的,如果这4个文件都不存在,将给出“Noinitfound.Trypassinginit=optiontokernel.错误提示,内核启动失败。详细分析见5.3节)。init进程是一个由内核启动的用户级进程,是系统上运行的所有其它进程的父进程,它会观察其子进程,并在需要的时候启动、停止、重启它们,主要用来完成系统的各项配置。该进程对于Linux系统的正常工作是非常重要的。init的主要工作是根据/etc/inittab文件来执行相应的脚本,进行系统的初始化,如设置键盘、字体、装载模块、设置网络等。所以,init进程执行的每一步都是由/etc/initab文件中的配置决定的,以下是RadHat的/etc/inittab文件的例子:#inittabThisfiledescribeshowtheINITprocessshouldsetup#thesysteminacertainrun-level.#Author:MiquelvanSmoorenburg,miquels@drinkel.nl.mugnet.org#ModifiedforRHSLinuxbyMarcEwingandDonnieBarnes#Defaultrunlevel.TherunlevelsusedbyRHSare:#0-halt(DoNOTsetinitdefaulttothis)//停机(不要把initdefault设置为0,否则开机之后就会自动关机)#1-Singleusermode//单用户模式#2-Multiuser,withoutNFS(Thesameas3,ifyoudonothavenetworking)//多用户模式,但是没有NFS#3-Fullmultiusermode//完全多用户模式#4-unused//没有使用#5-X11//X-windows模式#6-reboot(DoNOTsetinitdefaulttothis)//系统重新启动(不要把initdefault设置为6,否则开机之后就会重启)#id:5:initdefault://该命令指出缺省的运行级别为5,即开机后进入X-window模式#Systeminitialization.#系统启动之后自动执行/etc/rc.d/rc.sysinit脚本,当运行级别为5时,会以5为参数运行/etc/rc.d/rc5脚本,#init进程将等待其返回(wait)si::sysinit:/etc/rc.d/rc.sysinitl0:0:wait:/etc/rc.d/rc0l1:1:wait:/etc/rc.d/rc1l2:2:wait:/etc/rc.d/rc2l3:3:wait:/etc/rc.d/rc3l4:4:wait:/etc/rc.d/rc4l5:5:wait:/etc/rc.d/rc5l6:6:wait:/etc/rc.d/rc6#TrapCTRL-ALT-DELETE#在启动过程中如果按Crtl-Alt-Delete,将执行/sbin/shutdown-t3-rnow命令重启系统ca::ctrlaltdel:/sbin/shutdown-t3-rnow#WhenourUPStellsuspowerhasfailed,assumewehaveafewminutes#ofpowerleft.Scheduleashutdownfor2minutesfromnow.#Thisdoes,ofcourse,assumeyouhavepowerdinstalledandyour#UPSconnectedandworkingcorrectly.#如果系统有UPS电源,该行命令设定系统在掉电时提示“电源关闭,系统正在关闭”,并且在2min后自动关机pf::powerfail:/sbin/shutdown-f-h+2PowerFailure;SystemShuttingDown#Ifpowerwasrestoredbeforetheshutdownkickedin,cancelit.#如果工作电源恢复,该行命令提示“电源恢复,取消关机”,并且取消关机pr:12345:powerokwait:/sbin/shutdown-cPowerRestored;ShutdownCancelled#Rungettysinstandardrunlevels#init进程打开6个终端(虚拟控制台),以ttyn为参数执行/sbin/mingetty程序,打开ttyn终端用于用户登录1:2345:respawn:/sbin/mingettytty12:2345:respawn:/sbin/mingettytty23:2345:respawn:/sbin/mingettytty34:2345:respawn:/sbin/mingettytty45:2345:respawn:/sbin/mingettytty56:2345:respawn:/sbin/mingettytty6######0:12345:respawn:/sbin/mingettytty0######在1-5各个级别上以tty0为参数执行/sbin/mingetty程序,打开tty0终端用于用户登录,######如果进程退出则再次运行mingetty程序#Runxdminrunlevel5#在级别5上运行xdm程序,提供xdm图形方式登录界面,并在退出时重新执行(respawn)x:5:respawn:/etc/X11/prefdm-nodaemon/etc/inittab文件是以行为单位的描述性(非执行性)文本,每个指令行都具有以下格式:Id:runlevels:action:process从代码中可以看到,etc/inittab中语句的每一行包含4个域,格式如下。(1)id:是指入口标识符,它是一个字符串,是由两个独特的字元所组成的标识符,这个标识符在此文件中是唯一的。文件中的某些记录必须使用特定的id才能使系统工作正常。对于getty或mingetty等其它login程序项,要求id与tty的编号相同,否则getty程序不能正常工作。(2)runlevels:runlevels域给出的是本行的运行级别。运行级别会指出下一个操作域中的action以及process域会在哪些runlevels中被执行。而在正常的启动程序之后,root用户可以使用telinit这个指令来改变系统的runlevels。假定在Linux系统中runlevels的预设值是5,那么只有那些每一列中runlevel域的值为5时,后面的process才会被执行。所以,如果系统的runlevels值不同的话,所执行的process也不一样,所以系统启动时的资源配置情况,在不同的runlevels下会有差异。runlevels一般使用0~6以及S或s。0为shutdown;1为重启至单用户模式;2为无NFS支持的多用户模式;3是完全多用户模式(也是最常用的级别);4保留给用户自定义;5表示XDM图形登录方式;