Linux系统从启动到提供服务的过程是这样,先是机器加电,然后通过MBR或者UEFI加载GRUB,再启动内核,内核启动服务,然后开始对外服务。
步骤:
- 加载BIOS的硬件信息与进行自我测试,并依据设置取得第一个可启动的设备(比如硬盘);
- 读取并执行第一个开机装置内MBR 的boot Loader (即grub2, spfdisk 等程序);
- 依据boot loader 的设置加载Kernel ,Kernel 会开始检测硬件与加载驱动程序;
- 在硬件驱动成功后,Kernel 会主动调用init进程,而init会取得run-level信息;
- init 执行/etc/rc.d/rc.sysinit文件来准备软件执行的操作环境(如网络、时区);
- init 执行run-level的各个服务的启动(script方式);
- init 执行/etc/rc.d/rc.local 文件;
- init 执行终端机模拟程序mingetty来启动login进程,最后就等待用户登录。
下面详细介绍每一步程序。
BIOS和MBR都是硬件本身会支持的功能,Boot Loader则是操作系统安装在MBR上面的一套软件
BIOS:
写入到主板上的一个韧体(即写入到硬件上的一个软件程序),开机时计算机主动执行;功能:加载CMOS的信息,并通过CMOS内的设置值取得主机的各项硬件配置,然后进行开机自检,开始执行硬件检测的初始化,并配置PnP设备,并且根据用户的设置去取得能够开机的存储设备,读取并执行里面的第一个扇区的MBR位置。
MBR:
每块硬盘的第一个扇区内含有446B的MBR区域,称为主引导分区,内含引导加载程序
boot loader主要的功能如下:
a)提供菜单:用户可以选择不同的启动选项,这也是多重引导的重要功能
b)加载内核文件:直接指向可启动的程序区段来开始操作系统
c)转交其他loader:将引导装载功能转交给其他loader负责
Loader:
最主要的功能是要认识操作系统的文件格式并据以加载内核到内存中去执行,由于每种操作系统的文件格式不一致,因此每种操作系统都有自己的boot loader,只有使用自己的loader才能够加载属于自己的操作系统内核。每个文件系统都会保留一块引导扇区(boot sector)提供操作系统安装boot loader,而通常操作系统默认会安装一份loader到它根目录所在的文件系统的boot sector上。
Windows安装时,它默认会主动将MBR与boot sector都装上一份boot loader;而Linux系统可以选择安装或者不安装到MBR中去。由于boot loader的控制权转交功能,所以即使系统的MBR只有一个,我们是可以同时在一部主机上安装Windows和Linux的。不过要注意的是Windows的loader默认不具有控制权转交功能,因此不能使用Windows的loader来加载Linux的loader,所以最好应该先装Windows再装Linux,否则MBR的引导加载程序就只会有Windows的选项,而不会有Linux的选项,我们不需要重新安装Linux,只要用尽方法来处理MBR的内容即可。
内核文件:
开始操作系统的功能,放置在/boot里面,取名为/boot/vmlinuz。
加载内核检测硬件:
Linux会将内核解压缩到内存当中,并且利用内核的功能,开始测试与驱动各个周边设备(包括存储设备网卡声卡等)。
虚拟文件系统:
Linux内核是可以通过动态加载内核模块的(驱动程序),这些内核模块放在/lib/modules/目录内。由于模块放在磁盘根目录内,所以在启动的过程中内核必须要挂载根目录,这样才能够读取内核模块以提供驱动程序的功能。USB,SATA,SCSI等磁盘设备的驱动程序通常都是以模块的方式来存在的。假设linux是安装在SATA磁盘上面的,启动就会出现问题。内核根本不认识SATA磁盘,需要加载SATA磁盘的驱动程序,否则根本无法加载到根目录,但是它的驱动程序又在/lib/modules/中,我们根本无法挂载根目录,又怎么能读取到/modules/中的驱动程序呢。
我们通过虚拟文件系统解决这个问题,虚拟文件系统一般使用的文件名为/boot/initrd,boot loader可以加载kernel与initrd,然后在内存中让initrd解压缩成为根目录,kernel就能够借此加载适当的驱动程序,最终释放虚拟文件系统,并挂载实际的根目录文件系统,内核在重新调用 /sbin/init 来开始后续的正常启动流程。
那么,是否没有initrd就无法顺利启动?
不见得,当启动时无法挂载根目录的情况下,就一定需要initrd,例如根目录在特殊的磁盘接口(USB,SATA,SCSI)中,或者文件系统较为特殊(LVM,RAID)。如果你的Linux是安装在IDE接口的磁盘上,并且使用了默认的ext2/ext3文件系统,那么就不需要。
run level:
上述主机硬件准备就绪后,内核会调用第一个进程,即/sbin/init,PID为1,最主要的功能是准备软件执行的环境,包括系统主机名、网络设置等。所有操作都通过init的配置文件—/etc/inittab 来规划,其中一个很重要的设置选项就是默认的run level(启动执行等级)。
Linux通过设置run level来规定系统使用不同的服务来启动,让Linux的使用环境不同,基本上依据有无网络与有无X Window尔将run level分为7个等级,具体不细说了。一般我们默认都是3—完整含有网络功能的纯文本模式 或者5—与3类似加载使用X Window来作为run level的。
ps:Linux中启动脚本都被放在/etc/rc.d/中,rc—runlevel control,将名称设置为.d结尾是Linux系统的一种习惯,使得我们一看就知道是一个目录文件。
/etc/rc.d/rc.sysinit:
主要功能是设置系统功能,包括设定网络配置、测试挂载内存设备/proc、设置系统时间、启动swap分区、用户自定义模块的加载等。在这个文件中进行的许多工作的默认配置文件,或者说启动过程会用到的配置文件都在/etc/sysconfig/当中。
/etc/rc.d/rc N:
在系统模块和相关硬件信息的初始化后,我们还需要启动系统所需要的各项服务,这样主机才能提供给我们相关的网络或者是主机功能。依据 /etc/inittab/ 里面提到的run level设置值,比如run level 5 就是依据里面的这一行:15:5:wait:/etc/rc.d/rc 5,取到/etc/rc5.d/这个目录,这个目录里全部是连接文件,/etc/rc.5d/[SK]…,其实就是跑到/etc/init.d/去找到相对应的服务脚本,然后分别进行start(S…)或stop(K…)的操作。
/etc/rc.d/rc.local:
有任何想要在启动时就进行的工作时,直接将它写入/etc/rc.d/rc.local,那么该工作就会在启动的时候自动被加载。比如将自己制作的shell script完整文件名写入/etc/rc.d/rc.local,如此一来,启动就会执行自己的shell script。
run level的切换:
要每次启动都执行某个默认的run level,则需要修改/etc/inittab 内的设置选项,即是“id:5:initdafault:”里头的数字;
如果仅是暂时更改系统的run level时,则使用 init[0-6] 来进行run level 的更改,但下次启动时依旧是以/etc/inittab 内的设置为准。
runlevel命令查看当前run level。左边代表前一个run level,邮编代表目前的,因为我们没切换过,所以前一个为N。
使用init 3
命令将目前的runlevel切换为3。那么当切换时,系统会怎么处理呢?系统会先比较对应级别目录内的K与S开头的文件,在新的run level内有多的K开头的文件,则予以关闭,有多的 S开头的文件则 予以启动。这样两个run level都存在的服务就不会被关闭了,很容易切换。