[linux内核笔记-1]内核模块参数传递----module_param()函数

1.module_param()的定义

module_param()宏是Linux 2.6内核中新增的,该宏被定义在include/linux/moduleparam.h文件中,定义如下

 1 /**
 2   * module_param - typesafe helper for a module/cmdline parameter
 3   * @value: the variable to alter, and exposed parameter name.
 4   * @type: the type of the parameter
 5   * @perm: visibility in sysfs.
 6   *
 7   * @value becomes the module parameter, or (prefixed by KBUILD_MODNAME and a
 8   * ".") the kernel commandline parameter.  Note that - is changed to _, so
 9   * the user can use "foo-bar=1" even for variable "foo_bar".
10   *
11   * @perm is 0 if the the variable is not to appear in sysfs, or 0444
12   * for world-readable, 0644 for root-writable, etc.  Note that if it
13   * is writable, you may need to use kparam_block_sysfs_write() around
14   * accesses (esp. charp, which can be kfreed when it changes).
15   *
16   * The @type is simply pasted to refer to a param_ops_##type and a
17   * param_check_##type: for convenience many standard types are provided but
18   * you can create your own by defining those variables.
19   *
20   * Standard types are:
21   *      byte, short, ushort, int, uint, long, ulong
22   *      charp: a character pointer
23   *      bool: a bool, values 0/1, y/n, Y/N.
24   *      invbool: the above, only sense-reversed (N = true).
25   */
26
27 #define module_param(name, type, perm)
28           module_param_named(name, name, type, perm)
29
30
31  /**
32   * module_param_named - typesafe helper for a renamed module/cmdline parameter
33   * @name: a valid C identifier which is the parameter name.
34   * @value: the actual lvalue to alter.
35   * @type: the type of the parameter
36   * @perm: visibility in sysfs.
37   *
38   * Usually it‘s a good idea to have variable names and user-exposed names the
39   * same, but that‘s harder if the variable must be non-static or is inside a
40   * structure.  This allows exposure under a different name.41   */

原型:module_param(name, type, perm);

参数:

,name:既是用户看到的参数名,又是模块内接受参数的变量;;
     ,type:表示参数的类型;
     ,perm:指定了在sysfs中相应文件的访问权限;

这个宏定义应当放在任何函数之外, 典型地是出现在源文件的前面.定义如

static char *whom = "world";
static int howmany = 1;
module_param (howmany, int, S_IRUGO);
module_param (whom, charp, S_IRUGO); /*使用 S_IRUGO 作为参数可以被所有人读取*/

2.module_param()支持的类型:

bool,invbool /*一个布尔型( true 或者 false)值(相关的变量应当是 int 类型). invbool 类型颠倒了值, 所以真值变成 false, 反之亦然.*/
charp/*一个字符指针值. 内存为用户提供的字串分配, 指针因此设置.*/
int,long,short
uint,ulong,ushort /*基本的变长整型值. 以 u 开头的是无符号值.*/

4.prem参数:

该参数在include/linux/stat.h中给出定义

/*include/linux/stat.h */

 #ifndef _LINUX_STAT_H
 #define _LINUX_STAT_H

 #include <asm/stat.h>
 #include <uapi/linux/stat.h>

 #define S_IRWXUGO       (S_IRWXU|S_IRWXG|S_IRWXO)
 #define S_IALLUGO       (S_ISUID|S_ISGID|S_ISVTX|S_IRWXUGO)
 #define S_IRUGO         (S_IRUSR|S_IRGRP|S_IROTH)
 #define S_IWUGO         (S_IWUSR|S_IWGRP|S_IWOTH)
 #define S_IXUGO         (S_IXUSR|S_IXGRP|S_IXOTH)

 #define UTIME_NOW       ((1l << 30) - 1l)
 #define UTIME_OMIT      ((1l << 30) - 2l)

/*uapi/linux/stat.h */

 #ifndef _UAPI_LINUX_STAT_H
 #define _UAPI_LINUX_STAT_H

 #if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2)

 #define S_IFMT  00170000
 #define S_IFSOCK 0140000
 #define S_IFLNK  0120000
 #define S_IFREG  0100000
 #define S_IFBLK  0060000
 #define S_IFDIR  0040000
 #define S_IFCHR  0020000
 #define S_IFIFO  0010000
 #define S_ISUID  0004000
 #define S_ISGID  0002000
 #define S_ISVTX  0001000

 #define S_ISLNK(m)      (((m) & S_IFMT) == S_IFLNK)
 #define S_ISREG(m)      (((m) & S_IFMT) == S_IFREG)
 #define S_ISDIR(m)      (((m) & S_IFMT) == S_IFDIR)
 #define S_ISCHR(m)      (((m) & S_IFMT) == S_IFCHR)
 #define S_ISBLK(m)      (((m) & S_IFMT) == S_IFBLK)
 #define S_ISFIFO(m)     (((m) & S_IFMT) == S_IFIFO)
 #define S_ISSOCK(m)     (((m) & S_IFMT) == S_IFSOCK)

 #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

 #endif

 #endif /* _UAPI_LINUX_STAT_H */ 

