64位参数fcntl.ioctl()

问题描述:

在我的Python(2.7.3)代码中,我试图使用一个ioctl调用,接受一个long int(64位)作为参数。我在64位系统上,所以64位int与指针的大小相同。64位参数fcntl.ioctl()

我的问题是,Python似乎不接受64位int作为fcntl.ioctl()调用的参数。它愉快地接受一个32位int或一个64位指针 - 但我需要的是通过一个64位int。

这里是我的IOCTL处理程序:

static long trivial_driver_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) 
{ 
    long err = 0; 

    switch (cmd) 
    { 
     case 1234: 
      printk("=== (%u) Driver got arg %lx; arg<<32 is %lx\n", cmd, arg, arg<<32); 
      break; 
     case 5678: 
      printk("=== (%u) Driver got arg %lx\n", cmd, arg); 
      break; 
     default: 
      printk("=== OH NOES!!! %u %lu\n", cmd, arg); 
      err = -EINVAL; 
    } 

    return err; 
} 

在现有的C代码,我用这样的电话:

static int trivial_ioctl_test(){ 
    int ret; 
    int fd = open(DEV_NAME, O_RDWR); 

    unsigned long arg = 0xffff; 

    ret = ioctl(fd, 1234, arg); // ===(1234) Driver got arg ffff; arg<<32 is ffff00000000 
    arg = arg<<32; 
    ret = ioctl(fd, 5678, arg); // === (5678) Driver got arg ffff00000000 
    close(fd); 

} 

在Python中,我打开设备文件,然后我得到的以下结果:

>>> from fcntl import ioctl 
>>> import os 
>>> fd = os.open (DEV_NAME, os.O_RDWR, 0666) 
>>> ioctl(fd, 1234, 0xffff) 
0 
>>> arg = 0xffff<<32 
>>> # Kernel log: === (1234) Driver got arg ffff; arg<<32 is ffff00000000 
>>> # This demonstrates that ioctl() happily accepts a 32-bit int as an argument. 
>>> import struct 
>>> ioctl(fd, 5678, struct.pack("L",arg)) 
'\x00\x00\x00\x00\xff\xff\x00\x00' 
>>> # Kernel log: === (5678) Driver got arg 7fff9eb1fcb0 
>>> # This demonstrates that ioctl() happily accepts a 64-bit pointer as an argument. 
>>> ioctl(fd, 5678, arg) 

Traceback (most recent call last): 
    File "<pyshell#10>", line 1, in <module> 
    ioctl(fd, 5678, arg) 
OverflowError: signed integer is greater than maximum 
>>> # Kernel log: (no change - OverflowError is within python) 
>>> # Oh no! Can't pass a 64-bit int! 
>>> 

Python有没有办法通过m 64位参数ioctl()?

+0

如果可能的话,将有助于提供可重复的示例。鉴于'ioctl()'调用是特定于设备的,所以用'IOC_GET_VAL'代替正在使用的实际请求代码使得测试变得很困难。 – Aya

+0

@Aya:感谢您的评论。我是新手设备驱动程序,并且在构建一个微不足道的功能示例时遇到了一些问题。但我会看看我能做些什么。 :) – Ziv

+0

与此同时,我发布了一个基于ctypes的解决方案。 – Aya

这是否可能使用Python的fcntl.ioctl()将取决于系统。通过源代码跟踪,该错误信息是从下面的测试来对line 658 of getargs.c ...

else if (ival > INT_MAX) { 
    PyErr_SetString(PyExc_OverflowError, 
    "signed integer is greater than maximum"); 
    RETURN_ERR_OCCURRED; 
} 

...和我的系统上,​​告诉我...

# define INT_MAX 2147483647 

..这可能是(推测)(2 ** ((sizeof(int) * 8) - 1)) - 1

因此,除非您正在使用sizeof(int)至少为8的系统,否则您必须直接使用ctypes模块调用基础C函数,但它是平台特定的。

假设Linux中,这样的事情应该工作...

from ctypes import * 

libc = CDLL('libc.so.6') 

fd = os.open (DEV_NAME, os.O_RDWR, 0666) 
value = c_uint64(0xffff<<32) 
libc.ioctl(fd, 5678, value) 
+0

是的!这工作:)我很惊讶没有内置的fcntl.ioctl()内的支持,但这是一个完全合理的解决方法。 – Ziv

+0

比较http://*.com/questions/9257065/int-max-in-32-bit-vs-64-bit-environment。 – Ziv

+0

很好的回答。非常感谢:D – Ziv

符号在Python的ioctl 'ARG' 的(再根据1)是从C

什么

在蟒蛇不同它可以是python integer(不指定32位或64位),也可以是某种缓冲区对象(如字符串)。你并没有真正拥有Python中的“指针”(所以所有的底层架构细节 - 比如32位或64位地址都完全隐藏)。

如果我的理解正确,你需要的是实际需要的一个SET_VALstruct.pack(your 64-bit integer)首先进入字符串并将这个字符串传递给ioctl,而不是直接传递整数。

像这样:

struct.pack('>Q',1<<32)

对于你需要一个 'Q' 再次类型(而不是 'L')正常解压64位整数值的GET_VAL

+0

对不起,这是不正确的。 (对不起,如果我原来的帖子不够清楚。)据我所知,**任何**使用struct.pack()翻译(在C驱动程序内)到一个指向二进制数据被发送到C的ioctl论据。我不想要一个指针;我想直接控制传递的64位值。 – Ziv

+0

但严格来说,你不能通过32位参数传递任何64位值(不管它是一个指针还是一个'值')。在ioctl调用中的参数类型将是32位体系结构中的32位。 在64位系统上,一切都变成了64位,所以理论上你可以在C ***中将64位值传递给IOCTL **。 – Georgiy

+0

另一方面,Python试图隐藏所有这些平台细节,因此它不会暴露任何指针-API。想法是你一定不会在意建筑是什么。事实上,Python的整数可以是任意大的(即不受64位或其他限制) 因此,为了保持_Pythonic_(和平台无关),传递缓冲对象可能更好,即使对于像64位整数... – Georgiy