Chinaunix首页 | 论坛 | 博客
  • 博客访问: 526525
  • 博文数量: 51
  • 博客积分: 345
  • 博客等级: 民兵
  • 技术积分: 534
  • 用 户 组: 普通用户
  • 注册时间: 2011-03-21 12:02
个人简介

文章分类

全部博文(51)

文章存档

2023年(2)

2022年(1)

2021年(7)

2020年(10)

2019年(2)

2016年(20)

2015年(5)

2014年(1)

2011年(3)

我的朋友

分类: LINUX

2016-06-08 15:21:20

通过initcall段内函数初始化流程来看.init.data段的内容
start_kernel-->rest_init-->kernel_init-->do_basic_setup-->do_initcalls

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);
}


关键是内核如何存储函数地址的?
先来看声明:

typedef int (*initcall_t)(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,
};
这些函数指针数组的声明在链接脚本vmlinux.lds中,对于__initcallX_start的排列如下:

 .init.data : {
  *(.init.data) *(.cpuinit.data) *(.meminit.data) *(.init.rodata) *(.cpuinit.rodata) *(.meminit.rodata) . = ALIGN(32); __dtb_start = .; *(.dtb.init.rodata) __dtb_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)
 }
可以看出__initcall段存储在.init.data段中,
通过System.map可以看一下这些段中存储的是什么函数的指针:

c05f6dd8 T __initcall_start
c05f6dd8 T __setup_end
c05f6ddc t __initcall_init_static_idmapearly
c05f6de0 t __initcall_spawn_ksoftirqdearly
c05f6de4 t __initcall_init_workqueuesearly
c05f6de8 t __initcall_migration_initearly
c05f6dec t __initcall_cpu_stop_initearly
c05f6df0 t __initcall_rcu_scheduler_really_startedearly
c05f6df4 T __initcall0_start
c05f6df4 t __initcall_ipc_ns_init0
c05f6df8 t __initcall_init_mmap_min_addr0
c05f6dfc t __initcall_net_ns_init0
c05f6e00 T __initcall1_start
c05f6e00 t __initcall_ptrace_break_init1
c05f6e04 t __initcall_consistent_init1
c05f6e08 t __initcall_v6_userpage_init1
c05f6e0c t __initcall_ksysfs_init1
c05f6e10 t __initcall_init_jiffies_clocksource1
c05f6e14 t __initcall_init_zero_pfn1
c05f6e18 t __initcall_fsnotify_init1
c05f6e1c t __initcall_filelock_init1
c05f6e20 t __initcall_init_script_binfmt1
c05f6e24 t __initcall_init_elf_binfmt1
c05f6e28 t __initcall_debugfs_init1
c05f6e2c t __initcall_random32_init1
c05f6e30 t __initcall_sock_init1
c05f6e34 t __initcall_netlink_proto_init1
c05f6e38 T __initcall2_start
c05f6e38 t __initcall_bdi_class_init2
c05f6e3c t __initcall_kobject_uevent_init2
c05f6e40 t __initcall_gpiolib_sysfs_init2
c05f6e44 t __initcall_pcibus_class_init2
c05f6e48 t __initcall_pci_driver_init2
c05f6e4c t __initcall_tty_class_init2
c05f6e50 t __initcall_spi_init2
c05f6e54 t __initcall_i2c_init2
c05f6e58 T __initcall3_start
......
c05f7300 T __initcall_end
同样通过objdump也可以看出__initcall段的内容:

c05f6dd8 <__initcall_start>:
c05f6dd8:    c05cbc64     .word    0xc05cbc64

c05f6ddc <__initcall_init_static_idmapearly>:
c05f6ddc:    c05ccee4                                ..\.

c05f6de0 <__initcall_spawn_ksoftirqdearly>:
c05f6de0:    c05d048c                                ..].

c05f6de4 <__initcall_init_workqueuesearly>:
c05f6de4:    c05d0b20                                 .].

c05f6de8 <__initcall_migration_initearly>:
c05f6de8:    c05d1754                                T.].

c05f6dec <__initcall_cpu_stop_initearly>:
c05f6dec:    c05d25c0                                .%].

c05f6df0 <__initcall_rcu_scheduler_really_startedearly>:
c05f6df0:    c05d2944                                D)].

c05f6df4 <__initcall0_start>:
c05f6df4:    c05d8bd8     .word    0xc05d8bd8

c05f6df8 <__initcall_init_mmap_min_addr0>:
c05f6df8:    c05d8d0c                                ..].

c05f6dfc <__initcall_net_ns_init0>:
c05f6dfc:    c05e0f60                                `.^.
......

objdump还显示对应函数的地址;

可以看出内核在初始化阶段,找到__initcall0_start,然后依次读取存储的函数地址,并调用进行初始化操作。
内核中放在.init.data的函数声明需要用到如下宏定义:

#define __define_initcall(level,fn,id) \
    static initcall_t __initcall_##fn##id __used \
    __attribute__((__section__(".initcall" level ".init"))) = fn

/*
 * Early initcalls run before initializing SMP.
 *
 * Only for built-in code, not modules.
 */
#define early_initcall(fn)        __define_initcall("early",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.
 */
#define pure_initcall(fn)        __define_initcall("0",fn,0)

#define core_initcall(fn)        __define_initcall("1",fn,1)
#define core_initcall_sync(fn)        __define_initcall("1s",fn,1s)
#define postcore_initcall(fn)        __define_initcall("2",fn,2)
#define postcore_initcall_sync(fn)    __define_initcall("2s",fn,2s)
#define arch_initcall(fn)        __define_initcall("3",fn,3)
#define arch_initcall_sync(fn)        __define_initcall("3s",fn,3s)
#define subsys_initcall(fn)        __define_initcall("4",fn,4)
#define subsys_initcall_sync(fn)    __define_initcall("4s",fn,4s)
#define fs_initcall(fn)            __define_initcall("5",fn,5)
#define fs_initcall_sync(fn)        __define_initcall("5s",fn,5s)
#define rootfs_initcall(fn)        __define_initcall("rootfs",fn,rootfs)
#define device_initcall(fn)        __define_initcall("6",fn,6)
#define device_initcall_sync(fn)    __define_initcall("6s",fn,6s)
#define late_initcall(fn)        __define_initcall("7",fn,7)
#define late_initcall_sync(fn)        __define_initcall("7s",fn,7s)

#define __initcall(fn) device_initcall(fn)


例如i2c初始化声明为:

     postcore_initcall(i2c_init);

对应.init.data段的内容为:

c05f6e54 <__initcall_i2c_init2>:
c05f6e54:    c05e0604                                ..^.

阅读(2910) | 评论(0) | 转发(0) |
0

上一篇:i2c设备驱动初始化流程

下一篇:1905.1-2013

给主人留下些什么吧!~~