当前位置:首页>Linux>一文读懂 Linux 内核 Initcall 机制

一文读懂 Linux 内核 Initcall 机制

  • 2026-10-11 05:41:35
一文读懂 Linux 内核 Initcall 机制

Linux驱动入门课程:

https://www.bilibili.com/cheese/play/ss635583370

Linux驱动进阶课程:

https://www.bilibili.com/cheese/play/ss254727759

01

简介

Linux 内核的 Initcall 机制 是 Linux 系统从内核启动到用户空间初始化过程中,执行模块化初始化代码的核心手段。简单来说,它允许内核开发者通过宏定义,将不同的驱动、子系统初始化函数放置在内核镜像的特定内存段中,从而让内核在启动时按预定优先级自动调用它们。

02

Initcall作用

  • 模块化解耦:驱动开发者不需要修改内核的启动主逻辑,只需在驱动代码中添加 module_init() 或 device_initcall(),内核构建系统就会自动将其集成。

  • 解决依赖性:例如,文件系统驱动必须在块设备驱动初始化之后加载,Initcall 的分层机制保证了这种顺序。

  • 内存优化:这些初始化函数在执行完成后,会被内核从内存中释放(__init 修饰符),从而节省宝贵的 RAM。

03

工作原理

Initcall 机制的核心在于链接器脚本和代码段归类。

3.1. 宏定义 (The Macros)

内核提供了多个宏来标记初始化函数,例如:

  • early_initcall

  • core_initcall

  • postcore_initcall

  • arch_initcall

  • subsys_initcall

  • fs_initcall

  • device_initcall (最常用)

  • late_initcall

这些宏本质上是将函数地址放置到一个特定的代码段(Section)中。例如,__define_initcall(level, fn, id) 宏会将函数 fn 存入名为 .initcall<level>.init 的段中。

3.2. 链接器脚本

内核编译时,链接器(ld)会按照预定义的顺序,将所有这些分散在不同模块(. o 文件)中的 .initcall*.init 段,按优先级顺序排列并合并到内核镜像的特定内存区域。

04

执行流程

当内核启动到 kernel_init() 函数时,它会依次调用 do_initcalls()。

  • 分段扫描:do_initcalls() 会遍历预先定义好的各个 Initcall 级别。

  • 按序调用:它会遍历 .initcall0.init 到 .initcall7.init(或其他级别)对应的内存地址区间。

  • 循环执行:在每个级别内,内核会取出该段内的所有函数指针,并循环执行每一个函数。

05

Initcall 级别和优先级

不同的级别决定了初始化的时机,这对于存在依赖关系的子系统至关重要。

级别
宏名称
说明
0
early_initcall
极早期,仅限于底层核心初始化。
1
core_initcall
核心子系统(如调度器、内存管理)。
2
postcore_initcall
核心完成后的辅助初始化。
3
arch_initcall
架构相关的硬件平台初始化。
4
subsys_initcall
总线、系统设备初始化。
5
fs_initcall
文件系统初始化。
6
device_initcall
大多数驱动程序都在此阶段加载。
7
late_initcall
最后阶段,系统启动的收尾工作。

提示:驱动中的 module_init(),默认会映射到 device_initcall

END
往期推荐:

写Linux驱动,必须掌握的Runtime PM机制

Linux通知链

驱动之间如何共享寄存器?Syscon 给出了答案

延迟函数别乱用,Linux 内核开发者必须掌握的延迟“潜规则”

Linux驱动之SPI子系统

最新文章

随机文章