mobile wallpaper 1mobile wallpaper 2mobile wallpaper 3mobile wallpaper 4
3665 字
10 分钟
从系统加电到 Shell
2021-03-05

从系统加电到 Shell#

开发操作系统之前,首先需要了解底层硬件的基本工作方式和原理。在 汇编语言:从机器码到现代应用的底层探索 中介绍了传统计算机体系结构,也在 CPU 工作模式 中提到了 CPU 的三种工作模式。这里以系统加电到进入用户程序 Shell 的过程为例,理清从硬件到用户软件经历了哪些层次,以及需要完成哪些工作才能进入用户空间。

第 1 层:固件程序层#

CPU 上电复位后,会将寄存器初始化为预设值:

  • CS 指向烧录在主板 ROM 中的 BIOS(基本输入输出系统)程序入口地址,即 0xFFFF0;EIP = 0x0000FFF0,CS = 0xF000
  • 处理器处于 16 位实模式,关闭分页,即 CR0 = 0x60000010
  • 中断处于停用状态,即 EFLAGS = 0x00000002

目前 BIOS 程序分为 Legacy 和 UEFI 两类,下面分别说明。

Legacy BIOS#

Legacy BIOS 是传统的固件程序,只能运行在 16 位实模式下,主要限制包括:

  • 只能使用 1MB 内存
  • MBR 限制:512 字节主引导记录(446 字节引导代码 + 64 字节分区表 + 2 字节签名 0x55AA)
  • 仅支持 ≤4 个主分区(或 3 主分区 + 1 扩展分区)
  • 最大支持 2TB 磁盘
  • 无文件系统驱动(需直接读取磁盘扇区)

其界面和功能相对简单,执行流程如下:

  • 进行 POST(Power-On Self Test)自检,检查基本的输入输出设备。若检查失败,主板一般会发出滴滴声或闪烁信号灯
  • 在物理地址 0x0000 建立中断向量表(IVT),填充 BIOS 中断服务程序(如 INT 0x10 屏幕输出、INT 0x13 磁盘访问)
  • 加载 BIOS 设置,BIOS 读取存储在 CMOS 中的配置参数(如启动顺序、硬盘设置等),执行固件初始化(Firmware Initialization),初始化 CPU、内存控制器、芯片组、总线(PCIe、USB、SATA 等)、时钟等
  • 查找引导设备,BIOS 按照设置的启动顺序查找引导设备(如硬盘、光驱、USB 等),即按顺序读取设备最前面的 512 字节。如果这 512 字节的最后两个字节是 0x55 和 0xAA,表明该设备可用于启动;否则表明设备不可用于启动,控制权转交给启动顺序中的下一个设备
  • 加载 Bootloader,BIOS 将第一个可引导设备的主引导记录(MBR)加载到内存 0x7C00 处,并将控制权交给 Bootloader

注:传统意义上的 bootloader(如 GRUB)的一部分实现就位于 MBR 中。

UEFI#

UEFI(统一可扩展固件接口)没有 16 位实模式的限制,会更早进入保护模式以使用更大的内存,实现更复杂的硬件管理功能。其工作流程如下:

  • SEC(Security):安全验证阶段,进行硬件初始化和验证,确保系统安全。该过程相当于 BIOS 中的 POST 自检
  • PEI(Pre-EFI Initialization):EFI 前期初始化,进行内存和其他关键资源的初始化
  • DXE(Driver Execution Environment):驱动执行环境,初始化大部分硬件驱动和功能
  • BDS(Boot Device Selection):启动设备选择,确定从哪个设备加载操作系统
  • TSL(Transition to SMM):过渡到系统管理模式,准备操作系统加载
  • RT(Runtime):系统运行阶段,操作系统已加载并运行
  • AL(Advanced Launch):高级启动,可能涉及灾难恢复或关机过程

由于 UEFI 在操作系统启动前就已初始化和加载大部分硬件驱动,因此在加载操作系统前就能完整利用大部分硬件功能,例如直接识别文件系统、通过显卡显示丰富的图形界面以及使用网络功能等。它会直接在 ESP(EFI System Partition)中查找特定路径的引导程序(如 /EFI/BOOT/BOOTX64.EFI)进行启动。

注:在 UEFI+GPT 方案中,GRUB 以 EFI 文件形式存在于 ESP 分区,不再依赖 MBR。

第 2 层:引导加载层#

BIOS/UEFI 的最后一项工作是找到引导加载器并将其加载到内存的 0x7C00 处,然后开始调用。常见的引导加载器(Boot Loader)有 GRUB2 和 LILO 等。

这里主要介绍 GRUB2,它可以引导多个操作系统,可直接读取文件系统,拥有图形和文本界面,通过配置文件设置引导项的内核及启动参数等,也可在启动页面通过指令进行动态修改。其主要工作是将选定引导项的内核启动参数传递给内核,将内核和 initramfs(如果存在)加载到内存中,然后转移控制权。