最后的 module_param 字段是一个权限值,表示此参数在sysfs文件系统中所对应的文件节点的属性。你应当使用 中定义的值. 这个值控制谁可以存取这些模块参数在 sysfs 中的表示.当perm为0时,表示此参数不存在 sysfs文件系统下对应的文件节点。 否则, 模块被加载后,在/sys/module/ 目录下将出现以此模块名命名的目录, 带有给定的权限。

5.对参数的描述方法:

通过通过宏MODULE_PARM_DESC()对参数进行说明:

static unsigned short test = 1;
module_param(size, ushort, 0644);
MODULE_PARM_DESC(size, “this param is a test”);

7.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_named(maximum_line_test, max_test, int, 0);
/*此定义下,该参数的外部可见参数名为:maximum_line_test,*
 * 内部全局变量名为:max_test                                               */
module_param(max_test,int,0);
/*此定义下,该参数的外部可见参数名为:max_test,*
 * 内部全局变量名为:max_test                               */

8.其它衍生的方法:

原型:module_param_array(name, type, nump, perm);

参数:

,name:既是用户看到的参数名,又是模块内接受参数的变量;;
     ,type:表示参数的类型;

,nump:指针,指向一个整数,其值表示有多少个参数存放在数组name中。值得注意是name数组必须静态分配

,perm:指定了在sysfs中相应文件的访问权限;

例:

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

原型:module_param_string(name, string, len, perm);

参数:

,name:既是用户看到的参数名,又是模块内接受参数的变量;;

,string:是内部的变量名

,nump:以string命名的buffer大小(可以小于buffer的大小,但是没有意义)

,perm:指定了在sysfs中相应文件的访问权限;

例:

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

9.引导模块时传递参数:

# insmod module.ko [param1=value param2=value ...]

10.实例

 /*hello.c*/ 1 #include <linux/module.h>
 2 #include <linux/moduleparam.h>
 3 #include <linux/kernel.h>
 4
 5 #define MAX_ARRAY 6
 6
 7 static int int_var = 0;
 8 static const char *str_var = "default";
 9 static int int_array[6];
10 int narr;
11
12 module_param(int_var, int, 0644);
13 MODULE_PARM_DESC(int_var, "A integer variable");
14
15 module_param(str_var, charp, 0644);
16 MODULE_PARM_DESC(str_var, "A string variable");
17
18 module_param_array(int_array, int, &narr, 0644);
19 MODULE_PARM_DESC(int_array, "A integer array");
20
21
22 static int __init hello_init(void)
23 {
24        int i;
25        printk(KERN_ALERT "Hello, my LKM.\n");
26        printk(KERN_ALERT "int_var %d.\n", int_var);
27        printk(KERN_ALERT "str_var %s.\n", str_var);
28
29        for(i = 0; i < narr; i ++){
30                printk("int_array[%d] = %d\n", i, int_array[i]);
31        }
32        return 0;
33 }
34
35 static void __exit hello_exit(void)
36 {
37        printk(KERN_ALERT "Bye, my LKM.\n");
38 }
39 module_init(hello_init);
40 module_exit(hello_exit);
41 MODULE_LICENSE("GPL");
42 MODULE_AUTHOR("ydzhang");
43 MODULE_DEION("This module is a example.");

makefile文件:

### Makefile
obj-m := hello.o
KERNEL_DIR  := /lib/modules/$(shell uname -r)/build
PWD         := $(shell pwd)  

default:
    $(MAKE) -C $(KERNEL_DIR) M=$(PWD) modules
clean:
    $(MAKE) -C $(KERNEL_DIR) M=$(PWD) clean
时间: 2024-11-11 02:29:25

[linux内核笔记-1]内核模块参数传递----module_param()函数的相关文章

(笔记)Linux内核中内存相关的操作函数

linux内核中内存相关的操作函数 1.kmalloc()/kfree() static __always_inline void *kmalloc(size_t size, gfp_t flags) 内核空间申请指定大小的内存区域,返回内核空间虚拟地址.在函数实现中,如果申请的内存空间较大的话,会从buddy系统申请若干内存页面,如果申请的内存空间大小较小的话,会从slab系统中申请内存空间.有关buddy和slab,请参见<linux内核之内存管理.doc> gfp_t flags 的选项

