linux 内核模块 参数

module_param()理解
-------------------------------------------
在用户态下编程可以通过main()的来传递命令行参数,而编写一个内核模块则通过module_param()
module_param()宏是Linux 2.6内核中新增的,该宏被定义在include/linux/moduleparam.h文件中,具体定义如下:
#define module_param(name, type, perm)              
    module_param_named(name, name, type, perm)
其中使用了 3 个参数:要传递的参数变量名, 变量的数据类型, 以及访问参数的权限。



perm参数的作用是什么?
-------------------------------------------
perm参数是一个权限值,表示此参数在sysfs文件系统中所对应的文件节点的属性。你应当使用 <linux/stat.h> 中定义的值. 这个值控制谁可以存取这些模块参数在sysfs中的表示.当perm为0时,表示此参数不存在sysfs文件系统下对应的文件节点。 否则, 模块被加载后,在/sys/module/目录下将出现以此模块名命名的目录, 带有给定的权限.。
权限在include/linux/stat.h中有定义
#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

使用S_IRUGO作为参数可以被所有人读取, 但是不能改变; S_IRUGO|S_IWUSR允许root来改变参数. 注意, 如果一个参数被sysfs修改, 你的模块看到的参数值也改变了, 但是你的模块没有任何其他的通知. 你应当不要使模块参数可写, 除非你准备好检测这个改变并且因而作出反应.


module_param()应当放在任何函数之外, 典型地是出现在源文件的前面.定义如:
static char *whom = "world";
static int howmany = 1;
module_param(howmany, int, S_IRUGO);
module_param(whom, charp, S_IRUGO);

模块参数支持许多类型:
bool     一个布尔型(true或者false)值(相关的变量应当是int类型).
invbool invbool类型颠倒了值, 所以真值变成 false, 反之亦然.
charp    一个字符指针值. 内存为用户提供的字串分配, 指针因此设置.
int
long
short
uint
ulong
ushort


数组参数, 用逗号间隔的列表提供的值, 模块加载者也支持. 声明一个数组参数, 使用:
module_param_array(name, type, num, perm);
name    数组的名子(也是参数名),
type    数组元素的类型,
num    一个整型变量,
perm    通常的权限值.
如果数组参数在加载时设置, num被设置成提供的数的个数. 模块加载者拒绝比数组能放下的多的值.




hello.c
-------------------------------------------
#include <linux/init.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
MODULE_LICENSE ("Dual BSD/GPL");

static char *who = "world";
static int times = 1;
module_param (times, int, S_IRUSR);
module_param (who, charp, S_IRUSR);


static int hello_init (void)
{
   int i;
   for (i = 0; i < times; i++)
       printk (KERN_ALERT "(%d) hello, %s!\n", i, who);
   return 0;
}

static void hello_exit (void)
{
   printk (KERN_ALERT "Goodbye, %s!\n", who);
}

module_init (hello_init);
module_exit (hello_exit);


编译生成可执行文件hello

# insmod hello who="world" times=5
#(1) hello, world!
#(2) hello, world!
#(3) hello, world!
#(4) hello, world!
#(5) hello, world!
# rmmod hello
# Goodbye,world!

注: 如果加载模块hello时,没有输入任何参数,那么who的初始值为"world",times的初始值为1

 

 

给模块传递参数
日月 发表于 - 2010-1-20 7:38:00
3

对于如何向模块传递参数,Linux kernel 提供了一个简单的框架。其允许驱动程序声明参数,并且用户在系统启动或模块装载时为参数指定相应值,在驱动程序里,参数的用法如同全局变量。

使用下面的宏时需要包含头文件<linux/moduleparam.h>

 

    通过宏module_param()定义一个模块参数:
module_param(name, type, perm);
name既是用户看到的参数名,又是模块内接受参数的变量; 

type表示参数的数据类型,是下列之一:byte, short, ushort, int, uint, long, ulong, charp, bool, invbool;     

perm指定了在sysfs中相应文件的访问权限。访问权限与linux文件爱你访问权限相同的方式管理,如0644,或使用stat.h中的宏如S_IRUGO表示。

0表示完全关闭在sysfs中相对应的项。


这些宏不会声明变量,因此在使用宏之前,必须声明变量,典型地用法如下:
static unsigned int int_var = 0;   
module_param(int_var, uint, S_IRUGO);

这些必须写在模块源文件的开头部分。即int_var是全局的。也可以使模块源文件内部的变量名与外部的参数名有不同的名字,通过module_param_named()定义。module_param_named(name, variable, type, perm);其中name是外部可见的参数名,variable是源文件内部的全局变量名,而module_param通过module_param_named实现,只不过name与variable相同。

