Back to Linux Kernel |
See Also: SysV-style、 |
Linux Startup Process
Contents
Linux系统的启动过程是一个多级初始化过程。Linux startup process派生自Unix,因此引导过程在形式上非常类似于BSD和其他Unix。
Linux系统的引导涉及多个阶段和软件组件,包括:
- 固件初始化(Firmware Initialization)
- 执行引导加载程序(Boot Loader)
- 加载和启动Linux内核映像(Linux kernel image)
- 执行各种启动脚本和守护进程(Startup Scripts and Daemons)
每个阶段和组件可能采用不同的方法和变化,例如
Boot Loader: GRUB/LILO/SYSLINUX/Loadlin
- Startup Scripts: init-style/systemd/Upstart
1. Early User Space
initramfs,也称为早期用户空间,从V2.5.46版本开始引入到Linux内核中,用来取代之前内核会在启动过程中执行的尽可能多的功能。早期的用户空间的典型用途是检测并确定哪些设备驱动程序需要加载,并从临时的文件系统加载到主要用户空间文件系统。
1.1. initramfs
initramfs,"initial ram file system"的缩写,是initrd的继任者。在Linux启动过程中,initramfs作为cpio归档的最初文件系统加载到内存中。Linux内核挂载它作为根文件系统来启动init进程。因为需要在真正的根文件系统加载前前完成任务,initramfs需要包含所有的设备驱动程序和工具以完成挂载真正的根文件系统的工作。
对于某些应用程序,initramfs可以利用casper工具来创建一个可写的环境--使用一个unionfs文件系统覆盖在只读的根文件系统映像上。覆盖数据可以存储在U盘上,而压缩的SquashFS文件系统存储在一个live CD作为根文件系统。
initramfs是一个“鸡生蛋||蛋生鸡”问题的解决方案:对于大规模存储设备和文件系统--特别是加密文件系统,需要复杂的设备驱动程序来读取数据,而设备驱动程序通常存储在文件系统的大容量存储器上。
2. Boot Loader Phase
2.1. GRUB
- 第一阶段的加载程序(stage1):被BIOS从主引导记录(MBR)或被另一个引导加载程序从分区的引导扇区加载和执行;
- 如果有必要,Stage1会加载和执行一个中间阶段加载程序(stage1.5)。这可能是必要的,如果第二阶段加载程序不连续,或文件系统、硬件需要特殊处理才能得第二阶段加载程序;
- 然后第二阶段加载程序(stage2)被加载和执行。显示GRUB启动菜单,允许用户选择一个操作系统或检查和编辑启动参数;
- 选好操作系统后,GRUB加载内核到内存,将控制权交给内核。另外,通过使用链式加载,GRUB可以把启动过程控制权交给其它引导加载程序。
2.2. LILO
一个很古老的加载程序。
2.3. SYSLINUX
SYSLINUX基于FAT文件系统,一般不用于启动完整的Linux系统。它通常用于引导或救援盘、live USBs或其他轻量级引导系统。ISOLINUX通常使用Linux live cd和引导安装光盘。
3. Kernel Phase
Linux内核处理所有操作系统进程,如
- 内存管理
- 任务调度
- I/O
- 进程间通信
- 系统整体控制
在装载上分为两个阶段:
- 内核加载阶段:内核(作为一个压缩文件)加载到内存、解压、一些基本功能的设置(如内存管理等);然后控制权最后一次转交给主内核启动过程。
- 内核设置阶段:一旦内核全面启动--加载和执行--内核调用init进程,init进程会(单独)设置一个用户空间和一个用户环境所需的过程和最终登录。然后内核被允许闲置,其他进程允许调用。
3.1. Kernel loading stage
加载的内核通常是一个镜像文件,用zlib压缩成zImage或bzImage格式。包含常规的少量的硬件设置,解压缩镜像到高位内存,配置需要注意的任何RAM磁盘。然后通过./arch/i386/boot/head和startup_32 ()执行内核启动。
3.1.1. vmlinux
在linux系统中,vmlinux(vmlinuz)是一个包含linux kernel的静态链接的可执行文件,文件型态可能是linux接受的可执行文件格式之一(ELF、COFF或a.out),vmlinux若要用于除错时则必须要在开机前增加symbol table。
3.1.1.1. vmlinuz
vmlinuz 是vmlinux 经过 gzip和objcopy 制作出来的压缩文件,当然不再是vmlinux的一个简单的压缩版,这么简单。vmlinuz是一种统称,有两种具体的表现形式zImage 和bzImage。bzimage和zImage的区别在于本身的大小,以及加载到内存时的地址不同,zImage在0~640KB,而bzImage则在1M以上的位置!
3.1.1.2. vmlinux.bin
vmlinux.bin 是进行如下操作得来,除二进制内容一无所有,而vmlinx是elf格式的文件里面包含了elf头部内容:
#objcopy -O binary vmlinux vmlinux.bin.
3.1.1.3. bzImage
随着linux Kernel的成长,核心的内容日益增加超越了原本的限制大小。bzImage (big zImage) 格式则为了克服此缺点开始发展,利用将核心切割成不连续的存储器区块来克服大小限制。
3.2. Kernel startup stage
内核的启动函数(也称为swapper或process0)建立内存管理(分页表和内存分页),检测到CPU的类型和任何额外的功能(如浮点功能),然后通过调用start_kernel()切换到non-architecture的Linux内核功能。
start_kernel执行大量的初始化函数:
- 设置中断处理:终端请求(IRQs)
- 进一步配置内存
- 启动Init进程(第一个用户空间进程)
然后通过调用cpu_idle()开始空闲任务
值得注意的是,内核启动过程也挂载初始RAM磁盘(initrd),在启动阶段加载之前的临时根文件系统。
因此,内核初始化设备、挂载引导加载程序指定为只读的根文件系统,并运行Init(/sbin/init)--系统中的第一个进程(PID = 1)。
3.3. 更多参考
http://blog.csdn.net/bokee/article/details/6900361: Linux kernel boot process——从实模式(real mode)到保护模式(protected mode),再到分页(paging)
4. Init Process
截至2014年2月,很多Linux发行版,比如Debian/Arch/Fedora和openSUSE,已经使用systemd替代init进程作为初试进程在用户空间执行Linux启动。同时,systemd取代了传统的基于shell脚本的init系统,使用一组守护进程以及自己的初始化指令,记录在声明式配置文件。
4.1. SysV init
Init是所有进程的父亲。它的主要作用是根据脚本创建进程,创建脚本存储在文件/etc/inittab。这个文件一般会有访问入口--init spawn出终端(getty)允许用户登录。
init还控制特定系统所需的自治进程(autonomous process)。运行级别(run level)是一种软件的配置系统,只允许存在一组被选的过程。被init spawned的进程的运行基本在/etc/inittab文件中定义。
$ sudo cat /etc/inittab
id:3:initdefault:
是 Unix 和 类Unix 系统中用来产生其它所有进程的程序。它以守护进程的方式存在,其进程号为1。
init风格:
- System III/System V: 原生风格,大多数Linux发行版与System V兼容;
- BSD风格:如Arch/Slackware/Gentoo等
4.2. systemd
systemd是Linux下的一种init软件,由Lennart Poettering带头开发,并在LGPL 2.1及其后续版本许可证下开源发布。其开发目标是提供更优秀的框架以表示系统服务间的依赖关系,并依此实现系统初始化时服务的并行启动,同时达到降低Shell的系统开销的效果,最终代替现在常用的System V与BSD风格init程序。
与多数发行版使用的System V风格init相比,systemd采用了以下新技术:
- 采用Socket激活式与D-Bus激活式服务,以提高相互依赖的各服务的并行运行性能;
- 用cgroups代替进程ID来追踪进程,以此即使是两次fork之后生成的守护进程也不会脱离systemd的控制。
从设计构思上说,由于systemd使用了cgroup与fanotify等组件以实现其特性,所以只适用于Linux[5]。有鉴于此,考虑到kFreeBSD分支的软件源无法纳入systemd,为与其他分支保持一致,Debian开发者尽力避免纳入systemd。但Lennart Poettering本人对此并不在意,并称“Debian GNU/kFreeBSD不过是玩具系统”。
默认init程序为systemd的发行版
- Fedora 15及后续版本
- Mageia 2
- Mandriva 2011
- openSUSE 12.1及后续版本
- Arch Linux在2012年10月13日将systemd-sysvcompat纳入base软件组,自此Arch Linux默认安装完即以systemd为init程序,同时也提供了与Arch自带启动脚本兼容用的systemd启动脚本包以方便用户,使用户能“开箱即用”
- Chakra GNU/Linux,在2012.10的光盘映像文件发布后默认使用systemd。
可以使用systemd的发行版
- Debian GNU/Linux,于“testing”分支源中提供,并在2014年的技术委员会的init系统投票中决定在Debian 8 “Jessie”中将以Linux为核心的版本转换到systemd。
- Gentoo,同Openrc一起被Gentoo官方支持
4.3. Upstart
Upstart是一个基于事件的初始化守护进程,用于替代传统的init(多种类Unix计算机操作系统启动时用于执行任务的程序)。它是由Canonical公司前雇员Scott James Remnant所写。
传统的init进程原本只负责在开机后将计算机带入正常运行状态,并且在正常关机前关闭服务。因此,它的设计是严格同步的,且会阻塞未来的任务,直到完成当前任务。因为受限于准备或清除函数,它的任务也是事先定义的。这使得它无法简洁地处理现代桌面计算机上的各种非启动任务,其中包括:
- 机器运行时添加或删除U盘和其他便携式存储/网络设备
- 发现并扫描新存储设备而不锁定系统,尤其是当磁盘没被扫描就不运行时
- 固件需要在检测设备之后、在它可用之前加载
Upstart的事件驱动模型允许它以异步方式对生成的事件作出回应。
4.3.1. 设计
Upstart是异步工作的;它在系统运行时监督服务,并且在开关机时启动和关闭任务和服务。
对sysvinit简单的过渡和完善的向后兼容是明确的设计目标;因此,Upstart能运行未经修改的sysvinit脚本。因此,与大多数其他的init替代(除了systemd和OpenRC)不同,它们通常假设并要求彻底的过渡,以正常运行,且不支持新旧启动方法混合的环境。
通过使用initctl输入自定义的单一事件,或整合更多更复杂事件的事件桥,Upstart允许扩展其事件模型。默认情况下,Upstart包括接口(socket)、dbus、udev、文件及dconf事件桥;另外,可以有更多种桥(例如Mach端口桥,或devd(FreeBSD系统上)桥)。
4.3.2. chkconfig
# Check if service is enabled or disabled on startup:
$ chkconfig --list | grep SERVICE
# Disable service autostart in CentOS-6:
$ chkconfig SERVICE off
# Enable service autostart in CentOS-6:
$ chkconfig SERVICE on
4.4. runit
Runit是类Unix操作系统上的一个init方案,为整个操作系统初始化、监督和结束进程。这是一个“重新实现”的“再生”过程监控工具,运行在Linux/Mac OS X/*BSD和Solaris操作系统上。Runit并行化系统服务的启动特性,可以加快操作系统的启动时间。
Runit是一个init守护进程,因此它是所有其他进程的直接或间接祖先。它是系统启动后第一个开始的进程,持续运行直到系统关闭。
4.5. launchd
launchd是一个统一的、开源的服务管理框架,在Apple OS X系统下用于开始、停止并管理守护进程,、应用程序、进程。Dave Zarzycki在苹果时设计和编写了launchd;苹果从Mac OS X Tiger开始引入,采用Apache License。
在Mac OS X v10.4之前,系统由Mac OS X的BSD风格init启动,在Mac OS X v10.4及其后续版本中,由launchd启动。