天天看点

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表示。

表示完全关闭在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命令查看运行结果:

[email protected]:~/module$ dmesg #实际上是读取/var/log/messages文件的内容

... #省略以前的信息

[14801.675260] Hello module init.

[14801.675265] num=20

这就是运行结果。如果你插入的是sudo insmod hello.ko,那么:

使用dmesg命令查看运行结果:

[email protected]:~/module$ dmesg #实际上是读取/var/log/messages文件的内容

... #省略以前的信息

[14801.675260] Hello module init.

[14801.675265] num=10 #取默认值

以上是内核模块的编译和运行情况,实际上你还需要用到lsmod(查看模块是否被插入,一般在打印出来的第一行里)、rmmod(卸载装载的模块,只有当模块的引用计数为0时才能被卸载)等命令。

       那么实质上当你装载模块hello.ko时,系统会在/sys/module下生成一个hello文件夹:

[email protected]:/sys/module/hello$ tree

.

|-- holders

|-- initstate

|-- parameters

|   `-- num

|-- refcnt

|-- sections

|   |-- __param

|   `-- __versions

`-- srcversion

3 directories, 6 files

其中parameters目录中就存放的是该模块的参数,一个参数对应一个文件,文件的内容为参数的默认值例如:

[email protected]:/sys/module/hello/parameters$ tree

.

`-- num

0 directories, 1 file

xiy[email protected]:/sys/module/hello/parameters$ cat num

10

在module_param(num,int,S_IRUGO);

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

继续阅读