昆仑山

首页 » 问答 » 常识 » linux驱动2内核模块
TUhjnbcbe - 2025/4/13 18:52:00
北京最好的治疗白癜风医院 http://www.txbyjgh.com/m/

目录

前言2.内核模块2.1内核模块概念2.1.1内核2.1.2内核模块机制的引入2.2内核模块2.2.1内核模块参考例程2.2.2内核模块命令2.2.3系统自动加载模块**2.2.4导出符号2.2.5模块参数参考

前言

以野火i.M6U为例2.内核模块

本章节笔记主要理解内核模块代码框架和原理,分析一个简单的内核模块例子。需要明确的是模块和驱动是两回事。

2.1内核模块概念

2.1.1内核

内核,是一个操作系统的核心。是基于硬件的第一层软件扩充,提供操作系统的最基本的功能,是操作系统工作的基础,决定着整个操作系统的性能和稳定性。内核按照体系结构分为:微内核和宏内核。

参考图:

2.1.2内核模块机制的引入

提高系统灵活性,在调试驱动的时候不需要重新编译内核,也不需要重新启动内核,只需要插入需要调试的驱动即可。内核模块的特点:

模块本身不被编译入内核映像,这控制了内核的大小。模块一旦被加载,它就和内核中的其它部分完全一样。2.2内核模块

内核模块编译后会得到一个.ko的ELF文件。(ELF文件可以百度一下,也可以参考野火的内核模块章节。)ELF文件:这类文件包含了代码和数据,可以被用来链接成可执行文件或共享目标文件,静态链接库也可以归为这一类。

2.2.1内核模块参考例程

必须内容可分为以下几点:

入口函数:当通过insmod或modprobe命令加载内核模块时,模块的加载函数就会自动被内核执行,完成本模块相关的初始化工作。出口函数:执行rmmod命令卸载模块时,模块卸载函数就会自动被内核自动执行,完成相关清理工作。协议:许可证声明描述内核模块的许可权限,如果模块不声明,模块被加载时,将会有内核被污染的警告。非必须内容:

模块参数:模块参数是模块被加载时,可以传值给模块中的参数。模块导出符号:模块可以导出准备好的变量或函数作为符号,以便其他内核模块调用。模块的其他相关信息:可以声明模块作者等信息。hello_module.c

/**

filehello_module.c*

brief简要说明*

details详细说明*

authorlzm*

date-02-:08:07*

versionv1.0*

copyrightCopyrightBylizhuming,AllRightsReserved************************************************************

LOG修改日志:***********************************************************/#includelinux/module.h#includelinux/init.h#includelinux/kernel.h//入口函数:安装驱动时调用的函数staticint__inithello_init(void){printk(KERN_EMERG[KERN_EMERG]HelloModuleInit\n);printk([default]HelloModuleInit\n);return0;}//出口函数:卸载驱动时调用的函数staticvoid__exithello_exit(void){printk([default]HelloModuleExit\n);}module_init(hello_init);module_exit(hello_exit);//MODULE_LICENSE(GPL2);MODULE_AUTHOR(embedfire);MODULE_DESCRIPTION(helloworldmodule);MODULE_ALIAS(test_module);2.2.2内核模块命令

insmod:插入模块:insmod+模块完整路径。modprobe:插入模块,insmod具备同样的功能,同样可以将模块加载到内核中,除此以外modprobe还能检查模块之间的依赖关系,并且按照顺序加载这些依赖,可以理解为按照顺序多次执行insmod。depmod:创建模块依赖文件。modprobe是怎么知道一个给定模块所依赖的其他的模块呢?在这个过程中,depmod起到了决定性作用,当执行modprobe时,它会在模块的安装目录下搜索module.dep文件,这是depmod创建的模块依赖关系的文件。rmmod:删除模块:insmod+模块名称。lsmod:查看所有模块。modinfo:显示模块中的几个宏的定义。如协议、作者等等。

2.2.3系统自动加载模块**

让系统自动加载模块需要用到命令depmod和modprobe。

首先需要将我们想要自动加载的模块统一放到/lib/modules/内核版本目录下,内核版本使用uname-r查询;其次使用depmod建立模块之间的依赖关系,命令depmod-a;这个时候我们就可以在modules.dep中看到模块依赖关系,可以使用如下命令查看:

cat/lib/modules/内核版本/modules.dep

grepcalculation最后在/etc/modules加上我们自己的模块。

注意在该配置文件中,模块不写成.ko形式代表该模块与内核紧耦合,有些是系统必须要跟内核紧耦合,比如mm子系统,一般写成.ko形式比较好,如果出现错误不会导致内核出现panic错误,如果集成到内核,出错了就会出现panic。然后重启开发板,使用命令lsmod即可查看我们的模块开机就被加载到内核了。2.2.4导出符号

实际上,符号指的就是内核模块中使用EXPORT_SYMBOL声明的函数和变量。当模块被装入内核后,它所导出的符号都会记录在公共内核符号表中。可供给其它模块使用。导出方法:

符号必须在模块文件的全局部分导出,不能在函数中使用。_GPL使得导出的模块只能被GPL许可的模块使用。编译我们的模块时,这两个宏会被拓展为一个特殊变量的声明,存放在ELF文件中。具体也就是存放在ELF文件的符号表中:st_name:是符号名称在符号名称字符串表中的索引值;st_value:是符号所在的内存地址;st_size:是符号大小;st_info:是符号类型和绑定信息;st_shndx:表示符号所在section。EXPORT_SYMBOL(name)EXPORT_SYMBOL_GPL(name)//name为要导出的标志调用方法(例子):

externintname;2.2.5模块参数

模块参数:模块参数是模块被加载时,可以传值给模块中的参数。

Linux内核提供一个宏来实现模块的参数传递:

#definemodule_param(name,type,perm)module_param_named(name,name,type,perm)#definemodule_param_array(name,type,nump,perm)module_param_array_named(name,name,type,nump,perm)name:我们定义的变量名;type:参数的类型,目前内核支持的参数类型有byte,short,ushort,int,uint,long,ulong,charp,bool,invbool。其中charp表示的是字符指针,bool是布尔类型,其值只能为0或者是1;invbool是反布尔类型,其值也是只能取0或者是1,但是true值表示0,false表示1。变量是char类型时,传参只能是byte,char*时只能是charp。perm:表示的是该文件的权限,具体参数值见下表:

模块参数使用示例模块源码:

staticintnameA=0;module_param(nameA,int,0);staticboolnameB=0;module_param(nameB,bool,);加载模块后,会在路径/sys/module/模块名/parameters下存在以模块参数为名的文件。(注:若文件权限为0,则无法查看该文件,也不会显示在该路径)

参考

李柱明博客园野火文章转载自:

1
查看完整版本: linux驱动2内核模块