内核模块的特征:(如何传参和调用)

1、内核模块中传递参数

1.1 代码:

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

char *name;
int age;

//模块加载(入口)函数
static int __init hello_init(void)
{
	printk("------------调试 %s---------------------\n",__FUNCTION__);//打印函数名
	printk("name = %s,age = %d\n",name,age);
	return 0;
}

//模块卸载(出口)函数
static void __exit hello_exit(void)
{
	printk("------------调试 %s---------------------\n",__FUNCTION__);
}
//参数1 --- 要声明的变量
//参数2 --- 变量的类型
//参数3 --- 变量的权限
module_param(age, int, 0644);        
module_param(name, charp, 0644);//声明与认证
module_init(hello_init);
module_exit(hello_exit);

2.1 开发板中加载模块,同时传递参数

[root@farsight /drv_module]# insmod hello_drv.ko name=jack age=19
[  822.394221] ------------调试 hello_init---------------------
[  822.398429] name = jack,age = 19

内核模块中没有main函数,所以向模块内部传入参数可以通过module_param这个宏定义来实现:
// 原型

#define module_param(name, type, perm)     
        module_param_named(name, name, type, perm)
参数作用:        
    name:传入参数名称
    type:传入参数类型,有byte, short, ushort, int, uint, long, ulong, charp, bool,invbool这几种类型
    perm:这个为sysfs中资源的访问权限,下面再细说,主要有以下权限类型在uapi/linux/stat.h中定义

主要有以下权限类型在uapi/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    // 其他人可执行权限

使用 S_IRUGO 作为参数以被所有人读取, 但是不能改变; S_IRUGO|S_IWUSR 允许 root 来改变参数
注意: 如果一个参数被 sysfs 修改, 你的模块看到的参数值也改变了, 但是你的模块没有任何其他的通知. 你应当不要使模块参数可写, 除非你准备好检测这个改变并且因而作出反应.
————————————————
上文中宏定义的权限来自于该文章
原文链接:

https://blog.youkuaiyun.com/weixin_45619852/article/details/120514016

2、模块调用:

和c模块化编程一样,创建一个.c的源文件,并在头文件.h中声明;
再创建一个模块xxx_drv.c去调用该模块中的函数;

2.1 示例代码:

fun.c

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

int add(int a,int b)
{
    return a+b;
}

EXPORT_SYMBOL(add);
MODULE_LICENSE("GPL");
MODULE_INFO(intree,"Y");

EXPORT_SYMBOL作用是什么?

EXPORT_SYMBOL标签内定义的函数或者符号对全部内核代码公开不用修改内核代码就可以在您的内核模块中直接调用,即使用EXPORT_SYMBOL可以将一个函数以符号的方式导出给其他模块使用

使用方法
1、在模块函数定义之后使用“EXPORT_SYMBOL(函数名)”来声明。
2、在调用该函数的另外一个模块中使用extern对之声明。
3、先加载定义该函数的模块,然后再加载调用该函数的模块,请注意这个先后顺序。
————————————————
EXPORT_SYMBOL的解释来自于该文章
原文链接:https://blog.youkuaiyun.com/qq_37858386/article/details/78444168

fun.h

#ifndef __FUN_H__
#define __FUN_H__

int add(int a,int b);

#endif

hello_drv.c

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

#include "fun.h"

int a,b;

static int __init hello_init(void)
{
    //调试打印函数名
    printk("------------调试 %s---------------------\n",__FUNCTION__);
    
    printk("%d+%d=%d\n",a,b,add(a,b));
    
    return 0;
}

static void __exit hello_exit(void)
{
    printk("------------调试 %s---------------------\n",__FUNCTION__);
    
}

module_param(a,int,0644);
modele_param(b,int,0644);

module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");

2.2 修改makefile

修改Makefile如下:

 #指定内核源码路径
    KERNEL_DIR = 内核源码路径
    #指定当前模块所在的路径
    #CUR_DIR = $(shell pwd)
    CUR_DIR = `pwd`

    MODULE_NAME1 = hello_drv
    MODULE_NAME2 = fun

    all:
        #编译当前目录中的内核模块
            $(MAKE) -C $(KERNEL_DIR) M=$(CUR_DIR)  modules


    clean:
        #删除上面编译生成的文件
            $(MAKE) -C $(KERNEL_DIR) M=$(CUR_DIR)  clean

    install:
            cp *.ko /opt/rootfs/drv_module/

    #指定具体要编译的模块文件
    obj-m += fun.o
    obj-m += hello_drv.o

然后make编译、make install copy到文件系统中去

2.3 连接开发板,执行加载命令

需要先加载被调用的模块

  insmod fun.ko

再加载主模块同时并给里面的参数传值:

insmod hello_drv.ko a = 5 b = 3

为什么需要赋值?

因为用到了一个外部传参的一个宏 module_param(name, type, perm)

2.4 打印输出结果是:

[ 4604.910868] ------------调试 hello_init---------------------
[ 4604.918281] 5 + 3 = 8
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值