Linux 内核中的 start_kernel() 函数内部:流程图与总结

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:标记这个函数及其数据在初始化完成后可以被释放
相关推荐
qq_479875432 小时前
netlink(1)
linux·服务器·网络
hzulwy2 小时前
Linux网络配置与测试
linux·运维·网络
zxnbmk3 小时前
磁盘挂载与迁移【自用复制】
linux
rosir_zhong3 小时前
嵌入式开发中FIFO buffer的使用
单片机·嵌入式硬件
YQ_013 小时前
Ubuntu下安装WPS
linux·ubuntu·wps
广药门徒3 小时前
PADS同网络相邻引脚怎么走出粗线 FPC 电源布线如何布出粗线
嵌入式硬件
小义_3 小时前
【Docker】知识四
linux·运维·docker·容器
小志biubiu3 小时前
Linux_进程概念(A)-进程部分【Ubuntu】
linux·运维·服务器·ubuntu·操作系统·进程
普通网友3 小时前
Ubuntu 入门及安装全指南
linux·运维·ubuntu