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:标记这个函数及其数据在初始化完成后可以被释放