5

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

我的问题是 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 有什么方法可以将我的 64 位参数传递给 ioctl()?

4

2 回答 2

6

这是否可能使用 Pythonfcntl.ioctl()将取决于系统。跟踪源代码,错误消息来自...的第 658 行的以下测试getargs.c

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

...在我的系统上,/usr/include/limits.h告诉我...

#  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)
于 2013-06-23T17:55:28.580 回答
3

Python 中“arg”的表示法与ioctlC 中的不同。

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

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

像这样:

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

对于 a GET_VAL,您需要再次使用“Q”类型(而不是“L”)才能正确解压缩 64 位整数值。

于 2013-06-24T19:00:08.313 回答