这里仅仅是一个简单的说明,比较全面的说明可以查看开源书籍 lkmpg。
概述
Linux内核使用模块(Module)的方法使得需要的功能可以动态的方式被加载到内核中,它具有如下优点:
- 模块本身不被编译入内核镜像,可以灵活的控制内核大小
- 模块被加载后,和内核其他部分一样,也是通过函数的方式调用(宏内核)
基本操作
加载及卸载
1 2 3 4 5 6 7 8 9
| #加载模块 sudo insmod name.ko #以依赖的方式加载模块,这种方式默认模块位于 /lib/modules/<kernel> 目录下 sudo modprobe name.ko
#卸载模块 sudo rmmod name #以依赖的方式卸载模块 sudo modprobe -r name.ko
|
需要注意的是:当模块在卸载时,如果模块申请的资源没有被完全释放,那么下次再加载此模块时将有可能会出现各种错误。
Required key not available
在Linux内核4.4.0-20
之后(ubuntu16.04),默认打开了安全启动模式,也就是禁止第三方的模块加载。
所以需要关闭此安全启动模式:
1 2 3 4 5 6 7 8 9 10 11 12 13
| # # 方法1 # #简单粗暴的进入bios,然后关闭安全启动模式 # # 方法2 # sudo apt install mokutil #执行完此步骤后会输入一个8~16位密码 sudo mokutil --disable-validation #重启 #根据提示关闭安装启动模式(启动时可能不是输入密码,而是要你按照屏幕提示输入字符,和验证码一样) #再次重启
|
模块查看
- 使用
lsmod
命令可以获得系统中已加载的所有模块以及模块间的依赖关系。
- 此命令实际上是读取
/proc/modules
文件中的内容显示的
- 内核被加载后,也存在于
/sys/module/<module_name>
文件夹下。
refcnt
代表模块被引用的次数
sections
表示了模块的段信息,在进行GDB调试时,需要获取这些信息
parameters
中包含了模块中定义的参数变量,可以cat
出其值
- 使用
modinfo <module_name>.ko
可以查看模块信息
实例模版
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
|
#include <linux/init.h> #include <linux/module.h>
static char *module_name = "hello"; module_param(module_name, charp, S_IRUGO);
static int num = 1000; module_param(num, int, S_IRUGO);
static int hello_data __initdata = 1;
int add_integar(int a, int b) { return a + b; } EXPORT_SYMBOL_GPL(add_integar); int sub_integar(int a, int b) { return a - b; } EXPORT_SYMBOL_GPL(sub_integar);
static int __init hello_init(void) { printk(KERN_INFO "\n********************\n"); printk(KERN_INFO "[Hello world] module initialized! val = <%d>\n", hello_data); printk(KERN_INFO "module name = %s\n", module_name); printk(KERN_INFO "module num = %d\n", num); printk(KERN_INFO "********************\n");
return 0; } module_init(hello_init);
static void __exit hello_exit(void) { printk(KERN_INFO "\n********************\n"); printk(KERN_INFO "[Hello world] module exit!\n"); printk(KERN_INFO "********************\n"); } module_exit(hello_exit);
MODULE_AUTHOR("kcmetercec <kcmeter.cec@gmail.com>");
MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("A simple example module"); MODULE_ALIAS("a simplest module"); MODULE_VERSION("ver1.0");
|
编译(Makefile)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| KVERS = $(shell uname -r)
obj-m += example.o
build: kernel_modules
kernel_modules:
make -C /lib/modules/$(KVERS)/build M=$(CURDIR) modules
clean: make -C /lib/modules/$(KVERS)/build M=$(CURDIR) clean
|