我怎么使用读写()操纵我的核心模块?
-
20-09-2019 - |
题
所以我想写一个核心模块,使用linux/时。h文件。我得到了它的内工作只是模块,现在我试图让它的工作从用户的程序。
这里是我的核心模块:
//Necessary Includes For Device Drivers.
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/proc_fs.h>
#include <asm/uaccess.h>
#include <linux/timer.h>
#include <linux/ioctl.h>
#define DEVICE_NAME "mytimer"
#define DEVICE_FILE_NAME "mytimer"
#define MAJOR_NUM 61
#define MINOR_NUM 0
MODULE_LICENSE("Dual BSD/GPL");
static struct timer_list my_timer;
struct file_operations FileOps =
{
//No File Operations for this timer.
};
//Function to perform when timer expires.
void TimerExpire(int data)
{
printk("Timer Data: %d\n", data);
}
//Function to set up timers.
void TimerSetup(void)
{
setup_timer(&my_timer, TimerExpire, 5678);
mod_timer(&my_timer, jiffies + msecs_to_jiffies(5000));
}
//Module Init and Exit Functions.
int init_module(void)
{
int initResult = register_chrdev(MAJOR_NUM, "mytimer", &FileOps);
if (initResult < 0)
{
printk("Cannot obtain major number %d\n", MAJOR_NUM);
return initResult;
}
printk("Loading MyTimer Kernel Module...\n");
return 0;
}
void cleanup_module(void)
{
unregister_chrdev(MAJOR_NUM, "mytimer");
printk("Unloading MyTimer Kernel Module...\n");
}
更具体地说,我想我用户的程序来调TimerSetup()function.我知道我会需要用读写()但是我不知道该如何指定在我的模块文件,TimerSetup()应当可通过读写().
此外,我的第二个问题:我能够insmod我的模块,也mknod入/dev/mytimer正确的主要数字。但是当我试图打开()它这样我就可以获得该文件描述它,它保持返回-1,我假设是错误的。我确定的权限的罚款(事实上,我做了777只是要确定)...它仍然没有工作...有什么东西是我的失踪?
这里是用户的程序,只是在情况:
#include <stdio.h>
int main(int argc, char* argv[])
{
int fd = open("/dev/mytimer", "r");
printf("fd: %d\n", fd);
return 0;
}
解决方案
例码你需要可以发现在 drivers/watchdog/softdog.c
(从Linux2.6.33在当时,这是书面的),这说明了适当的文件的操作以及如何允许用户态,以填补一个结构有读写().
它实际上是一个伟大的,工作程序的任何人需要编写琐碎字装置驱动程序。
我解剖softdog的读写接口的时候 回答我自己的问题, ,这可能是有帮助的。
这里是它的要点(虽然远未穷尽的)...
在 softdog_ioctl()
你看到一个简单的初始化的结构watchdog_info做广告功能,版本和设备的信息:
static const struct watchdog_info ident = {
.options = WDIOF_SETTIMEOUT |
WDIOF_KEEPALIVEPING |
WDIOF_MAGICCLOSE,
.firmware_version = 0,
.identity = "Software Watchdog",
};
然后我们看着一个简单的情况下,用户只是想获得这些能力:
switch (cmd) {
case WDIOC_GETSUPPORT:
return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
...这当然,将填补的相对应的用户watchdog_info与初始化价值观之上。如果copy_to_user()失败,-EFAULT返回其原因相应的用户读写()呼要返回-1与一个有意义的errno被设定。
注意,魔法请求实际上都是定义在linux/看门狗。h,使核心和用户分享他们:
#define WDIOC_GETSUPPORT _IOR(WATCHDOG_IOCTL_BASE, 0, struct watchdog_info)
#define WDIOC_GETSTATUS _IOR(WATCHDOG_IOCTL_BASE, 1, int)
#define WDIOC_GETBOOTSTATUS _IOR(WATCHDOG_IOCTL_BASE, 2, int)
#define WDIOC_GETTEMP _IOR(WATCHDOG_IOCTL_BASE, 3, int)
#define WDIOC_SETOPTIONS _IOR(WATCHDOG_IOCTL_BASE, 4, int)
#define WDIOC_KEEPALIVE _IOR(WATCHDOG_IOCTL_BASE, 5, int)
#define WDIOC_SETTIMEOUT _IOWR(WATCHDOG_IOCTL_BASE, 6, int)
#define WDIOC_GETTIMEOUT _IOR(WATCHDOG_IOCTL_BASE, 7, int)
#define WDIOC_SETPRETIMEOUT _IOWR(WATCHDOG_IOCTL_BASE, 8, int)
#define WDIOC_GETPRETIMEOUT _IOR(WATCHDOG_IOCTL_BASE, 9, int)
#define WDIOC_GETTIMELEFT _IOR(WATCHDOG_IOCTL_BASE, 10, int)
WDIOC显然标志着"看门狗读写"
你可以很容易地采取这一步的步骤,具有驱动程序做某事,并将结果,一些在结构和复制到用户空间。例如,如果结构watchdog_info还有一件 __u32 result_code
.注意, __u32
只是内核的版本 uint32_t
.
有读写()、用户传对象的地址,将它结构,整数,不论的核心期望的核写答复在一个相同的对象和复制的结果的地址,提供。
第二件事你需要做的是确保设备知道该怎么做,当有人打开了,读,写,或者采用一种挂钩喜欢读写(),这你可以很容易地看到通过研究softdog.
感兴趣的是:
static const struct file_operations softdog_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = softdog_write,
.unlocked_ioctl = softdog_ioctl,
.open = softdog_open,
.release = softdog_release,
};
你在哪里看到的unlocked_ioctl处理程序要...你猜对了,softdog_ioctl().
我想你可能会把一层复杂性,不存在处理读写(),这真的是这么简单。出于同样的原因,大部分的内核开发的皱眉新的读写的接口正在增加,除非他们是绝对必要的。它只是太容易失去的轨道类型,读写()是去填补与魔术的使用做到这一点,其主要原因,copy_to_user()失败常常导致在核心腐烂成群的用户进程停留在盘睡觉。
一定时,我同意,读写()是最短的路要理智。
其他提示
您在您的.open
结构指定函数缺少file_operations
函数指针,当一个进程试图打开设备文件被调用。您需要指定一个.ioctl
函数指针,你的ioctl函数为好。
尝试通过 Linux内核模块编程指南,具体章节4(字符设备文件)和7(交谈设备文件)。
第4章介绍file_operations
结构,它保存的指针的是执行各种操作,诸如open
或ioctl
由模块/驱动器定义的函数。
第7章提供与模块通信信息/通过读写控制驱动。
Linux设备驱动程序,第三版是另一个很好的资源。
<强>最小可运行示例强>
在一个完全可重复的QEMU + Buildroot里面的环境测试,因此可能帮助别人得到他们ioctl
工作。 GitHub的上游:
内核模块 |
共享头 |
用户态。
最讨厌的部分被理解,一些低IDS被劫持: IOCTL是如果CMD = 2 ,则必须使用_IOx
宏不被调用。
内核模块:
#include <asm/uaccess.h> /* copy_from_user, copy_to_user */
#include <linux/debugfs.h>
#include <linux/module.h>
#include <linux/printk.h> /* printk */
#include "ioctl.h"
MODULE_LICENSE("GPL");
static struct dentry *dir;
static long unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long argp)
{
void __user *arg_user;
union {
int i;
lkmc_ioctl_struct s;
} arg_kernel;
arg_user = (void __user *)argp;
pr_info("cmd = %x\n", cmd);
switch (cmd) {
case LKMC_IOCTL_INC:
if (copy_from_user(&arg_kernel.i, arg_user, sizeof(arg_kernel.i))) {
return -EFAULT;
}
pr_info("0 arg = %d\n", arg_kernel.i);
arg_kernel.i += 1;
if (copy_to_user(arg_user, &arg_kernel.i, sizeof(arg_kernel.i))) {
return -EFAULT;
}
break;
case LKMC_IOCTL_INC_DEC:
if (copy_from_user(&arg_kernel.s, arg_user, sizeof(arg_kernel.s))) {
return -EFAULT;
}
pr_info("1 arg = %d %d\n", arg_kernel.s.i, arg_kernel.s.j);
arg_kernel.s.i += 1;
arg_kernel.s.j -= 1;
if (copy_to_user(arg_user, &arg_kernel.s, sizeof(arg_kernel.s))) {
return -EFAULT;
}
break;
default:
return -EINVAL;
break;
}
return 0;
}
static const struct file_operations fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = unlocked_ioctl
};
static int myinit(void)
{
dir = debugfs_create_dir("lkmc_ioctl", 0);
/* ioctl permissions are not automatically restricted by rwx as for read / write,
* but we could of course implement that ourselves:
* https://stackoverflow.com/questions/29891803/user-permission-check-on-ioctl-command */
debugfs_create_file("f", 0, dir, NULL, &fops);
return 0;
}
static void myexit(void)
{
debugfs_remove_recursive(dir);
}
module_init(myinit)
module_exit(myexit)
共享头:
#ifndef IOCTL_H
#define IOCTL_H
#include <linux/ioctl.h>
typedef struct {
int i;
int j;
} lkmc_ioctl_struct;
#define LKMC_IOCTL_MAGIC 0x33
#define LKMC_IOCTL_INC _IOWR(LKMC_IOCTL_MAGIC, 0, int)
#define LKMC_IOCTL_INC_DEC _IOWR(LKMC_IOCTL_MAGIC, 1, lkmc_ioctl_struct)
#endif
用户空间:
#define _GNU_SOURCE
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include "../ioctl.h"
int main(int argc, char **argv)
{
int fd, arg_int, ret;
lkmc_ioctl_struct arg_struct;
if (argc < 2) {
puts("Usage: ./prog <ioctl-file>");
return EXIT_FAILURE;
}
fd = open(argv[1], O_RDONLY);
if (fd == -1) {
perror("open");
return EXIT_FAILURE;
}
/* 0 */
{
arg_int = 1;
ret = ioctl(fd, LKMC_IOCTL_INC, &arg_int);
if (ret == -1) {
perror("ioctl");
return EXIT_FAILURE;
}
printf("arg = %d\n", arg_int);
printf("ret = %d\n", ret);
printf("errno = %d\n", errno);
}
puts("");
/* 1 */
{
arg_struct.i = 1;
arg_struct.j = 1;
ret = ioctl(fd, LKMC_IOCTL_INC_DEC, &arg_struct);
if (ret == -1) {
perror("ioctl");
return EXIT_FAILURE;
}
printf("arg = %d %d\n", arg_struct.i, arg_struct.j);
printf("ret = %d\n", ret);
printf("errno = %d\n", errno);
}
close(fd);
return EXIT_SUCCESS;
}