我正在尝试实现一个程序来访问嵌入式系统上的内存。我需要访问一些控制寄存器,所以我认为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 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的嵌入式系统。
答案 0 :(得分:7)
您的代码存在的问题是您使用的请求编号 - 0
。内核有一些保留供内部使用的请求编号。内核将请求编号视为结构,将其分隔为字段并为其调用正确的子系统。
请参阅Documentation / ioctl / ioctl-number.txt(来自Linux 3.4.6):
Code Seq#(hex) Include File Comments
========================================================
0x00 00-1F linux/fs.h conflict!
0x00 00-1F scsi/scsi_ioctl.h conflict!
0x00 00-1F linux/fb.h conflict!
0x00 00-1F linux/wavefront.h conflict!
0x02 all linux/fd.h
0x03 all linux/hdreg.h
...
根据您的使用情况,您必须遵循内核指南添加新的ioctls():
If you are adding new ioctl's to the kernel, you should use the _IO
macros defined in <linux/ioctl.h>:
_IO an ioctl with no parameters
_IOW an ioctl with write parameters (copy_from_user)
_IOR an ioctl with read parameters (copy_to_user)
_IOWR an ioctl with both write and read parameters.
有关如何构建这些数字的更多详细信息,请参阅内核自己的Documentation/ioctl/ioctl-decoding.txt
文档。
实际上,如果你选择代码1,这意味着从0x100
开始直到0x1ff
,你就可以了。
答案 1 :(得分:3)
aes_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以来它已经过时(参见here,直接来自GCC文档)。你真的应该使用正确的方法(即受ISO标准祝福的方法)来做到这一点。
答案 2 :(得分:1)
在不知道返回的错误的情况下,很难说......我的第一个问题是您对文件描述符的权限。我以前见过类似的问题。首先,如果您看一下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);
}
检查返回值,这应该有助于您搜索。 为什么检查?请参阅帖子的底部...... 接下来,为了检查它是否是权限问题,请运行命令:
ls -l /dev/aes
如果您看到类似的内容:
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;
}
那么输出是什么?让我们假设/ dev / hello上的文件权限不正确(意味着我们的用户空间程序无法访问/ dev / hello)。
dmesg |尾巴显示:
[ 2388.051660] Hello!
所以看起来我们没有“进入”ioctl。该计划的输出是什么?
error: -1, errno: 9, meaning: Bad file descriptor
大量有用的输出。很明显,ioctl调用做了一些事情,而不是我们想要的。现在更改权限并重新运行我们可以看到新的dmesg:
[ 2388.051660] Hello!
[ 2625.025339] in ioctl