ioctl命令在64位系统中从32位用户代码错误



我正在将一个设备驱动程序从32位RHEL 2.6.32升级到64位RHEL 2.633.9。

我有一个使用ioctl与该驱动程序进行对话的程序。当驱动程序和程序都是64位或32位时,它可以完美地工作。但是,当驱动程序是64位,而我的程序是32位时,驱动程序接收到的ioctl命令(在compat_iotl中)与_IOR和_IOW宏定义的值不匹配。

在我的驱动程序的switch语句中,默认情况下打印出所有有效命令的值,它们是1-12。32位ioctl命令与这些值相去甚远。

有人能告诉我,当在64位驱动程序中接收到来自32位用户程序的命令时,是什么原因导致命令出错?

下面是一些代码:我必须输入它;该代码是在一个没有互联网接入的安全系统上,所以请原谅任何拼写错误。它真的很滑稽而且跑!

// IOCTL commands from the include file - most omitted
// ...
#define PORTIO_GET_IRQ_CNT_CMD  10
#define PORTIO_CLR_IRQ_CNT_CMD  11
#define PORTIO_GET_IRQ_TIME_CMD 12
#define PORTIO_IOCTL     'k'  // magic number for ioctl
// IOCTL Macros
#define PORTIO_GET_IRQ_CNT_IOCTL    _IOR(PORTIO_IOCTL, PORTIO_GET_IRQ_CNT_CMD, unsigned long)
#define PORTIO_CLR_IRQ_CNT_IOCTL    _IOR(PORTIO_IOCTL, PORTIO_CLR_IRQ_CNT_CMD, unsigned long)
#define PORTIO_GET_IRQ_TIME_IOCTL   _IOR(PORTIO_IOCTL, PORTIO_GET_IRQ_TIME_CMD, unsigned long)

这是portio.c中的32位兼容IOCTL例程。我已经确认,只有当我的程序被编译为32位,并且驱动程序是64位时,才会调用它。

static long portio_compat_ioctl( struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
{
unsigned char cmd_number;
int cmd_size=0;
//...
cmd_number = _IOC_NR( cmd );
cmd_size = _IOC_SIZE( cmd );
printk( KERN_ALERT "Portio Compat IOCTL number,size = %d,%d, cmd_number, cmd_size );
//... Switch statement and cases, based on cmd_number
}

输出如下:

Portio Compat IOTCL编号,大小=2243157

当然,该代码期望IOCTL编号为1-12,大小约为4或8。当代码和驱动程序都是64位或32位时,就会出现这种情况。

在我看来,函数compat_ioctl占用了太多参数。看看Linux内核中的其他定义:

long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg)

http://lxr.linux.no/#linux+v3.5.3/block/compat_ioctl.c#L654

#define PORTIO_GET_IRQ_CNT_IOCTL    _IOR(PORTIO_IOCTL, PORTIO_GET_IRQ_CNT_CMD, unsigned long)
#define PORTIO_CLR_IRQ_CNT_IOCTL    _IOR(PORTIO_IOCTL, PORTIO_CLR_IRQ_CNT_CMD, unsigned long)
#define PORTIO_GET_IRQ_TIME_IOCTL   _IOR(PORTIO_IOCTL, PORTIO_GET_IRQ_TIME_CMD, unsigned long)

将unsigned long更改为unit64_t(固定数据类型)从ioctl宏参数中删除所有指针,具有:

.compat_ioctl
.unlocked_ioctl in kernel pointing to same function.

相关内容

最新更新