例如:
static unsigned int max_test = 9;
module_param_name(maximum_line_test, max_test, int, 0);

 

如果模块参数是一个字符串时,通常使用charp类型定义这个模块参数。内核复制用户提供的字符串到内存,并且相对应的变量指向这个字符串。

例如:
static char *name;
module_param(name, charp, 0);

另一种方法是通过宏module_param_string()让内核把字符串直接复制到程序中的字符数组内。
module_param_string(name, string, len, perm);

这里,name是外部的参数名,string是内部的变量名,len是以string命名的buffer大小(可以小于buffer的大小,但是没有意义),perm表示sysfs的访问权限(或者perm是零,表示完全关闭相对应的sysfs项)。

例如:
static char species[BUF_LEN]
module_param_string(specifies, species, BUF_LEN, 0);

 

如果需要传递多个参数可以通过宏module_param_array()实现。 
module_param_array(name, type, nump, perm);
其中,name既是外部模块的参数名又是程序内部的变量名,type是数据类型,perm是sysfs的访问权限。指针nump指向一个整数,其值表示有多少个参数存放在数组name中。值得注意是name数组必须静态分配。

例如:
static int finsh[MAX_FISH];
static int nr_fish;
module_param_array(fish, int, &nr_fish, 0444); //最终传递数组元素个数存在nr_fish中

通过宏module_param_array_named()使得内部的数组名与外部的参数名有不同的名字。

例如:
module_param_array_named(name, array, type, nump, perm);

通过宏MODULE_PARM_DESC()对参数进行说明:
static unsigned short size = 1;
module_param(size, ushort, 0644);
MODULE_PARM_DESC(size, “The size in inches of the fishing pole”
“connected to this computer.” );

 

 

 说明:from  http://blog.csdn.net/iczyh/archive/2008/10/26/3149727.aspx

module_param() 和 module_param_array() 的作用就是让那些全局变量对 insmod 可见,使模块装载时可重新赋值。

module_param_array() 宏的第三个参数用来记录用户 insmod 时提供的给这个数组的元素个数,NULL 表示不关心用户提供的个数

module_param() 和 module_param_array() 最后一个参数权限值不能包含让普通用户也有写权限,否则编译报错。这点可参考 linux/moduleparam.h 中 __module_param_call() 宏的定义。

字符串数组中的字符串似乎不能包含逗号,否则一个字符串会被解析成两个

 

一个测试用例:parm_hello.c

 

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


#define MAX_ARRAY 6

static int int_var= 0;
static const char *str_var ="default";
static int int_array[6];
int narr;

module_param(int_var,int, 0644);
MODULE_PARM_DESC(int_var,"A integer variable");


module_param(str_var, charp, 0644);
MODULE_PARM_DESC(str_var,"A string variable");

module_param_array(int_array,int, &narr, 0644);
MODULE_PARM_DESC(int_array,"A integer array");
 

static int __init hello_init(void)
{
       int i;
       printk(KERN_ALERT "Hello, my LKM.\n");
       printk(KERN_ALERT "int_var %d.\n", int_var);
       printk(KERN_ALERT "str_var %s.\n", str_var);

       for(i = 0; i < narr; i++){
               printk("int_array[%d] = %d\n", i, int_array[i]);
       }
       return 0;
}

