实现insmod 模块名.ko 参数1=值 参数2=值 参数3=值.......
目标:
实现模块读取uboot参数;
实现给模块传递参数;
实现proc文件系统属性的读写。
背景:
因一项目使用的模块,在加载时需要传入参数。于是对这一知识点进行整理,附带实现模块读取uboot参数样例和实现proc文件系统属性的读写的样例。部分代码网络摘抄,部分自己实现。
模块源码(param_proc.c):
#include <linux/kernel.h>
#include <linux/module.h> //for init_module()
#include <linux/init.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/sched.h> //for init_task
#include <linux/cdev.h>
#include <asm/io.h>
#include <linux/version.h>
#if LINUX_VERSION_CODE > KERNEL_VERSION(3, 3, 0)
#include <asm/switch_to.h>
#include <linux/slab.h> //for kzalloc, kfree
#include <linux/proc_fs.h> //for create_proc_info_entry()
#else
#include <asm/system.h>
#endif
#include <asm/uaccess.h>
#include <linux/uaccess.h>
//root@wmh-VirtualBox:/opt/param_proc# uname -a
//Linux wmh-VirtualBox 5.15.0-69-generic #76~20.04.1-Ubuntu SMP Mon Mar 20 15:54:19 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux
//root@wmh-VirtualBox:/opt# uname -a
//Linux wmh-VirtualBox 4.15.0-142-generic #146~16.04.1-Ubuntu SMP Tue Apr 13 09:27:15 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux
//insmod paramproc.ko val1=2 val2=4 pstr="abc" 后执行dmesg,可以看到打印:val1:2, val2:4, pstr:abc
//insmod paramproc.ko 后执行dmesg,可以看到打印:val1:0, val2:0, pstr:(null)
//uboot启动参数里面添加参考(未验证):noinitrd root=/dev/mtdblock2 init=/linuxrc console=ttySAC0 getval=1,2 getstr=abc
//cat /proc/result_f/result
//cat /proc/result
int val1 = 0, val2 = 0;
char *pstr = NULL;
module_param(val1, int, S_IRUGO);
module_param(val2, int, S_IRUGO /*0664 ???*/);
module_param(pstr, charp, S_IRUGO);
static int ccnt = 0;
static ssize_t fts_debug_read(struct file *filp, char __user *buff, size_t count, loff_t *ppos)
{
size_t size = 0;
if(ccnt == 0) { ccnt++; } else if(ccnt > 0) { ccnt =0; return 0; } //因为执行cat /proc/result时,控制台一直打印,所以通过这种方法,当第二次进入
//这个函数时,返回0,就可以防止控制台一直打印,及防止执行cat /proc/result不退出。
if(NULL == pstr) { pstr = kmalloc(56, GFP_KERNEL); memset(pstr, 0, 56); memcpy(pstr, "111111\r\n", 8);}
printk("%s():%d, count:%ld, pstr:%s, len:%ld\r\n", __FUNCTION__, __LINE__, count, pstr, strlen(pstr)); /*count打印处理的值为:131072*/
size = copy_to_user(buff, pstr, strlen(pstr)<count?strlen(pstr):count);
printk("%s():%d, count:%ld, pstr:%s, len:%ld, size:%ld\r\n", __FUNCTION__, __LINE__, count, pstr, strlen(pstr), size);
return strlen(pstr);
}
//insmod paramproc.ko val1=12 val2=13 pstr=123456qwer 后执行dmesg,可以看到打印:val1:12, val2:13, pstr:123456qwer
//echo "qwer123456ghjwe" > /proc/result 后执行dmesg,可以看到打印:
// fts_debug_write():50, count:16, pstr:10
//copy_from_user最后一个参数填count的打印: fts_debug_write():52, pstr:qwer123456ghjwe cpuacct.usage_pe\xbfFo\xf64\xf4\xf1, count:16, size:0
//copy_from_user最后一个参数填strlen(pstr)的打印:fts_debug_write():55, pstr:qwer123456, count:16, size:0
static ssize_t fts_debug_write(struct file *filp, const char __user *buff, size_t count, loff_t *ppos)
{
int size = 0; /*count打印处理的值为:写入值的长度+回车*/
if(NULL == pstr) { pstr = kmalloc(56, GFP_KERNEL); }
printk("%s():%d, count:%ld, pstr:%ld\r\n", __FUNCTION__, __LINE__, count, strlen(pstr));
size = copy_from_user(pstr, buff, strlen(pstr)<count?strlen(pstr):count); //返回的是没有被拷贝成功的数量。
printk("%s():%d, pstr:%s, count:%ld, size:%d\r\n", __FUNCTION__, __LINE__, pstr, count, size);
return count; //必须返回count,否则会循环写,直到写满count个字节为止。
}
static struct proc_dir_entry *g_proc_dir = NULL;
static struct proc_dir_entry *proc1 = NULL;
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0))
static struct proc_ops fts_proc_fops={
.proc_read = fts_debug_read,
.proc_write = fts_debug_write,
};
#else
static struct file_operations fts_proc_fops={
.owner = THIS_MODULE,
.read = fts_debug_read,
.write = fts_debug_write,
};
#endif
static __init int test_init_module(void) {
printk("val1:%d, val2:%d, pstr:%s\r\n", val1, val2, pstr);
g_proc_dir = proc_mkdir("result_f", NULL); //会在 /proc目录下创建result_f目录
if(NULL == g_proc_dir) { return -EINVAL; }
//#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0))
// proc = proc_create("result", 0664, /*g_proc_dir*/NULL, &fts_proc_fops);
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0))
proc1 = proc_create("result", 0664, /*g_proc_dir*/NULL, &fts_proc_fops); //如果有g_proc_dir,则会在result_f目录下创建result文件
//如果没有g_proc_dir,则会在 /proc目录下创建 result文件
#else
proc1 = create_proc_entry("result", 0664, /*g_proc_dir*/NULL);
if(NULL != proc1) { //proc->read_proc = read_result;
proc1->write_proc = fts_debug_write;
proc1->read_proc = fts_debug_read;
}
#endif
if(NULL == proc1) { proc_remove(g_proc_dir); }
return 0;
}
static void test_exit_module(void) {
//#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0))
// proc_remove(proc1);
// proc_remove(g_proc_dir);
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0))
proc_remove(proc1);
proc_remove(g_proc_dir);
#else
remove_proc_entry("result", g_proc_dir);
#endif
}
#ifndef MODULE
static __init int get_val(char *str) {
int ints[10];
str = get_options(str, ARRAY_SIZE(ints), ints);
if(ints[0] == 2) {
val1 = ints[1];
val2 = ints[2];
}
return 1;
}
static __init int get_str(char *str) {
if(NULL == pstr) { pstr = kmalloc(56, GFP_KERNEL); }
memcpy(pstr, str, min(strlen(str), 56));
return 1;
}
__setup("getval=", get_val);
__setup("getstr=", get_str);
__initcall(test_init_module);
#else
module_init(test_init_module);
#endif
module_exit(test_exit_module);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("wmh");
MODULE_DESCRIPTION("wmh's program");
Makefile文件:
#make modules
#make clean
#make install
CONFIG_MODULE_SIG = n
TARGET_MODULE:=paramproc
$(TARGET_MODULE)-objs := param_proc.o
ifneq ($(KERNELRELEASE),)
obj-m := $(TARGET_MODULE).o
else
PWD := $(shell pwd)
KDIR := /lib/modules/$(shell uname -r)/build
modules:
$(MAKE) -C $(KDIR) M=$(PWD) modules
install:
$(MAKE) -C $(KDIR) M=$(PWD) modules_install
clean:
rm -rf *.o *.mod.c *.ko *.symvers *.order *.cmd *.maker .tmp_versions *.mod *.cmd
endif
编译、运行结果:
执行make编译出 paramproc.ko
执行 insmod paramproc.ko val1=2 val2=4 pstr="abc" ,后执行dmesg,可以看到打印:val1:2, val2:4, pstr:abc。
执行:echo "12345678" > /proc/result 往result里面写值,实际上值写到了pstr指向的地址。
执行:cat /proc/result读取数据。
疑问:
fts_debug_read函数中如果没有添加 if(ccnt == 0) { ccnt++; } else if(ccnt > 0) { ccnt =0; return 0; },执行cat /proc/result会一直打印?????。
实现insmod 模块名.ko 参数1=值 参数2=值 参数3=值.......相关推荐
- mysql安装服务:Internal error (值不能为null.参数名:path1)The installer will now close
因为之前安装的是mysql8,我重新卸载后再安装mysql5.6时报错: Internal error (值不能为null.参数名:path1)The installer will now close ...
- insmod: error inserting '***.ko': -1 Invalid parameters 真正原因以及解决方法
原因1 :的确是你的内核版本和你Makefile制定的不一样. 这个我就不谈了 原因二:是我们在确保了内核版本和我们Makefile指定的一样的情况下: 竟然还报错 insmod: error ins ...
- python函数参数定义顺序_Python函数定义-位置参数-返回值
原标题:Python函数定义-位置参数-返回值 1 函数介绍 函数在编程语言中就是完成特定功能的一个词句组(代码块),这组语句可以作为一个单位使用,并且给它取一个名字.可以通过函数名在程序的不同地方多 ...
- db2自定义函数能返回几个参数_函数的定义、参数、返回值
一.昨日内容回顾 昨日内容回顾 其他模式补充 r+ w+ a+ 文件内光标移动 在rt模式下read内n表示的读取字符的个数 其他情况及其他方法内n表示都是字节数 f.read(n) f.seek(o ...
- insmod: init_module ‘xxx.ko‘ failed (No such file or directory)
linux 加载模块时遇到: insmod: init_module 'xxx.ko' failed (No such file or directory) 解决办法: 使用dmesg查看问题 dme ...
- 2020-09-22C++学习笔记之引用1(1.引用(普通引用)2.引用做函数参数 3.引用的意义 4.引用本质5.引用结论 6.函数返回值是引用(引用当左值)7测试代码)
2020-09-22C++学习笔记之引用1(1.引用(普通引用)2.引用做函数参数 3.引用的意义 4.引用本质5.引用结论 6.函数返回值是引用(引用当左值)7测试代码) 1.引用(普通引用) 变量 ...
- MVC路由学习:自定义路由参数(用户看不到参数名),重新定义路由规则
MVC路由:由于路由global中注册了,在程序第一次运行时,在MVC会自动生成路由,类似于字典的格式缓存下来,但路由生成的规则又是怎样的呢? 路由生成规则是: 1>更具你定义的的顺序查找路由规 ...
- php 去掉多维数组的键名,去除多维数组的最外层key 保留值
如果你是要将JSON转成PHP数组,方法如下 首先,你这个数据格式是JSON的,要先转成PHP数组. $a = json_decode($a, TRUE); json_decode第二个参数为TRUE ...
- allure报告---动态显示模块名和用例标题
一.allure报告动态参数化展示模块名和用例标题 使用@pytest.mark.parametrize 参数化完成数据驱动时,如果标题写死或者使用别名的方式 这样在报告中的可读性也不高 如何更美观的 ...
最新文章
- windows7、windows 2008和windows 2008 R2 的系统封装介绍
- R向量化操作(Data Transformations)
- sqoop 1.4.5 增量导入hive 0.12.0
- hp代码改成linux代码,HP Database Archiving Software远程任意代码执行漏洞
- Asp.Net Core Blazor之容器部署
- Tp框架中模板中if条件如何使用?
- (14)VHDL测试激励编写(时钟)
- Linux——vi的使用
- python 两个变量同时循环_python基础篇(子非鱼)
- 带你快速玩转canvas——写个折线图
- 《算法竞赛入门经典》——刘汝佳
- 用Python分析北京二手房房价
- linux+磁盘清理工具,linux centos 磁盘清理
- 物联网NB-IoT技术商用正全面铺开 竞争日趋激烈
- java 文件上传乱码_java上传txt文件,出现中文乱码
- 【CodingNoBorder - 04】无际软工队 - 求职岛:技术规格说明书
- 压力测试 闪存_[实验]苹果今年大范围使用的TLC闪存颗粒真的是那么不堪吗?
- 多项式插值中的一些定理证明
- 【教学类-17-01】20221122《世界杯七巧板A4整页-随机参考图+七巧板+画框》(大班)
- 刚刚开通,感受一下此地气氛