從命令行傳遞參數給內核模塊 (MODULE_PARM)

http://blog.chinaunix.net/u1/54524/showart_470321.html

模塊也可以從命令行獲取參數。但不是通過以前你習慣的argc/argv

要傳遞參數給模塊,首先將獲取參數值的變量聲明爲全局變量。然後使用宏MODULE_PARM()(在頭文件linux/module.h)。運行時,insmod將給變量賦予命令行的參數,如同 ./insmod mymodule.o myvariable=5。爲使代碼清晰,變量的聲明和宏都應該放在 模塊代碼的開始部分。以下的代碼範例也許將比我公認差勁的解說更好。

MODULE_PARM()需要兩個參數,變量的名字和其類型。支持的類型有" b": 比特型,"h": 短整型, "i": 整數型," l: 長整型和 "s": 字符串型,其中正數型既可爲signed也可爲unsigned。 字符串類型應該聲明爲"char *"這樣insmod就可以爲它們分配內存空間。你應該總是爲你的變量賦初值。 這是內核編程,代碼要編寫的十分謹慎。舉個例子:

int myint = 3;
char *mystr;

MODULE_PARM(myint, "i");
MODULE_PARM(mystr, "s");

數組同樣被支持。在宏MODULE_PARM中在類型符號前面的整型值意味着一個指定了最大長度的數組。 用'-'隔開的兩個數字則分別意味着最小和最大長度。下面的例子中,就聲明瞭一個最小長度爲2,最大長度爲4的整形數組。

int myshortArray[4];
MODULE_PARM (myintArray, "3-9i");

將初始值設爲缺省使用的IO端口或IO內存是一個不錯的作法。如果這些變量有缺省值,則可以進行自動設備檢測, 否則保持當前設置的值。我們將在後續章節解釋清楚相關內容。在這裏我只是演示如何向一個模塊傳遞參數。

最後,還有這樣一個宏,MODULE_PARM_DESC()被用來註解該模塊可以接收的參數。該宏 兩個參數:變量名和一個格式自由的對該變量的描述。

Example 2-7. hello-5.c

/*
* hello-5.c - Demonstrates command line argument passing to a module.
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/stat.h>

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Peter Jay Salzman");

static short int myshort = 1;
static int myint = 420;
static long int mylong = 9999;
static char *mystring = "blah";

/*
* module_param(foo, int, 0000)
* The first param is the parameters name
* The second param is it's data type
* The final argument is the permissions bits,
* for exposing parameters in sysfs (if non-zero) at a later stage.
*/

