模块参数

我们在运行用户空间的程序的时候可以接参数,驱动程序也可以接参数运行。参数在加载模块的时候指定,在模块代码中用module_param(参数名,参数类型,参数读写权限)来为模块定义参数。具体用法看代码如下:

#include <linux/init.h>
#include <linux/module.h>static char* str = "hello";
static int value = 1;static int hello_init(void) {printk(KERN_EMERG "hello_init str: %s\n", str);return 0;
}static void hello_exit(void) {printk(KERN_EMERG "hello_exit value: %d\n", value);
}module_param(value, int, 0644);
module_param(str, charp, 0644);module_init(hello_init);
module_exit(hello_exit);MODULE_LICENSE("GPL");

上面的驱动在加载的时候就可以将a的值通过参数来指定,命令如下

sudo insmod hello.ko value=5 str="vegeta"

这样在加载模块时就会打印str=vegeta,卸载模块时打印value=5。

sysfs
sysfs是内核给资源创建的目录或者文件,模块会在/sys/module下创建一个跟模块名称一样的目录,目录在模块卸载的时候也会被一并删除掉。
例如上述hello模块加载之后,就会生成/sys/module/hello目录,在其中存放hello模块的资源信息。
上述模块传参中使用的str/value,会在/sys/module/hello/parameters目录下创建两个文件,跟参数名称一致

str和value中存放的的内容跟我们传参的内容是一致的

我所使用的版本,vim是可以修改value和str的内容的,并且是能生效的。例如当你修改了value之后,卸载模块打印的就是你修改之后的值了。

模块的文件格式

通过命令file hello.ko来查看模块是以何种格式存储在硬盘中。基本可以分为如下几个结构

名称 释义
ELF Header 描述整个文件的基本属性
.text 代码段,存放文件的代码部分
.data 数据段,存放已经初始化的数据等
.Section Table 描述了ELF文件包含的所有段的信息
.symtab 符号表,映射函数到真实内存地址的数据结构,就像一个字典,记录了在编译阶段无法确定地址的函数,在模块加载的时候由系统赋予真实的地址

模块通信(符号导出)

需要实现2个模块,目标是模块1(add_sub.ko)提供函数供模块2(hello.ko)来进行调用。
具体实现方式是将模块1的符号表提供给模块2,从而使得模块2能调用到模块1的函数和变量等。

模块(add_sub.ko)代码

/*模块1代码 add_sub.c,提供2个函数供其他模块调用*/
#include <linux/module.h>
#include <linux/init.h>int add_integer(int value1, int value2) {printk(KERN_EMERG "add_integer value1:%d value2:%d \n", value1, value2);return value1 + value2;
}int sub_integer(int value1, int value2) {printk(KERN_EMERG "sub_integer value1:%d value2:%d \n", value1, value2);return value1 - value2;
}static int add_sub_init(void) {return 0;
}static void add_sub_exit(void) {}EXPORT_SYMBOL(add_integer);
EXPORT_SYMBOL(sub_integer);module_init(add_sub_init);
module_exit(add_sub_exit);MODULE_LICENSE("GPL");

模块1提供了加和减(add_integer/sub_integer)2个函数,这2个函数需要导出到内核符号表,才能被其他模块调用。EXPORT_SYMBOL()就是导出宏,就是定义函数能够被其他模块调用到。要注意的是内核函数很多,不能出现重名。但是编译器认为所有模块的函数都是私有的,不同模块之间出现重名不影响编译,所以如果只是模块自己内部使用的话不需要担心重名问题。

模块2(hello.ko)代码

/*模块2代码 hello.c,调用模块1的函数*/
/*模块2代码 hello.c,调用模块1的函数*/
#include <linux/module.h>
#include <linux/init.h>static int value1 = 2;
static int value2 = 1;extern int add_integer(int value1, int value2);
extern int sub_integer(int value1, int value2);static int hello_init(void) {int result = add_integer(value1, value2); /*调用模块1的函数*/printk(KERN_EMERG "hello_init value1:%d value2:%d result: %d\n", value1, value2, result);return 0;
}static void hello_exit(void) {int result = sub_integer(value1, value2); /*调用模块1的函数*/printk(KERN_EMERG "hello_exit value1:%d value2:%d result: %d\n", value1, value2, result);
}module_init(hello_init);
module_exit(hello_exit);MODULE_LICENSE("GPL");

模块2在加载的时候调用模块1的加法,卸载的时候调用模块2的减法。

模块通信的编译
add_sub模块的编译的Makefile与上一篇的hello world程序没有差异,直接可用。但是hello模块的Makefile需要修改一下,加上KBUILD_EXTRA_SYMBOLS否则会报错找不到add_sub两个函数的实现。Makefile如下:

ifneq ($(KERNELRELEASE),)
obj-m := hello.o
else
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
KBUILD_EXTRA_SYMBOLS += ./Modules.symvers
export KBUILD_EXTRA_SYMBOLSall:make -C $(KDIR) M=$(PWD) modules
clean:rm -rf *.o *~ codre .depend .*.cmd *.ko *.mod *.mod.c *.tmp_versions *.order *.symvers .cache.mk .tmp_versions
endif

编译的步骤为:

  1. 编译add_sub模块
  2. 将add_sub模块生成的Module.symvers复制到hello模块Makefile同级目录下
  3. 编译hello模块

模块通信测试

在加载的时候需要先加载add_sub.ko再加载hello.ko。在hello.ko加载的时候调用add_sub.ko中的加法,卸载的时候调用add_sub.ko中的减法。输出log如下

模块的加载过程解释

