驱动init/exit函数链接、内核启动运行init/exit函数原理分析
/* 1. s3c24xx spi控制器驱动分配、初始化 */
-------------------------------------------------------------------------------------------------------------------
static struct platform_driver s3c24xx_spi_driver = {
.probe = s3c24xx_spi_probe,
.remove = s3c24xx_spi_remove,
.driver = {
.name = "s3c2410-spi",
.owner = THIS_MODULE,
.pm = S3C24XX_SPI_PMOPS,
},
};
/* 2. s3c24xx spi控制器驱动的init、exit函数 */
-------------------------------------------------------------------------------------------------------------------
module_platform_driver(s3c24xx_spi_driver);
#define module_platform_driver(__platform_driver) \
module_driver(__platform_driver, platform_driver_register, \
platform_driver_unregister)
#define module_driver(__driver, __register, __unregister, ...) \
static int __init __driver##_init(void) \
{ \
return __register(&(__driver) , ##__VA_ARGS__); \
} \
module_init(__driver##_init); \
static void __exit __driver##_exit(void) \
{ \
__unregister(&(__driver) , ##__VA_ARGS__); \
} \
module_exit(__driver##_exit);
/* 3. module_init、module_exit函数详解,将函数首地址保存在 .initcall6.init */
-------------------------------------------------------------------------------------------------------------------
module_init(__driver##_init)
#define module_init(x) __initcall(x);
#define __initcall(fn) device_initcall(fn)
#define device_initcall(fn) __define_initcall(fn, 6)
#define __define_initcall(fn, id) \
static initcall_t __initcall_##fn##id __used \
__attribute__((__section__(".initcall" #id ".init"))) = fn
initcall_t 原型: typedef int (*initcall_t)(void);
函数属性__attribute__((__section__()))表示将函数指针放到section所表示的代码段中
/* 4. 内核编译时,链接脚本解析,所有输入文件相同段数据被链接到输出文件xiang一段 */
-------------------------------------------------------------------------------------------------------------------
arch/arm/kernel/vmlinux.lds.S
.init.data : {
#ifndef CONFIG_XIP_KERNEL
INIT_DATA
#endif
INIT_SETUP(16)
INIT_CALLS
CON_INITCALL
SECURITY_INITCALL
INIT_RAM_FS
}
#ifndef CONFIG_XIP_KERNEL
.exit.data : {
ARM_EXIT_KEEP(EXIT_DATA)
}
include/asm-generic/vmlinux.lds.h
#define INIT_CALLS \
VMLINUX_SYMBOL(__initcall_start) = .; \
*(.initcallearly.init) \
INIT_CALLS_LEVEL(0) \
INIT_CALLS_LEVEL(1) \
INIT_CALLS_LEVEL(2) \
INIT_CALLS_LEVEL(3) \
INIT_CALLS_LEVEL(4) \
INIT_CALLS_LEVEL(5) \
INIT_CALLS_LEVEL(rootfs) \
INIT_CALLS_LEVEL(6) \
INIT_CALLS_LEVEL(7) \
VMLINUX_SYMBOL(__initcall_end) = .;
#define INIT_CALLS_LEVEL(level) \
VMLINUX_SYMBOL(__initcall##level##_start) = .; \
*(.initcall##level##.init) \
*(.initcall##level##s.init) \
/* 5. Linux内核启动,上面的s3c24xx_spi_driver_init、s3c24xx_spi_driver_exit何时调用 */
-------------------------------------------------------------------------------------------------------------------
start_kernel
rest_init
kernel_init
kernel_init_freeable
do_basic_setup
driver_init(); --> 创建/sys/各子目录
init_irq_proc();
do_ctors();
usermodehelper_enable();
do_initcalls();
for (level = 0; level < ARRAY_SIZE(initcall_levels) - 1; level++)
do_initcall_level(level);
for (fn = initcall_levels[level]; fn < initcall_levels[level+1]; fn++)
do_one_initcall(*fn);
阅读(1463) | 评论(0) | 转发(0) |