1.模块示例
首先,创建一个名为xuedaon.c的C源文件,内容如下:
#include <linux/module.h>
#include <linux/kernel.h>
static int __init xuedaon_init(void)
{
printk(KERN_INFO "modules init! ");
return 0;
}
static void __exit xuedaon_exit(void)
{
printk(KERN_INFO "modules exit! ");
}
module_init(xuedaon_init);
module_exit(xuedaon_exit);
MODULE_LICENSE("GPL"); //模块许可证(通常必须)
MODULE_DESCRIPTION(“Xuedaon Module”); //模块描述(可选)
MODULE_VERSION(“V1.0”); //模块版本(可选)
MODULE_ALIAS(“a simple module”); //模块别名(可选)
MODULE_AUTHOR(“xuedaon.com”); //模块开发作者(可选)
然后,创建一个名为Makefile的文件,内容如下:
KDIR= /lib/modules/$(uname -r)/build
default:
make -C $(KDIR) M=$(pwd) modules
clean:
make -C $(KDIR) M=$(pwd) modules
obj-m += xuedaon.o
这个Makefile文件定义了模块的名称和源文件。obj-m指定了模块名称。
接下来,打开终端并进入包含Makefile和源文件的目录,然后运行以下命令来编译模块:
make
这将在内核源代码树的相应目录下编译模块。编译完成后,会生成一个名为xuedaon.ko的模块文件。
要加载模块,可以使用以下命令:
sudo insmod xuedaon.ko
要卸载模块,可以使用以下命令:
sudo rmmod xuedaon
要查看系统中已插入模块,可以使用以下命令:
sudo lsmod
加载模块后,可以在内核日志中看到打印的消息,可以使用dmesg命令查看内核日志。
2.Makefile内容详解
make -C $(KDIR) M=moddir modules 是一个在Linux内核开发中常用的命令,用于编译内核模块。这个命令的各个部分的意义如下:
1.make: 调用 make 工具,它是用于自动化构建的工具。
2.-C $(KDIR): 这个选项告诉 make 工具更改到 $(KDIR)目录,并从那里开始执行。通常是内核源代码的目录。
3.M=moddir: 这个选项指定模块的源代码所在的路径。在内核开发中,有时模块的源代码并不直接位于内核源代码的相应目录下,而是位于另一个位置。使用 M= moddir可以告诉 make 工具去哪里查找模块的源代码。
4.modules: 这个目标告诉 make 工具要编译所有的模块。
综上所述,此命令为进入$(KDIR)目录,并从那里开始编译所有的模块,其中模块的源代码位于 moddir目录。
3.MODULE_LICENSE
MODULE_LICENSE() 是一个宏,通常在 Linux 内核模块的源代码中使用,用于声明模块的许可证类型。MODULE_LICENSE() 宏是用于在 Linux 内核模块中声明许可证信息的一种机制,它有助于确保模块遵循适当的许可协议并正确地与内核交互。
这个宏的目的是为了告知内核模块的许可证信息,以便内核可以正确地处理模块的许可要求。使用 MODULE_LICENSE() 宏可以帮助确保模块遵循适当的许可协议,并确保模块与内核的许可要求兼容。
例如,如果一个模块遵循 GNU General Public License (GPL),则可以在模块的源代码中使用 MODULE_LICENSE("GPL") 宏来声明这一点。这样,当内核加载和链接该模块时,它会检查模块的许可证是否与内核的许可证兼容,并根据需要进行相应的处理。
声明可以如下:
1."GPL" 是指明了 这是GNU General Public License的任意版本
2.“GPL v2” 是指明 这仅声明为GPL的第二版本
3."GPL and addtional"
4. "Dual BSD/GPL"
5.“Dual MPL/GPL"
6."Proprietary" 私有的
除非你的模块显式地声明一个开源版本,否则内核会默认你这是一个私有的模块(Proprietary)。
4.module_init和module_exit宏
module_init 是一个宏,用于在 Linux 内核模块中指定模块的初始化函数。当内核加载模块时,module_init 宏指定的函数将被调用,以便进行模块的初始化工作。
module_init 宏的语法如下:
module_init(function)
其中,function 是模块的初始化函数的名称。该函数必须具有以下原型:
int function(void)
当模块被加载时,内核将调用 module_init 宏指定的函数,并传递 NULL 作为参数。初始化函数应该返回一个整数值,表示模块的初始化状态。如果初始化成功,应该返回 0;如果初始化失败,可以返回一个负的错误代码。
module_exit 是一个宏,用于在 Linux 内核模块中指定模块的退出函数。当内核卸载模块时,module_exit 宏指定的函数将被调用,以便进行模块的清理工作。它的调用形式和module_init几乎一致,除了不用关注其返回值。
当模块被卸载时,内核将调用 module_exit 宏指定的函数,并传递 NULL 作为参数。退出函数应该执行模块所需的任何清理操作,例如释放资源或关闭设备驱动程序。