【转载】linux内核笔记之高端内存映射

原文:linux内核笔记之高端内存映射 在32位的系统上,内核使用第3GB~第4GB的线性地址空间,共1GB大小.内核将其中的前896MB与物理内存的0~896MB进行直接映射,即线性映射,将剩余的128M线性地址空间作为访问高于896M的内存的一个窗口. 引入高端内存映射这样一个概念的主要原因就是我们所安装的内存大于1G时,内核的1G线性地址空间无法建立一个完全的直接映射来触及整个物理内存空间,而对于80x86开启PAE的情况下,允许的最大物理内存可达到64G,因此内核将自己的最后128M的线

Linux 内核编程 or 内核模块编程的文件读写与信号传输问题

Linux内核编程时,内核代码执行只能直接访问内存上的数据,硬盘上的文件系统必须通过间接的方式才能被内核读写.一般内核操作文件读写的方式有三种:1.通过/proc/文件作为桥梁完成硬盘文件系统与内核的交互:2.通过ioctl方式实现交互:3.直接利用虚拟文件系统的函数vfs_read().vfs_write()读写文件.三种方式的具体实现方法网上有很多详细教程,可以参考.这里对三种方法做出比较. proc机制是一种很老的文件读写方式,通用性好,实现也算成熟,使用时需要自己实现内核上层的读写函数,

【转载】linux内核笔记之进程地址空间

原文:linux内核笔记之进程地址空间 进程的地址空间由允许进程使用的全部线性地址组成,在32位系统中为0~3GB,每个进程看到的线性地址集合是不同的. 内核通过线性区的资源(数据结构)来表示线性地址区间,线性区是由起始线性地址,长度和一些访问权限来描述的.线性区的大小为页框的整数倍,起始地址为4096的整数倍. 下图展示了x86 Linux 进程的地址空间组织结构: 正文段 .text ,这是CPU执行的机器指令部分.通常正文段是共享的,而且是只读的,以防止程序修改其自身的指令. 数据段 .d

Linux内核笔记:epoll实现原理

一.说明 针对的内核版本为4.4.10. 本文只是我自己看源码的简单笔记,如果想了解epoll的实现,强烈推荐下面的文章: The Implementation of epoll(1) The Implementation of epoll(2) The Implementation of epoll(3) The Implementation of epoll(4) 二.epoll_create() 系统调用epoll_create()会创建一个epoll实例并返回该实例对应的文件描述符fd.

linux 内核移植(七)——rest_init函数分析

代码在start_kernel函数运行的最后到了rest_init()函数中 1:rest_init()函数分析 (1)rest_init中调用kernel_thread函数启动了2个内核线程,分别是:kernel_init和kthreadd (2)调用schedule函数开启了内核的调度系统,从此linux系统开始转起来了. (3)rest_init最终调用cpu_idle函数结束了整个内核的启动.也就是说linux内核最终结束了一个函数cpu_idle.这个函数里面肯定是死循环. (4)简单

linux内核中的排序接口--sort函数

linux内核中的sort函数,事实上跟我们所说的qsort函数非常像,我们来看看qsort: qsort 的函数原型是 void qsort(void*base,size_t num,size_t width,int(__cdecl*compare)(const void*,const void*)); 參数:  1 .待排序数组首地址 2 .数组中待排序元素数量 3 .各元素的占用空间大小 4 .指向函数的指针.用于确定排序的顺序. 当中compare函数应写为: 1 2 3 4 int c

linux内核中对双向链表的操作函数

在linux内核中用的非常多的一种链表是:双向链表.内核中对所用的进程的管理就是通过双向链表来实现的.所以对链表的操作非常的常用也非常的重要,因此内核通过提供一个通用的方法来帮助我们方便的对双链表实现各种操作. struct list_head {struct list_head *next, *prev;} 0,对双向链表中的某个项进行初始化操作的函数: INIT_LIST_HEAD(struct list_head *entry) INIT_LIST_HEAD()的实现方法: static

linux内核设计的艺术-开始执行main函数

为了执行linux内的C语言main函数,上一篇讲到了,为了从汇编语言环境跳转到C语言环境下执行,将CPU工作模式从16位转变到32位模式(C语言是32位的),并且重新建立了GDT与IDT,但是此时GDT和IDT中并没有内容,所以不能进行内存寻址与中断,接下来就是初始化GDT和IDT了. 进入32位模式后,寄存器也将变为32位寄存器,下面的汇编语法和之前的intel汇编有些不同,为AT&T汇编,至于差别不在赘述. Head.S startup_32: //重设段寄存器内容 movl $0x10,