fs_initcall、early_initcall、__init宏

本文深入探讨Linux内核中的fs_initcall、early_initcall宏及其调用时机。分析了它们在内核启动过程中的作用,包括何时被调用、如何通过链接脚本组织以及它们与module_init的关系。同时,详细阐述了__init宏的意义和在内存管理中的角色。

fs_initcall、early_initcall...分析

在内核代码中经常可以看到类似fs_initcall\early_initcall\late_initcall这样的宏,这些宏有什么作用?如何实现的?下面来具体分析

具体定义

include/linux/init.h中可以找到这些宏的定义

/*
 * Early initcalls run before initializing SMP.
 *
 * Only for built-in code, not modules.
 */
#define early_initcall(fn)      __define_initcall(fn, early)

/*
 * A "pure" initcall has no dependencies on anything else, and purely
 * initializes variables that couldn't be statically initialized.
 *
 * This only exists for built-in code, not for modules.
 * Keep main.c:initcall_level_names[] in sync.
 */
#define pure_initcall(fn)       __define_initcall(fn, 0)

#define core_initcall(fn)       __define_initcall(fn, 1)
#define core_initcall_sync(fn)      __define_initcall(fn, 1s)
#define postcore_initcall(fn)       __define_initcall(fn, 2)
#define postcore_initcall_sync(fn)  __define_initcall(fn, 2s)
#define arch_initcall(fn)       __define_initcall(fn, 3)
#define arch_initcall_sync(fn)      __define_initcall(fn, 3s)
#define subsys_initcall(fn)     __define_initcall(fn, 4)
#define subsys_initcall_sync(fn)    __define_initcall(fn, 4s)
#define fs_initcall(fn)         __define_initcall(fn, 5)
#define fs_initcall_sync(fn)        __define_initcall(fn, 5s)
#define rootfs_initcall(fn)     __define_initcall(fn, rootfs)
#define device_initcall(fn)     __define_initcall(fn, 6)
#define device_initcall_sync(fn)    __define_initcall(fn, 6s)
#define late_initcall(fn)       __define_initcall(fn, 7)
#define late_initcall_sync(fn)      __define_initcall(fn, 7s)

可以看到它们利用了__define_initcall宏:

<think>我们正在讨论Linux内核初始化过程中`subsys_initcall(mmc_init)`的执行机制。根据引用[3]和[4],我们可以了解到内核初始化时通过调用`do_initcalls`函数来执行各个级别的初始化函数。`subsys_initcall`是一个,用于将函数指针放入特定的初始化段中。 首先,`subsys_initcall`将函数指针(如`mmc_init`)放入一个特定的初始化调用段(section)中。具体来说,它使用链接器将函数指针放置在名为`.initcall4.init`的段中(根据引用[3]中的定义:`subsys_initcall(fn)` 被定义为 `__define_initcall("4",fn,4)`)。 在系统启动过程中,内核会调用`do_initcalls`函数(引用[4]),该函数会遍历所有级别的初始化函数(从0到某个最大值),并按级别顺序执行它们。每个级别对应一个段,例如,级别4对应`.initcall4.init`段。 具体到`subsys_initcall(mmc_init)`: 1. 在内核链接时,`mmc_init`函数指针被放置在`.initcall4.init`段中。 2. 在启动过程中,当内核执行到`do_initcalls`时,它会按级别顺序(0,1,...,7)调用各个段中的函数。 3. 当执行到级别4时(即`do_initcall_level(4)`),会遍历`.initcall4.init`段中的所有函数指针,并依次调用它们,因此`mmc_init`函数会被执行。 此外,引用[1]中展示了`do_pre_smp_initcalls`函数,它执行的是从`__initcall_start`到`__early_initcall_end`之间的初始化函数,这些是更早期的初始化调用(在SMP启动之前执行)。而`subsys_initcall`属于较晚的初始化级别(级别4),因此它在`do_pre_smp_initcalls`之后执行。 总结:`subsys_initcall(mmc_init)`的执行机制是通过将`mmc_init`函数指针放入特定的初始化段(`.initcall4.init`)中,在内核启动过程中,由`do_initcalls`函数按级别顺序调用执行。 相关问题: 1. 内核初始化过程中,`subsys_initcall`与其他初始化级别(如`fs_initcall`、`device_initcall`)有何区别? 2. 如何查看内核初始化调用的顺序和详细信息? 3. 在编写内核模块时,应该使用哪个初始化(`module_init`、`subsys_initcall`等)?</think>### subsys_initcall(mmc_init)的执行和调用机制 在Linux内核启动过程中,`subsys_initcall(mmc_init)`的调用机制遵循以下流程: 1. **定义机制** `subsys_initcall`将函数指针注册到特定内存段: ```c #define subsys_initcall(fn) __define_initcall("4", fn, 4) ``` 这会将`mmc_init`函数指针放入`.initcall4.init`内存段[^3]。 2. **初始化调用入口** 内核启动时执行`start_kernel()` -> `rest_init()` -> `kernel_init()`,最终调用: ```c static void __init do_initcalls(void) { for (level = 0; level < ARRAY_SIZE(initcall_levels); level++) do_initcall_level(level); // 按优先级遍历所有initcall级别 } ``` [^4] 3. **按优先级执行** 初始化调用分7个优先级(0-6),`subsys_initcall`对应级别4: ``` 0: core_initcall 1: postcore_initcall 2: arch_initcall 3: subsys_initcall // 此处执行mmc_init 4: fs_initcall 5: device_initcall 6: late_initcall ``` [^3][^4] 4. **具体执行过程** 当遍历到级别4时: ```c do_initcall_level(4) { call_fn = __initcall_start[4]; // 定位.initcall4.init段 while (call_fn < __initcall_end[4]) { do_one_initcall(*call_fn++); // 执行mmc_init() } } ``` [^1][^4] 5. **MMC驱动初始化** `mmc_init()`函数主要完成: ```c subsys_initcall(mmc_init) { mmc_register_host_class(); // 注册MMC主机类 mmc_register_driver(); // 注册MMC/SD卡驱动框架 sdhci_register_driver(); // 注册SDHCI控制器驱动 } ``` 最终调用`mmc_add_host()`激活控制器[^2][^5]。 **关键特性**: - 所有`subsys_initcall`函数按编译链接顺序执行 - 级别3的初始化在设备模型建立后、文件系统初始化前执行 - 错误会导致内核启动失败(panic/oops) ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值