Chinaunix首页 | 论坛 | 博客
  • 博客访问: 347999
  • 博文数量: 94
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 606
  • 用 户 组: 普通用户
  • 注册时间: 2015-09-30 08:58
个人简介

x

文章分类

全部博文(94)

文章存档

2019年(4)

2018年(10)

2017年(26)

2016年(38)

2015年(16)

我的朋友

分类: LINUX

2017-01-11 15:00:08

驱动init/exit函数链接、内核启动运行init/exit函数原理分析

/* 1. s3c24xx spi控制器驱动分配、初始化 */
-------------------------------------------------------------------------------------------------------------------
static struct platform_driver s3c24xx_spi_driver = {
    .probe      = s3c24xx_spi_probe,
    .remove     = s3c24xx_spi_remove,
    .driver     = {
        .name   = "s3c2410-spi",
        .owner  = THIS_MODULE,
        .pm = S3C24XX_SPI_PMOPS,
    },
};

/* 2. s3c24xx spi控制器驱动的init、exit函数 */
-------------------------------------------------------------------------------------------------------------------
module_platform_driver(s3c24xx_spi_driver);

#define module_platform_driver(__platform_driver) \
    module_driver(__platform_driver, platform_driver_register, \
            platform_driver_unregister)
            
#define module_driver(__driver, __register, __unregister, ...) \
static int __init __driver##_init(void) \
{ \
    return __register(&(__driver) , ##__VA_ARGS__); \
} \    
module_init(__driver##_init); \
static void __exit __driver##_exit(void) \
{ \
    __unregister(&(__driver) , ##__VA_ARGS__); \
} \
module_exit(__driver##_exit);

/* 3. module_init、module_exit函数详解,将函数首地址保存在 .initcall6.init */
-------------------------------------------------------------------------------------------------------------------
module_init(__driver##_init)
    #define module_init(x)  __initcall(x);
        #define __initcall(fn) device_initcall(fn)
            #define device_initcall(fn)     __define_initcall(fn, 6)
                #define __define_initcall(fn, id) \
                    static initcall_t __initcall_##fn##id __used \
                    __attribute__((__section__(".initcall" #id ".init"))) = fn

initcall_t 原型: typedef int (*initcall_t)(void);
函数属性__attribute__((__section__()))表示将函数指针放到section所表示的代码段中

/* 4. 内核编译时,链接脚本解析,所有输入文件相同段数据被链接到输出文件xiang一段 */
-------------------------------------------------------------------------------------------------------------------
arch/arm/kernel/vmlinux.lds.S
    .init.data : {
#ifndef CONFIG_XIP_KERNEL
        INIT_DATA
#endif
        INIT_SETUP(16)
        INIT_CALLS
        CON_INITCALL
        SECURITY_INITCALL
        INIT_RAM_FS
    }
#ifndef CONFIG_XIP_KERNEL
    .exit.data : {
        ARM_EXIT_KEEP(EXIT_DATA)
    }

include/asm-generic/vmlinux.lds.h
#define INIT_CALLS                          \
        VMLINUX_SYMBOL(__initcall_start) = .;           \
        *(.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)                 \
        VMLINUX_SYMBOL(__initcall_end) = .;


#define INIT_CALLS_LEVEL(level)                     \
    VMLINUX_SYMBOL(__initcall##level##_start) = .;      \
    *(.initcall##level##.init)              \
    *(.initcall##level##s.init)             \

/* 5. Linux内核启动,上面的s3c24xx_spi_driver_init、s3c24xx_spi_driver_exit何时调用 */
-------------------------------------------------------------------------------------------------------------------
start_kernel
    rest_init
        kernel_init
            kernel_init_freeable
                do_basic_setup
                    driver_init();      -->  创建/sys/各子目录
                    init_irq_proc();
                    do_ctors();
                    usermodehelper_enable();
                    do_initcalls();
                        for (level = 0; level < ARRAY_SIZE(initcall_levels) - 1; level++)
                            do_initcall_level(level);
                                for (fn = initcall_levels[level]; fn < initcall_levels[level+1]; fn++)
                                    do_one_initcall(*fn);



阅读(1322) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~