内核模块参数和依赖

一、模块传参

module_param(name,type,perm);//将指定的全局变量设置成模块参数
/*
name:全局变量名
type:
    使用符号      实际类型                传参方式
	bool	     bool           insmod xxx.ko  变量名=0 或 1
	invbool      bool           insmod xxx.ko  变量名=0 或 1
	charp        char *         insmod xxx.ko  变量名="字符串内容"
	short        short          insmod xxx.ko  变量名=数值
	int          int            insmod xxx.ko  变量名=数值
	long         long           insmod xxx.ko  变量名=数值
	ushort       unsigned short insmod xxx.ko  变量名=数值
	uint         unsigned int   insmod xxx.ko  变量名=数值
	ulong        unsigned long  insmod xxx.ko  变量名=数值
perm:给对应文件 /sys/module/name/parameters/变量名 指定操作权限
	#define S_IRWXU 00700
	#define S_IRUSR 00400
	#define S_IWUSR 00200
	#define S_IXUSR 00100
	#define S_IRWXG 00070
	#define S_IRGRP 00040
	#define S_IWGRP 00020
	#define S_IXGRP 00010
	#define S_IRWXO 00007
	#define S_IROTH 00004
	#define S_IWOTH 00002  //不要用 编译出错
	#define S_IXOTH 00001
*/
module_param_array(name,type,&num,perm);
/*
name、type、perm同module_param,type指数组中元素的类型
&num:存放数组大小变量的地址,可以填NULL(确保传参个数不越界)
    传参方式 insmod xxx.ko  数组名=元素值0,元素值1,...元素值num-1  
*/

可用MODULE_PARAM_DESC宏对每个参数进行作用描述,用法:

MODULE_PARM_DESC(变量名,字符串常量);

字符串常量的内容用来描述对应参数的作用

modinfo可查看这些参数的描述信息

示例:
testparam.c

#include <linux/module.h>
#include <linux/kernel.h>

int gt = 10;
char *gstrr = "hello";
int garr[5] = {1,2,3,4,5};

module_param(gt, int, 0664);
module_param(gstrr, charp, 0664);
module_param_array(garr, int, NULL, 0664);

/* 入口 */
int __init testparam_init(void)
{
	int i=0;
	printk("gt = %d\n", gt);
	printk("gstrr = %s\n", gstrr);
	
	for(i = 0; i < 5; i++) {
		printk("%d ", garr[i]);
	}
	printk("\n");

	return 0;
}

/* 出口 */
void __exit testparam_exit(void)
{
	printk("testparam will exit\n");
}

MODULE_LICENSE("GPL");
module_init(testparam_init);
module_exit(testparam_exit);

在这里插入图片描述

二、模块依赖

​ 既然内核模块的代码与其它内核代码共用统一的运行环境,也就是说模块只是存在形式上独立,运行上其实和内核其它源码是一个整体,它们隶属于同一个程序,因此一个模块或内核其它部分源码应该可以使用另一个模块的一些全局特性。

一个模块中这些可以被其它地方使用的名称被称为导出符号,所有导出符号被填在同一个表中这个表被称为符号表。

最常用的可导出全局特性为全局变量和函数

查看符号表的命令:nm
nm查看elf格式的可执行文件或目标文件中包含的符号表,用法:

nm 文件名 (可以通过man nm查看一些字母含义)

两个用于导出模块中符号名称的宏:

EXPORT_SYMBOL(函数名或全局变量名)
EXPORT_SYMBOL_GPL(函数名或全局变量名)   需要GPL许可证协议验证

使用导出符号的地方,需要对这些符号进行extern声明后才能使用这些符号

B模块使用了A模块导出的符号,此时称B模块依赖于A模块,则:

  1. 编译次序:先编译模块A,再编译模块B,当两个模块源码在不同目录时,
    需要:
    i. 先编译导出符号的模块A
    ii. 拷贝A模块目录中的Module.symvers到B模块目录
    iii. 编译使用符号的模块B。否则编译B模块时有符号未定义错误
  2. 加载次序:先插入A模块,再插入B模块,否则B模块插入失败
  3. 卸载次序:先卸载B模块,在卸载A模块,否则A模块卸载失败

