收到。启动流程用 ASCII 图表达,按 5 个块拆开,每块一张图:


块一:固件与引导

                              ┌──────────────────────┐
                              │   按下电源键          │
                              │   CPU 复位向量        │
                              │   0xFFFFFFF0          │
                              └──────────┬───────────┘
                                         │
                                         ▼
                    ┌────────────────────────────────────┐
                    │           固件层                   │
                    │  (BIOS / UEFI)                    │
                    └─────────────────┬──────────────────┘
                                      │
          ┌───────────────────────────┼───────────────────────────┐
          │                           │                           │
          ▼                           ▼                           ▼
┌─────────────────┐       ┌─────────────────────┐    ┌─────────────────────┐
│     BIOS        │       │       UEFI          │    │        MBR          │
│   POST 自检     │       │  读取 NVRAM 变量    │    │   第一扇区 512B     │
│   读取 MBR      │       │  加载 *.efi 文件    │    │   446B 引导代码     │
│   跳转 0x7C00   │       │  从 ESP 分区加载    │    │   64B 分区表        │
└────────┬────────┘       └──────────┬──────────┘    │   0x55AA 魔数       │
         │                           │               └─────────────────────┘
         └───────────────┬───────────┘
                         ▼
         ┌───────────────────────────────────────┐
         │          GRUB / systemd-boot          │
         │   读取 grub.cfg / loader/*.conf       │
         │   加载内核到 0x100000                 │
         │   加载 initramfs 到高位内存           │
         │   填充 struct boot_params             │
         │   跳转到内核 _start                   │
         └───────────────────────────────────────┘

数据结构关键点

  • MBR 位于磁盘 LBA 0,512 字节,最后两字节必须为 0x55 0xAA
  • ESP 分区类型 GUID(UEFI):C12A7328-F81F-11D2-BA4B-00A0C93EC93B
  • struct boot_params 位于物理地址 0x10000,传递 initramfs 地址 (hdr.ramdisk_image) 和大小

块二:内核入口与架构初始化

                              ┌─────────────────────┐
                              │     _start          │
                              │  header.S           │
                              │  实模式 (16-bit)    │
                              └──────────┬──────────┘
                                         │
                                         ▼
                              ┌─────────────────────┐
                              │   go_to_protected   │
                              │   设置 A20 线       │
                              │   加载 GDT          │
                              │   → 保护模式 32-bit │
                              └──────────┬──────────┘
                                         │
                                         ▼
                              ┌─────────────────────┐
                              │   startup_32        │
                              │   head_64.S         │
                              │   设置临时页表      │
                              │   → 长模式 64-bit   │
                              └──────────┬──────────┘
                                         │
                                         ▼
                              ┌─────────────────────┐
                              │   startup_64        │
                              │   decompress_kernel │
                              │   解压 vmlinuz      │
                              │   跳转 C 入口       │
                              └──────────┬──────────┘
                                         │
                                         ▼
┌────────────────────────────────────────────────────────────────────┐
│  start_kernel()  [init/main.c]                                    │
│  ┌──────────────────────────────────────────────────────────┐     │
│  │ setup_arch()      解析 boot_params,初始化 init_mm.pgd  │     │
│  │ trap_init()       设置 IDT,注册 syscall 入口           │     │
│  │ mm_init()         伙伴系统,SLAB 分配器                 │     │
│  │ sched_init()      为每个 CPU 创建 struct rq,CFS 红黑树 │     │
│  └──────────────────────────────────────────────────────────┘     │
│                              │                                    │
│                              ▼                                    │
│  rest_init()  ──────────→  kernel_thread(kernel_init) → PID 1   │
│                 ─────────→  kernel_thread(kthreadd)   → PID 2   │
│                              │                                    │
│                              ▼                                    │
│                 ┌───────────────────────┐                        │
│                 │   cpu_startup_entry   │                        │
│                 │   idle 进程 (PID 0)   │                        │
│                 └───────────────────────┘                        │
└────────────────────────────────────────────────────────────────────┘

数据结构关键点

  • struct boot_params:位于 0x10000,引导程序填充,内核 setup_arch 读取
  • init_mm:内核初始 mm_structpgd 指向内核页表,mm_users 初始为 1
  • struct rq:每 CPU 一个,包含 cfs_rq(红黑树根 tasks_timeline
  • task_struct:PID 1 初始 mm=NULL(内核线程),files=NULL

块三:initramfs

┌─────────────────────────────────────────────────────────────────┐
│  kernel_init()                                                 │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │  populate_rootfs()  解压 initramfs 到 rootfs (tmpfs)   │   │
│  │  /init 成为 PID 1 (用户态进程)                         │   │
│  └─────────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────────┐
│  /init 脚本 (busybox / dracut / mkinitcpio)                    │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │ mount -t proc proc /proc                               │   │
│  │ mount -t sysfs sysfs /sys                              │   │
│  │ mount -t devtmpfs devtmpfs /dev                        │   │
│  │                                                         │   │
│  │ modprobe nvme      ← 加载存储驱动                       │   │
│  │ modprobe ext4                                          │   │
│  │ modprobe dm-crypt                                      │   │
│  │                                                         │   │
│  │ cryptsetup open /dev/sda2 root     ← 解锁 LUKS        │   │
│  │ mount /dev/mapper/root /sysroot   ← 挂载真实根         │   │
│  │                                                         │   │
│  │ switch_root /sysroot /sbin/init                         │   │
│  │   ├─ chroot("/sysroot")          ← 修改 fs->root      │   │
│  │   └─ execve("/sbin/init")        ← PID 1 替换          │   │
│  └─────────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────────┘
                              │
                              ▼
              ┌───────────────────────────────┐
              │  initramfs 内存释放           │
              │  free_initrd()                │
              │  控制权交给 /sbin/init        │
              └───────────────────────────────┘

数据结构关键点

  • initramfs 是 cpio 归档(非 ext2 镜像),populate_rootfs 解压到 rootfstmpfs 类型的 super_block
  • switch_rootchroot 修改当前进程 task_struct->fs->rootexecve 替换 PID 1
  • modprobe 通过 init_module 系统调用将 .ko 加载到内核,module 数据结构加入 modules 链表

块四:PID 1(systemd)启动阶段

┌─────────────────────────────────────────────────────────────────┐
│  /sbin/init  →  systemd  main()                               │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │  解析内核命令行 (systemd.unit=)                        │   │
│  │  挂载 /sys/fs/cgroup (cgroup2)                         │   │
│  │  初始化 struct Manager (unit 哈希表)                   │   │
│  │  加载 /usr/lib/systemd/system/*.service                │   │
│  └─────────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────────┘
                              │
                              ▼
              ┌───────────────────────────────────────┐
              │        default.target                 │
              │   (graphical.target / multi-user)     │
              └───────────────────┬───────────────────┘
                                  │
          ┌───────────────────────┼───────────────────────┐
          │                       │                       │
          ▼                       ▼                       ▼
┌─────────────────┐   ┌─────────────────────┐   ┌─────────────────────┐
│  sysinit.target │ → │   basic.target      │ → │ multi-user.target   │
│  ┌─────────────┐│   │  ┌───────────────┐  │   │  ┌───────────────┐  │
│  │ udevd       ││   │  │ D-Bus        │  │   │  │ NetworkManager│  │
│  │local-fs     ││   │  │ logind       │  │   │  │ sshd          │  │
│  │swap         ││   │  │ journald     │  │   │  │ cron          │  │
│  │sysctl       ││   │  │ timers       │  │   │  │               │  │
│  └─────────────┘│   │  └───────────────┘  │   │  └───────────────┘  │
└─────────────────┘   └─────────────────────┘   └──────────┬──────────┘
                                                           │
                                                           ▼
                                              ┌─────────────────────┐
                                              │ graphical.target   │
                                              │  ┌───────────────┐  │
                                              │  │ gdm/sddm     │  │
                                              │  │ greetd       │  │
                                              │  └───────────────┘  │
                                              └─────────────────────┘

数据结构关键点

  • systemd struct Manager:包含 units 哈希表(key=unit 名称),jobs 队列(当前正在执行的操作)
  • unit 依赖图:After= / Before= / Wants= / Requires= 构成有向图,systemd 拓扑排序执行
  • cgroup v2:/sys/fs/cgroup/system.slice/ 下每个 service 有独立 cgroup 目录(cpu.maxmemory.max 等控制文件,systemd 通过写入这些文件应用资源限制)

块五:用户登录与会话建立

                                    ┌──────────────────────┐
                                    │  multi-user.target   │
                                    │  就绪                │
                                    └──────────┬───────────┘
                                               │
                    ┌──────────────────────────┼──────────────────────────┐
                    │                          │                          │
                    ▼                          ▼                          ▼
     ┌──────────────────────────┐  ┌──────────────────────────┐  ┌──────────────────────────┐
     │   TTY 登录 (文本)        │  │   图形登录 (DM)          │  │   SSH 登录 (远程)        │
     │                          │  │                          │  │                          │
     │  getty 打开 /dev/ttyN    │  │  gdm/sddm/greetd 启动   │  │  systemd 启动 sshd      │
     │  ├─ login 验证密码       │  │  ├─ 启动 Xorg/Wayland   │  │  ├─ 监听 0.0.0.0:22     │
     │  │   /etc/passwd +       │  │  ├─ 显示登录界面        │  │  ├─ fork() 处理连接      │
     │  │   /etc/shadow         │  │  ├─ PAM 认证            │  │  ├─ pty 分配             │
     │  ├─ execve(/bin/bash)    │  │  └─ execve(desktop)     │  │  └─ execve(/bin/bash)    │
     │  └─ 继承 tty fd 0/1/2    │  │     systemd --user      │  │                         │
     └──────────────────────────┘  └──────────────────────────┘  └──────────────────────────┘
                    │                          │                          │
                    └──────────────────────────┼──────────────────────────┘
                                               ▼
                              ┌─────────────────────────────────────┐
                              │       用户 Shell 会话              │
                              │  task_struct (用户态 mm_struct)   │
                              │  继承 stdin/stdout/stderr          │
                              │  (指向 tty / pty 设备文件)        │
                              │                                     │
                              │  读取启动文件:                     │
                              │  ~/.bashrc / ~/.zshrc / config.fish│
                              │  ───────────────────────────────   │
                              │  等待用户输入命令                  │
                              │  fork() + execve() 执行命令        │
                              └─────────────────────────────────────┘

数据结构关键点

  • getty 使用 fork() + execve("/bin/login")login 验证后 fork() + execve("/bin/bash"),Shell 继承 fd 0/1/2(指向 /dev/ttyN
  • /etc/passwd用户名:密码占位:UID:GID:描述:家目录:Shell/etc/shadow用户名:加密密码哈希:最后修改:...
  • PAM 认证:通过 /etc/pam.d/ 配置文件动态加载认证模块(pam_unix.so 读取 /etc/shadow
  • systemd --user:用户级 systemd 实例,管理用户会话服务(pipewiregpg-agent 等),其 Manager 结构独立于系统级实例,--user 启动的进程 task_struct->signal->user 指向当前用户而非 root

五块总览(数据流链)

固件 (MBR/GPT/ESP)
    ↓ 加载
引导程序 (GRUB/systemd-boot)
    ↓ 加载内核到 0x100000 + initramfs + boot_params
内核入口 (header.S → startup_32 → startup_64 → decompress_kernel)
    ↓ 初始化 start_kernel (arch/mem/sched/trap)
PID 1 (kernel_init → /init → systemd)
    ↓ target 依赖链 (sysinit → basic → multi-user → graphical)
用户登录 (getty / DM / sshd)
    ↓ fork + execve
用户 Shell