麻烦从用户空间C调用ioctl

时间:2012-08-21 03:05:09

标签: 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 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的嵌入式系统。

3 个答案:

答案 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