前言

  • 以野火i.M 6U为例

2. 内核模块

本章节笔记主要理解内核模块代码框架和原理,分析一个简单的内核模块例子。

需要明确的是模块驱动是两回事。

2.1 内核模块概念

2.1.1 内核

内核,是一个操作系统的核心。是基于硬件的第一层软件扩充,提供操作系统的最基本的功能, 是操作系统工作的基础,决定着整个操作系统的性能和稳定性。

内核按照体系结构分为:微内核宏内核

  • 参考图:

2.1.2 内核模块机制的引入

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

内核模块的特点:

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

2.2 内核模块

内核模块编译后会得到一个 .koELF 文件。(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-内核模块的更多相关文章

  1. Linux驱动设计—— 内核模块(一)

    Linux内核理论基础 组成Linux内核的5个子系统:进程调度(SCHED)/内存管理(MM)/虚拟文件系统(VFS)/网络接口(NET)/进程间通信(IPC). 进程调度(SCHED) 在设备驱动 ...

  2. linux 驱动学习笔记04--简单驱动

    首先贴代码helloworld.c和Makefile /************************************************************************ ...

  3. Linux驱动学习之常用的模块操作命令

    1.常用的模块操作命令 (1)lsmod(list module,将模块列表显示),功能是打印出当前内核中已经安装的模块列表 (2)insmod(install module,安装模块),功能是向当前 ...

  4. linux 驱动学习笔记01--Linux 内核的编译

    由于用的学习材料是<linux设备驱动开发详解(第二版)>,所以linux驱动学习笔记大部分文字描述来自于这本书,学习笔记系列用于自己学习理解的一种查阅和复习方式. #make confi ...

  5. linux驱动的入口函数module_init的加载和释放【转】

    本文转载自:http://blog.csdn.net/zhandoushi1982/article/details/4927579 就像你写C程序需要包含C库的头文件那样,Linux内核编程也需要包含 ...

  6. Linux驱动设计—— 中断与时钟

    中断和时钟技术可以提升驱动程序的效率 中断 中断在Linux中的实现 通常情况下,一个驱动程序只需要申请中断,并添加中断处理函数就可以了,中断的到达和中断函数的调用都是内核实现框架完成的.所以程序员只 ...

  7. Linux 驱动开发

    linux驱动开发总结(一) 基础性总结 1, linux驱动一般分为3大类: * 字符设备 * 块设备 * 网络设备 2, 开发环境构建: * 交叉工具链构建 * NFS和tftp服务器安装 3, ...

  8. Linux驱动面试题

    1. Linux设备中字符设备与块设备有什么主要的区别?请分别列举一些实际的设备说出它们是属于哪一类设备. 字符设备:字符设备是个能够像字节流(类似文件)一样被访问的设备,由字符设备驱动程序来实现这种 ...

  9. Linux驱动开发必看详解神秘内核(完全转载)

    Linux驱动开发必看详解神秘内核 完全转载-链接:http://blog.chinaunix.net/uid-21356596-id-1827434.html   IT168 技术文档]在开始步入L ...

  10. linux驱动之一语点破天机

    <const 关键字> 在嵌入式系开发中,const关键字就是“只读”的意思   <为什么要ARM需要进行C语言环境的初始化> 在汇编情况下,指令的跳转,保护现场需要保存的数据 ...

随机推荐

  1. DC1(msf drupal7+suid-find提权)

    这边我们靶机是仅主机模式,IP是192.168.56.101,,直接上msf拿到shell,  不过payload要改一下 改成php/meterperter/bind_tcp 拿到shell了 ,采 ...

  2. 虚拟环境之间批量pip安装包"迁移"

    在某个虚拟环境中通过 pip freeze > requirements.txt 将该环境下所有的包写入文档, 然后切换至另一虚拟环境, pip install -r requirements. ...

  3. CSON vs JSON

    CSON vs JSON 今天在github浏览资料时,无意发现了这个很像json,却优于json的cson.故,再次分享给大家! 官方fork文档:https://github.com/xgqfrm ...

  4. 关于Google Chrome的使用小技巧!

    1 1 http://www.runoob.com/w3cnote/chrome-skip.html Chrome是Google公司开发的一个现代化的网页浏览器,作为三大浏览器之一 它搭载了被称为V8 ...

  5. HTTP2.0 的学习笔记

    1 1 1 HTTP2.0 1 11 1 1 1 1 1 1 超文本传输安全协议(英语:Hypertext Transfer Protocol Secure,缩写:HTTPS,也被称为HTTP ove ...

  6. Principle for iOS App Animation Design

    Principle for iOS App Animation Design Animate Your Ideas, Design Better Apps https://principleforma ...

  7. vue-parent-child-lifecycle-order

    vue-parent-child-lifecycle-order vue parent child lifecycle order live demo https://99kyx.csb.app/ h ...

  8. Webpack 4.x 默认支持 ES6 语法

    Webpack 4.x 默认支持 ES6 语法 Q: 为什么 webpack4 默认支持 ES6 语法的压缩? A: terser 里面实现了 ES6 语法的 AST解析. webpack 4 里使用 ...

  9. How to use JavaScript to implement precise setTimeout and setInterval

    How to use JavaScript to implement precise setTimeout and setInterval 如何使用 JavaScript 实现精确的 setTimeo ...

  10. 如何取消 Google Cloud Platform 试用 & 关闭 GCP 帐号 & 删除信用卡 & 取消订阅

    如何取消 Google Cloud Platform 试用 & 关闭 GCP 帐号 & 删除信用卡 & 取消订阅 关闭您的 Google Cloud Platform 帐号 s ...