I’m trying to understand the rationale behind the Linux kernel’s initcall mechanism. My current understanding:
Kernel subsystems expose one-time initialization functions using macros like core_initcall(), device_initcall(), etc. The build system places these functions into named sections (e.g., .initcall0.init, .initcall1.init, …).
At boot, the kernel iterates over these sections in order and calls each function once.
From the linker script (vmlinux.lds.S), I see something like:
#define INIT_CALLS \
__initcall_start = .; \
KEEP(*(.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) \
__initcall_end = .;
Is the understanding above correct (i.e., functions are grouped into .initcall* sections and invoked in a defined order during boot)?
Why does the kernel use initcalls instead of calling these init functions “manually” from start_kernel() or early assembly? What concrete problems does the initcall mechanism solve?
Why are the initcall entries laid out contiguously between __initcall_start and __initcall_end?