从用户空间C调用ioctl时出错
我正在尝试实现一个程序来访问嵌入式系统上的内存。我需要访问一些控制寄存器,所以我认为ioctl是最好的方法。我已将ioctl添加到fops:从用户空间C调用ioctl时出错,c,linux-kernel,ioctl,C,Linux Kernel,Ioctl,我正在尝试实现一个程序来访问嵌入式系统上的内存。我需要访问一些控制寄存器,所以我认为ioctl是最好的方法。我已将ioctl添加到fops: struct file_operations aes_fops = { read: aes_read, write: aes_write, unlocked_ioctl: aes_ioctl, open: aes_open, release: aes_release }; 并设置了以下功能: int aes_ioctl(struct
struct file_operations aes_fops = {
read: aes_read,
write: aes_write,
unlocked_ioctl: aes_ioctl,
open: aes_open,
release: aes_release
};
并设置了以下功能:
int aes_ioctl(struct inode *inode,
struct file *file,
unsigned int ioctl_num,
unsigned long ioctl_param){
printk(KERN_INFO "in ioctl\n");
....
}
但是我没有进入这个函数的内部。这是我的用户空间代码。请帮助我理解,如果我这样做是完全错误的
int main(int argc, char* argv[]){
int fd = fopen("/dev/aes", "r+");
ioctl(fd, 0, 1);
fclose(fd);
}
有些代码显然是针对较旧的内核的,因为我编译的是一个嵌入式系统,其中修改了较旧版本的Linux。您的
aes\u fops
结构设置正确吗?我从来没有见过这样做。我所有的代码都是:
.unlocked_ioctl = aes_ioctl,
而不是:
unlocked_ioctl: aes_ioctl,
据我所知(以及在定义过程中),结构中的冒号(正如您在设置中所做的)字段用于位字段,而不是初始化单个字段
换句话说,尝试:
struct file_operations aes_fops = {
.read = aes_read,
.write = aes_write,
.unlocked_ioctl = aes_ioctl,
.open = aes_open,
.release = aes_release
};
注:gcc似乎曾经允许该结构字段初始化的变体,但自gcc 2.5(见gcc文档中的直接内容)以来,该变体已经过时。您确实应该使用适当的方法(即ISO标准所认可的方法)来完成此操作。代码的问题在于您使用的请求编号-
0
。内核保留了一些请求号供内部使用。内核将请求号视为一个结构,将其划分为字段并为其调用正确的子系统
请参阅文档/ioctl/ioctl-number.txt(来自Linux 3.4.6):
根据您正在执行的操作,您必须遵循添加新ioctls()的内核指南:
如果要向内核添加新的ioctl,则应使用
在中定义的宏:
_IO是一个不带参数的ioctl
_IOW带有写入参数的ioctl(从用户处复制)
_IOR具有读取参数的ioctl(复制到用户)
_IOWR具有写入和读取参数的ioctl。
请参阅内核自己的文档/ioctl/ioctl decoding.txt
文档,了解有关这些数字的结构的更多详细信息
实际上,如果您选择代码1,即从
0x100
开始,一直到0x1ff
,您就可以了。如果不知道返回的错误,很难说。。。我的第一个想法是您对文件描述符的权限。我以前也见过类似的问题。首先,如果查看ioctl的返回,您可以获得有关失败的更多信息:
#include <errno.h>
int main(int argc, char* argv[])
{
long ret;
int fd = fopen("/dev/aes", "r+");
ret = ioctl(fd, 0, 1);
if (ret < 0)
printf("ioctl failed. Return code: %d, meaning: %s\n", ret, strerror(errno));
fclose(fd);
}
如果您看到以下内容:
crw------- 1 root root 10, 57 Aug 21 10:24 /dev/aes
然后只需发布一个:
sudo chmod 777 /dev/aes
然后再试一次。我打赌这对你会有用的。(注意,我使用root权限运行,因为root是我的mod版本的所有者)
如果权限已经确定,那么我还有一些建议:
1) 对我来说,fopen/fclose的用法很奇怪。你真的只需要做:
int fd = open("/dev/aes");
close(fd);
我的系统甚至不允许你的代码按原样编译
2) 您的IOCTL参数列表很旧,我不知道编译的内核版本,但最近的内核使用以下格式:
long aes_ioctl(struct file *file, unsigned int ioctl_num, unsigned long ioctl_param){
注意inode的删除和返回类型的更改。当我在我的系统上运行你的代码时,我做了这些更改
祝你好运
注意:当我们“没有进入ioctl”时,为什么要检查退货?让我举个例子:
//Kernel Code:
//assume include files, other fops, exit, miscdev struct, etc. are present
long hello_ioctl(struct file *file, unsigned long ioctl_num, unsigned long ioctl_param) {
long ret = 0;
printk("in ioctl");
return ret;
}
static const struct file_operations hello_fops = {
owner: THIS_MODULE,
read: hello_read,
unlocked_ioctl: hello_ioctl,
};
static int __init hello_init(void) {
int ret;
printk("hello!\n");
ret = misc_register(&hello_dev); //assume it worked...
return ret;
}
用户空间代码:
//assume includes
void main() {
int fd;
long ret;
fd = open("/dev/hello");
if(fd) {
c = ioctl(fd, 0, 1);
if (c < 0)
printf("error: %d, errno: %d, meaning: %s\n", c, errno, strerror(errno));
close(fd);
}
return;
}
看来我们没有“进入”ioctl。程序的输出是什么
error: -1, errno: 9, meaning: Bad file descriptor
许多有用的输出。显然ioctl电话做了些什么,只是不是我们想要的。现在更改权限并重新运行,我们可以看到新的dmesg:
[ 2388.051660] Hello!
[ 2625.025339] in ioctl
C99标准是向后兼容的,如果愿意,他可以使用旧的初始化方法(除非驱动程序提交给内核维护人员)。不过,这与手头的问题无关。c99标准和早期的ISO标准都没有提到这种方法。我想你指的是gcc的“标准版”,即扩展版。你可能在实际原因上是对的,在这种情况下,你的答案无疑会把我的答案从水里吹出来:-)我还是把我的留在这里,因为我认为使用适当的语言功能是个好主意。请看。@Don,我知道C99已经指定了初始化器,但
字段:value
变体是一个gcc扩展(现已过时),不是标准的一部分。实际上,它在您在另一个答案中提供的链接文档中推断了同样多的内容。这种形式已经过时了,因为标准现在提供了一种实现这种形式的方法。这就是我要说的重点,并不是说你对指定初始值设定者本身的描述有缺陷。事实上,@DanAloni,因为你的答案无疑比我对问题的实际原因的回答更正确,所以我向你投赞成票:-)不要回应,我想确保最好的答案排在第一位。我不相信我会进入ioctl函数,所以不会有任何返回值。我也有适当的权限。你能进一步解释一下“打开”功能吗。这适合C语言吗?你能给我指一些文档吗?我更新了OP,解释说这是针对嵌入式系统的旧版本Linux。你试过检查吗?如果您的代码编译并运行,那么您确实“进入”了ioctl调用,您可能还没有完全进入您的aes_ioctl处理程序。如果是这种情况,那么返回不是您设置的,而是系统让您知道您没有访问函数的内容/方式的方式。例如,您可能会得到一个EBADF(坏文件处理程序)或EFAULT(不可访问内存中的引用)。很好地说明了为什么没有调用ioclt处理程序。对于open()和close(),这些只是C系统调用,我认为用户空间ioctl调用的函数不对。我在ioctl函数中有一个printk,它没有出现在控制台中,所以我假设这两个函数还没有连接。“打开”功能有3个参数,对吗?与“fopen”相比,它有什么优势?请查看我的编辑,了解为什么您应该
//assume includes
void main() {
int fd;
long ret;
fd = open("/dev/hello");
if(fd) {
c = ioctl(fd, 0, 1);
if (c < 0)
printf("error: %d, errno: %d, meaning: %s\n", c, errno, strerror(errno));
close(fd);
}
return;
}
[ 2388.051660] Hello!
error: -1, errno: 9, meaning: Bad file descriptor
[ 2388.051660] Hello!
[ 2625.025339] in ioctl