module_param(myshort, short, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
MODULE_PARM_DESC(myshort, "A short integer");
module_param(myint, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
MODULE_PARM_DESC(myint, "An integer");
module_param(mylong, long, S_IRUSR);
MODULE_PARM_DESC(mylong, "A long integer");
module_param(mystring, charp, 0000);
MODULE_PARM_DESC(mystring, "A character string");

static int __init hello_5_init(void)
{
printk(KERN_ALERT "Hello, world 5/n=============/n");
printk(KERN_ALERT "myshort is a short integer: %hd/n", myshort);
printk(KERN_ALERT "myint is an integer: %d/n", myint);
printk(KERN_ALERT "mylong is a long integer: %ld/n", mylong);
printk(KERN_ALERT "mystring is a string: %s/n", mystring);
return 0;
}

static void __exit hello_5_exit(void)
{
printk(KERN_ALERT "Goodbye, world 5/n");
}

module_init(hello_5_init);
module_exit(hello_5_exit);

我建議用下面的方法實驗你的模塊:

satan# insmod hello-5.o mystring="bebop" mybyte=255 myintArray=-1
mybyte is an 8 bit integer: 255
myshort is a short integer: 1
myint is an integer: 20
mylong is a long integer: 9999
mystring is a string: bebop
myintArray is -1 and 420

satan# rmmod hello-5
Goodbye, world 5

satan# insmod hello-5.o mystring="supercalifragilisticexpialidocious" /
> mybyte=256 myintArray=-1,-1
mybyte is an 8 bit integer: 0
myshort is a short integer: 1
myint is an integer: 20
mylong is a long integer: 9999
mystring is a string: supercalifragilisticexpialidocious
myintArray is -1 and -1

satan# rmmod hello-5
Goodbye, world 5

satan# insmod hello-5.o mylong=hello
hello-5.o: invalid argument syntax for mylong: 'h'

module_param(name, type, perm)是一個宏,向當前模塊傳入參數,對源碼分析如下

在include/linux/moduleparam.h中

#define module_param(name, type, perm) /
module_param_named(name, name, type, perm)

#define module_param_named(name, value, type, perm) /
param_check_##type(name, &(value)); /
module_param_call(name, param_set_##type, param_get_##type, &value, perm); /
__MODULE_PARM_TYPE(name, #type)



#define module_param_call(name, set, get, arg, perm) /
__module_param_call(MODULE_PARAM_PREFIX, name, set, get, arg, perm)


#define __module_param_call(prefix, name, set, get, arg, perm) /
/* Default value instead of permissions? */ /
static int __param_perm_check_##name __attribute__((unused)) = /
BUILD_BUG_ON_ZERO((perm) < 0 || (perm) > 0777 || ((perm) & 2)); /
static char __param_str_##name[] = prefix #name; /
static struct kernel_param const __param_##name /
__attribute_used__ /
__attribute__ ((unused,__section__ ("__param"),aligned(sizeof(void *)))) /
= { __param_str_##name, perm, set, get, arg }



__attibute__ 是gcc的關鍵字,可參考
http://gcc.gnu.org/onlinedocs/gcc-4.0.0/gcc/Variable-Attributes.html
__attibute__將參數編譯到__param段中,

module_param是一步一步展開的,
上面幾個宏在include/linux/moduleparam.h中的順序剛好相反

module_param宏的類似函數調用的順序
module_param->module_param_named->module_param_call->__module_param_call

展開的順序正好相反
__module_param_call->module_param_call->module_param_named->module_param



type類型可以是byte,short,ushort,int,
uint,long,ulong,charp(注:字符指針),bool,invbool,
perm表示此參數在sysfs文件系統中所對應的文件節點的屬性。
權限在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

當perm爲0時,表示此參數不存在 sysfs文件系統下對應的文件節點。
模塊被加載後,在/sys/module/ 目錄下將出現以此模塊名命名的目錄。


測試一下,插入一個驅動模塊mp.ko,
sudo insmod mp.ko
發現 /sys/module下出現mp這個文件夾
mp中有drivers/,sections/,parameters/,initstate,refcnt,srcversion

其中initstate 裏面內容爲:live
refcnt裏面內容爲:0
srcversion裏面內容爲:F9BDEBF706329B443C28E08,很長,應該是一個唯一數字
driver文件夾裏面是空的
sections有__param,__versions
__param裏面內容爲0xd081e0a8
__versions裏面內容爲0xd081e100

parameters有count,info(注:自己定義的參數)
count裏面的內容爲1(注:輸出次數)
info裏面的內容爲a site about linux driver.(注:輸出內容)


如果此模塊存在perm不爲0的命令行參數,
在此模塊的目錄下將出現parameters目錄,
包含一系列以參數名命名的文件節點,
這些文件的權限值等於perm,文件的內容爲參數的值。


在/sys/module/mp/出現的參數,在module結構中的對應如下
struct module
{
enum module_state state;

/* Member of list of modules */
struct list_head list;

......

/* Sysfs stuff. */
struct module_kobject mkobj;
struct module_param_attrs *param_attrs;
struct module_attribute *modinfo_attrs;
const char *version;
const char *srcversion;
struct kobject *drivers_dir;

/* Exported symbols */
const struct kernel_symbol *syms;
unsigned int num_syms;
const unsigned long *crcs;

......

/* Section attributes */
struct module_sect_attrs *sect_attrs;
#endif

......
};


enum module_state
{
MODULE_STATE_LIVE,
MODULE_STATE_COMING,
MODULE_STATE_GOING,
};

state對應/sys/module/mp/initstate
drivers_dir對應/sys/module/mp/driver文件夾
version對應/sys/module/mp/sections/__version
srcversion對應/sys/module/mp/srcversion


測試模塊,源程序mp.c內容如下:


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

static char *info= "a site about linux driver.";
static int count= 1;
static int mp= 0;

module_param(mp,int,0);

module_param(count,int,S_IRUSR);

module_param(info,charp,S_IRUSR);

MODULE_AUTHOR("ioctrl");
MODULE_LICENSE("Dual BSD/GPL");

static int hello_init(void)
{
int i;
for(i=0;i<count;i++)
{
printk(KERN_NOTICEwww.linuxdriver.cn is ");
printk(info);
printk("/n");
}
return 0;
}

static void hello_exit(void)
{
printk(KERN_NOTICE"exit!/n");
}

module_init(hello_init);
module_exit(hello_exit);

編譯

手工插入,插入時傳遞參數 count=10,info="驅動開發網站。"
命令如下:
sudo insmod mp.ko count=10 info="驅動開發網站。"
然後用dmesg查看消息
看到如下,共10條記錄
[16122.280000]www.linuxdriver.cn is 驅動開發網站
[16122.280000]www.linuxdriver.cn is 驅動開發網站
[16122.280000]www.linuxdriver.cn is 驅動開發網站
[16122.280000]www.linuxdriver.cn is 驅動開發網站
[16122.280000]www.linuxdriver.cn is 驅動開發網站
[16122.280000]www.linuxdriver.cn is 驅動開發網站
[16122.280000]www.linuxdriver.cn is 驅動開發網站
[16122.280000]www.linuxdriver.cn is 驅動開發網站
[16122.280000]www.linuxdriver.cn is 驅動開發網站
[16122.280000]www.linuxdriver.cn is 驅動開發網站


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章