[ 1.245816] [<c0743af5>] dump_stack+0x49/0x73
[ 1.246279] [<c022fe2e>] warn_slowpath_common+0x62/0x79
[ 1.247396] [<c022fecb>] warn_slowpath_null+0xf/0x13
[ 1.247899] [<c05eeaaa>] goldfish_pipe_probe+0x16/0x17e
[ 1.248428] [<c0484f9d>] platform_drv_probe+0x24/0x5f
[ 1.248942] [<c0484011>] driver_probe_device+0x85/0x1a5
[ 1.249471] [<c04841a4>] __driver_attach+0x47/0x63
[ 1.249950] [<c0482e8b>] bus_for_each_dev+0x5e/0x6f
[ 1.250570] [<c0484249>] driver_attach+0x14/0x16
[ 1.251686] [<c04834c3>] bus_add_driver+0xc4/0x174
[ 1.252859] [<c0484855>] driver_register+0x6f/0xa4
[ 1.253886] [<c04856ab>] __platform_driver_register+0x3b/0x3d
[ 1.254440] [<c0a4c6be>] goldfish_pipe_init+0xf/0x11
[ 1.254927] [<c0a19b24>] do_one_initcall+0xd0/0x142
do_initcall_level(内联)
do_initcalls(内联)
do_basic_setup (内联)
[ 1.256325] [<c0a19c7e>] kernel_init_freeable+0xe8/0x165
[ 1.256837] [<c0740bec>] kernel_init+0x8/0xb8
[ 1.257261] [<c074a101>] ret_from_kernel_thread+0x21/0x30
[ 1.257788] [<c0740be4>] ? rest_init+0x70/0x70
这是一段内核启动driver初始化的调用栈,今天要分析的是do_initcalls的过程
static void __init do_initcalls(void)
{
int level;
for (level = 0; level < ARRAY_SIZE(initcall_levels) - 1; level++)
do_initcall_level(level);
}
init函数的调用过程从do_initcalls开始
然后按照leve调用 do_initcall_level函数
这里维护level的信息的数据结构为数组 initcall_levels
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,
};
typedef int (*initcall_t)(void);
__initcall{$level}_start 这些不同level的数组里存放的都是 int (*initcall_t)(void)类型的函数指针
这些不同的level函数来自哪里? 这要看链接脚本
. = ALIGN((1 << 12)); .init.text : AT(ADDR(.init.text) - 0xC0000000) { _sinittext = .; *(.init.text) *(.meminit.text) _einittext = .; }
.init.data : AT(ADDR(.init.data) - 0xC0000000) { *(.init.data) *(.meminit.data) *(.init.rodata) . = ALIGN(8); __start_ftrace_events = .; *(_ftrace_events) __stop_ftrace_events = .; *(.meminit.rodata) . = ALIGN(8); __cpu_method_of_table = .; *(__cpu_method_of_table) *(__cpu_method_of_table_end) . = ALIGN(32); __dtb_start = .; *(.dtb.init.rodata) __dtb_end = .; . = ALIGN(8); __earlycon_of_table = .; *(__earlycon_of_table) *(__earlycon_of_table_end) . = ALIGN(16); __setup_start = .; *(.init.setup) __setup_end = .; __initcall_start = .; *(.initcallearly.init) __initcall0_start = .; *(.initcall0.init) *(.initcall0s.init) __initcall1_start = .; *(.initcall1.init) *(.initcall1s.init) __initcall2_start = .; *(.initcall2.init) *(.initcall2s.init) __initcall3_start = .; *(.initcall3.init) *(.initcall3s.init) __initcall4_start = .; *(.initcall4.init) *(.initcall4s.init) __initcall5_start = .; *(.initcall5.init) *(.initcall5s.init) __initcallrootfs_start = .; *(.initcallrootfs.init) *(.initcallrootfss.init) __initcall6_start = .; *(.initcall6.init) *(.initcall6s.init) __initcall7_start = .; *(.initcall7.init) *(.initcall7s.init) __initcall_end = .; __con_initcall_start = .; *(.con_initcall.init) __con_initcall_end = .; __security_initcall_start = .; *(.security_initcall.init) __security_initcall_end = .; . = ALIGN(4); __initramfs_start = .; *(.init.ramfs) . = ALIGN(8); *(.init.ramfs.info) }
.x86_cpu_dev.init : AT(ADDR(.x86_cpu_dev.init) - 0xC0000000) {
__x86_cpu_dev_start = .;
*(.x86_cpu_dev.init)
__x86_cpu_dev_end = .;
}
.init.data节的一段信息 以level3为例__initcall3_start 这个变量其实是通过链接脚本定义的 .__initcall3_start = .; *(.initcall3.init) *(.initcall3s.init)
也就是.initcall3.init的节和.initcall3s.init的节都被链接到 __initcall3_start这个节中
那么一个函数是如何放入这些节的呢
#define __define_initcall(fn, id) \
static initcall_t __initcall_##fn##id __used \
__attribute__((__section__(".initcall" #id ".init"))) = fn; \
LTO_REFERENCE_INITCALL(__initcall_##fn##id)
#define __define_initcakk(fn, 6)
static initcall_t __initcall_fn6 __used __attribute__((__section__(.initcall6.init))) = fn
/*
* 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)
通过上面这些宏 如 core_initcall , device_initcall
以goldfish pipe设备驱动为例
#define __initcall(fn) device_initcall(fn)
arch/x86/platform/goldfish/goldfish.c
device_initcall(goldfish_init);
#define module_init(x) __initcall(x);
例外 module_init 也是会注册到level 为6的节中