linux内核启动init.setup执行流程

[    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的节中

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值