【linux】驱动-2-内核模块
前言
- 以野火i.M 6U为例
2. 内核模块
本章节笔记主要理解内核模块代码框架和原理,分析一个简单的内核模块例子。
需要明确的是模块和驱动是两回事。
2.1 内核模块概念
2.1.1 内核
内核,是一个操作系统的核心。是基于硬件的第一层软件扩充,提供操作系统的最基本的功能, 是操作系统工作的基础,决定着整个操作系统的性能和稳定性。
内核按照体系结构分为:微内核和宏内核。
- 参考图:
2.1.2 内核模块机制的引入
提高系统灵活性,在调试驱动的时候不需要重新编译内核,也不需要重新启动内核,只需要插入需要调试的驱动即可。
内核模块的特点:
- 模块本身不被编译入内核映像,这控制了内核的大小。
- 模块一旦被加载,它就和内核中的其它部分完全一样。
2.2 内核模块
内核模块编译后会得到一个 .ko 的 ELF 文件。(ELF 文件可以百度一下,也可以参考野火的内核模块章节。)
ELF 文件:这类文件包含了代码和数据,可以被用来链接成可执行文件或共享目标文件,静态链接库也可以归为这一类。
2.2.1 内核模块参考例程
必须内容可分为以下几点:
- 入口函数:当通过insmod或modprobe命令加载内核模块时,模块的加载函数就会自动被内核执行,完成本模块相关的初始化工作。
- 出口函数:执行rmmod命令卸载模块时,模块卸载函数就会自动被内核自动执行,完成相关清理工作。
- 协议:许可证声明描述内核模块的许可权限,如果模块不声明,模块被加载时,将会有内核被污染的警告。
非必须内容:
- 模块参数:模块参数是模块被加载时,可以传值给模块中的参数。
- 模块导出符号: 模块可以导出准备好的变量或函数作为符号,以便其他内核模块调用。
- 模块的其他相关信息: 可以声明模块作者等信息。
hello_module.c
/** @file hello_module.c
* @brief 简要说明
* @details 详细说明
* @author lzm
* @date 2021-02-21 18:08:07
* @version v1.0
* @copyright Copyright By lizhuming, All Rights Reserved
*
**********************************************************
* @LOG 修改日志:
**********************************************************
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
// 入口函数:安装驱动时调用的函数
static int __init hello_init(void)
{
printk(KERN_EMERG "[ KERN_EMERG ] Hello Module Init\n");
printk( "[ default ] Hello Module Init\n");
return 0;
}
// 出口函数:卸载驱动时调用的函数
static void __exit hello_exit(void)
{
printk("[ default ] Hello Module Exit\n");
}
module_init(hello_init);
module_exit(hello_exit);
//MODULE_LICENSE("GPL2");
MODULE_AUTHOR("embedfire ");
MODULE_DESCRIPTION("hello world module");
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 | grep calculation
最后在/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为要导出的标志
调用方法(例子):
extern int name;
2.2.5 模块参数
模块参数:模块参数是模块被加载时,可以传值给模块中的参数。
Linux内核提供一个宏来实现模块的参数传递:
#define module_param(name, type, perm) module_param_named(name, name, type, perm)
#define module_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:表示的是该文件的权限,具体参数值见下表:
对应用户 | 字符 | 说明 |
---|---|---|
当前用户 | S_IRUSR | 用户具有读权限 |
当前用户 | S_IWUSR | 用户具有写权限 |
当前用户组 | S_IRGRP | 当前用户组的其它用户拥有读权限 |
当前用户组 | S_IWGRP | 当前用户组的其它用户拥有写权限 |
其它用户 | S_IROTH | 其它用户具有读权限 |
其它用户 | S_IWOTH | 其它用户具有写权限 |
模块参数使用示例
模块源码:
static int nameA=0;
module_param(nameA,int,0);
static bool nameB=0;
module_param(nameB,bool,0644);
加载模块后,会在路径 /sys/module/模块名/parameters 下存在以模块参数为名的文件。(注:若文件权限为0,则无法查看该文件,也不会显示在该路径)
参考
- 李柱明博客园
- 野火
【linux】驱动-2-内核模块的更多相关文章
- Linux驱动设计—— 内核模块(一)
Linux内核理论基础 组成Linux内核的5个子系统:进程调度(SCHED)/内存管理(MM)/虚拟文件系统(VFS)/网络接口(NET)/进程间通信(IPC). 进程调度(SCHED) 在设备驱动 ...
- linux 驱动学习笔记04--简单驱动
首先贴代码helloworld.c和Makefile /************************************************************************ ...
- Linux驱动学习之常用的模块操作命令
1.常用的模块操作命令 (1)lsmod(list module,将模块列表显示),功能是打印出当前内核中已经安装的模块列表 (2)insmod(install module,安装模块),功能是向当前 ...
- linux 驱动学习笔记01--Linux 内核的编译
由于用的学习材料是<linux设备驱动开发详解(第二版)>,所以linux驱动学习笔记大部分文字描述来自于这本书,学习笔记系列用于自己学习理解的一种查阅和复习方式. #make confi ...
- linux驱动的入口函数module_init的加载和释放【转】
本文转载自:http://blog.csdn.net/zhandoushi1982/article/details/4927579 就像你写C程序需要包含C库的头文件那样,Linux内核编程也需要包含 ...
- Linux驱动设计—— 中断与时钟
中断和时钟技术可以提升驱动程序的效率 中断 中断在Linux中的实现 通常情况下,一个驱动程序只需要申请中断,并添加中断处理函数就可以了,中断的到达和中断函数的调用都是内核实现框架完成的.所以程序员只 ...
- Linux 驱动开发
linux驱动开发总结(一) 基础性总结 1, linux驱动一般分为3大类: * 字符设备 * 块设备 * 网络设备 2, 开发环境构建: * 交叉工具链构建 * NFS和tftp服务器安装 3, ...
- Linux驱动面试题
1. Linux设备中字符设备与块设备有什么主要的区别?请分别列举一些实际的设备说出它们是属于哪一类设备. 字符设备:字符设备是个能够像字节流(类似文件)一样被访问的设备,由字符设备驱动程序来实现这种 ...
- Linux驱动开发必看详解神秘内核(完全转载)
Linux驱动开发必看详解神秘内核 完全转载-链接:http://blog.chinaunix.net/uid-21356596-id-1827434.html IT168 技术文档]在开始步入L ...
- linux驱动之一语点破天机
<const 关键字> 在嵌入式系开发中,const关键字就是“只读”的意思 <为什么要ARM需要进行C语言环境的初始化> 在汇编情况下,指令的跳转,保护现场需要保存的数据 ...
随机推荐
- event duplication bind bug & h5 dataset flag solution
event duplication bind bug & h5 dataset flag solution https://codepen.io/xgqfrms/full/PaRBEy/ OK ...
- 二叉搜索树 & 二叉树 & 遍历方法
二叉搜索树 & 二叉树 & 遍历方法 二叉搜索树 BST / binary search tree https://en.wikipedia.org/wiki/Binary_searc ...
- 视屏剪辑软件 & free video editor
视屏剪辑软件 & free video editor purpose add animation keyframe to tutorials video vlog demos tutorial ...
- yarn & uninstall global & yarn global remove
yarn uninstall global yarn global remove https://yarnpkg.com/lang/en/docs/cli/remove/ https://yarnpk ...
- how to auto open a url in the browser by using terminal
how to auto open a url in the browser by using terminal Linux / MacOS # bash / zsh $ open http://loc ...
- ES6 Arrow Function return Object
ES6 Arrow Function return Object https://github.com/lydiahallie/javascript-questions/issues/220#issu ...
- how to change sketch language to chinese
how to change sketch language to Chinese https://www.sketch.com/support/troubleshooting/chinese-loca ...
- JMM内存模型相关笔记整理
JMM 内存模型是围绕并发编程中原子性.可见性.有序性三个特征来建立的 原子性:就是说一个操作不能被打断,要么执行完要么不执行,类似事务操作,Java 基本类型数据的访问大都是原子操作,long 和 ...
- 冷饭新炒:理解JWT的实现原理和基本使用
前提 这是<冷饭新炒>系列的第五篇文章. 本文会翻炒一个用以产生访问令牌的开源标准JWT,介绍JWT的规范.底层实现原理.基本使用和应用场景. JWT规范 很可惜维基百科上没有搜索到JWT ...
- MarkDown编辑器基础使用教程
教程原创链接 MarkDown 段落和换行 一个 Markdown 段落是由一个或多个连续的文本行组成,它的前后要有一个以上的空行(空行的定义是显示上看起来像是空的,便会被视为空行.比方说,若某一行只 ...