补充说明
内核符号表(直接当文本文件查看)

   /proc/kallsyms运行时    /boot/System.map编译后

在同一目录下

modulea.c

#include <linux/module.h>
#include <linux/kernel.h>

int gt = 10; // 全局变量

EXPORT_SYMBOL(gt); // 

int __init modulea_init(void)
{
	printk("modulea_init gt = %d\n", gt);

	return 0;
}

void __exit modulea_exit(void)
{
	printk("modulea will exit\n");
}

MODULE_LICENSE("GPL");
module_init(modulea_init);
module_exit(modulea_exit);

moduleb.c

#include <linux/module.h>
#include <linux/kernel.h>

extern int gt; //声明gt变量 

int __init moduleb_init(void)
{
	printk("moduleb_init gt = %d\n", gt);

	return 0;
}

void __exit moduleb_exit(void)
{
	printk("moduleb will exit\n");
}

MODULE_LICENSE("GPL");
module_init(moduleb_init);
module_exit(moduleb_exit);

Makefile

ifeq ($(KERNELRELEASE),)

ifeq ($(ARCH),arm)
KERNELDIR ?= /home/myubuntu/Linux_4412/kernel/linux-3.14 
ROOTFS ?= /opt/4412/rootfs
else
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
endif
PWD := $(shell pwd)

modules:
	$(MAKE) -C $(KERNELDIR) M=$(PWD) modules

modules_install:
	$(MAKE) -C $(KERNELDIR) M=$(PWD) modules INSTALL_MOD_PATH=$(ROOTFS) modules_install

clean:
	rm -rf  *.o  *.ko  .*.cmd  *.mod.*  modules.order  Module.symvers   .tmp_versions

else

obj-m += modulea.o # 注意编译顺序
obj-m += moduleb.o
endif

不在同目录下

/module_a/module_a.c

#include <linux/module.h>
#include <linux/kernel.h>

int gt = 10;

EXPORT_SYMBOL(gt); 

int __init module_a_init(void)
{
	printk("module_a_init gt = %d\n", gt);

	return 0;
}

void __exit module_a_exit(void)
{
	printk("module_a will exit\n");
}

MODULE_LICENSE("GPL");
module_init(module_a_init);
module_exit(module_a_exit);

/module_a/Makefile

ifeq ($(KERNELRELEASE),)

ifeq ($(ARCH),arm)
KERNELDIR ?= /home/myubuntu/Linux_4412/kernel/linux-3.14 
ROOTFS ?= /opt/4412/rootfs
else
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
endif
PWD := $(shell pwd)

modules:
	$(MAKE) -C $(KERNELDIR) M=$(PWD) modules

modules_install:
	$(MAKE) -C $(KERNELDIR) M=$(PWD) modules INSTALL_MOD_PATH=$(ROOTFS) modules_install

clean:
	rm -rf  *.o  *.ko  .*.cmd  *.mod.*  modules.order  Module.symvers   .tmp_versions

else

obj-m += module_a.o
endif

/module_b/module_b.c

#include <linux/module.h>
#include <linux/kernel.h>

extern int gt;

int __init module_b_init(void)
{
	printk("module_b_init gt = %d\n", gt);

	return 0;
}

void __exit module_b_exit(void)
{
	printk("module_b will exit\n");
}

MODULE_LICENSE("GPL");
module_init(module_b_init);
module_exit(module_b_exit);

/module_b/Makefile

ifeq ($(KERNELRELEASE),)

ifeq ($(ARCH),arm)
KERNELDIR ?= /home/myubuntu/Linux_4412/kernel/linux-3.14 
ROOTFS ?= /opt/4412/rootfs
else
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
endif
PWD := $(shell pwd)

modules:
	$(MAKE) -C $(KERNELDIR) M=$(PWD) modules

modules_install:
	$(MAKE) -C $(KERNELDIR) M=$(PWD) modules INSTALL_MOD_PATH=$(ROOTFS) modules_install

clean:
	rm -rf  *.o  *.ko  .*.cmd  *.mod.*  modules.order  Module.symvers   .tmp_versions

else

obj-m += module_b.o
endif

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值