initcall 驱动初始化机制与实现详解

initcall 驱动初始化机制与实现详解

源码路径rk3588/kernel-6.1/init/main.cinclude/linux/init.h
内核版本:Linux 6.1(RK3588 / ARM64)
文档目录linuxDoc/init/


目录


一、原理

1.1 设计目标

内核与子系统在编译期通过 __define_initcall(level, fn) 把初始化函数放入链接器段;启动时 按级别顺序 调用,无需中央注册表。执行完毕后,__init 代码随 free_initmem() 回收。

1.2 与 module_init 的关系

可加载模块的 module_init()insmod 时执行;内置驱动等价逻辑通常落在 devicelate 级 initcall。


二、实现方式

2.1 调用链

1
2
3
4
5
6
7
kernel_init_freeable()
do_pre_smp_initcalls() // early: __initcall_start .. __initcall0_start
smp_init()
do_basic_setup()
driver_init()
do_ctors() // CONFIG_CONSTRUCTORS
do_initcalls() // level 0..7

2.2 七级划分

Level 名称 段边界
0 pure __initcall0_start
1 core __initcall1_start
7 late __initcall7_start__initcall_end

do_initcall_level() 每级:

  1. 用该级名解析 级别相关 内核参数(parse_args + level 匹配)
  2. 遍历该级段内所有 entry,调用 do_one_initcall()

2.3 do_one_initcall()

1
2
3
4
5
6
7
8
int __init_or_module do_one_initcall(initcall_t fn)
{
if (initcall_blacklisted(fn))
return -EPERM;
ret = fn();
// 检查 preempt_count、irqs_disabled,WARN
return ret;
}
  • initcall_blacklist=:跳过指定符号(需 CONFIG_KALLSYMS
  • initcall_debug:打印每个函数耗时(tracepoint 或 printk)

2.4 异步 initcall(CONFIG_INITCALL_ASYNC

  • 启动参数 initcall_nr_threads= 控制 worker 数(默认约 2 * num_online_cpus
  • 每级内部分 initcall 在 init/%d kthread worker 上并行
  • __initcallNs_start__initcallN_start 区分 sync/async 边界
  • 级末 kthread_flush_worker 保证该级完成后再进下一级

三、关键数据结构与宏

宏(init.h) 级别
pure_initcall(fn) 0
core_initcall(fn) 1
postcore_initcall(fn) 2
arch_initcall(fn) 3
subsys_initcall(fn) 4
fs_initcall(fn) 5
device_initcall(fn) 6
late_initcall(fn) 7

rootfs 相关:rootfs_initcall(在 initramfs populate 等中使用,与上述七级并列概念,见 05)。

early initcallspure..corearch subsysfs devicelatefree_initmem

四、RK3588 平台说明

RK3588 上 eMMC/UFS/PCIe/DRM/VPU 等驱动 probe 主要在 subsys / fs / device 级完成。prepare_namespace() 之前的 wait_for_device_probe()(在 do_mounts.c)会等待异步 probe,因此 initcall 慢的驱动 会直接拉长 挂根时间(见 04)。

Thunder Boot 路径上,部分内存初始化被推迟,不改变 initcall 级别顺序,但可能改变 内存分配压力 的时间分布。


五、调试与观测

1
2
3
4
# 内核命令行
initcall_debug
initcall_blacklist=some_init_func
initcall_nr_threads=4 # 若启用 CONFIG_INITCALL_ASYNC
工具 用途
dmesgcalling ... / returned 定位慢 initcall
cat /proc/interrupts 之后 确认 device 级 IRQ 注册

附录:源码索引

符号 文件
do_initcalls init/main.c ~1574
do_initcall_level ~1552
do_one_initcall ~1304
initcall_levels[] ~1345

相关02 kernel_init

文章互动

阅读 --

留言

0 条留言

正在加载留言…