module_init()

来源:互联网 发布:java生产者和消费者 编辑:程序博客网 时间:2024/06/11 22:21

本文基于mips架构的Cavium的CPU。linux内核版本2.6.27.32 


几乎每个module都有两个接口:
     module_init()一般调用一个register的接口注册一个driver的驱动接口,例如:
static int __init cfi_probe_init(void)
{
    register_mtd_chip_driver(&cfi_chipdrv); //注册驱动接口到链表:chip_drvs_list 
     //注意不同类型的设备挂载在不同类型的结构体链表上
    return 0;
}
     static struct mtd_chip_driver cfi_chipdrv = {
    .probe        = cfi_probe,
    .name        = "cfi_probe", //后续根据这个名字调用对应的驱动接口和驱动处理函数
    .module        = THIS_MODULE
     };

     module_exit()

     下面说一下module_init接口的实现以及调用流程
     在头文件init.h中/include/linux
          #define module_init(x)    __initcall(x);
          #define __initcall(fn) device_initcall(fn)
          #define device_initcall(fn)        __define_initcall("6",fn,6)
#define __define_initcall(level,fn,id) \               //     如上level = 6,id = 6
    static initcall_t __initcall_##fn##id __used \
    __attribute__((__section__(".initcall" level ".init"))) = fn
__define_initcall 宏将module_init里面注册的函数名XXX,更改为:__initcall_XXX6 并将其注册到代码段.initcall6.init里面
     
而其调用在什么位置呢?调用分两部分,中间从__early_initcall_end隔开
start_kernel()---》rest_init()---》kernel_init()----》do_basic_setup()----》do_initcalls()
    for (call = __early_initcall_end; call < __initcall_end; call++)  //后半部分调用
        do_one_initcall(*call);
start_kernel()--->rest_init()-->kernel_init((init/main.c)--->do_pre_smp_initcalls()
    for (call = __initcall_start; call < __early_initcall_end; call++) //前半部分调用
        do_one_initcall(*call);

那啥时候调用这个代码段呢? 在文件 vmlinux.lds.h中有如下定义:               
#define INITCALLS                            \
    *(.initcallearly.init)                        \
    VMLINUX_SYMBOL(__early_initcall_end) = .;            \
      *(.initcall0.init)                        \
      *(.initcall0s.init)                        \
      *(.initcall1.init)                        \
      *(.initcall1s.init)                        \
      *(.initcall2.init)                        \
      *(.initcall2s.init)                        \
      *(.initcall3.init)                        \
      *(.initcall3s.init)                        \
      *(.initcall4.init)                        \
      *(.initcall4s.init)                        \
      *(.initcall5.init)                        \
      *(.initcall5s.init)                        \
    *(.initcallrootfs.init)                        \
      *(.initcall6.init)                        \
      *(.initcall6s.init)                        \
      *(.initcall7.init)                        \
      *(.initcall7s.init)

#define INIT_CALLS                            \
        VMLINUX_SYMBOL(__initcall_start) = .;            \
        INITCALLS                        \
        VMLINUX_SYMBOL(__initcall_end) = .;

#define INIT_DATA_SECTION(initsetup_align)                \
    .init.data : AT(ADDR(.init.data) - LOAD_OFFSET) {        \
        INIT_DATA                        \
        INIT_SETUP(initsetup_align)                \
        INIT_CALLS                        \
        CON_INITCALL                        \
        SECURITY_INITCALL                    \
        INIT_RAM_FS                        \
    }

   //在文件:./arch/mips/kernel/vmlinux.lds.S:114:   INIT_DATA_SECTION(16)  中;
    /* will be freed after init */
    . = ALIGN(PAGE_SIZE);        /* Init code and data */
    __init_begin = .;
    INIT_TEXT_SECTION(PAGE_SIZE)
    INIT_DATA_SECTION(16)

表示INITCALLS宏内含有的相关代码放在__initcall_start和__initcall_end之间 ,并规划了其内存的存放位置对其字节数等信息 
初始化数据区的流程和接口
main(modpost.c)--->read_symbols--->check_sec_ref--->section_rela/section_rel--->check_section_mismatch-->secref_whitelist--->init_data_sections--->ALL_INIT_DATA_SECTIONS--->".init.data$等。。。

 而其调用在什么位置呢?调用分两部分,中间从__early_initcall_end隔开
start_kernel()---》rest_init()---》kernel_init()----》do_basic_setup()----》do_initcalls()
    for (call = __early_initcall_end; call < __initcall_end; call++)  //后半部分调用
        do_one_initcall(*call);
start_kernel()--->rest_init()-->kernel_init((init/main.c)--->do_pre_smp_initcalls()
    for (call = __initcall_start; call < __early_initcall_end; call++) //前半部分调用
        do_one_initcall(*call);

在./arch/mips/kernel/vmlinux.lds.S里面

Main()--->linux_main()--->start_uml()--->start_kernel_proc()--->start_kernel()--->rest_init()--->kernel_init()--->do_basic_setup()--->do_initcalls()

#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)



0 0
原创粉丝点击