Linux API 分析- module_init与module_exit

【Linux API 分析】module_init与module_exit

Linux版本:4.19

1、前言

module_initmodule_exit用于我们驱动的加载,卸载,是我们驱动初始化/退出的入口函数。

下面主要分析一下这两个接口的底层实现。


2、调用层次分析

2.1 module_init

 #ifndef MODULE
 /**
  * module_init() - driver initialization entry point
  * @x: function to be run at kernel boot time or module insertion
  *
  * module_init() will either be called during do_initcalls() (if
  * builtin) or at module insertion time (if a module).  There can only
  * be one per module.
  */
 #define module_init(x)  __initcall(x);
 
 /**
  * module_exit() - driver exit entry point
  * @x: function to be run when driver is removed
  *
  * module_exit() will wrap the driver clean-up code
  * with cleanup_module() when used with rmmod when
  * the driver is a module.  If the driver is statically
  * compiled into the kernel, module_exit() has no effect.
  * There can only be one per module.
  */
 #define module_exit(x)  __exitcall(x);
 
 #else /* MODULE */
 
 /*
  * In most cases loadable modules do not need custom
  * initcall levels. There are still some valid cases where
  * a driver may be needed early if built in, and does not
  * matter when built as a loadable module. Like bus
  * snooping debug drivers.
  */
 #define early_initcall(fn)      module_init(fn)
 #define core_initcall(fn)       module_init(fn)
 #define core_initcall_sync(fn)      module_init(fn)
 #define postcore_initcall(fn)       module_init(fn)
 #define postcore_initcall_sync(fn)  module_init(fn)
 #define arch_initcall(fn)       module_init(fn)
 #define subsys_initcall(fn)     module_init(fn)
 #define subsys_initcall_sync(fn)    module_init(fn)
 #define fs_initcall(fn)         module_init(fn)
 #define fs_initcall_sync(fn)        module_init(fn)
 #define rootfs_initcall(fn)     module_init(fn)
 #define device_initcall(fn)     module_init(fn)
 #define device_initcall_sync(fn)    module_init(fn)
 #define late_initcall(fn)       module_init(fn)
 #define late_initcall_sync(fn)      module_init(fn)
 
 #define console_initcall(fn)        module_init(fn)
 #define security_initcall(fn)       module_init(fn)
 
 /* Each module must use one module_init(). */
 #define module_init(initfn)                 
     static inline initcall_t __maybe_unused __inittest(void)        
     { return initfn; }                  
     int init_module(void) __copy(initfn) __attribute__((alias(#initfn)));
 
 /* This is only required if you want to be unloadable. */
 #define module_exit(exitfn)                 
     static inline exitcall_t __maybe_unused __exittest(void)        
     { return exitfn; }                  
     void cleanup_module(void) __copy(exitfn) __attribute__((alias(#exitfn)));
 
 #endif


2.2 __initcall

 #define __initcall(fn) device_initcall(fn)
 
 #define __exitcall(fn)                      
     static exitcall_t __exitcall_##fn __exit_call = fn


2.3 device_initcall

 #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)  
   
 #define __initcall(fn) device_initcall(fn)  


2.4 ___define_initcall

 #ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS
 #define ___define_initcall(fn, id, __sec)           
     __ADDRESSABLE(fn)                   
     asm(".section   "" #__sec ".init", "a"  
" 
     "__initcall_" #fn #id ":            
" 
         ".long  " #fn " - .         
" 
         ".previous                  
");
 #else
 #define ___define_initcall(fn, id, __sec) 
     static initcall_t __initcall_##fn##id __used 
         __attribute__((__section__(#__sec ".init"))) = fn;
 #endif


2.5、module_init调用顺序汇总

 module_init
     ---> __initcall
         ---> device_initcall
             ---> __define_initcall(include/linux/init.h)
                 ---> ___define_initcall(/include/linux/init.h)

综上,我们调用顺序:module_init(fn)---> initcall(fn) ---> device_initcall(fn) ---> define_initcall(fn, 6)


3、源码分析

通过上面了解,我们最后调用的是___define_initcall的函数,下面我们主要分析该函数的意义。

了解之前呢,我们先来学习一下###的作用!


3.1 # 与 ## 的作用

符号

作用

举例

##

“##”符号 可以是连接的意思

例如 initcall_##fn##id 为initcall_fnid那么,fn = test_init,id = 6时, initcall_##fn##id为 initcall_test_init6

#

“#”符号 可以是字符串化的意思

例如 #id 为 “id”,id=6 时,#id 为“6”


3.2 __define_initcall

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

这里我们以module_init(test_init)为例,转换后的结果为:

 static initcall_t __initcall_test_init6 __used __attribute__((__section__(".initcall6.init"))) = test_init

通过__attribute__(__section__)设置函数属性,将test_init放在字段.initcall6.init中。


该字段通过链接器链接起来,形成一个列表进行统一管理。

 ......
 __initcall6_start = .; KEEP(*(.initcall6.init)) KEEP(*(.initcall6s.init)) 
 ......

还记得__define_initcall的定义吗?

#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)  
  
#define __initcall(fn) device_initcall(fn) 

不同的宏定义,被赋予了不同的调用等级,最后将不同的驱动初始化函数统一汇总到__initcallx_start字段统一管理,形成一个有序的列表。

这样,我们在内核中,按照顺序遍历这个列表,最后执行对应的模块初始化函数fn即可实现驱动的初始化。

这篇内容主要分析module_init的调用以及作用,后续再详细分析内核是如何调用初始化函数的。


展开阅读全文

页面更新:2024-05-12

标签:时调   字段   初始化   内核   函数   符号   顺序   模块   作用   列表

1 2 3 4 5

上滑加载更多 ↓
推荐阅读:
友情链接:
更多:

本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828  

© CopyRight 2008-2024 All Rights Reserved. Powered By bs178.com 闽ICP备11008920号-3
闽公网安备35020302034844号

Top