Linux版本:4.19
module_init与module_exit用于我们驱动的加载,卸载,是我们驱动初始化/退出的入口函数。
下面主要分析一下这两个接口的底层实现。
#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
#define __initcall(fn) device_initcall(fn)
#define __exitcall(fn)
static exitcall_t __exitcall_##fn __exit_call = fn
#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)
#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
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)
通过上面了解,我们最后调用的是___define_initcall的函数,下面我们主要分析该函数的意义。
了解之前呢,我们先来学习一下#与##的作用!
符号 | 作用 | 举例 |
## | “##”符号 可以是连接的意思 | 例如 initcall_##fn##id 为initcall_fnid那么,fn = test_init,id = 6时, initcall_##fn##id为 initcall_test_init6 |
# | “#”符号 可以是字符串化的意思 | 例如 #id 为 “id”,id=6 时,#id 为“6” |
#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
本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828
© CopyRight 2008-2024 All Rights Reserved. Powered By bs178.com 闽ICP备11008920号-3
闽公网安备35020302034844号