Linux kernel __init,core_initcall分析
下面内容都是以kernel 4.14版本分析;通常linux驱动定义为如下:
static int __init gpiolib_dev_init(void)
{
...
}
core_initcall(gpiolib_dev_init);
1. __init分析
__init是个宏,定义为 define __init __section(.init.text) __cold __inittrace __latent_entropy __noinitretpoline __nocfi
通常编译器把把代码放在.text段,全局初始化的变量放在.data段,全局未初始化的变量放在.bss段。而使用session属性,连接器(vmlinux.lds)可以把需要的内容,放在指定的段中。
上面的__init被放在.init.text中,因此所有的_init都放入到’.init.text’中,初始化完后就可以把该内存删除掉。
2. core_initcall分析
路径为include/linux/init.h
#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_name(fn, id) __initcall_##fn##id
#define __define_initcall(fn, id) \
static initcall_t __initcall_name(fn, id) __used \
__attribute__((__section__(".initcall" #id ".init"))) = fn;
typedef int (*initcall_t)(void)声明一个函数指针
core_initcall(gpiolib_dev_init) =
__define_initcall(gpiolib_dev_init, 1) =
static initcall_t __initcall_gpiolib_dev_init_1 __used __attribute__((__section__(.initcall.1.init))) = gpiolib_dev_init;
上面宏展开的意思为声明了一个函数__initcall_gpiolib_dev_init_1,该函数指向了gpiolib_dev_init。同时__initcall_gpiolib_dev_init_1是储存在__section__(.initcall.1.init) ,储存方式通过lds连接如下(查看out目录下的vmlinux.lds)
initcall_start = .;
KEEP(*(.initcallearly.init))
__initcall0_start = .;
KEEP(*(.initcall0.init)) KEEP(*(.initcall0s.

本文详细分析了Linux内核4.14版本中__init宏和core_initcall的工作原理。__init宏将代码置于.init.text段,初始化后可删除。core_initcall用于驱动加载,其调用顺序可通过不同_initcall函数调整。init/main.c中的initcall_blacklist()处理禁载驱动,而do_one_initcall()则用于按顺序执行初始化函数。
最低0.47元/天 解锁文章
2960

被折叠的 条评论
为什么被折叠?



