系统启动流程
1)加载BIOS的硬件信息与进行自我测试,并依据设置取得第一个可启动的设备;
2)读取并执行第一个启动设备内的MBR的boot Loader(即grub,spfdisk等程序);
3)依据boot loader的设置加载Kernel,Kernel会开始检测硬件与加载驱动程序;
4)在硬件驱动成功后,Kernel会主动调用init进程,而init会取得run-level信息;
5)init执行/etc/rc.d/rc.sysinit文件来准备软件执行的操作环境(如网络、时区等);
6)init执行run-level的各个服务的启动(script方式);
7)init执行/etc/rc.d/rc.local文件;
8)init执行终端机模拟程序mingetty来启动login进程,最后就等待用户登录。
BIOS开机自我检测与MBR
在个人计算机架构下,想要启动整个系统,首先要让系统加载BIOS(Basic Input Output System),并通过BIOS程序去加载CMOS的信息,并且通过CMOS内的设置取得主机的各项配置。然后BIOS进行开机自检,之后指定启动设备读取磁盘中的操作系统内核文件。引导装载程序被称为BootLoader。它放在启动设备的第一个扇区(sector)内,即第一个MBR(主引导分区中)。Loader最重要的功能就是要认识操作系统的文件格式并据以加载到内核中去执行。
boot Loader主要功能
Loader最主要功能是要认识操作系统的文件格式并据以加载内核到内存中去执行。boot Loader主要功能如下:
提供菜单:用户可以选择不同的启动选项,这也是多重引导的重要功能。
加载内核文件:直接指向可启动的程序区段来开始操作系统。
转交其他loader:将引导装载功能转交给其他loader负责。
加载内核检测硬件与initrd功能
经boot loader管理后,开始读取内核文件,然后Linux会将内核解压缩到内存中,并利用内核的功能,开始测试与驱动各个周边设备,包括存储设备、CPU、网卡、声卡等。此时Linux内核会以自己的功能重新检测一次硬件,而不一定会使用BIOS检测到硬件信息。即内核此时开始接管BIOS后的工作。
Linux内核可以通过动态加载内核模块,其内核模块放置在/lib/modules目录内。由于模块放置到磁盘根目录内,故启动过程中内核必须要挂载根目录,这样才能够读取内核模块提供加载驱动程序的功能。而一些非必要的功能,可以编译成为模块的内核功能。如USB、SATA、SCSI等磁盘设备的驱动程序通常都是以模块的方式来存在的。
内核不认识SATA磁盘,所以需要加载SATA磁盘的驱动程序,否则根本就无法挂载根目录。但是SATA的驱动程序在/lib/modules内,无法挂载根目录,此时,需要通过虚拟文件系统来处理。
虚拟文件系统(InitialRAM Disk)一般使用的文件名为/boot/initrd,此文件可以通过boot loader来加载内存,然后这个文件会被解压缩并且在内存当中仿真成一个根目录,且此仿真在内存当中的文件系统能够提供一个可执行的程序,通过该程序来加载启动过程中最需要的内核模块,通过这些模块,即USB、RAID、LVM、SCSI等文件系统与磁盘接口的驱动程序。
Boot Loader可以加载kernel与initrd,然后在内存中让initrd解压缩成为根目录,kernel就能够借此加载适当的程序,最终释放虚拟文件系统,并挂载实际的根目录文件系统,就能够开始后续的正常启动。
BIOS与boot loader及内核加载流程如下图:
**第一个进程init及配置文件/etc/inittab与runlevel
内核加载完毕后进行完硬件检测与驱动程序加载后,此时主机硬件应该已经准备就绪了,此时内核会主动调用第一个进程,即/sbin/init。init的进程ID为1,/sbin/init主要功能是准备软件执行的环境,包括主机名,网络设置,语系处理,文件系统格式以及其他服务的启动等。所有的操作都会通过init的配置文件,即/etc/inittab来规划,而inittab内还有一个很重要的设置选项,即默认run level(启动执行等级)。
run level:执行等级
run level执行等级主要有7个,分别是:
0-系统直接关机
1-单用户模式,用在系统出问题时的维护
2-完整含有网络功能的纯文本模式,无nfs服务
3-完整含有网络功能的纯文本模式
4-系统保留功能
5-X11(与runlevel3类似,但加载使用X window)
6-重新启动
注意:由于run level 0/4/6不是关机、重新启动就是系统保留,所以不能将默认的run level设置为这三个值,否则系统会不断自动关机或自动重新启动。
init的处理流程
1)先取得runlevel即默认执行等级的相关等级;
2)使用/etc/rc.d/rc.sysinit进行系统初始化;
3)由于runlevel是5,因此只进行”5:5:wait:/etc/rc.d/rc5”,其他行则略过;
4)设置好 ctrl + alt + del这组的组合键功能;
5)设置不断电系统的pf,pr两种机制;
6)启动mingetty的6个周东南机(tty1~tty6)
7)最终将/etc/X11/perfdm -nodaemon启动图形界面。
init处理系统初始化流程(/etc/rc.d/rc.sysinit)
开始加载各项系统服务之前,得先设置好整个系统环境,主要利用/etc/rc.d/rc.sysinit这个shell script来设置好系统环境。
/etc/rc.d/rc.sysinit主要工作如下:
1)取得网络环境与主机类型:如读取网络配置文件/etc/sysconfig/network,取得主机名与默认网关(gateway)等网络环境;
2)测试与挂载内存设备/proc及USB设备/sys;
3)决定是否启动SELinux;
4)启动系统的随机数生成器;
5)设置终端机(console)字体;
6)设置显示与启动过程中的欢迎界面;
7)设置系统时间(clock)和时区设置:需读入/etc/sysconfig/clock设置值
8)接口设备的检测与Plug and Plya(PnP)参数的测试;
9)用户自定义模块的加载;
10)加载内核的相关设置;
11)设置主机名与初始化电源管理模块(ACPI);
12)初始化软件磁盘阵列;主要通过/etc/mdadm.conf来设置好;
13)初始化LVM的文件系统功能;
14)以fsck检验磁盘文件系统:会进行filesystem check;
15)进行磁盘配额quota的转换(非必要);
16)重新可以读写模式挂载系统磁盘;
17)启动quota功能,故不需要自定义quotaon的操作;
18)启动系统伪随机数生成器(pseudo-random)
19)清除启动过程当中的临时文件;
20)将启动相关信息加载/var/log/dmesg文件中。
启动系统服务与相关启动配置文件(/etc/rc.d/rc N & /etc/sysconfig)
run level要执行的脚本,主要存放在/etc/rc.d/rc中。模式使用run level 5,故/etc/rc.d/rc5的意义如下:
通过外部的一号参数($1)来取得想要执行的脚本目录,即由/etc/rc.d/rc 5可以取得/etc/rc5.d/这个目录来准备处理相关的脚本程序;
找到/etc/rc5.d/K??*开头的文件,并进行“/etc/rc5.d/K??*stop”的操作;
找到/etc/rc5.d/S??*开头的文件,并进行”/etc/rc5.d/S??*start”的操作;
用户自定义开机启动程序(/etc/rc.d/rc.local)
当我们有任何想要在启动时就进行的工作时,可以将其写入/etc/rc.d/rc.local中,这样,工作就可以自动在启动时加载,执行。
根据/etc/initatb的设置加载终端机或X Window界面
完成系统所有服务的启动后,接下来Linux就会启动终端机或者X Window来等待用户登录。此时就是根据/etc/initatb来执行的。
启动过程中会用到的主要配置文件
关于模块:/etc/modprobe.conf
/etc/sysconfig(atuconfig, clock, i18n, keyboard&mouse, network, network-scripts等。
run level的切换
run level有关的启动其实是在/etc/rc.d/rc.sysinit执行完毕之后。run level设置方式有以下两种:
1)要每次启动都执行某个默认的run level,则需要修改/etc/inittab内的设置选项,即是”id:5:initdefault:”里面的数字;
2)如果仅只是暂时更改系统的run level时,在使用init[0-6]来进行run level的更改,但下次重新启动时,依旧会以/etc/inittab的设置为准。
内核与内核模块
整个启动过程中,是否能够成功驱动主机硬件配置,是内核的工作。内核一般是压缩文件,故在使用前,需要解压缩后才能加载到内存中。目前内核具有可读取模块化驱动程序的功能,即模块化功能。而模块化实质就是想成为一个插件,该插件可能由硬件开发商提供,也可能有内核本身支持。
内核与内核模块存放:
内核:/boot/vmlinuz或/boot/vmlinuz-version;
内核解压缩所需RAMDisk:/boot/initrd(/boot/initrd-version);
内核模块:/lib/modules/version/kernel或/lib/modules/$(uname -r) /kernel;
内核源码:/usr/src/linux或/usr/src/kernels
内核版本:/proc/version
系统内核功能:/proc/sys/kernel
内核模块依赖性
内核模块放置处是在/lib/modules/$(uname -r) /kernel中,里面主要分为以下目录:
arch:与硬件平台有关的选项,如CPU等级等;
cypto:内核所支持的加密的技术,如md5或者des等;
drivers:一些硬件的驱动程序,如显卡,网卡,PCI相关硬件等;
fs:内核所支持的文件系统,如vfat,reiserfs,nfs等;
lib:一些函数库;
net:与网络有关的各项协议数据,还有防火墙模块(net/ipv4/netfilter/*)等;
sound:与音效有关的各项模块
使用depmod命令,程序会到模块标准放置目录,并将其全部模块分析出来,写入modules.dep文件中。
查看内存模块
使用lsmod命令,显示内核中的模块,显示内容如下:
模块名称(Module);
模块的大小(size);
此模块是否被其他模块所使用(Used by)。
此外,modinfo也可以查阅内核内的模块,并检查某个模块文件。
内核模块加载与删除
内核模块加载,使用如下命令:insmod [/full/path/module_name] [parameters]
内核模块删除,使用如下命令:rmmod [-fw] module)name
上述两个命令,都需要自行找到模块的完整文件名才行。为方便,可以使用modprobe来处理模块加载,命令为:modprobe [-lcfr] module_name
内核模块的额外参数设置:/etc/modprobe.conf
想要设置默写模块的额外参数,可以在/etc/modprobe.conf文件中进行设置。
* boot loader执行*
MBR是整个硬盘的第一个sector内的一个块,充其量整个大小为446byte。但程序代码和数据一定大于446字节,故安装时,需要boot loader执行,具体分两个阶段:
阶段1:执行boot loader主程序;
阶段2:主程序加载配置文件;
配置文件存放的位置为/boot/grub/目录下,最重要的为menu.lst以及各种文件系统的定义。
grub的配置文件/boot/grub/menu.lst与菜单类型
grub是Linux的引导程序,其主要优点如下:
认识与支持较多的文件系统,并且可以使用grub的主程序直接在文件系统中查找内核文件名;
启动的时候,可以自行编辑与修改启动设置选项,类似bash的命令模式;
可以动态查找配置文件,而不需要再修改配置文件后重新安装grub,即只要修改完/boot/grub/menu.lst里面的设置,下次启动就生效。
initrd的重要性与创建新initrd文件
initrd的目的是提供启动过程中所需要的最重要内核模块,以让系统启动过程可以顺利完成。initrd内所包含的模块大多是与启动过程有关的,而主要以文件系统及硬盘模块(如usb,SCSI等)为主。一般需要initrd的时刻为:
根目录所在磁盘为SATA、USB或SCSI等连接接口;
根目录所在文件系统为LVM、RAID等特殊格式;
根目录所在文件系统为非传统Linux“认识”的文件系统时;
其他必须要在内核加载时提供的模块。
创建新的initrd文件,可以使用如下命令:mkinitrd [-v] [–with=模块名称] initrd文件名 内核版本
安装grub
使用grub-install就可以安装grub相关的文件(如文件系统定义文件)到设备上面,然后等待在启动时被读取,此外还需要设置好配置文件(menu.lst)后,再以grub shell来安装grub主程序到MBR或者是boot sector上面去。
grub安装过程中,常用命令如下:
用root(hdx, x)选择含有grub目录的那个分区代号;
用find/boot/grub/stage1看看能否找到到安装信息文件;
用find/boot/vmlinuz看看能否找到内核文件(不一定要成功);
用setup(hdx,x)或setup(hdx)将grub安装在boot sector或MBR中;
用quit来离开grub shell
总结如下:
1)如果是从其他boot loader转成grub时,得先使用grub-install安装grub配置文件;
2)开始编辑menu.lst这个重要的配置文件;
3)通过grub来将主程序安装到系统中,如MBR的(hd0)或boot sector的(hd0,0)等。
BIOS无法读取大硬盘的问题
系统使用DVD启动安装时,可以顺利安装好Linux,但是第一次启动时,屏幕出现黑黑一片,且出现grub>的字样,而无法进入Liunx系统中,原因可能是BIOS无法读取大容量磁盘内的kernel与initrd文件。解决办法:新建/boot独立分区,并将/boot放置到最前面即可。
启动过程中忘记密码解决办法
linux下root密码忘记时,还可以救回来,只要能够进入并且挂载,然后重新设置root密码,即可。原因是启动流程中,若强制内核进入runlevel 1时,默认是不需要密码即可取得一个root的shell来救援,整个操作像如下:
1)重新启动,必须重新启动;
2)启动进入grub菜单后,在要进入的菜单上点击e进入详细设置,将光标移动到kernel上面,并点击e进入编辑界面,输入single后,按下enter再按在b就能够启动进入单用户维护模式;
进入单用户维护模式后,系统会以root的权限直接给你shell,此时能够执行passwd命令重建root密码。然后直接执行init 5就可以切换到X窗口界面。
init配置文件错误
当/etc/inittab文件设置错误,则即使在单用户下也无法启动。故知single mode也要读取/etc/inittab来开机。此时方法是,先执行mount -o remout,rw/,主要用途是将根目录重新挂载成为可读写,然后执行mout -a重新挂载文件,就可以启动救援,但救援完成后,需要执行reboot重新启动加载一次。
利用chroot切换到另一个块硬盘工作
chroot命令含义:可以暂时将根目录移动到某个目录下,然后去处理某个问题,最后再离开该root而回到原来的系统当中。
重点总结
Linux不可随意关机,否则容易造成文件系统错乱或者其它无法启动的问题;
启动流程主要是BIOS、MBR、Loader、kernel+initrd、/sbin/init等流程;
loader具有提供菜单、加载内核文件、转交控制权给其他loader等功能;
boot loader可以安装在MBR或者是每个分区的bootsector区域中;
initrd可以提供内核在启动过程中所需要的重要的模块(通常是与磁盘及文件系统有关的模块);
init的配置文件为/etc/inittab,此文件内容可以设置默认runlevel,系统初始化脚本,不同执行等级的服务启动等;
额外的设备与模块对应可写入/etc/modprobe.conf中;
内核模块的管理可使用lsmod,modinfo,rmmod,insmod,modprobe等命令;
modprobe主要参考/lib/modules/$(uname -r)/modules.dep的设置来加载与卸载内核模块;
grub的配置文件与相关文件系统定义文件大多数放置于/boot/grub目录中,配置文件名为menu.lst;
grub对磁盘的代号设置与Linux不同,主要通过检测的顺序来给予设置,如(hd0)及(hd0,0)等;
menu.lst内每个菜单与title有关,而直接指定内核启动时,至少需要kernel及initrd两个文件;
menu.lst内设置loader控制权移交时,最重要的为chainloader+1这个选项;
若想重建initrd,可使用mkinitrd处理;
重新安装grub到MBR或boot sector时,可以利用grub shell来处理;
若想要进入救援模式,可于启动菜单过程中,在kernel的选项后面加入single或init=/bin/bash等方式来进入救援模式;
可以对grub的各个菜单给予不同的密码。
- 参考文献:鸟哥的私房菜