GRUB2 启动阶段:

BIOS#

阶段 1(boot.img)#

BIOS 开机后执行 MBR(第一个扇区,512 字节),MBR 的前 446 字节由 GRUB2 的 boot.img 占据。由于空间很小,只能初始化最基本的执行环境并加载下一阶段(core.img)。

阶段 1.5(core.img 前半段,包含 disk driver modules)#

MBR 的后续「空闲扇区」中,GRUB 会放置 core.img(远大于 512 字节)。core.img 包含:

  • 文件系统驱动(ext4、xfs、btrfs 等)
  • 磁盘访问模块
  • 压缩和解压工具

这使得 GRUB 拥有了读取磁盘文件系统的能力,并能从磁盘加载必要的模块和配置以进入下一阶段。

阶段 2(加载 /boot/grub 下的模块和配置文件)#

core.img 找到 /boot/grub/grub.cfg,加载必要的模块(如 ext2.mod、part_msdos.mod、normal.mod 等),初始化完整的 GRUB2 环境。

此时 GRUB 进入 normal mode,可进行图形界面或命令行操作,支持解析配置(内核路径、initrd、内核参数等)以及高级功能(LVM、RAID、加密分区支持)。

阶段 3(加载 Linux 内核与 initrd/initramfs)#

根据 grub.cfg 的配置,执行类似:

linux /boot/vmlinuz-xxx root=/dev/sda1 ro quiet
initrd /boot/initrd-xxx.img
boot
  • 将 Linux 内核(vmlinuz)和 initrd 装入内存
  • 跳转执行内核 → 内核接管控制权

UEFI#

UEFI 下没有 MBR 的 512 字节限制,流程更简单:

  1. UEFI 固件从 EFI 系统分区(ESP)加载 grubx64.efi
  2. grubx64.efi 内部包含 GRUB2 的核心功能(类似 BIOS 模式的 core.img)
  3. 加载 /boot/grub/grub.cfg 和其他模块
  4. 显示菜单,加载内核 + initrd,跳转执行

注 1:GRUB2 在执行过程中会进入保护模式,但后续内核会覆盖修改 GDT 等相关配置。

注 2:initramfs 是进入真正的根文件系统之前的一个垫片,通常包含必要的设备驱动程序、工具、配置文件以及运行这些工具的环境。引导加载器直接将它和内核加载到内存。这样内核可以更加精简(不必将不同格式的磁盘驱动直接编译进内核),并且在挂载真正根文件系统前也可完成加密解密等初始化操作。

这一层也是可以着手编码的层。

第 3 层:内核初始化层#

当引导加载程序(如 GRUB)成功将操作系统的内核映像加载到内存中,并将 CPU 的控制权移交给内核入口点(通常是 _start 或类似符号)时,就进入了内核初始化层。此时内核面对的是一个几乎原始的硬件环境——没有内存管理、中断处理、文件系统,也没有进程等概念。内核初始化层的核心任务是建立这些核心子系统,将硬件抽象化,直到准备好执行第一个用户空间进程(通常为 init 或 systemd)。

1. 架构相关初始化(Architecture-Specific Setup)#

  • CPU 模式切换:在 x86 上,从实模式进入保护模式/长模式(64 位),设置段寄存器
  • 内存管理:建立初始页表,启用分页(MMU),保留引导信息中的物理内存布局
  • 中断机制:设置 GDT(全局描述符表)、IDT(中断描述符表),初始化 APIC/IOAPIC
  • CPU 特性检测:检测并启用 CPU 扩展功能(FPU、MMX、SSE 等)
  • 早期输出:初始化 early console 以便 printk() 能输出调试信息
  • 内核解压:bzImage 格式的内核先在低地址执行解压,再把完整内核搬到高地址运行

2. 内核通用初始化(start_kernel())#

进入内核 C 语言入口点 start_kernel(),这里会初始化几乎所有核心子系统:

  • 内存管理:伙伴系统初始化(物理页分配器),虚拟内存子系统建立
  • 进程调度器:sched_init() 初始化调度框架
  • 同步机制:初始化 RCU(Read-Copy Update)等高性能同步机制
  • 时钟和定时器:time_init() 设置系统时钟和定时器中断
  • 内核日志:printk() 正式启用环形缓冲
  • 安全机制:初始化 Linux Security Modules(LSM)
  • 虚拟文件系统:初始化 VFS、挂载内存中的临时根文件系统 rootfs(ramfs/tmpfs)
  • 设备模型:建立总线/设备/驱动模型,准备后续设备探测

3. 关键内核线程和进程#

在 rest_init() 中,内核启动几个关键进程:

  • 0 号进程(idle 或 swapper):最初的内核上下文,最终进入空闲循环
  • 1 号进程(kernel_init):内核初始化线程,后续会尝试执行 /init 或 /sbin/init
  • 2 号进程(kthreadd):内核线程管理器,负责创建其他内核线程

