There are many initialization calls in Linux kernel and these initcalls are grouped by functionality into separate subsections in Linux-2.6.18, such as “core_initcall(ksysfs_init)” and “arch_initcall(au1xxx_platform_init)”.
Both “core_initcall” and “arch_initcall” are macros which are defined in linux-2.6.18/include/linux/init.h. The following shows the definition when these are built in kernel (not in module):
#define __define_initcall(level,fn) /
static initcall_t __initcall_##fn __attribute_used__ /
__attribute__((__section__(".initcall" level ".init"))) = fn
#define core_initcall(fn) __define_initcall("1",fn)
#define postcore_initcall(fn) __define_initcall("2",fn)
#define arch_initcall(fn) __define_initcall("3",fn)
#define subsys_initcall(fn) __define_initcall("4",fn)
#define fs_initcall(fn) __define_initcall("5",fn)
#define device_initcall(fn) __define_initcall("6",fn)
#define late_initcall(fn) __define_initcall("7",fn)
#define __initcall(fn) device_initcall(fn)
From these, we can find that all initcalls declared with these initcall macros will be linked to “.initcall” section.
In linux kernel link file for MIPS (linux-2.6.18/arch/mips/kennel/vmlinux.lds.S), we can find “.initcall” section is linked like this:
__initcall_start = .;
.initcall.init : {
*(.initcall1.init)
*(.initcall2.init)
*(.initcall3.init)
*(.initcall4.init)
*(.initcall5.init)
*(.initcall6.init)
*(.initcall7.init)
}
__initcall_end = .;
So all initcalls functions is saved in the memory range between __initcall_start and __initcall_end.
All these initcalls will be called in do_initcalls() which is implemented in linux-2.6.18/init/main.c and it is called by “init” thread when booting up Linux kernel. These initcalls are called like this:
static void __init do_initcalls(void)
{
initcall_t *call;
int count = preempt_count();
for (call = __initcall_start; call < __initcall_end; call++) {
char *msg = NULL;
char msgbuf[40];
int result;
…
result = (*call)();
…
}
}
/* Make sure there is no pending stuff from the initcall sequence */
flush_scheduled_work();
}
From the code we can find we get the initcall function pointer with “__initcall_start” and “__initcall_end” which is defined in linux link file vmlinux.lds.S.