asmlinkage __visible void __init start_kernel(void)

 

start_kernel 开始

    │

    ├── 早期基础初始化

    │   ├── lockdep_init()                       ── 锁依赖检查初始化

    │   ├── set_task_stack_end_magic() ── 设置 init_task 栈边界

    │   ├── smp_setup_processor_id()   ── 设置 SMP 处理器 ID

    │   ├── debug_objects_early_init()   ── 调试对象早期初始化

    │   ├── boot_init_stack_canary()     ── 初始化栈 canary(防溢出)

    │   └── cgroup_init_early()                  ── cgroup 早期初始化

    │

    ├── 关中断 & 架构相关初始化

    │   ├── local_irq_disable()       ── 关闭本地中断

    │   ├── boot_cpu_init()            ── 启动 CPU 初始化

    │   ├── page_address_init()      ── 页地址初始化

    │   ├── 打印 Linux 版本信息

    │   ├── setup_arch()                      ── 架构特定设置(解析命令行)

    │   ├── mm_init_cpumask()           ── 内存管理 CPU 掩码初始化

    │   ├── setup_command_line()     ── 保存命令行

    │   ├── setup_nr_cpu_ids()           ── 设置 CPU 数量

    │   ├── setup_per_cpu_areas()      ── 每 CPU 数据区初始化

    │   └── smp_prepare_boot_cpu()   ── SMP 启动 CPU 准备

    │

    ├── 内存管理初始化(第一阶段)

    │   ├── build_all_zonelists()         ── 构建内存区域列表

    │   ├── page_alloc_init()              ── 页分配器初始化

    │   └── 解析内核参数

    │       ├── parse_early_param()    ── 解析早期参数

    │       └── parse_args()                    ── 解析内核参数

    │

    ├── 核心子系统初始化(第一阶段)

    │   ├── jump_label_init()            ── jump label 初始化

    │   ├── setup_log_buf()              ── 设置日志缓冲区

    │   ├── pidhash_init()                  ── PID 哈希表初始化

    │   ├── vfs_caches_init_early()   ── VFS 缓存早期初始化

    │   ├── sort_main_extable()       ── 异常表排序

    │   ├── trap_init()                       ── 陷阱/中断向量初始化

    │   └── mm_init()                          ── 内存管理初始化

    │

    ├── 调度器初始化

    │   ├── sched_init()                    ── 调度器初始化

    │   ├── preempt_disable()         ── 禁止抢占

    │   ├── idr_init_cache()             ── IDR 缓存初始化

    │   └── rcu_init()                          ── RCU 初始化

    │

    ├── 中断和时间子系统

    │   ├── trace_init()                    ── 追踪系统初始化

    │   ├── radix_tree_init()            ── radix 树初始化

    │   ├── early_irq_init()              ── 早期 IRQ 初始化

    │   ├── init_IRQ()                      ── IRQ 子系统初始化

    │   ├── tick_init()                      ── tick 系统初始化

    │   ├── rcu_init_nohz()              ── NOHZ 模式 RCU 初始化

    │   ├── init_timers()                  ── 定时器初始化

    │   ├── hrtimers_init()              ── 高精度定时器初始化

    │   ├── softirq_init()                 ── 软中断初始化

    │   ├── timekeeping_init()       ── 时间维护系统初始化

    │   ├── time_init()                     ── 时间子系统初始化

    │   ├── sched_clock_postinit()       ── 调度时钟后初始化

    │   ├── perf_event_init()            ── 性能事件初始化

    │   ├── profile_init()                   ── 性能分析初始化

    │   └── call_function_init()         ── 跨 CPU 调用初始化

    │

    ├── 开中断

    │   ├── early_boot_irqs_disabled = false

    │   └── local_irq_enable()             ── 打开中断

    │

    ├── 后期初始化

    │   ├── kmem_cache_init_late()      ── slab 分配器后期初始化

    │   ├── console_init()                       ── 控制台初始化

    │   ├── lockdep_info()                      ── 锁依赖信息

    │   ├── locking_selftest()                 ── 锁自测试

    │   ├── 处理 initrd(如果存在)

    │   ├── page_ext_init()                        ── 页扩展信息初始化

    │   ├── debug_objects_mem_init()     ── 调试对象内存初始化

    │   ├── kmemleak_init()                      ── 内存泄漏检测初始化

    │   ├── setup_per_cpu_pageset()       ── 每 CPU 页集初始化

    │   ├── numa_policy_init()                 ── NUMA 策略初始化

    │   ├── calibrate_delay()                    ── 校准延迟(计算 BogoMIPS)

    │   ├── pidmap_init()                         ── PID 位图初始化

    │   ├── anon_vma_init()                    ── 匿名 VMA 初始化

    │

    ├── 进程和文件系统相关

    │   ├── thread_info_cache_init()     ── 线程信息缓存初始化

    │   ├── cred_init()                            ── 凭证子系统初始化

    │   ├── fork_init()                             ── fork 子系统初始化

    │   ├── proc_caches_init()               ── proc 文件系统缓存初始化

    │   ├── buffer_init()                         ── 缓冲区缓存初始化

    │   ├── key_init()                             ── 密钥管理初始化

    │   ├── security_init()                     ── 安全子系统初始化

    │   ├── vfs_caches_init()                ── VFS 缓存初始化

    │   ├── signals_init()                      ── 信号系统初始化

    │   ├── page_writeback_init()        ── 页回写初始化

    │   ├── proc_root_init()                 ── proc 根文件系统初始化

    │   ├── nsfs_init()                          ── 命名空间文件系统初始化

    │   ├── cpuset_init()                      ── cpuset 初始化

    │   ├── cgroup_init()                      ── cgroup 初始化

    │   ├── taskstats_init_early()        ── 任务统计早期初始化

    │   └── delayacct_init()                   ── 延迟会计初始化

    │

    ├── 最后检查与收尾

    │   ├── check_bugs()                       ── 检查 CPU 漏洞/错误

    │   ├── acpi_subsystem_init()        ── ACPI 子系统初始化

    │   ├── ftrace_init()                        ── 函数追踪初始化

    │   └── rest_init()                              ── 进入 rest_init(永不返回)

    │

    └── start_kernel 结束(永不返回,进入 rest_init)

 

 