4. initramfs 处理#

如果引导加载器提供了 initramfs,内核会:

  • 解压 initramfs 到内存中的 rootfs
  • 将其作为临时根文件系统使用
  • 尝试执行 initramfs 内的 /init 程序(第一个用户态程序)

如果没有 initramfs,或 /init 执行失败,内核会直接查找并执行指定根文件系统上的 /sbin/init、/bin/init 或 /bin/sh。

initramfs 本质上是一个临时的基于内存的根文件系统,使命是为挂载真实的根文件系统做准备。内核启动 initramfs 后,会运行其中的 /init 脚本或可执行文件,最后切换到真正的用户根文件系统。

第 4 层:用户空间层#

当真正的根文件系统挂载完成后,内核会启动第一个用户空间进程 /sbin/init(现代系统多为 systemd,也可能是 SysV init、OpenRC 等)。它成为 PID 1,是所有用户空间进程的祖先进程。

systemd 启动流程(主流 Linux 发行版)#

1. 读取配置文件#
  • /etc/systemd/system.conf
  • /usr/lib/systemd/system.conf(发行版默认)
  • 管理单元文件:/etc/systemd/system/(本地自定义)、/usr/lib/systemd/system/(系统默认)
2. 确定启动目标(Target)#
  • graphical.target:图形界面多用户模式
  • multi-user.target:命令行多用户模式
  • rescue.target:单用户维护模式
  • 默认目标通过 /etc/systemd/system/default.target 符号链接指定
3. 初始化基础系统#
  • 挂载必要的虚拟文件系统:/proc、/sys、/dev、/run 等
  • 设置主机名、时区、本地化、随机数种子
  • 初始化内核模块和网络服务(如 systemd-networkdNetworkManager
  • 启动日志服务 systemd-journald、认证服务 systemd-logind、定时任务服务 systemd-timedated
  • 设备管理:初始化 udev,为 /dev 创建设备节点,响应热插拔事件
4. 进入用户工作环境#
  • 达到 multi-user.target:系统进入命令行多用户模式(可登录终端)
  • 达到 graphical.target:启动显示管理器(gdm、lightdm、sddm 等),进入图形桌面环境
核心机制#
  • 依赖管理:服务之间通过 .service、.target、.socket 等单元文件声明依赖关系
  • 并行启动:systemd 会自动分析依赖关系并尽可能并行启动服务,大幅加快启动速度
  • 激活机制
    • Socket Activation:按需启动服务(当端口有连接时启动服务)
    • D-Bus Activation:通过 D-Bus 消息按需启动服务
    • Path / Mount Activation:监控路径或挂载事件触发服务

SysV init 启动流程(对比 systemd)#

  • 使用 /etc/inittab 定义默认运行级别(0–6)
  • 每个运行级别对应 /etc/rcX.d/,包含启动/关闭脚本链接,顺序执行
  • 串行启动,缺乏依赖关系管理,启动较慢

第 5 层:登录管理器 / Shell#

当 systemd 或 init 启动完目标服务后,系统进入可交互的登录阶段。

文本登录(multi-user.target)#

  • getty:在虚拟终端(tty1–tty6)启动,显示 login: 提示符
  • 认证:用户输入用户名和密码,经由 PAM(Pluggable Authentication Modules) 认证
  • 启动 Shell:认证成功后,执行 /etc/passwd 中指定的登录 shell(如 /bin/bash/bin/zsh
  • 加载配置:shell 执行其初始化配置文件(如 .bashrc.zshrc

图形登录(graphical.target)#

  • 显示管理器(Display Manager, DM):如 gdmlightdmsddm
    • 提供图形化登录界面
    • 通过 PAM 完成用户认证
  • 桌面会话:认证通过后,DM 启动桌面会话(如 GNOME、KDE Plasma、XFCE、Wayland 或 X11 会话)
    • 启动桌面环境核心进程(会话管理器、面板、文件管理器等)
    • 执行用户自定义的自动启动脚本(~/.xinitrc~/.config/autostart/ 等)

参考#

osdev
GNU GRUB 手册
JamesM’s kernel development tutorials
Why BIOS loads MBR into 0x7C00 in x86 ?
How to create an OS from scratch - github
The little book about OS development
The Linux Boot Process: From Power Button to Kernel
从零开始写 OS 内核
南京大学:操作系统:设计与实现(2023 春季学期)

支持与分享

如果这篇文章对你有帮助,欢迎支持作者或分享给更多人

从系统加电到 Shell
https://blog.souloss.com/posts/os/from-power-on-to-shell/
作者
Souloss
发布于
2021-03-05
许可协议
CC BY-NC-SA 4.0

部分信息可能已经过时