module_init
/**
* 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.
*/
module_exit
/**
* 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.
*/
参考:![](https://i-blog.csdnimg.cn/blog_migrate/93cb210021442d092934b162058a80a5.png)
驱动基础(一)-- module_init,module_exit。-mjcc007-ChinaUnix博客
linux设备驱动中的module_init_linux module_init_飘忽不定的bug的博客-CSDN博客
module_init(linux kernel 宏函数之“模块的起点”) - 知乎 (zhihu.com)
Linux内核模块分析(module_init宏)_阿基米东的博客-CSDN博客
module_init解析_尚先生的博客的博客-CSDN博客
linux驱动加载流程分析_linux驱动加载过程_rayylee的博客-CSDN博客
ChatGPT
在Linux内核模块编程中,`module_init`和`module_exit`是两个宏,分别用来声明模块初始化函数和模块卸载函数。
- module_init: 定义加载模块时内核需要调用的初始化函数。当用`insmod`命令加载模块时,这个宏指定的函数会被执行。
- module_exit: 定义卸载模块时内核需要调用的清理函数。使用`rmmod`命令卸载模块时,这个宏指定的函数会被执行。
这两个宏定义在`linux/init.h`头文件中。在简单的模块中,这些函数通常执行如分配资源、设置初始状态、注册设备等操作,以及其相反的操作来释放资源和注销设备。
一个简单的模块示例如下:
#include <linux/module.h> // Needed by all modules
#include <linux/kernel.h> // Needed for KERN_INFO
#include <linux/init.h> // Needed for the macros
static int __init hello_start(void)
{
printk(KERN_INFO "Loading hello module...\n");
printk(KERN_INFO "Hello world\n");
return 0;
}
static void __exit hello_end(void)
{
printk(KERN_INFO "Goodbye Mr.\n");
}
module_init(hello_start);
module_exit(hello_end);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("A simple Hello World Kernel Module");
在上面的代码中:
- __init: 这是一个宏,指示编译器,初始化函数(如`hello_start`)只会在模块的初始化阶段被调用一次。加载之后,这部分内存可以被释放和重用。
- __exit: 这是一个宏,指示编译器,清理函数(如`hello_end`)在模块卸载时会被调用。这个标记对于内置到内核的模块是没有意义的(因为内置模块不会被卸载),所以它通常在与`module_exit`宏一起使用时被内核用来避免编译不必要的代码。
注意,加载模块代码到内核需要具有管理员权限。而且,模块必须与正在运行的内核版本和配置有兼容性,否则无法加载。在最近的Linux内核版本中,如果内核经过了模块签名,只有签名的模块才能被加载进内核,这是出于安全考虑的策略。