内核模块传参
内核模块传参
1.类比应用层
int main(int argc, const char * argv[ ])
main应用程序传参:./a.out 123 abc
- argc:命令行传递参数的个数:3个
- argv:具体的传递过来的参数(字符串):argv[0] = ./a.out , argv[1] = “123”, argv[2] = “abc”
2.内核层
1)驱动安装时传参
内核模块通过下面操作:
- 查看内核模块的信息:modinfo xxx.ko
- sudo insmod xxx.ko 参数列表
- 普通传参:module_param(name, type, perm)
- 数组传参:module_param_array(name, type, nump, perm)
- 参数描述:MODULE_PARM_DESC(_parm, desc)
2)驱动运行时传参
在linux文件系统中,在 /sys/module/模块命名的目录/parameters/以变量命令的文件
修改此文件,可实现驱动运行时传参。
eg:
linux@ubuntu:/sys/module/hello/parameters$ ls
a arr b p
一、普通传参:module_param
vi -t module_param
#include <linux/moduleparam.h>
变量的标准类型:
* Standard types are:
* //注意没有char类型(单字节:byte),单字符不能直接传'字符',只能传ASCII值。
* byte, short, ushort, int, uint, long, ulong
* charp: a character pointer //传递的时候字符串之间不能出现空格,只能hello_world
* bool: a bool, values 0/1, y/n, Y/N. //布尔类型
* invbool: the above, only sense-reversed (N = true).//反布尔类型
#define module_param(name, type, perm) \
module_param_named(name, name, type, perm)
module_param(name, type, perm);
1)功能:用来接收参数
2)参数:
- name :变量的名字
- type :变量的类型
- perm :权限 0661 0775 0664
注:权限的最后一个参数不能有写权限 != 2,故只能为1(执行),4(可读),5
二、数组传参:module_param_array
399 * module_param_array - a parameter which is an array of some type
400 * @name: the name of the array variable
401 * @type: the type, as per module_param()
402 * @nump: optional pointer filled in with the number written
403 * @perm: visibility in sysfs
404 *
405 * Input and output are as comma-separated values. Commas inside values
406 * don't work properly (eg. an array of charp).
407 *
408 * ARRAY_SIZE(@name) is used to determine the number of elements in the
409 * array, so the definition must be visible.
410
#define module_param_array(name, type, nump, perm) \
module_param_array_named(name, name, type, nump, perm)
module_param_array(name, type, nump, perm) ;
1)功能:用来接收数组参数
2)参数:
- name:数组名
- type :类型
- nump :用来接收用户实际传递的数组成员的个数,内核接收到实际用户传递的个数赋值到num对应地址空间
- perm :权限 0664 0775 0661
eg:
int a[10];
int num;
module_param_array(a, int, &num, 0664);
注意:
- &num,如果不取地址,则改变不了宏里面对应地址里面的内容。不取地址形参值改了,但是实参的值并没有改变。
- 数组传参操作 :sudo insmod hello.ko arr=1,2,3,4,5,6 等号两边、参数逗号之间都不能有空格间隔
三、参数描述:MODULE_PARM_DESC
One for each parameter, describing how to use it. Some files do
multiple of these per line, so can't just use MODULE_INFO.
#define MODULE_PARM_DESC(_parm, desc) \
__MODULE_INFO(parm, _parm, #_parm ":" desc)
MODULE_PARM_DESC(_parm, desc);
功能:对变量进行描述
参数:
- _parm :变量的名字
- desc :描述的"字符串字段"
导出符号表
应用层和内核层程序运行的区别
1)应用层
应用层程序运行时,各程序之间各自分配0G-3G的独立用户空间,A进程不能直接调用B进程中的任何函数。进程通信只能通过内核。
2)内核层
内核中的程序运行时,内核只有一份3G-4G的内核空间,每个驱动程序各占实际的物理内存,即每个驱动程序都有自己的独立唯一的地址,驱动程序调用可以直接指向调用的函数地址。
内核内存设计机制的优点
- 解决代码冗余的问题,相同功能的函数只需写一份代码。
- 开发更简单,当想使用别人写的某功能的驱动时,只需在自己驱动代码中调用别人封装好的功能函数即可。应用层程序则不可直接访问另一个程序。
因此把一个模块调用另一个模块中函数的过程,可以转化成自己写的驱动如何获取别人写的函数在内核内存中存放的地址即可。
借助导出符号表,到出功能函数在内核内存中存放的地址。
导出符号表:EXPORT_SYMBOL_GPL(sym)
在B驱动模块中,如果想调用A驱动模块中某个函数(或变量),只需要将A模块中的这个函数(变量)的地址导出即可。
实现原因:A 、B内核驱动模块都是运行在同一个3-4G的内核内存空间。
- 好处:
1)解决代码冗余的现象
2)让你开发效率更高(让开发过程更简单)
EXPORT_SYMBOL_GPL(函数名/变量名)
在被调函数:
int func(void)
{
return 0;
}
EXPORT_SYMBOL_GPL(func);
-
编译:
先编译提供者,会产生一个Module.symvers符号表文件
将这个文件拷贝到调用者目录下,再编译调用者模块 -
安装:
先安装提供者
在安装调用者 -
卸载:
先卸载调用者
在卸载提供者
代码演示
1 #include <linux/init.h>
2 #include <linux/module.h>
3 #include <linux/moduleparam.h>
4
5 char a;
6 int b = 0;
7 char * p = NULL;
8 int arr[10];
9 int num;
10 module_param(a, byte, 0665);
11 module_param(b, int, 0665);
12 module_param(p, charp, 0665);
13 module_param_array(arr, int, &num, 0665);
14
15 MODULE_PARM_DESC(a, "this is a");
16 MODULE_PARM_DESC(b, "this is b");
17 MODULE_PARM_DESC(p, "this is char point");
18 MODULE_PARM_DESC(arr, "this is array");
19
20 static int __init demo_init(void)
21 {
22 int i = 0;
23 printk(KERN_INFO "enter to init\n");
24
25 printk("a = %d\n", a);
26 printk("b = %d\n", b);
27 printk("p = %s\n", p);
28 for(i = 0; i < num; i++)
29 {
30 printk("arr[%d] = %d, real_num = %d\n", i, arr[i], num);
31 }
32
33 return 0;
34 }
35
36 static void __exit demo_exit(void)
37 {
38 printk(KERN_INFO "enter to exit\n");
39
40 }
41
42 module_init(demo_init);
43 module_exit(demo_exit);
44 MODULE_LICENSE("GPL");
45
~
结果:
modinfo
linux@ubuntu:~/test/drivers$ modinfo hello.ko
filename: hello.ko
license: GPL
srcversion: 2524DDB77DA22E24F96057F
depends:
vermagic: 3.2.0-29-generic-pae SMP mod_unload modversions 686
parm: a:this is a (byte)
parm: b:this is b (int)
parm: p:this is char point (charp)
parm: arr:this is array (array of int)
insmod
linux@ubuntu:~/test/drivers$ sudo insmod hello.ko a=65 b=666 p="hello_world" arr=1,2,3,4,5,6
dmesg
linux@ubuntu:~/test/drivers$ dmesg
[ 9420.001302] enter to init
[ 9420.001305] a = 65
[ 9420.001306] b = 666
[ 9420.001308] p = hello_world
[ 9420.001310] arr[0] = 1, real_num = 6
[ 9420.001312] arr[1] = 2, real_num = 6
[ 9420.001314] arr[2] = 3, real_num = 6
[ 9420.001316] arr[3] = 4, real_num = 6
[ 9420.001317] arr[4] = 5, real_num = 6
[ 9420.001319] arr[5] = 6, real_num = 6
linux@ubuntu:~/test/drivers$ sudo rmmod hello