引导装入程序(Bootloader)是BIOS将操作系统内核映像装载到RAM中执行的第一个程序。
软盘启动与磁盘启动过程稍有不同,软盘启动时,BIOS将启动软盘的第一扇区指令装载到RAM中,由于通常现代内核都大于一个扇区大小(512B),因此第一扇区的指令通常是将包含内核映像的扇区加载到RAM中。
从硬盘启动时,硬盘的第一个扇区MBR中包含分区表和一小段程序,这段小程序用来装载被启动的操作系统所在分区的第一个扇区。Win98采用MBR中的小程序加载操作系统内核,而Linux在用一种更灵活的加载方式,bootloader。
Linux2.4及以前的版本,在第一个512字节有一个最小的引导程序,因此在第一扇区拷贝一个内核镜像就可以使软盘启动,但在2.6内核中不再有该引导程序,要想在软盘中启动,必须采用与磁盘类似的方式,在第一个扇区中装入一个引导程序。
Bootloader通常被安装在MBR上代替上面负责引导的小程序。Bootloader通常由于大于一个扇区,会被分为两部分,在BIOS将 Bootloader的第一部分加载到RAM的0x00007c00处开始执行,bootloader自己加载到0x00096a00,建立实模式站 (0x00098000~0x000969ff),并将bootloader的第二部分装入到0x00096c00开始的RAM中。
第二部分一次从此版读取操作系统映射表,提示给用户,用户可以选择要启动的系统,引动程序将相应分区的引导扇区拷贝到RAM中并执行,或直接将内核拷贝到RAM中。
Bootloader的主要执行过程:
setup()函数有汇编实现放在内核映像文件的偏移量0x200处,bootloader将其装载到0x00090200开始的RAM中。
setup()函数的主要工作是初始化计算机中的硬件设备,并为内核程序的执行建立环境。尽管BIOS已经完成大部分设备的初始化,但是Linux并不依赖与BIOS,而已自己的方式重新初始化设备,以增强可移植性和健壮性。
@TO-DO setup()过程
存在两个startup_32函数,setup()的最后是跳转执行的是arch/i386/boot/compressed/head.S中的 startup_32(),此时startup_32已经被移动到0x00100000或0x00001000,对应于高装载或低装载。该函数的主要工作 是解压内核。
解压完的内核映像从arch/i386/kernel/head.S开始执行。该文件中包含另一个startup_32函数。改startup_32为Linux的第一个进程(pid=0)建立执行环境。
@TO-DO startup_32()过程
startup_32函数最后回跳转执行start_kernel(),start_kernel完成内核初始化工作。start_kernel开始执行后会显示"Linux version 2.6.11..."
该函数中最主要的一个步骤是调用kernel_thread()为进程1创建内核线程。这个线程回创建其它线程并执行/sbin/init程序。该程序会在控制台输出初始化信息,直至最后出现登录提示符,或X登录窗口。通知用户内核已启动,正在运行。
(该部分只适用Redhat系,如RHEL,CentOS,Fedora等,Debian/Ubuntu启动过程与此不同,后期会有分析)
/sbin/init(进程1)会利用/etc/inittab获取运行级,并根据不同运行级的配置启动不同的服务项目。
inittab配置文件格式
[设置项目]:[run level]:[init的操作行为]:[命令项目]
设置项目:最多4个字符,表示init的主要目的,就是一个名字
run level:该条目的运行级别
init操作行为:
主要可选值如下:
initdefault:表示默认的运行级别值
sysinit:系统初始化操作项目
ctrlaltdel:表示[ctrl+alt+del
wait:表示必须等待后面的命令执行完才可以执行后续操作
respawn:表示后面的操作会重新启动
命令项目:执行该项目的命令,通常为一个脚本命令
inittab中的有个条目是
si::sysinit:/etc/rc.d/rc.sysinit
按上述条目解释,系统初始化时会执行/etc/rc.d/rc.sysinit脚本,该脚本的主要功能如下:
1.获取网络环境与主机名
2.测试与载入内存设备/proc以及USB设备/sys
3.决定是否启动SELinux
4.检测接口设备与即插即用设备参数
5.用户自定义模块加载
6.加载核心的相关设置
7.设置系统时间
8.设置终端控制台字体
9.设置RAID与LVM等硬盘功能
10.fsck检查磁盘文件系统
11.进行磁盘配额quota的转换
12.重新怡可读取模式载入系统磁盘
13.启动quota功能
14.启动系统随机设备(产生随机数)
15.清除启动过程的临时文件
16.将启动相关信息加载到/var/log/dmesg文件中
inittab中包含
id:3:initdefault:
l3:3:wait:/etc/rc.d/rc 3
第一行表示默认运行级为3,第二行表示第3级运行时以wait方式执行/etc/rc.d/rc 参数为3。
rc脚本的主要功能是调用相应运行级X的配置脚本目录/etc/rcX.d/下的脚本。例如3级时对应的脚本目录是/etc/rc3.d/目录。
脚本目录下的脚本名分为两类:一类是以K开头的,用于kill相应服务;另一类是以S开头的,用于开启相应服务。文件中还包含一个两位数字和服务名。rc脚本负责按照数字有小到大先kill所有服务然后开启所有服务的顺序执行。
每个rcX.d的目录下的脚本都是链接到init.d目录下的脚本的软连接。并且均包含一个S99local->../rc.local,该脚本表示最后执行../rc.local脚本。
rc.local即用户自定义的启动项配置脚本。可以在其中添加想开机启动的命令。比如想自动挂载一个windows下的分区,可以在rc.local中添加
mount -ntfs /dev/sda5 /media/disk5
根据inittab中的配置,需要等待/etc/rc 3 运行完成。rc.local时期最后一个脚本。在rc.local执行完之后,继续按照inittab执行
# Run gettys in standard runlevels
1:2345:respawn:/sbin/mingetty tty1
2:2345:respawn:/sbin/mingetty tty2
3:2345:respawn:/sbin/mingetty tty3
4:2345:respawn:/sbin/mingetty tty4
5:2345:respawn:/sbin/mingetty tty5
6:2345:respawn:/sbin/mingetty tty6
# Run xdm in runlevel 5
x:5:respawn:/etc/X11/prefdm -nodaemon
该段配置表示在2,3,4,5运行级下执行/sbin/mingetty开启终端,并且执行六次,由此可知为何会有6个纯文本终端。最后的x:5:respawn:/etc/X11/prefdm -nodaemon表示在运行级5时开启X Window。