linux驱动read函数 copytouser,copytouser和copyfromuser函数分析

《copytouser和copyfromuser函数分析》由会员分享,可在线阅读,更多相关《copytouser和copyfromuser函数分析(10页珍藏版)》请在金锄头文库上搜索。

1、在内核的学习中会遇到很多挺有意思的函数,而且能沿着一个函数扯出来很多个相关的函数。copy_to_user 和 copy_from_user 就是在进行驱动相关程序设计的时候,要经常遇到的两个函数。由于内核空间与用户空间的内存不能直接互访,因此借助函数 copy_to_user()完成用户空间到内核空间的复制,函数 copy_from_user()完成内核空间到用户空间的复制。下面我们来仔细的理一下这两个函数的来龙去脉。首先,我们来看一下这两个函数的在源码文件中是如何定义的:/arch/i386/lib/usercopy.cunsigned longcopy_to_user(void _use。

2、r *to, const void *from, unsigned long n)might_sleep();BUG_ON(long) n addr_limit.seg); flag; )其实现的功能为:(u33)addr + (u33)size = (u33)current-addr_limit.seg判断上式是否成立,若不成立则表示地址有效,返回零;否则返回非零接下来的这个函数才是最重要的函数,它实现了拷贝的工作:_copy_to_user(to, from, n)其实现方式如下(在/include/asm-i386/uaccess.h 中):static _always_inline u。

3、nsigned long _must_check_copy_to_user(void _user *to, const void *from, unsigned long n)might_sleep();return _copy_to_user_inatomic(to, from, n);有一个_always_inline 宏,其内容就是 inline,一个_must_check,其内容是在 gcc3和 gcc4 版本里为_attribute_(warn_unused_result)其中 might_sleep 同上面_user 时候的注释。最终调用的是_copy_to_user_inatom。

4、ic(to, from, n)来完成拷贝工作的,此函数的实现如下(在/include/asm-i386/uaccess.h 中):static _always_inline unsigned long _must_check_copy_to_user_inatomic(void _user *to, const void *from, unsigned long n) if (_builtin_constant_p(n) unsigned long ret;switch (n) case 1:_put_user_size(*(u8 *)from, (u8 _user *)to, 1, ret,。

5、 1);return ret;case 2:_put_user_size(*(u16 *)from, (u16 _user *)to, 2, ret, 2);return ret;case 4:_put_user_size(*(u32 *)from, (u32 _user *)to, 4, ret, 4);return ret;return _copy_to_user_ll(to, from, n);其中_builtin_constant_p(n)为 gcc 的内建函数,_builtin_constant_p 用于判断一个值是否为编译时常熟,如果参数 n 的值为常数,函数返回 1,否则返回 0。

6、。很多计算或操作在参数为常数时有更优化的实现,在 GNU C 中用上面的方法可以根据参数是否为常数,只编译常数版本或非常数版本,这样既不失通用性,又能在参数是常数时编译出最优化的代码。如果 n 为常数 1、2 或者 4,就会选择某个 swith 来执行拷贝动作,拷贝是通过如下函数来实现的(在/include/asm-i386/uaccess.h 中):#ifdef CONFIG_X86_WP_WORKS_OK#define _put_user_size(x,ptr,size,retval,errret) do retval = 0; _chk_user_ptr(ptr); switch (si。

7、ze) case 1: _put_user_asm(x,ptr,retval,b,b,iq,errret);break; case 2: _put_user_asm(x,ptr,retval,w,w,ir,errret);break; case 4: _put_user_asm(x,ptr,retval,l,ir,errret); break; case 8: _put_user_u64(_typeof_(*ptr)(x),ptr,retval); break;default: _put_user_bad(); while (0)#else#define _put_user_size(x,pt。

8、r,size,retval,errret) do _typeof_(*(ptr) _pus_tmp = x; retval = 0; if(unlikely(_copy_to_user_ll(ptr, &_pus_tmp, size) != 0) retval = errret; while (0)#endif其中_put_user_asm 为一个宏,拷贝工作是通过如下的内联汇编来实现的(在/include/asm-i386/uaccess.h 中):#define _put_user_asm(x, addr, err, itype, rtype, ltype, errret) _asm_ _。

9、volatile_( 1: movitype %rtype1,%2n 2:n .section .fixup,axn 3: movl %3,%0n jmp 2bn .previousn .section _ex_table,an .align 4n .long 1b,3bn .previous : =r(err) : ltype (x), m(_m(addr), i(errret), 0(err)以上这两个函数是为了在拷贝小字节数据比如 char/int 等数据的时候考虑到效率来实现小数据拷贝。而若 n 不是如上所说的常数,则进行数据块区域拷贝,其实现如下(/arch/i386/lib/use。

10、rcopy.c):unsigned long _copy_to_user_ll(void _user *to, const void *from, unsigned long n)BUG_ON(long) n */while (n) unsigned long offset = (unsigned long)to)%PAGE_SIZE;unsigned long len = PAGE_SIZE - offset;int retval;struct page *pg;void *maddr;if (len n)len = n;survive:down_read(&current-mm-mmap_。

11、sem);retval = get_user_pages(current, current-mm,(unsigned long )to, 1, 1, 0, &pg, NULL);if (retval = -ENOMEM & current-pid = 1) up_read(&current-mm-mmap_sem);blk_congestion_wait(WRITE, HZ/50);goto survive; if (retval != 1) up_read(&current-mm-mmap_sem);break;maddr = kmap_atomic(pg, KM_USER0);memcpy。

12、(maddr + offset, from, len);kunmap_atomic(maddr, KM_USER0);set_page_dirty_lock(pg);put_page(pg);up_read(&current-mm-mmap_sem);from += len;to += len;n -= len;return n;#endifif (movsl_is_ok(to, from, n)_copy_user(to, from, n);elsen = _copy_user_intel(to, from, n);return n;EXPORT_SYMBOL(_copy_to_user_l。

13、l);下面是 copy_from_user 函数的实现:unsigned longcopy_from_user(void *to, const void _user *from, unsigned long n)might_sleep();BUG_ON(long) n 0);if (access_ok(VERIFY_READ, from, n)n = _copy_from_user(to, from, n);elsememset(to, 0, n);return n;EXPORT_SYMBOL(copy_from_user);其实现方式与 copy_to_user 函数的实现方式类似:就不再累述了。如上就是 copy_to_user 和 copy_from_user 两个函数的工作方式,这些进行简单的分析与跟踪。细节的部分还有待于进一步研究。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值