所以我试图编写一个使用linux / timer.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: %dn",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 %dn",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()函数。 我知道我需要使用ioctl(),但我不知道如何在我的MODULE FILE中指定TimerSetup()应该可以通过ioctl()调用。
另外,我的第二个问题是:我可以将模块和mknod用正确的主编号写入/ dev / mytimer。 但是当我试图打开()它,以便我可以从它得到文件描述符,它保持返回-1,我假设是错误的。 我确定权限没有问题(实际上,我只是确定了777)…它仍然不起作用…有什么我失踪了吗?
如何捕捉使用sigsegv的内存读取和写入?
task_struct存储在哪里?
Linux 3/1虚拟地址分割
VirtualBox如何处理来宾Linux的中断?
Docker for Windows如何运行Linux容器?
以下是用户程序,以防万一:
#include <stdio.h> int main(int argc,char* argv[]) { int fd = open("/dev/mytimer","r"); printf("fd: %dn",fd); return 0; }
有没有从Xenomai实时线程调用gettimeofday()的安全方法?
批量邮件传输USB Linux
如何加快Linux内核编译?
在我的内核中保险丝版本?
为什么flush_dcache_page()在Linux内核中什么都不做?
你需要的示例代码可以在drivers/watchdog/softdog.c (在编写时从Linux 2.6.33开始),它说明了正确的文件操作以及如何允许userland用ioctl()填充结构。 。
对于需要编写简单字符设备驱动程序的人来说,这实际上是一个很好的工作教程。
回答我自己的问题时 ,我解剖了softdog的ioctl界面,这可能对您有所帮助。
这是它的要点(尽管非常详尽)。
在softdog_ioctl()您可以看到struct watchdog_info的一个简单初始化,它softdog_ioctl()了功能,版本和设备信息:
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,导致相应的用户空间ioctl()调用返回-1,并设置有意义的errno。
请注意,魔术请求实际上在linux / watchdog.h中定义,以便内核和用户空间共享它们:
#define WdioC_GETSUPPORT _IOR(WATCHDOG_IOCTL_BASE,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明显表示“看门狗书”
您可以轻松地进一步,让您的驱动程序做一些事情,并将结果放入结构中,并将其复制到用户空间。 例如,如果struct watchdog_info也有一个成员__u32 result_code 。 请注意, __u32只是uint32_t的内核版本。
使用ioctl(),用户可以传递一个对象的地址,无论是内核的结构,整型,还是内核都要在相同的对象中写回答,并将结果复制到提供的地址。
你需要做的第二件事是确保你的设备知道当某人打开,读取,写入或者使用像ioctl()这样的钩子,你可以通过学习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()。
我想你可能会并列一层在处理ioctl()时并不存在的复杂性,这真的很简单。 出于同样的原因,大多数内核开发人员都对新的ioctl接口感到厌烦,除非他们是绝对必要的。 它很容易失去ioctl()将要填充的类型与你使用的魔法的类型,这是copy_to_user()失败的主要原因经常导致内核被用户空间阻塞磁盘睡眠。
对于一个计时器,我同意,ioctl()是理智的最短路径。
您在file_operations结构中缺少.open函数指针,以指定在进程尝试打开设备文件时要调用的函数。 您还需要为您的ioctl函数指定一个.ioctl函数指针。
尝试通读“Linux内核模块编程指南” ,特别是第4章(字符设备文件)和第7章(与设备文件交谈)。
第4章介绍了file_operations结构,该结构持有指向由模块/驱动程序定义的函数的指针,用于执行各种操作,如open或ioctl 。
第7章提供了通过ioctls与模块/驱动器进行通信的信息。
Linux设备驱动程序,第三版是另一个很好的资源。
最小的可运行示例
在完全可重复的QEMU + buildroot环境中进行测试,因此可以帮助其他人获得他们的ioctl工作。 GitHub上游: 内核模块 | 共享标题 | 用户区 。
最烦人的部分是理解一些低ID被劫持: 如果cmd = 2 , 则不调用ioctl ,则必须使用_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 = %xn",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 = %dn",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,sizeof(arg_kernel.s))) { return -EFAULT; } pr_info("1 arg = %d %dn",arg_kernel.si,arg_kernel.sj); arg_kernel.si += 1; arg_kernel.sj -= 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",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,int) #define LKMC_IOCTL_INC_DEC _IOWR(LKMC_IOCTL_MAGIC,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 = %dn",arg_int); printf("ret = %dn",ret); printf("errno = %dn",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 %dn",arg_struct.i,arg_struct.j); printf("ret = %dn",errno); } close(fd); return EXIT_SUCCESS; }
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。