资源描述:
《基于arm 构架(带mmu)的copy_from_user与copy_to_user详细分析》由会员上传分享,免费在线阅读,更多相关内容在学术论文-天天文库。
1、基于ARM构架(带MMU)的copy_from_user与copy_to_user详细分析在学习Linux内核驱动的时候,一开始就会碰到copy_from_user和copy_to_user这两个常用的函数。这两个函数在内核使用的非常频繁,负责将数据从用户空间拷贝到内核空间以及将数据从内核空间拷贝到用户空间。在4年半前初学Linux内核驱动程序的时候,我只是知道这个怎么用,并没有很深入的分析这两个函数。这次研究内核模块挂载的时候,又碰到了它们。决定还是认真跟踪一下函数。首先这两个函数的原型在arch/arm/include/asm/uaccess.h文件中:1s
2、taticinlineunsignedlong__must_checkcopy_from_user(void*to,constvoid__user*from,unsignedlongn)2{3if(access_ok(VERIFY_READ,from,n))4n=__copy_from_user(to,from,n);5else/*securityhole-plugit*/6memset(to,0,n);7returnn;8}910staticinlineunsignedlong__must_checkcopy_to_user(void__user*to,con
3、stvoid*from,unsignedlongn)11{12if(access_ok(VERIFY_WRITE,to,n))1n=__copy_to_user(to,from,n);2returnn;3}这两个函数从结构上来分析,其实都可以分为两个部分:1、首先检查用户空间的地址指针是否有效(难点)2、调用__copy_from_user和__copy_to_user函数在这个分析中,我们先易后难。首先看看具体数据拷贝功能的__copy_from_user和__copy_to_user函数对于ARM构架,没有单独实现这两个函数,所以他们的代码位于include
4、/asm-generic/uaccess.h4/*5*带有MMU的构架应该覆盖这两个函数6*/7#ifndef__copy_from_user8staticinline__must_checklong__copy_from_user(void*to,9constvoid__user*from,unsignedlongn)10{11if(__builtin_constant_p(n)){12switch(n){13case1:1*(u8*)to=*(u8__force*)from;2return0;3case2:4*(u16*)to=*(u16__force*)f
5、rom;5return0;6case4:7*(u32*)to=*(u32__force*)from;8return0;9#ifdefCONFIG_64BIT10case8:11*(u64*)to=*(u64__force*)from;12return0;13#endif14default:15break;16}17}1819memcpy(to,(constvoid__force*)from,n);20return0;21}22#endif2324#ifndef__copy_to_user25staticinline__must_checklong__copy_t
6、o_user(void__user*to,26constvoid*from,unsignedlongn)27{28if(__builtin_constant_p(n)){29switch(n){30case1:31*(u8__force*)to=*(u8*)from;32return0;33case2:34*(u16__force*)to=*(u16*)from;35return0;1case4:2*(u32__force*)to=*(u32*)from;3return0;4#ifdefCONFIG_64BIT5case8:6*(u64__force*)to=*
7、(u64*)from;7return0;8#endif9default:10break;11}12}1314memcpy((void__force*)to,from,n);15return0;16}17#endif点击(此处)折叠或打开18GCC的内建函数__builtin_constant_p用于判断一个值是否为编译时常数,如果参数值是常数,函数返回1,否则返回0。从这两个函数中可以看出其实结构是一样的,首先看看n是不是常数,如果是并为1、2、4、8(64bit)则直接就用一个赋值语句拷贝数据。如果不是常数或n过大,则使用memcpy函数。而这个memcpy函
8、数位于lib/strin