模块1(add_sub.ko)的加载过程:
1、内核为模块1分配空间,将模块的代码和数据装入分配的内存中
2、内核发现模块1的符号表中有函数可以导出,就将其内存地址记录在内核的符号表中

模块2(hello.ko)的加载过程:
1、内核为模块2分配空间,将模块的代码和数据装入分配的内存中
2、内核在模块2的符号表中发现一些未解析的函数。所以查找内核符号表找到对应的函数,将函数的地址填到模块2的符号表中,这个地址就是模块1中的函数地址。
通过上述的操作,就可以实现模块之间函数的调用

【2】模块参数与模块之间的通信相关推荐

  1. insmod module_param 模块参数

    模块参数 引导模块时,可以向它传递参数.要使用模块参数加载模块,这样写: insmod module.ko [param1=value param2=value ...] 为了使用这些参数的值,要在模 ...

  2. HC-05(ZS-040)蓝牙模块使用详情(蓝牙模块配置、手机蓝牙控制单片机、蓝牙与蓝牙之间的通信)含51、32程序

    HC-05是一款主从一体化的蓝牙模块,因此其使用起来比较方便,只需要进行简单的配置即可. 本文就手把手的介绍小白入手模块后如何使用. 对于模块使用:1.蓝牙配置→2.手机与蓝牙的传输→3.手机通过蓝牙 ...

  3. linux 内核空间 sy,在 Linux 下用户空间与内核空间数据交换的方式,第 1 部分: 内核启动参数、模块参数与sysf...

    级别: 初级 燚 杨 (), 计算机科学硕士 2006 年 2 月 16 日 本系列文章包括两篇,它们文详细地介绍了 Linux 系统下用户空间与内核空间数据交换的九种方式,包括内核启动参数.模块参数 ...

  4. Python命令行参数解析模块getopt使用实例

    这篇文章主要介绍了Python命令行参数解析模块getopt使用实例,本文讲解了使用语法格式.短选项参数实例.长选项参数实例等内容,需要的朋友可以参考下 格式 getopt(args, options ...

  5. ESP8266调试-P2P(AP模块与STA模块通信)

    ESP8266调试-P2P(AP模块与STA模块通信) ESP8266有三种模式可以选择,AP/STA/AP+STA, 下面我们要实现的是模块与模块之间点对点的通信 通信的三个过程 1. 建立WiFi ...

  6. python getopt使用_Python命令行参数解析模块getopt使用实例

    这篇文章主要介绍了Python命令行参数解析模块getopt使用实例,本文讲解了使用语法格式.短选项参数实例.长选项参数实例等内容,需要的朋友可以参考下 格式 getopt(args, options ...

  7. 电平是什么?单片机的I/0口输入和输出,1和0是什么?什么是TTL电平?TTL电平分析?TTL、CMOS、RS232、RS485电平差异?usb转ttl?CH340模块驱动安装?电平之间的转换?

    电平是什么 理想的数字电路电平是这样的: 输入小于1/2VCC(电源电压)就是低电平,反之是高电平.实际的器件是做不到的,也不实用,如果输入电压在1/2VCC附近有干扰,就会发生错误的输入信号.现在常 ...

  8. 简述GPRS模块和GSM模块之间的区别

    GSM模块是将GSM射频芯片,基带处理芯片,存储器,放大器设备等集成在基板上的功能模块,以提供独立的OS,GSM射频处理,基带处理和标准接口. 简单来讲,GPRS无线模块就是将串口通讯转为GPRS无线 ...

  9. 三菱fx3u使用st语言adprw指令通过485-adp-mb模块与台达变频器进行通信

    三菱fx3u使用st语言adprw指令通过485-adp-mb模块与台达变频器进行通信 作者:东莞市天翔环境工程有限公司,广东东极环保科技有限公司 使用ST语言作为PLC控制程序编写的通信方面的资料比 ...

最新文章

  1. 读取csv数据存到list,批量写入mysql
  2. AP付款出现(-1)例外处理
  3. 浅析IT软件项目团队人力资源管理
  4. 好程序员大数据点睛:关于HDFS的二三事
  5. Base64加密处理
  6. 蔚来汽车为国人长脸,牌照和品牌将是今后的两大重点
  7. java graham_Graham Scan凸包算法
  8. 在线就能用的 SQL 练习平台我给你找好了
  9. JAAS(Java 认证和授权服务)
  10. layui下select大数据卡顿问题
  11. Kotlin 动态代理的使用以及一些坑点
  12. 万字长文分析递归算法的时间和空间复杂度,从此对递归不再迷茫!
  13. 《大秦帝国之裂变》感悟与经典语录
  14. 为什么现在一些年轻人放弃缴纳社保?
  15. Unreal Engine 4 —— Smear Frame效果的实现与分析
  16. matlab之计算排列组合
  17. 微信jssdk图片上传给服务器,使用微信JSSDK进行图片选择和上传
  18. 【C++笔记】 判断两个数互质(做大公约数为1)
  19. 班级分组小程序-列表
  20. ADMET性质预测服务:药物分子吸收评估服务与药物分子毒性评估服务

热门文章

  1. MPLAB程序中如何设置配置字
  2. Vue页面与页面之间的传值(router.push()编程式导航)
  3. 图像金字塔、特征金字塔(FPN)
  4. 最优化理论复习视频合集
  5. 爬虫系列:某家小区房产信息及POI数据获取
  6. 获得联系人姓名、电话号码的方法
  7. 韦东山jz2440开发板重烧系统
  8. Linux命令——性能监控glance命令详解
  9. 将阿拉伯数字转换成中文大写金额的形式
  10. gurobi学习笔记(一)