1. BIOS
上电,然后从指定内存地址开始执行。BIOS 从 CMOS 读取系统硬件配置信息,上电自检,硬件初始化
主板电池主要就是给 CMOS (RAM)和硬件时钟供电。CMOS 里面存的一个东西就是启动磁盘是哪个
找到 MBR(主引导记录)里面的 bootloader,然后在指定偏移开始执行
2. BootLoader
因为 MBR 里面空间很小,bootloader 需要分段(GRUB 分成三段)。最核心的工作是将操作系统内核解压并载入到 0x100000
因为 bootloader 能够识别文件系统,所以很大一部分都是文件系统驱动。
也要先把文件系统映像载入内存(临时文件系统 initrd),这包含了驱动、配置文件和其他资源
告知内核必要的启动参数(根文件系统的 ID 和类型,initrd 内存位置和大小),然后到内核
3. 内核启动
将 initrd 解压,作为临时根文件系统挂载。重新检测计算机硬件,尝试加载必要的驱动程序,进行内核启动。
启动完成之后,释放临时根文件系统,并挂载真正的根文件系统。创建 1 号进程,控制权交给它
4. 一号进程
是用户空间的第一个进程,没有父进程
0 号进程 idle,是内核本身留下来的 2 号进程 kthreadd
负责用户态初始化:设置主机名,挂载用户指定的文件系统,设置内核参数,加载驱动。启动系统支持服务。启动终端管理进程
1 号进程的实现方式有两种:
- old Linux 采用 SysV init
- new Linux 采用 systemd
SysV init
- 在
/etc/inittab
找到运行级别。(关机、单用户、多用户、图像界面等,用来启动不同的服务 - 执行脚本
/etc/rc.d/rc.sysinit
初始化系统的基本设置和环境 - 执行脚本
/etc/rc.d/rc
根据不同的运行环境执行不同的服务 - 最终调用
/etc/rc.d/rc.local
用户自定义的开机启动任务 - 进入终端交互:给每个系统配置的用户终端上启动 getty 程序,读取用户名,转到 login,获取密码,启动 shell
- 用户退出的时候,会启动一个新的 getty 程序等待
通过 fork-exec 创建 getty 进程守候在各个终端,当终端上有字符输入的时候,exec login 程序,验证通过之后 fork-exec 创建 passwd 指定的 shell(或者其他程序)
shell 启动的时候,执行一系列用户配置脚本
systemd
专门针对 Linux 开发的操作系统和服务管理器
- 支持并行启动系统服务
- 通过 unit 进行依赖管理,自动解决依赖关系
- 日志管理采用二进制格式,提供更加高效的日志记录和查询功能
- 引入 cgroups 管理系统资源
- 统一命令行工具接口
但是不是 POSIX 标准,依赖 Linux 内核特性
一些常用服务
- openssh
- chrony 时间同步服务
- cron 定时服务
- ufw 防火墙