start_kernel 总结

start_kernel 是 Linux 内核启动的入口函数,也是整个内核初始化过程的核心。当 bootloader 将控制权交给内核后,首先执行的就是这个函数。

1. 函数特点

2. 主要职责

start_kernel 负责初始化 Linux 内核的所有核心子系统,按照严格的依赖顺序执行数百个初始化函数。它的工作可以概括为:

第一阶段:基础环境搭建

第二阶段:内存管理初始化

第三阶段:核心子系统初始化

第四阶段:进程和文件系统

第五阶段:最后的准备

3. 执行顺序原则

start_kernel 的初始化顺序遵循严格的依赖关系:

4. 关键转折点

在 start_kernel 中有几个关键的转折点:

5. 永不返回

start_kernel 的最后调用了 rest_init(),而 rest_init 永远不会返回。它创建了 init 进程和 kthreadd,然后当前线程转变为 idle 线程,进入无限的空闲循环。所以从逻辑上讲,start_kernel 是内核执行的最后一个函数,也是第一个函数。

6. 整个启动流程回顾

bootloader
    ↓
start_kernel (初始化所有内核子系统)
    ↓
rest_init
    ├── 创建 init (PID 1)
    ├── 创建 kthreadd (PID 2)
    └── 当前线程 → idle 线程
         ↓
    kernel_init (PID 1 执行)
         ↓
    执行用户空间的 init 程序
         ↓
    用户空间初始化完成,系统正常运行

结语

start_kernel 是 Linux 内核的"创世纪"。它从零开始,一步步构建出完整的内核运行环境,最终孵化出第一个用户进程,完成从内核态到用户态的华丽转变。理解 start_kernel,就是理解了 Linux 内核是如何"活起来"的。

 

  • local_irq_disable() → local_irq_enable():中断从关闭到打开
  • preempt_disable():确保早期调度不会破坏系统
  • console_init():控制台可用,可以输出调试信息
  • rest_init():进入最后的初始化阶段,创建用户空间进程
  • 先基础后上层:先初始化架构相关代码,再初始化通用代码
  • 先核心后外围:先初始化调度器、内存管理等核心系统,再初始化文件系统、网络等外围系统
  • 先关中断后开中断:早期初始化在关中断状态下进行,确保原子性;基础打好后再开中断
  • 先内核后用户:先完成内核本身的初始化,再创建用户空间的 init 进程
  • 检查 CPU 漏洞(如 Meltdown、Spectre)
  • 初始化追踪系统
  • 调用 rest_init 创建 init 进程
  • fork 子系统—— 能够创建新进程
  • VFS 文件系统—— 提供文件操作接口
  • 安全子系统—— 提供安全框架
  • cgroup 和命名空间—— 提供资源隔离
  • 调度器(sched)—— 让系统能够进行任务调度
  • RCU 机制—— 提供无锁同步
  • 定时器和时间子系统—— 提供时间概念
  • 中断子系统—— 能够响应硬件中断
  • 构建内存区域列表
  • 初始化页分配器
  • 设置每 CPU 数据区
  • 初始化锁依赖检查(lockdep)
  • 设置栈保护(canary)
  • 关闭中断,确保初始化过程的原子性
  • 架构相关初始化(setup_arch
  • asmlinkage:表示函数参数从堆栈中获取(而不是寄存器)
  • __visible:确保函数符号在汇编代码中可见
  • __init:标记这个函数及其数据在初始化完成后可以被释放
Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