static void __exit hello_exit(void)
{
       printk(KERN_ALERT "Bye, my LKM.\n");
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("ydzhang");
MODULE_DEION("This module is a example.");

 

测试:insmod parm_hello.ko int_var=100 str_var=hello int_array=100,200

 

Linux内核模块参数权限 (2010-03-03 18:21)
分类: kernel


在进行linux内核模块编程时,常常需要给模块传递参数,其作用是从使用的设备号到驱动应当任何操作的几个方面. 例如, SCSI 适配器的驱动常常有选项控制标记命令队列的使用, IDE 驱动允许用户控制 DMA 操作. 如果你的驱动控制老的硬件, 还需要被明确告知哪里去找硬件的 I/O 端口或者 I/O 内存地址. 内核通过在加载驱动的模块时指定可变参数的值, 支持这些要求。
    参数常常被声明为一个静态全局变量,如static int num=10;然后使用module_param(参数名,参数类型,参数读写权限)为模块定义一个参数,例如:
module_prarm(num,int,S_IRUGO);
这样你就可以在insmod(装载模块)的时候为参数指定值,如果没有指定则使用默认值,例如上面的num=10,则10是参数num的默认值。下面以一个例子说明:
#include <linux/init.h>
#include <linux/module.h>
MODULE_LICENSE("Dual BSD/GPL");
static int num=10;
module_param(num,int,S_IRUGO);
static int hello_init(void)
{
    printk("Hello module init.\n");
    printk("num=%d\n",num);
    return 0;
}

static void   hello_exit(void)
{
    printk("Goodbye module exit.\n");
}

module_init(hello_init);
module_exit(hello_exit);

MODULE_DESCRIPTION("a simple module");
MODULE_ALIAS("hello");
将以上代码保存为文件hello.c,编写Makefile文件对其进行编译:
# Makefile2.6
ifneq ($(KERNELRELEASE),)
obj-m := hello.o
else
PWD  := $(shell pwd)
KVER ?= $(shell uname -r)
KDIR := /lib/modules/$(KVER)/build
all:
    $(MAKE) -C $(KDIR) M=$(PWD)
endif
然后make就可以了,make会生成:
|-- Module.symvers
|-- built-in.o
|-- hello.ko
|-- hello.mod.c
|-- hello.mod.o
`-- hello.o
这些文件,其中的hello.ko就是编译生成的模块,使用insmod将hello.ko模块装载进内核,这个需要超级用户权限,我的系统是ubuntu7.10,所以使用如下命令装载:
sudo insmod hello.ko num=20
使用dmesg命令查看运行结果:
xiyoulinux@xiyoulinux-desktop:~/module$ dmesg #实际上是读取/var/log/messages文件的内容
... #省略以前的信息
[14801.675260] Hello module init.
[14801.675265] num=20
这就是运行结果。如果你插入的是sudo insmod hello.ko,那么:
使用dmesg命令查看运行结果:
xiyoulinux@xiyoulinux-desktop:~/module$ dmesg #实际上是读取/var/log/messages文件的内容
... #省略以前的信息
[14801.675260] Hello module init.
[14801.675265] num=10 #取默认值
以上是内核模块的编译和运行情况,实际上你还需要用到lsmod(查看模块是否被插入,一般在打印出来的第一行里)、rmmod(卸载装载的模块,只有当模块的引用计数为0时才能被卸载)等命令。
       那么实质上当你装载模块hello.ko时,系统会在/sys/module下生成一个hello文件夹:

xiyoulinux@xiyoulinux-desktop:/sys/module/hello$ tree
.
|-- holders
|-- initstate
|-- parameters
|   `-- num
|-- refcnt
|-- sections
|   |-- __param
|   `-- __versions
`-- srcversion

3 directories, 6 files
其中parameters目录中就存放的是该模块的参数,一个参数对应一个文件,文件的内容为参数的默认值例如:
xiyoulinux@xiyoulinux-desktop:/sys/module/hello/parameters$ tree
.
`-- num

0 directories, 1 file
xiyoulinux@xiyoulinux-desktop:/sys/module/hello/parameters$ cat num
10

在module_param(num,int,S_IRUGO);
定义参数时,其中的参数读写权限S_IRUGO其实是对参数文件的读写权限,所以权限的设置值就和对文件的设置值一样,例如上面对num参数权限的设置S_IRUGO就是对所有用户具有读的权限,而S_IRUGO|S_IWUSR 则允许 root 来改变参数。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Linux内核模块是一种可以动态加载到Linux内核中的程序,它可以扩展和定制内核的功能。内核模块相对于直接编译到内核的代码而言,更加灵活和可扩展。 Linux内核模块详解主要包括以下内容: 1. 动态加载和卸载:与静态编译到内核不同,内核模块可以动态加载到内核中,并在不需要时卸载。这样可以减小内核的体积和开机启动时间,同时方便模块的管理和更新。 2. 内核符号表:内核模块中包含了一些导出的符号,其他模块或内核可以通过这些符号与模块进行交互和调用。内核提供了一系列函数和宏来管理和使用内核符号表。 3. 模块的编写:编写一个内核模块需要包括初始化函数和清理函数。初始化函数是模块加载时被调用的函数,通常用来注册模块的功能和初始化资源。清理函数是模块卸载时被调用的函数,用于清理资源和注销已注册的功能。 4. 模块参数:模块还可以定义一些可配置的参数,通过在模块加载时指定参数的值,可以动态改变模块的行为。内核提供了一套机制来管理模块参数。 5. 模块依赖性:模块间可能存在依赖关系,一个模块可能依赖于其他模块的功能。内核提供了机制来声明和管理模块的依赖关系,确保模块的加载顺序和依赖关系正确。 6. 内核接口:内核提供了一系列的接口供模块使用,包括文件系统、设备驱动、网络协议等。模块可以通过这些接口来访问内核的功能和资源。 总的来说,Linux内核模块是一种动态加载到内核中的程序,可以扩展和定制内核的功能。通过内核模块,可以实现新的功能、优化性能和对内核进行定制,是Linux内核开发和定制的重要手段。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值