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 号进程的实现方式有两种:

  1. old Linux 采用 SysV init
  2. new Linux 采用 systemd

SysV init

  1. /etc/inittab 找到运行级别。(关机、单用户、多用户、图像界面等,用来启动不同的服务
  2. 执行脚本 /etc/rc.d/rc.sysinit 初始化系统的基本设置和环境
  3. 执行脚本 /etc/rc.d/rc 根据不同的运行环境执行不同的服务
  4. 最终调用 /etc/rc.d/rc.local 用户自定义的开机启动任务
  5. 进入终端交互:给每个系统配置的用户终端上启动 getty 程序,读取用户名,转到 login,获取密码,启动 shell
  6. 用户退出的时候,会启动一个新的 getty 程序等待

通过 fork-exec 创建 getty 进程守候在各个终端,当终端上有字符输入的时候,exec login 程序,验证通过之后 fork-exec 创建 passwd 指定的 shell(或者其他程序)

shell 启动的时候,执行一系列用户配置脚本

systemd

专门针对 Linux 开发的操作系统和服务管理器

  • 支持并行启动系统服务
  • 通过 unit 进行依赖管理,自动解决依赖关系
  • 日志管理采用二进制格式,提供更加高效的日志记录和查询功能
  • 引入 cgroups 管理系统资源
  • 统一命令行工具接口

但是不是 POSIX 标准,依赖 Linux 内核特性

一些常用服务

  • openssh
  • chrony 时间同步服务
  • cron 定时服务
  • ufw 防火墙