Linux内核中的copy_from_user如何在内部工作?

时间:2011-11-25 06:53:13

标签: linux linux-kernel memory-mapping

copy_from_user()功能在内部如何运作?考虑到内核确实有权访问用户内存空间,它是否使用任何缓冲区或者是否进行了内存映射?

4 个答案:

答案 0 :(得分:20)

copy_from_user()的实施高度依赖于架构。

在x86和x86-64上,它只是直接从用户空间地址读取并写入内核空间地址,同时暂时禁用SMAP(Supervisor模式访问保护)(如果已配置)。其中棘手的部分是将copy_from_user()代码放入特殊区域,以便页面错误处理程序可以识别其中发生错误的时间。 copy_from_user()中发生的内存保护错误不会像任何其他进程上下文代码触发的那样终止进程,或者像在中断环境中发生的情况一样让内核感到恐慌 - 它只是恢复在代码路径中执行,将-EFAULT返回给调用者。

答案 1 :(得分:8)

关于“自内核传递内核空间地址后如何回复copy_to_user,用户空间进程如何访问它”

用户空间进程可以尝试访问任何地址。但是,如果地址未映射到该进程用户空间(即在该进程的页表中),或者如果存在访问问题,例如对只读位置的写入尝试,则会生成页面错误。请注意,至少在x86上,每个进程都将所有内核空间映射到该进程的虚拟地址空间的最低1千兆字节,而4GB总地址空间中的3千兆字节(我在这里使用的是32位经典空间) case)用于过程文本(即代码)和数据。 进出用户空间的副本由代表进程执行的内核代码执行,实际上它是在复制期间正在使用的该进程的内存映射(即页表)。这在执行处于内核模式时发生 - 即x86语言中的特权/管理员模式。 假设用户空间代码已经通过合法的目标位置(即在该进程地址空间中正确映射的地址)以将数据复制到,copy_to_user,从内核上下文运行将能够正常写入该地址/区域w / out问题并且在控制返回给用户之后,用户空间也可以从该位置设置读取进程本身开始。 更多有趣的细节可以在了解Linux内核,第3版,作者Daniel P. Bovet,Marco Cesati的第9章和第10章中找到。特别是,access_ok()是必要但不充分的有效性检查。用户仍然可以传递不属于进程地址空间的地址。在这种情况下,内核代码执行副本时将发生页面错误异常。最有趣的部分是内核页面错误处理程序如何确定在这种情况下页面错误不是由于内核代码中的错误而是来自用户的错误地址(特别是如果所讨论的内核代码来自内核模块)加载)。

答案 2 :(得分:1)

使用来自不同地址空间的两个缓冲区完成copy_from_user()系统调用的实现:

  • 用户虚拟地址空间中的用户空间缓冲区
  • 内核虚拟地址空间中的内核空间缓冲区

调用copy_from_user()系统调用时,数据将从用户缓冲区复制到内核缓冲区。

下面给出了使用copy_from_user()的字符设备驱动程序代码的一部分(写操作):

ssize_t cdev_fops_write(struct file *flip, const char __user *ubuf,
                        size_t count, loff_t *f_pos) 
{     
    unsigned int *kbuf;
    copy_from_user(kbuf, ubuf, count);
    printk(KERN_INFO "Data: %d",*kbuf); 
}

答案 3 :(得分:1)

最好的答案有问题,copy_(from | to)用户不能在中断上下文中使用,他们可能会睡觉,复制(从|到)用户功能只能在过程环境中使用, 进程的页面表包含内核访问它所需的所有信息,因此如果我们可以确保页面地址在内存中,内核可以直接访问用户空间地址,使用copy (from | to)_user函数,因为他们可以为我们检查它,如果用户空间寻址页面不是常驻页面,它将直接为我们修复它。