Linux 驱动开发之内核模块分析3(基于Linux6.6)---内核模块编译 Makefile分析
一、module_param() 定义
通常在用户态下编程,即应用程序,可以通过main()的来传递命令行参数,而编写一个内核模块,则通过module_param() 来传参。
include/linux/moduleparam.h
#define module_param(name, type, perm) \
module_param_named(name, name, type, perm)
通过宏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中相对应的项。
二、module_param() 使用方法
在 Linux 内核模块中,module_param()
宏用于将模块的参数暴露给内核,并允许用户通过模块加载时传递参数值。这些参数可以在内核中被访问和修改,通常用于调整模块行为。
2.1、module_param()
宏的基本用法
module_param()
宏的语法如下:
module_param(name, type, perm);
- name:参数名,表示传入模块的参数变量名称。
- type:参数的类型,通常使用以下类型:
int
:整数类型。bool
:布尔值类型(true
或false
)。charp
:字符串类型。long
:长整型。unsigned int
:无符号整数类型。unsigned long
:无符号长整型。
- perm:权限设置(可选)。它控制模块参数的读写权限,通常用于设置文件的权限。例如,
S_IRUGO
表示只读,S_IWUSR
表示用户可写。常用的权限设置包括:S_IRUGO
:只读权限(用户可以读取该参数,但不能修改)。S_IWUSR
:用户可写权限。S_IRUSR
:用户可读权限。
2.2、示例:使用 module_param()
定义模块参数
假设我们要定义几个模块参数,并在模块加载时根据这些参数的值调整模块的行为。
1. 简单的整数参数
我们将创建一个简单的模块,该模块有一个整数参数 param1
,允许在模块加载时传递。
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
static int param1 = 42; // 默认值为 42
module_param(param1, int, S_IRUGO | S_IWUSR); // 允许读取和写入
static int __init hello_init(void) {
pr_info("Hello, World! param1 = %d\n", param1);
return 0;
}
static void __exit hello_exit(void) {
pr_info("Goodbye, World!\n");
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("A simple Hello World Kernel Module with Parameters");
2. 编译并加载模块
-
编译模块:
-
make
-
加载模块并传递参数:
-
sudo insmod hello.ko param1=100
-
查看内核日志(
dmesg
):
dmesg | tail -n 10
你会看到类似以下的输出:
-
[ 1234.567890] Hello, World! param1 = 100
这表明模块加载时,参数
param1
被设置为 100。
3. 卸载模块
sudo rmmod hello
2.3、支持不同类型的参数
1. 字符串参数(charp
)
你也可以使用 module_param()
宏定义一个字符串参数。例如,定义一个字符串参数 param_str
:
static char *param_str = "default_value";
module_param(param_str, charp, S_IRUGO | S_IWUSR);
在模块加载时,你可以通过命令行传递字符串参数:
sudo insmod hello.ko param_str="Hello, Kernel!"
2. 布尔参数(bool
)
布尔类型参数允许你在加载模块时通过 1
或 0
来指定布尔值:
static bool enable_feature = false;
module_param(enable_feature, bool, S_IRUGO | S_IWUSR);
加载模块时传递布尔值:
sudo insmod hello.ko enable_feature=1
3. 长整型(long
)和无符号长整型(unsigned long
)
你可以定义长整型或无符号长整型参数:
static long param_long = 1000;
module_param(param_long, long, S_IRUGO | S_IWUSR);
static unsigned long param_ulong = 1000;
module_param(param_ulong, unsigned long, S_IRUGO | S_IWUSR);
4. 整数数组(array
类型)
内核也支持通过 module_param_array()
宏来传递数组参数。例如,传递一个整数数组:
static int param_array[5] = {1, 2, 3, 4, 5};
module_param_array(param_array, int, NULL, 0644);
在加载模块时,传递数组:
sudo insmod hello.ko param_array=10,20,30,40,50
2.4、module_param()
常见问题
-
参数类型不匹配:确保在使用
module_param()
时传入的类型与定义的类型匹配。如果你使用了int
类型的参数,确保在加载时传入的参数是整数类型。 -
权限问题:
module_param()
的权限设置控制模块参数的可读写性。S_IRUGO
表示只读,S_IWUSR
表示用户可写。确保在设置权限时根据实际需求设置合适的权限。 -
无法修改参数值:如果在加载模块时修改参数的值,但该参数是只读的,内核会返回错误。如果需要修改参数的值,确保为该参数设置了写权限。