copy_to_user() 和 copy_from_user() 用于基本数据类型

copy_to_user() and copy_from_user() for basic data type

我正在编写一个 linux 内核驱动程序,对于将数据发送到用户空间或从用户空间读取数据的每个函数,我正在使用 copy_to_user() 和 copy_from_user( ).我的问题是:如果我只是复制基本数据类型(例如 u32 或 int),是否需要使用这些调用?

如果函数接收到指向用户space数据的指针,您必须使用copy_from_user()从用户space 进入内核 space (反之亦然)。

请注意,指针值本身是按值传递的(就像所有 C 参数一样),因此您不必先 copy_from_user() 获取指针值,然后才能 copy_from_user()它指向的数据。

数字参数与指针参数的工作方式相同;用 C 术语来说,它们都是标量。您不必使用 copy_from_user() 来复制参数的值;那已经被复制了。您只需使用它来复制传递的指针指向的数据。

所以如果你有一个int类型的参数,你可以直接使用它。如果你的参数指向一个 int,那么 int 对象将在用户 space 中,你需要使用 copy_to_user 将该对象的值复制到内核 space.

当用户将数据传递给内核时space,这些数据可以被拆分成几个页面,这些页面甚至可以在换出内存。在这些情况下,您将不得不等待内核交换页面并访问数据所在的页面。对于基本数据类型(如 int 或指针),某些体系结构也是如此(尤其是 x86 intel)不要强迫用户对齐数据,因此即使是整数也可以围绕页面边框拆分。您可以访问整数的第一部分,但要等待第二部分在访问整个内容之前被内存管理器换入。

您可以通过将所有用户数据放在一个指针传递给内核的结构中来节省一些往返。您可以 copy_from_user 它作为一个块并保存访问(并且 运行 进入被多次阻止的风险)

因此,作为结论,即使是基本类型也可以使用这些函数,因为它们有很多。在内核模式下 运行 时,不要假设用户数据的位置。你可以访问它,但是用户数据的内核虚拟地址与用户模式下看到的虚拟地址无关。

我是这样做的(可行,但我不确定这是否正确): 首先创建一个该数据类型的数组,然后用数据填充数组,然后传递对该数组的引用,例如只传递一个整数:

    int *from_user = (int *)kmalloc(sizeof(int), GFP_KERNEL);
    if (copy_from_user(from_user, buff, count))
        return -EFAULT;
    printk(KERN_INFO "The value copied from user =   %d", *from_user);
    return sizeof(buff);

以及用户 space 的代码:

    int to_be_passed[1];
    to_be_passed[0] = 4; // 4 is just an example
    int fd = open(DEVICE_NAME, O_RDWR);
    write(fd, to_be_passed, sizeof(to_be_passed));