设备驱动-模块-module_init宏解析

module_init 

这个宏定义在 

include/linux/module.h

module 的含义,即 模块; 有两类:  builtin  的模块 (存在在 Image 中) 或者  独立的模块(存在在  xx.ko 中)

 

根据当前在编译 builtin 还是 编译 独立模块, module 宏有不同的 定义

  80#ifndef MODULE

  89#define module_init(x)  __initcall(x);

 103#else /* MODULE */

 131#define module_init(initfn)                                     \
 132        static inline initcall_t __maybe_unused __inittest(void)                \
 133        { return initfn; }                                      \
 134        int init_module(void) __copy(initfn) __attribute__((alias(#initfn)));

 142#endif

 

MODULE 宏从哪儿控制? 

如果一个 xx.c 文件在 Kconfig 中配置的是 obj-m += xx.c ,那么编译这个 xx.c 文件时,就会 定义MODULE 宏。

这个机制是 顶层的  Makefile 和 script/Makefile.lib 配合实现的

Makefile

 503KBUILD_AFLAGS_MODULE  := -DMODULE
 504KBUILD_CFLAGS_MODULE  := -DMODULE

scripts/Makefile.lib

 188part-of-module = $(if $(filter $(basename $@).o, $(real-obj-m)),y)
 189quiet_modtag = $(if $(part-of-module),[M],   )
 190
 191modkern_cflags =                                          \
 192        $(if $(part-of-module),                           \
 193                $(KBUILD_CFLAGS_MODULE) $(CFLAGS_MODULE), \
 194                $(KBUILD_CFLAGS_KERNEL) $(CFLAGS_KERNEL) $(modfile_flags))

$@ 表示正在编译的目标,如果是 module 的一部分,则使用 KBUILD_CFLAGS_MODULE 作为 cflags ,即 -DMODULE 被引入 gcc 命令行 ;

 

作为  builtin 模块时的module_init 

就是  __initcall(x); 

include/linux/init.h

 195#define ___define_initcall(fn, id, __sec) \
 196        static initcall_t __initcall_##fn##id __used \
 197                __attribute__((__section__(#__sec ".init"))) = fn;
 

 200#define __define_initcall(fn, id) ___define_initcall(fn, id, .initcall##id)
 
 207#define early_initcall(fn)              __define_initcall(fn, early)

 216#define pure_initcall(fn)               __define_initcall(fn, 0)
 218#define core_initcall(fn)               __define_initcall(fn, 1)
 219#define core_initcall_sync(fn)          __define_initcall(fn, 1s)
 220#define postcore_initcall(fn)           __define_initcall(fn, 2)
 221#define postcore_initcall_sync(fn)      __define_initcall(fn, 2s)
 222#define arch_initcall(fn)               __define_initcall(fn, 3)
 223#define arch_initcall_sync(fn)          __define_initcall(fn, 3s)
 224#define subsys_initcall(fn)             __define_initcall(fn, 4)
 225#define subsys_initcall_sync(fn)        __define_initcall(fn, 4s)
 226#define fs_initcall(fn)                 __define_initcall(fn, 5)
 227#define fs_initcall_sync(fn)            __define_initcall(fn, 5s)
 228#define rootfs_initcall(fn)             __define_initcall(fn, rootfs)
 229#define device_initcall(fn)             __define_initcall(fn, 6)
 230#define device_initcall_sync(fn)        __define_initcall(fn, 6s)
 231#define late_initcall(fn)               __define_initcall(fn, 7)
 232#define late_initcall_sync(fn)          __define_initcall(fn, 7s)

 234#define __initcall(fn) device_initcall(fn)

红色 标识 出 __initcall 用到的部分 ;

编译:

234 行 -  __initcall 其实就是  device_initcall 

229 - device_initcall  是 __define_initcall(fn, 6 )  // 6 标识 id ;

200  -  __define_initcall(fn, id) 是  __define_initcall(fn, id, .initcall##id )  // 即 __define_initcall(fn, 6 , initcall6 ) ; 

195 - __define_initcall(fn , id, sec)  做出定义 

      static    initcall_t        __initcall_fn6    __used  __attribute__((__section__(  initcall6.init ))    =   fn

 

只需要将上面的 fn 替换为 module_init(xx) 中填入的 xx 即可。

示例: module_init (i2c_init) ; 

static  int    __initcall_i2c_init6     __used          __attribute__((__section__(  initcall6.init ))    =   i2c_init ; 

在 initcall6.init  这个 section 里面定义了一个函数指针变量  __initcall_i2c_init6  , 指针赋值为  i2c_init 函数地址; 

调用

do_basic_setup -> do_initcalls  里面会 遍历  __initcall6.init 这个section 里面的函数指针,一个个调用 对应的函数; 即会调用到  i2c_init 函数 ; 

 

作为 外部 xx.ko 模块时的module_init 

编译

module_init(xx)  即是 希望 在 insmod xx.ko 时 调用 xx 函数; 

 131#define module_init(initfn)                                     \
 132        static inline initcall_t __maybe_unused __inittest(void)                \
 133        { return initfn; }                                      \
 134        int init_module(void) __copy(initfn) __attribute__((alias(#initfn)));

 

132  定义 一个 static  inline 的函数; 返回值 为 initcall_t  即 int ;  名称为   __inittest ; 

   static  inline  int  __inittest(){

            return initfn ; 

   }

  这个的关键 在于  检查 返回值;   如果  initfn 返回值 不是 int , 就会打印错误信息; 

GPIO/fsl-gpio.c:46: warning: return from incompatible pointer type

 

133 行  - 为  initfn 定义一个别名函数    init_module  ; 关于gcc alias 定义别名函数, 参考这儿

https://www.cnblogs.com/zhangzhiwei122/p/16125210.html

 

这样,每个 xx.ko 里面肯定有一个 函数   init_module , 它是代码中的   module_init(xx) 定义的函数的别名 ;

调用流程

insmod 调用 init_module 函数

/include/linux/module.h 有 module 结构体定义; 里面有 init 指针,指向 模块的 init 函数; 

 361struct module {
 362        enum module_state state;

 
 423        /* Startup function. */
 424        int (*init)(void);

在 kernel/module.c 中  do_init_module 函数 会 触发  mod->init 函数的调用。

3604static noinline int do_init_module(struct module *mod)
3605{

3622        do_mod_ctors(mod);
3623        /* Start the module */
3624        if (mod->init != NULL)
3625                ret = do_one_initcall(mod->init);

 

从 insertmod 到  do_init_module 的过程,参考:

 

模块加载流程上

https://blog.csdn.net/lidan113lidan/article/details/119813256

模块加载流程下

https://blog.csdn.net/lidan113lidan/article/details/119813552

 

do_one_initcall 就是 init/main.c 中定义的,之前在 do_initcalls 里面也使用的,调用 1 个 init 函数; 

1207int __init_or_module do_one_initcall(initcall_t fn)
1208{
1209        int count = preempt_count();
1210        char msgbuf[64];
1211        int ret;
1212
1213        if (initcall_blacklisted(fn))
1214                return -EPERM;
1215
1216        do_trace_initcall_start(fn);
1217        ret = fn();
1218        do_trace_initcall_finish(fn, ret);
1219
1220        msgbuf[0] = 0;
1221
1222        if (preempt_count() != count) {
1223                sprintf(msgbuf, "preemption imbalance ");
1224                preempt_count_set(count);
1225        }
1226        if (irqs_disabled()) {
1227                strlcat(msgbuf, "disabled interrupts ", sizeof(msgbuf));
1228                local_irq_enable();
1229        }
1230        WARN(msgbuf[0], "initcall %pS returned with %s\n", fn, msgbuf);
1231
1232        add_latent_entropy();
1233        return ret;
1234}

 

下一篇:

设备驱动-i2c驱动-module_i2c_driver的使用

https://www.cnblogs.com/zhangzhiwei122/p/16125079.html

 

posted @ 2022-04-10 12:55  张志伟122  阅读(998)  评论(0编辑  收藏  举报