当前位置:  技术问答>linux和unix

新手第一次写驱动,发现一个关于数据传递的问题

    来源: 互联网  发布时间:2016-07-07

    本文导语:  刚开始学习LINUX字符设备驱动开发,写了一个小模块练手  以下是驱动程序中IOCTL部分的片段:  static int uda_ioctl  (struct inode *node, struct file *filp, unsigned int cmd, unsigned long arg)                    int g...

刚开始学习LINUX字符设备驱动开发,写了一个小模块练手 

以下是驱动程序中IOCTL部分的片段: 
static int uda_ioctl  (struct inode *node, struct file *filp, unsigned int cmd, unsigned long arg) 

                  int get_data; 

                  case DATA_READ: 
                           get_data = read_data();//read_data返回所读寄存器的值 
                           copy_to_user (arg, &get_data, sizeof(get_data)); 
                           break; 

相应的测试程序片段为: 
                  int getdata = 0; 

                  fd = open(DEV_NAME, O_RDWR); 
                  ioctl(fd, DATA_READ, &getdata); 
                  printf ("getdata = %dn", getdata); 

以上程序运行后打印出的getdata即为所读寄存器的值。 

本人的理解是, &getdata是用户空间的地址, 作为arg参数传入驱动程序; 而&get_data是内核空间中的地址, 所以需要使用copy_to_user函数. 这个本来没错, 但是实际试验中却发现将copy_to_user换成memcpy甚至copy_from_user, 参数不变, 所得结果依然正确, 这令我百思不得其解.

请问之所以有这样的结果, 是我对用户空间和内核空间的理解有误还是代码本身有问题? 

|


static inline long copy_to_user(void *to,
const void __user * from, unsigned long n)
{
if (access_ok(VERIFY_WRITE, to, n))
memcpy(to, from, n);
else
return n;
return 0;
}

static inline long copy_from_user(void *to,
  const void __user * from, unsigned long n)
{
if (access_ok(VERIFY_READ, from, n))
memcpy(to, from, n);
else
return n;
return 0;
}

kernel 中long copy_to_user ,copy_from_user,函数的实现。
从kernel 的意图来说, 始终是检查用户空间的地址是否可访问,如果你传反了,
自然也不会有错误,除非你传进来的内核地址本身就是错误的,或者是空地址。


|
进程的地址空间跟内核的地址空间有所不同。
正如你所见,进程的地址空间记录在VMA中。所以进程访问内存的方式是:
地址->VMA->MMU (page table和各种检查还有page fault)->物理内存。所以,进程要访问内核的地址的话,在MMU阶段会被检查,而且会发现进程没有访问内核地址的权限,不能直接访问。
相反,内核可以访问进程的空间,不过要保证地址合法,就像copy to from user那样(这样应该不能说是直接访问吧)。
总结就是,通常情况下,进程不能访问内核地址,内核要访问进程地址时要做相应检查。

通过向内核提交一些map的请求,进程可以访问某些设备或文件,但个人觉得,这并不完全算是内核的地址空间。

|
楼主研究好细致。
你在驱动里把arg地址打出来看看?  然后直接对那个地址赋个值,看用户空间能不能得到这个值。如果可以的话,就明了了

|
copy_to_user检查了相应的地址是否可以访问,因为相应的页面可能会在内存吃紧的时候交换出去。不能依赖memcpy做正确的事的,因为相应的页面可能可能不在当前内存中。

copy_from_user也能用?这个你怎么用?

|
copy_to_user最终也就是类似于memcpy功能,只是之前会进行地址的检查,所以在正常情况下两者一样

|

请问之所以有这样的结果, 是我对用户空间和内核空间的理解有误还是代码本身有问题?
===============================================
前面极几位说了, copy_to_user 出了 copy 数据以外,还会检查地址的合法性。

内核有最高的权限,内核态可以访问用户态的数据,而用户态的程序则不能访问内核态的数据。
 


|

我直接把那句换成copy_from_user (arg, &get_data, sizeof(get_data)); 最后在应用层依然能读到0x000101.
对于这点我还是没想明白,有没有高人能解释下?
==========================================================================
你两个地址填反了,
你这么填地址,当然能copy 出去了,  arg 是用户空间地址, &get_data是内核空间地址。
还句话说,你把 copy_from_user 当 memcpy 使用了 。

|
没有看copy_from_user具体实现。你把两个参数(from to)位置对调,如果copy_from_user能够成功,那么似乎说明内核在检查地址合法性的时候没有检查访问权限。每个进程对于0xc0000000以后的地址映射跟内核中的page table是一样的,所以这个地址总会在进程的空间中,但进程没有它的访问权限。把from to调换以后,内核检查到的是内核自己的地址,所以肯定是在进程的地址空间中的,但似乎它没有检查访问权限,所以它认为地址是可访问的,然后还是memory copy操作,所以成功了。

内核会假设自己是bug free的,copy_from_user这种东西只会在内核空间使用,所以它认为程序员应该自己保证使用正确吧。

    
 
 
 
本站(WWW.)旨在分享和传播互联网科技相关的资讯和技术,将尽最大努力为读者提供更好的信息聚合和浏览方式。
本站(WWW.)站内文章除注明原创外,均为转载、整理或搜集自网络。欢迎任何形式的转载,转载请注明出处。












  • 相关文章推荐
  • 新手关于驱动开发的疑问
  • Linux新手请教声卡驱动!!!!!!!!!!!
  • 新手请教:我的声卡所附光盘提供了下面的这些文件,我怎么安装驱动?
  • 新手:在FC5下如何配置驱动开发环境?
  • 新手问题,如何应用内核中的i2c设备驱动
  • 驱动加载(新手问题)
  • 新手RedHat Linux问题, 显卡驱动与Codeblocks
  • 新手求助:BSP与驱动程序的差别
  • 新手着手Linux驱动程序开发~~~关于搭建环境的基础问题
  • 请教:新手入门,该怎么学习linux驱动?
  • 显示驱动求助!新手提问
  • 我是新手,不要笑我。问一个关于驱动安装的问题
  • 新手上路,Linux8下双网卡,驱动都装上了,怎么设置ip啊??
  • 我是个新手,请问个编译驱动的问题
  • Linux新手,求学习流程(近期要跟着老师做基于ARM的驱动……)
  • 大家好,我是新手。我正在看《linux驱动程序程序》问大家一个简单问题。
  • 我是linux新手,不会装显卡驱动程序,有人肯教我吗?
  • linux新手请教静态加载gpio驱动的问题
  • 新手驱动问题
  • 新手如何加入开源项目 有什么好的c++,java 开源适合新手 请指点!
  • JDBC的问题,新手高手都来看看吧,说不定能帮帮我这个新手呢,谢谢!
  • jquery iis7站长之家
  • 新手有关linux的问题!
  • 新手急求~~~~~~~~~~~~~~~~~~~
  • 新手学习该用哪个版本
  • 面向新手的终端辅助工具 Clicompanion
  • 我是个新手,请各位老兄给介绍基本好书?
  • 新手请教啦~~能不能帮忙推荐几本书
  • 我是新手
  • 新手:用WEB页面修改数据库中的表?
  • Java新手上路之问题


  • 站内导航:


    特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

    ©2012-2021,,E-mail:www_#163.com(请将#改为@)

    浙ICP备11055608号-3