1.作用:类似于驱动模块,动态手动挂载到内存,减少内存使用量,提高速度
2.挂载,查看,删除命令:
insmod /xx(路径)/yy.ko 挂载名为yy的内核模块
lsmod 查看当前挂载的所有模块 可以看到上面挂载的模块yy
rmmod yy 删除挂载的模块yy ,此处不用加.ko后缀
3.内核模块编写框架:
头文件:#include<linux/init.h> <linux/module.h>
出入口:module_init(入口函数名)出口函数module_exit(出口函数名)
入出口函数: 定义 static int/void(入口/出口) nameXXX (viod)
最简单实例:#include<linux/init.h> #include<linux/module.h>
static int func_init(viod){ printk(KERN_INFO”hh\n”);return 0;}
static void func_exit(viod){ printk(KERN_INFO”pp\n”);}
module_init(func_init); module_exit(func_exit);
内核运行执行流程:使用insmod命令加载模块,函数module_init被调用
使用rmmod命令卸载模块,函数module_exit被调用
4.内核模块的手动编译Makefile书写:依赖于的的内核源码位置 编写的内核模块源码的位置 编译内核模块时使用的工具,环境
例:obj-m := modulename1.o modulename2.o#(最后生成相应的.ko,固定格式,如果有多个生成模块,就有对应的多个文件名)
modulename1-objs := file1.o file2.o ...
Modulename2-objs := file3.o file4.o ...
#(说明最后生成模块文件依赖的中间文件,modulename模块名与上面的obj-m指定的名字二者一样,固定格式,obj-m后面可以加多个生成的独立模块文件,如果生成的独立模块文件都只依赖于一个.c源文件,那么当模块的名字和源文件的名字一样时,可以不加这个环境变量,如果有不一样的或者依赖文件有多个,那么每一个名字不一样的模块都需要通过这种方式将它所依赖的所用中间文件列举出来)
KDIR := 内核源码所在路径 (编译模块需要内核源码支持)
all:
make -C $(KDIR) M=$(pwd) modules CROSS_COMPILE=arm-linux ARCH=arm
clean:
rm -rf *.o *.ko *.order *.symvers
注:obj-m,modulename-objs为固定格式的环境变量,modulename可以自定义名字,-C指定后面需要去哪个路径下执行make命令 后面的是对应的make命令参数,去那个路径下执行make命令,此时的工作路径并没有改变,M手动指定需要编译的驱动源文件
5.内核模块的项:
模块申明:
MODULE_LICENSE(”遵守的协议”)申明该模块遵守的许可证协议如:”GPL ”、”GPL v2”等等
MODULE_AUTHOR(“作者”)申明模块的作者
MODULE_DESCRIPTION(“模块的功能描述")申明模块的功能
MODULE_VERSION("V1.0")申明版本
模块参数:通过宏module_param(name,type,perm)将全局变量的值可以从外 部安装模块时获取
name:已经定义好的参数的名字
type:name指定参数的类型 整型int
字符串(定义还是用char*)charp 布尔bool
perm:对于参数的权限 S_IRUGO:读权限 S_IWUSR:写权限 用|或起来
例子:int a=3;char *p=NULL;
module_param(a,int,S_IRUGO|S_IWUSR);
module_param(p,charp,S_IRUGO|S_IWUSR);
使用命令insmod modulename.ko a=10 p=jj 那么全局变量在最开始就变成 了输入值,a原来的值3倍覆盖成10,如果不带对应变量的参数 那么变量 值不变,为代码里面的值
6.符号导出:为了实现模块与模块之间的的函数调用,变量调用方法一样
①:在一个模块中实现一个函数功能,假设函数名为symb_func
②:将函数中使用宏,将写好的函数导出
EXPORT_SYMBOL(symb_func);/EXPORT_SYMBOL_GPL(symb_func);
说明:其中EXPORT_SYMBOL_GPL只能用于包含GPL许可证的模块。
③:在需要使用函数的模块内加上extern方法声明,说明函数在外部
④:先安装实现定义函数模块,后安装使用函数的模块