Linux内核模块
Linux内核模块是可动态加载到正在运行的内核中、用于扩展其功能(如添加硬件驱动或文件系统支持)的代码片段,无需重新编译或重启整个系统。
一个简单的模块
- test.c示例如下:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/stat.h>
// 声明模块的通用许可证
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("Nrvcer");
MODULE_DESCRIPTION("A simple Linux module");
MODULE_VERSION("0.1");
// 向内核模块传递参数
short myshort = 10 ;
// S_IRUGO表示用户,组,其他用户可以读
module_param(myshort, short, S_IRUGO);
MODULE_PARM_DESC(myshort, "A short integer");
int myint = 10 ;
module_param(myint, int, S_IRUGO);
MODULE_PARM_DESC(myint, "An integer");
long mylong = 10 ;
module_param(mylong, long, S_IRUGO);
MODULE_PARM_DESC(mylong, "A long integer");
char *mycharp = "hello" ;
module_param(mycharp, charp, S_IRUGO);
MODULE_PARM_DESC(mycharp, "A character pointer");
int myarray[4] = {1, 2, 3, 4};
int size = sizeof(myarray) / sizeof(int);
module_param_array(myarray, int, &size, S_IRUGO);
MODULE_PARM_DESC(myarray, "An array of integers");
// 模块初始化函数
// insmod xxx.ko -> module_init() -> mymodule_init()
static int __init mymodule_init(void)
{
printk(KERN_INFO "Hello world!\n");
printk(KERN_INFO "myshort = %hd\n", myshort);
printk(KERN_INFO "myint = %d\n", myint);
printk(KERN_INFO "mylong = %ld\n", mylong);
printk(KERN_INFO "mycharp = %s\n", mycharp);
printk(KERN_INFO "myarray = %d, %d, %d, %d\n", myarray[0], myarray[1], myarray[2], myarray[3]);
return 0;
}
// 模块退出函数
// rmmod xxx.ko -> module_exit() -> mymodule_exit()
static void __exit mymodule_exit(void)
{
printk(KERN_INFO "Goodbye world!\n");
}
module_init(mymodule_init);
module_exit(mymodule_exit);
- Makefile如下所示:
$(warning KERNELRELEASE=$(KERNELRELEASE)) # 打印提示,打印变量内的值
ifeq ($(KERNELRELEASE),)
#KERNELDIR ?= /home/linux/emb2307/12-linuxsys/myir-imx-linux #交叉开发内核路径
KERNELDIR ?= /lib/modules/$(shell uname -r)/build # 本地开发, ubuntu22.04的路径,内核头文件目录
PWD := $(shell pwd) # 获取路径
modules:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
rm -rf *.o *~ core .depend .*.cmd *.mod *.mod.c .tmp_versions Module* modules*
modules_install:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install
clean:
rm -rf *.o *~ core .depend .*.cmd *.ko *.mod *.mod.c .tmp_versions Module* modules*
.PHONY: modules modules_install clean
else
MODULE_NAME ?= hello
obj-m := ${MODULE_NAME}.o
endif
- 编译:sudo make MODULE_NAME=test
- 查看信息:
wzh@wzh:~/code$ sudo dmesg -c
wzh@wzh:~/code$ sudo insmod test.ko
wzh@wzh:~/code$ sudo dmesg
[ 2800.124737] test: loading out-of-tree module taints kernel.
[ 2800.124751] test: module verification failed: signature and/or required key missing - tainting kernel
[ 2800.128365] Hello world!
[ 2800.128371] myshort = 10
[ 2800.128374] myint = 10
[ 2800.128376] mylong = 10
[ 2800.128377] mycharp = hello
[ 2800.128379] myarray = 1, 2, 3, 4
wzh@wzh:~/code$ lsmod | grep test
test 12288 0
wzh@wzh:~/code$ sudo rmmod test
wzh@wzh:~/code$ lsmod | grep test
wzh@wzh:~/code$ sudo dmesg
[ 2800.124737] test: loading out-of-tree module taints kernel.
[ 2800.124751] test: module verification failed: signature and/or required key missing - tainting kernel
[ 2800.128365] Hello world!
[ 2800.128371] myshort = 10
[ 2800.128374] myint = 10
[ 2800.128376] mylong = 10
[ 2800.128377] mycharp = hello
[ 2800.128379] myarray = 1, 2, 3, 4
[ 2877.839972] Goodbye world!
模块的相关操作
- 模块的安装
# 手动加载内核模块
insmod xxx.ko
# 动态加载内核模块
modprobe xxx.ko
- 查看模块信息:
# 显示后不清除信息
dmesg
# 显示后清除信息
dmesg -c
- 卸载模块:rmmod moduleName
- 查看系统中已经安装的模块:lsmod
浙公网安备 33010602011771号