3、Linux驱动开发:模块_传递参数

目录

点击这里查看所有博文

  随着自己工作的进行,接触到的技术栈也越来越多。给我一个很直观的感受就是,某一项技术/经验在刚开始接触的时候都记得很清楚。往往过了几个月都会忘记的差不多了,只有经常会用到的东西才有可能真正记下来。存在很多在特殊情况下有一点用处的技巧,用的不多的技巧可能一个星期就忘了。

  想了很久想通过一些手段把这些事情记录下来。也尝试过在书上记笔记,这也只是一时的,书不在手边的时候那些笔记就和没记一样,不是很方便。

  很多时候我们遇到了问题,一般情况下都是选择在搜索引擎检索相关内容,这样来的也更快一点,除非真的找不到才会去选择翻书。后来就想到了写博客,博客作为自己的一个笔记平台倒是挺合适的。随时可以查阅,不用随身携带。

  同时由于写博客是对外的,既然是对外的就不能随便写,任何人都可以看到。经验对于我来说那就只是经验而已,公布出来说不一定我的一些经验可以帮助到其他的人。遇到和我相同问题时可以少走一些弯路。

  既然决定了要写博客,那就只能认真去写。不管写的好不好,尽力就行。千里之行始于足下,一步一个脚印,慢慢来 ,写的多了慢慢也会变好的。权当是记录自己的成长的一个过程,等到以后再往回看时,就会发现自己以前原来这么菜。

  本系列博客所述资料均来自互联网资料,并不是本人原创(只有博客是自己写的)。出于热心,本人将自己的所学笔记整理并推出相对应的使用教程,方面其他人学习。为国内的物联网事业发展尽自己的一份绵薄之力,没有为自己谋取私利的想法。若出现侵权现象,请告知本人,本人会立即停止更新,并删除相应的文章和代码。

前言

  在用户态下编程可以通过main来传递命令行参数,而编写一个内核模块则可通过module_param来传递命令行参数。

给模块定义外部参数

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

