15.系统启动流程
- POST(power on self testing)
- BIOS(boot sequence)
- MBR(bootloader,446B)
- kernel(ko)
- initrd
- /sbin/init(rootfs),执行/etc/inittab中的服务。
学习磁盘及文件系统时说过,bootloader可以识别磁盘中的内核分区。
Linux内核启动的下一过程是启动第一个进程init(管理用户空间进程),但必须以根文件系统为载体,所以在启动init之前,还要挂载根文件系统。
根能够自识别。
回忆根文件系统必需的5个目录。
BootLoader
不同os的bootloader是不一样的,它由os安装程序提供,但mbr是不属于任何os的,是硬盘级别的。
win8后,mbr被微软锁定,不能引导其它os,其它os也不能引导windows,导致不能兼容其它系统。
linux的bootloader是很开放的,常用的有2种:
LILO(LInux LOader),不能引导1024柱面以后分区的内核,所以不支持大硬盘(一般8G),一般用在嵌入式里。
另一种是grub(GRand Unified Bootloader)。
Grub
两段式,或者三段式。有两个版本,grub2更新更广泛。这里以grub1为例。
- stage1:位于mbr中,目的是引导第2阶段,而不是引导os。代码很小,文件通常被叫做引导镜像(boot.img)。
- stage1.5:识别文件系统,文件名为/boot/grubFSNAME1_5。
- stage 2:定位和加载 Linux 内核(vmlinuz)到内存中,并转移控制权到内核。
第2阶段有配置文件/boot/grub/grub.conf
,定义了可以引导哪些os和kernel,还可以选择要加载的图片。
rpm -q grub
可查询信息。
/etc/grub.conf是个链接,指向/boot/grub/grub.conf
.
cat /etc/grub.conf
default:设定默认os或kernel编号
timeout:等待用户选择的超时时间
splashimage:grub背景图片,格式为.xpm.gz,可以用作图软件gimp制作。
hiddenmenu:隐藏菜单,没有该字段则不隐藏。
password指定编辑密码
grub-md5-cryp
t命令直接生成密码,添加:
password --md5 CYPHER每个title指定一个os或kernel
- root一行记录内核文件所在设备,对grub而言硬盘类型全是hd,后跟第几个盘,第几个分区。
- kernel一行指定内核文件路径以及传递参数,参数可执行cat /proc/cmdline查看
- initrd一行记录ramdisk文件路径,里面是完整的linux系统,大小几m。
注意,/boot是单独分区的,但title的kernel和initrd两行路径并没有/boot,而是直接/vmlinuz,因为是通过grub直接访问的,而不是通过文件系统。
#模拟修复grub
fdisk -l # 找到系统盘sda的boot分区/dev/sda1
dd if=/dev/zero of=/dev/sda bs=446 count=1 #破坏bootloader
sync
#此时已经无法重启
# 第一种方式
#执行grub进入新的交互界面
grub
# 安装stage1
grub> root (hd0,0)
grub> setup (hd0) #安装grub
grub> quit
shutdown -r now #重启
#第二种方式
grub-install --root-directory=/ /dev/sda
# grub.conf的信息可能和命令不一致,比如系统盘
#练习 给其他硬盘装上grub
# 分3个区(内核,根,swap)
partprobe /dev/sda
mke2fs -j /dev/sda1
mke2fs -j /dev/sda2
mkswap /dev/sda3
# 把/mnt作为根
mkdir /mnt/boot
mount /dev/sda2 /mnt/boot
grub--install --root-directory=/mnt /dev/sda
# 这样就会自动创建/mnt/boot/grub/device.map
vim /mnt/boot/grub/grub.conf
# 现在,提供内核、initrd、init就可以启动了。
# 把grub.conf mv到别处模拟损坏的情况
shutdown -r now
# 会出现grub提示符
grub> find (hd0,0)/ #挨个寻找内核文件vmlinuz在哪,根据possible files判断,若是则执行root (hd0,0)。
grub> root (hd0,0)
grub> kernel /vmlinuz # 若知道根可以附上root=...
grub> initrd /initrd-*.img
grub> boot #尝试找根
内核
内核设计风格:
- 单内核:所有功能做进内核,实现简单,目前向微内核靠拢。线程被称作轻量级进程(lwp);核心叫做kernel object(KO),支持动态加载模块。
- 微内核:外围功能做成子系统,要求耦合度低,更安全,但实现复杂导致优势不明显。
linux属于单内核,windows、solaris属于微内核。
微内核才真正意义上支持多线程
linux支持20种内核架构,如arm。
查看内核:uname -r
内核的模块机制
系统启动时只是启动内核的核心,它很小,可以动态加载内核模块(KO),又称动态可加载内核模块(Loadable Kernel Module,LKM),KO位于/lib/modules
,该目录下有内核版本号命名的目录,里面的模块都很大。
目录里的net
是协议栈,/drivers/net
才是网卡驱动。
lsmod
命令,列出模块。
vmlinuz
/boot/vmlinuz
是压缩的,可引导的、可执行的Linux内核,它一般是一个软链接。
du -sh /boot/vmlinuz*
会显示大小只有几m。
内核初始化过程
- 设备检测
- 驱动初始化,可能从initrd文件中装载驱动模块。
- 以只读方式挂载根文件系统
- 装载第一个进程init
initrd
内核访问根,需要设备驱动和设备文件系统。
启动时,kernel不具备这两个条件,不能直接访问init,所以用到如下机制:
初始化时内核访问文件系统用到了根切换,其下有/proc,/sys,/dev,然后才能装载真正的文件系统。这里的中间层次是个文件,能把一块内存模拟为硬盘来用。这个文件叫做ramdisk或者ramfs。
可以把initrd理解为一个带有根文件系统的虚拟磁盘。
红帽5:ramdisk,文件名为initrd(initial ramdisk)。
红帽6:ramfs,文件名为initramfs
initrd装载进内存后,内核挂载真正的根文件系统,然后将此initrd从内存中卸掉。所以说initrd起到过渡的作用。
注意,initrd一定是和kernel位于同一分区,与kernel同时被bootloader装载,然后kernel借助它找到rootfs,进而找到/sbin/init
。
init
# 根切换
#chroot命令,把一个目录临时作为根。其下需要有/bin/bash
mkdir -pv /testroot/bin
cp /bin/bash /testroot/bin/
ldd /bin/bash # 显示依赖库
mkdir -pv /testroot/lib
# 将依赖库依次cp进/testroot/lib
tree /testroot # 查看
chroot /testroot # 这样就完成了根切换
# 红帽5有一种shell叫做nash,提供命令switch_root
运行级别
windows有安全模式,linux有运行级别,不同模式/级别启动的服务不同。
linux运行级别:0-6
- 0:halt
- 1:single user mode,直接管理员登录。
- 2:multi user mode,no NFS(网络文件系统)
- 3:multi user mode,text mode
- 4:reserved,保留
- 5:multi user mode,graphic mode
- 6:reboot
/etc/inittab
记录了默认运行级别,init会读取。
查看运行级别
runlevel
命令显示运行级别,输出上一个级别和当前级别。who -r
也能显示运行级别
inittab
/sbin/init
,读取配置文件/etc/inittab
;它是串行启动服务的。
init
并不是只有一种。红帽6以后使用upstart
,是另一种init
,由ubuntu开发,可以并行启动一些进程。
进程间通信基于d-bus,是事件驱动(event-driven)的。
另一种更好的是systemd
(红帽6.2),实现了完整意义上并行启动多个进程,但不太稳定,6.3以后又换回upstart。
红帽6的/etc/init
包含inittab
拆分后的文件。而/etc/init.d
是脚本目录。
man inittab
可以查看字段意义
id:runlevel:action:process
runlevel为空则表示所有级别action:在什么情况下执行此行
initdefault:设定默认运行级别
sysinit:系统初始化,会执行/etc/rc.d/rc.sysinit脚本,该脚本至关重要。
rc:run cmd
wait:等待级别切换完成
ctrlaltdel:关机
powerfail:停电
powerwaitok:电源恢复
respawn:一旦程序终止,重新启动。
inittab
中的这一行用于系统初始化
si::sysinit:/etc/rc.d/rc.sysinit
/etc/rc.d/rc.sysinit任务:
1.激活udev和selinux
2.根据/etc/sysctl.conf设置内核参数
3.设定时钟
4.装载键盘映射
5.启用交换分区
6.设置主机名
7.根文件系统检测,并以读写方式重新挂载
8.激活raid和lvm设备
9.启用磁盘配额
10.根据/etc/fatab检查并挂载其它fs
11.清理过期的锁和pid文件
对于/etc/rc#.d/
下的文件,rc.sysinit
先关闭K*
服务,再启动S*
服务。