一、Include/linux/init.h中:
/* initcalls are now grouped by functionality into separate
* subsections. Ordering inside the subsections is determined
* by link order.
* For backwards compatibility, initcall() puts the call in
* the device init subsection.
*
* The `id' arg to __define_initcall() is needed so that multiple initcalls
* can point at the same handler without causing duplicate-symbol build errors.
*/
#define __define_initcall(fn, id) \
static initcall_t __initcall_##fn##id __used \
__attribute__((__section__(".initcall" #id ".init"))) = fn
/*
* 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的封装。
__define_initcall中的第二个参数是调用顺序,数字越小在linux启动过程中调用的越早。
可以看到我们熟悉的模块入口函数device_initcall的优先级是6,subsys_initcall的优先级是4.
这个宏定义是将我们定义的模块初始化函数按照初始化优先级放到相应的.initcallX.init段中,如subsys_initcall定义的函数放到.initcall4.init段中。
详细解释一下这个宏的定义:
#define __define_initcall(fn, id) \
static initcall_t __initcall_##fn##id __used \
__attribute__((__section__(".initcall" #id ".init"))) = fn
1,__define_initcall(fn, id)
这个宏有两个参数fn、id
2,static initcall_t _initcall##fn##id __used
定义了一个initcall_t类型的函数指针。
initcall_t的定义为typedef int (*initcall_t)(void);,是一个参数为空,返回值为int的函数指针类型。
传递给module_init 的函数就是这个类型的static int hello_init();
这个新定义的函数指针名称是有fn和id两个参数组成的_initcall##fn##id;
__used告诉编译器无论 GCC 是否发现这个函数的调用实例,都要使用这个函数。
3,attribute((section(“.initcall” #id “.init”))) = fn;
attribute((section(“”)))是为链接器指定链接的section,这里按照id将各个初始化函数放置到不同的.initcallX.init段中。
然后将初始化函数指针赋值给了新定义的函数指针。
二、arch\arm\kernel\vmlinux.lds发现lds中定义的各个section的具体内容如下:
.init.data : {
*(.init.data) *(.cpuinit.data) *(.meminit.data) *(.init.rodata) *(.cpuinit.rodata) *(.meminit.rodata) . = ALIGN(8);
__clk_of_table = .; KEEP(*(__clk_of_table)) KEEP(*(__clk_of_table_end)) . = ALIGN(8);
__clksrc_of_table = .; KEEP(*(__clksrc_of_table)) KEEP(*(__clksrc_of_table_end)) . = ALIGN(32);
__dtb_start = .; KEEP(*(.dtb.init.rodata)) __dtb_end = .; . = ALIGN(8);
__irqchip_begin = .; KEEP(*(__irqchip_of_table)) KEEP(*(__irqchip_of_end)) . = ALIGN(16);
__setup_start = .; KEEP(*(.init.setup)) __setup_end = .;
__initcall_start = .; KEEP(*(.initcallearly.init))
__initcall0_start = .; KEEP(*(.initcall0.init)) KEEP(*(.initcall0s.init))
__initcall1_start = .; KEEP(*(.initcall1.init)) KEEP(*(.initcall1s.init))
__initcall2_start = .; KEEP(*(.initcall2.init)) KEEP(*(.initcall2s.init))
__initcall3_start = .; KEEP(*(.initcall3.init)) KEEP(*(.initcall3s.init))
__initcall4_start = .; KEEP(*(.initcall4.init)) KEEP(*(.initcall4s.init))
__initcall5_start = .; KEEP(*(.initcall5.init)) KEEP(*(.initcall5s.init))
__initcallrootfs_start = .; KEEP(*(.initcallrootfs.init)) KEEP(*(.initcallrootfss.init))
__initcall6_start = .; KEEP(*(.initcall6.init)) KEEP(*(.initcall6s.init))
__initcall7_start = .; KEEP(*(.initcall7.init)) KEEP(*(.initcall7s.init))
__initcall_end = .;
__con_initcall_start = .; KEEP(*(.con_initcall.init)) __con_initcall_end = .;
__security_initcall_start = .; KEEP(*(.security_initcall.init)) _security_initcall_end = .;
}
三、Init/main.c中:
asmlinkage void __init start_kernel(void)
{
static noinline void __init_refok rest_init(void)
{
kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);
static int __ref kernel_init(void *unused)
{
static noinline void __init kernel_init_freeable(void)
{
static void __init do_basic_setup(void)
{
extern initcall_t __initcall_start[];
extern initcall_t __initcall0_start[];
extern initcall_t __initcall1_start[];
extern initcall_t __initcall2_start[];
extern initcall_t __initcall3_start[];
extern initcall_t __initcall4_start[];
extern initcall_t __initcall5_start[];
extern initcall_t __initcall6_start[];
extern initcall_t __initcall7_start[];
extern initcall_t __initcall_end[];
static initcall_t *initcall_levels[] __initdata = {
__initcall0_start,
__initcall1_start,
__initcall2_start,
__initcall3_start,
__initcall4_start,
__initcall5_start,
__initcall6_start,
__initcall7_start,
__initcall_end,
};
static void __init do_initcalls(void)
{
int level;
for (level = 0; level < ARRAY_SIZE(initcall_levels) - 1; level++)
do_initcall_level(level);
static void __init do_initcall_level(int level)
{
extern const struct kernel_param __start___param[], __stop___param[];
initcall_t *fn;
strcpy(static_command_line, saved_command_line);
parse_args(initcall_level_names[level],
static_command_line, __start___param,
__stop___param - __start___param,
level, level,
&repair_env_string);
for (fn = initcall_levels[level]; fn < initcall_levels[level+1]; fn++)
do_one_initcall(*fn);
int __init_or_module do_one_initcall(initcall_t fn)
{
int count = preempt_count();
int ret;
if (initcall_debug)
ret = do_one_initcall_debug(fn);
{
......
ret = fn();
......
}
else
ret = fn();
msgbuf[0] = 0;
if (preempt_count() != count) {
sprintf(msgbuf, "preemption imbalance ");
preempt_count() = count;
}
if (irqs_disabled()) {
strlcat(msgbuf, "disabled interrupts ", sizeof(msgbuf));
local_irq_enable();
}
WARN(msgbuf[0], "initcall %pF returned with %s\n", fn, msgbuf);
return ret;
}
}
}
}
}
}
}
}
参考:https://blog.youkuaiyun.com/asklw/article/details/79698422