/**
 * module_param - typesafe helper for a module/cmdline parameter
 * @value: the variable to alter, and exposed parameter name.
 * @type: the type of the parameter
 * @perm: visibility in sysfs.
 *
 * @value becomes the module parameter, or (prefixed by KBUILD_MODNAME and a
 * ".") the kernel commandline parameter.  Note that - is changed to _, so
 * the user can use "foo-bar=1" even for variable "foo_bar".
 *
 * @perm is 0 if the the variable is not to appear in sysfs, or 0444
 * for world-readable, 0644 for root-writable, etc.  Note that if it
 * is writable, you may need to use kparam_block_sysfs_write() around
 * accesses (esp. charp, which can be kfreed when it changes).
 *
 * The @type is simply pasted to refer to a param_ops_##type and a
 * param_check_##type: for convenience many standard types are provided but
 * you can create your own by defining those variables.
 *
 * Standard types are:
 *	byte, short, ushort, int, uint, long, ulong
 *	charp: a character pointer
 *	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使用了3个参数:变量名,它的类型,以及一个权限掩码用来做一个辅助的sysfs入口。这个宏定义应当放在函数之外,典型的是出现在源文件的前面。

   module_param_named则是另一个变种,以示例说明可使得var变量在内核外的变量名称为var_out。在内核外给var_out赋值等同于给模块内var变量赋值。

static char *whom = "hello \n";
static int var = 1;
module_param(whom,charp,0644);
module_param_named(var_out,var,int,0644);

示例代码

#include 
#include 
MODULE_LICENSE("GPL");
MODULE_AUTHOR("PD");
static char *whom = "hello";
static int var = 1;
module_param(whom,charp,0644);
module_param_named(var_out,var,int,0644);
static int hello_init(void)
{
	printk("hello_init %s \n",whom);
	printk("hello_init %d\n",var);
	return 0;
}
static void hello_exit(void)
{
	printk("hello_exit %s \n",whom);
	printk("hello_exit %d\n",var);
	return;
}
module_init(hello_init);
module_exit(hello_exit);

参数传入

   insmod加载模块时,可直接携带对应的参数。当传入不存在的参数时,会报错unknown parameter

root@ubuntu:# insmod ./hello.ko var=100 var_out=200 whom="test"
root@ubuntu:# rmmod ./hello.ko
root@ubuntu:# dmesg
[ 9730.375507] hello: unknown parameter 'var' ignored
[ 9730.375536] hello_init test
[ 9730.375537] hello_init 200 
[ 9733.244654] hello_exit  test
[ 9733.244655] hello_exit  200

   如不携带参数,则使用模块的默认值。

root@ubuntu:# insmod ./hello.ko
root@ubuntu:# rmmod ./hello.ko
root@ubuntu:# dmesg
[ 9520.771593] hello_init hello 
[ 9520.771594] hello_init 1
[ 9534.227683] hello_exit hello 
[ 9534.227684] hello_exit 1

参数修改

   sysfs: 内核会给一些重要的资源创建专属目录或者文件。每个模块会在/sys/module下创建一个同名的文件夹。

   文件夹在加载时被创建,卸载后立即被销毁。

root@ubuntu:# insmod ./hello.ko var=100 var_out=200 whom="test"
root@ubuntu:# ls /sys/module/hello
coresize  holders  initsize  initstate  notes  parameters  refcnt  sections  srcversion  taint  uevent
root@ubuntu:# rmmod ./hello.ko
root@ubuntu:# ls /sys/module/hello
ls: cannot access '/sys/module/hello': No such file or directory

   在专属目录下的parameters目录中记录了模块参数的外部节点。均是虚拟字符设备,可直接通过控制台echo修改,cat读取。

root@ubuntu:# /sys/module/hello# cat ./parameters/var_out 
200
root@ubuntu:# /sys/module/hello# cat ./parameters/whom 
test
root@ubuntu:# /sys/module/hello# echo 300 > ./parameters/var_out 
root@ubuntu:# /sys/module/hello# echo "hahahaha" > ./parameters/whom 
root@ubuntu:# /sys/module/hello# cat ./parameters/var_out 
300
root@ubuntu:# /sys/module/hello# cat ./parameters/whom 
hahahaha

  上述修改立即生效,在模块退出时查看日志,可知变量值已经被修改。

root@ubuntu:# dmesg
[10522.899811] hello: unknown parameter 'var' ignored
[10522.899837] hello_init test 
[10522.899838] hello_init  200
[10572.883954] hello_exit hahahaha
[10572.883955] hello_exit  300

补充说明

模块信息查询(modinfo)

  源文件中记录的额外信息,都会在编译后被打包到ko文件中,以下示例中仅列出一部分。

MODULE_LICENSE("GPL");
MODULE_AUTHOR("PD");
MODULE_DESCRIPTION("3_param example");
MODULE_ALIAS("example3");
MODULE_PARM_DESC(var,"Boolean to enable debugging (0/1 == off/on)");

  在shell中可通过modinfo查询模块的全部信息。

root@ubuntu:# modinfo ./hello.ko
filename:       ./hello.ko
alias:          example3
description:    3_param example
author:         PD
license:        GPL
srcversion:     6D5DF27C63EBFF621C183E3
depends:        
retpoline:      Y
name:           hello
vermagic:       4.15.0-142-generic SMP mod_unload 
parm:           whom:charp
parm:           var_out:int
parm:           var:Boolean to enable debugging (0/1 == off/on)

mask权限问题

  parameters中的对外参数所持有的权限,与代码中module_param注册时填写的权限一致。


module_param(whom,charp,0644);
module_param_named(var_out,var,int,0644);

root@ubuntu:# ll /sys/module/hello/parameters/
total 0
drwxr-xr-x 2 root root    0 Jul 22 03:59 ./
drwxr-xr-x 6 root root    0 Jul 22 03:58 ../
-rw-r--r-- 1 root root 4096 Jul 22 03:59 var_out
-rw-r--r-- 1 root root 4096 Jul 22 03:59 whom

  该权限不能超过module_param_call的mask最大权限,若填写的权限比mask大,则最终效果是以mask为准。对外的现象就是设置的权限不起作用。

/* This is the fundamental function for registering boot/module
   parameters. */
#define __module_param_call(prefix, name, ops, arg, perm, level)	\
	/* Default value instead of permissions? */			\
	static int __param_perm_check_##name __attribute__((unused)) =	\
	BUILD_BUG_ON_ZERO((perm) < 0 || (perm) > 0777 || ((perm) & 2))	\
	+ BUILD_BUG_ON_ZERO(sizeof(""prefix) > MAX_PARAM_PREFIX_LEN);	\
	static const char __param_str_##name[] = prefix #name;		\
	static struct kernel_param __moduleparam_const __param_##name	\
	__used								\
    __attribute__ ((unused,__section__ ("__param"),aligned(sizeof(void *)))) \
	= { __param_str_##name, ops, perm, level, { arg } }

  本例中参数声明时指定权限为0666,结果实际加载后参数文件的权限还是0644。

module_param(whom,charp,0666);
module_param_named(var_out,var,int,0666);
root@ubuntu:# ll /sys/module/hello/parameters/
total 0
drwxr-xr-x 2 root root    0 Jul 22 03:59 ./
drwxr-xr-x 6 root root    0 Jul 22 03:58 ../
-rw-r--r-- 1 root root 4096 Jul 22 03:59 var_out
-rw-r--r-- 1 root root 4096 Jul 22 03:59 whom

  那么本篇博客就到此结束了,这里只是记录了一些我个人的学习笔记,其中存在大量我自己的理解。文中所述不一定是完全正确的,可能有的地方我自己也理解错了。如果有些错的地方,欢迎大家批评指正。如有问题直接在对应的博客评论区指出即可,不需要私聊我。我们交流的内容留下来也有助于其他人查看,说不一定也有其他人遇到了同样的问题呢。

你可能感兴趣的:(Linux驱动开发,linux,驱动开发,模块,参数传递)