在为连接到旧PowerPC的自定义硬件的字符设备驱动程序编写IOCTL时,我发现了一个奇怪的问题。这是我的代码的抽象:
u32 mydev_data;
...
static long mydev_ioctl(struct file * file, unsigned int cmd, unsigned long arg)
{
void __user *user_arg = (void __user *)arg;
long result;
switch(cmd) {
case MYDEV_GETDATA:
result = put_user(mydev_data, user_arg);
break;
...
}
return result;
}
现在,这会返回垃圾。但是,当我更换线
result = put_user(mydev_data, user_arg);
与
result = put_user(mydev_data, (unsigned long __user *) user_arg);
问题消失了。
这里发生了什么?由于user_arg被标记为__user *,唯一的区别是void与unsigned long。但我不认为指针类型在这里很重要。显然我错了,但有人可以解释原因吗?
答案 0 :(得分:2)
如果查看put_user
宏的定义,您会看到它根据大小复制数据,执行sizeof(*ptr)
以确定要复制的字节数。 sizeof(void) == 1
,但sizeof(unsigned long)
更大。
#define __put_user_check(x, ptr, size) \
({ \
long __pu_err = -EFAULT; \
__typeof__(*(ptr)) __user *__pu_addr = (ptr); \
might_sleep(); \
if (access_ok(VERIFY_WRITE, __pu_addr, size)) \
__put_user_size((x), __pu_addr, (size), __pu_err); \
__pu_err; \
})
#define put_user(x, ptr) \
__put_user_check((__typeof__(*(ptr)))(x), (ptr), sizeof(*(ptr)))