您的位置 首页 元件

linux内核中的get_user和put_user

内核版本:2614CPU平台:arm在内核空间和用户空间交换数据时,get_user和put_user是两个两用的函数。相对于copy_to_user和copy_from_user

内核版别:2.6.14

CPU渠道:arm

在内核空间和用户空间交流数据时,get_userput_user是两个两用的函数。相关于copy_to_user和copy_from_user(将在另一篇博客中剖析),这两个函数首要用于完结一些简略类型变量(char、int、long等)的复制使命,关于一些复合类型的变量,比方数据结构或许数组类型,get_user和put_user函数仍是无法担任,这两个函数内部将对指针指向的目标长度进行检查,在arm渠道上只支撑长度为1,2,4,8的变量。下面我具体剖析,首先看get_user的界说(linux/include/asm-arm/uaccess.h):

[plain]view plaincopy

print?

  1. externint__get_user_1(void*);
  2. externint__get_user_2(void*);
  3. externint__get_user_4(void*);
  4. externint__get_user_8(void*);
  5. externint__get_user_bad(void);
  6. #define__get_user_x(__r2,__p,__e,__s,__i…)\
  7. __asm____volatile__(\
  8. __asmeq(“%0″,”r0”)__asmeq(“%1″,”r2″)\//进行判别(#define__asmeq(x,y)”.ifnc”x”,”y”;.err;.endif\n\t”)
  9. “bl__get_user_”#__s\//依据参数调用不同的函数,此刻r0=指向用户空间的指针,r2=内核空间的变量
  10. :”=&r”(__e),”=r”(__r2)\
  11. :”0″(__p)\
  12. :__i,”cc”)
  13. #defineget_user(x,p)\
  14. ({\
  15. constregistertypeof(*(p))__user*__pasm(“r0”)=(p);\//__p的数据类型和*(p)的指针数据类型是相同的,__p=p,且存放在r0寄存器中
  16. registertypeof(*(p))__r2asm(“r2”);\//__r2的数据类型和*(p)的数据类型是相同的,且存放在r2寄存器中
  17. registerint__easm(“r0”);\//界说__e,存放在寄存器r0,作为回来值
  18. switch(sizeof(*(__p))){\//对__p所指向的目标长度进行检查,并依据长度调用呼应的函数
  19. case1:\
  20. __get_user_x(__r2,__p,__e,1,”lr”);\
  21. break;\
  22. case2:\
  23. __get_user_x(__r2,__p,__e,2,”r3″,”lr”);\
  24. break;\
  25. case4:\
  26. __get_user_x(__r2,__p,__e,4,”lr”);\
  27. break;\
  28. case8:\
  29. __get_user_x(__r2,__p,__e,8,”lr”);\
  30. break;\
  31. default:__e=__get_user_bad();break;\//默许处理
  32. }\
  33. x=__r2;\
  34. __e;\
  35. })

上面的源码涉及到gcc的内联汇编,不太了解的朋友能够参阅前面的博客(http://blog.csdn.net/ce123/article/details/8209702)。持续,盯梢__get_user_1等函数的履行,它们的界说如下(linux/arch/arm/lib/getuser.S)。

[plain]view plaincopy

print?

  1. .global__get_user_1
  2. __get_user_1:
  3. 1:ldrbtr2,[r0]
  4. movr0,#0
  5. movpc,lr
  6. .global__get_user_2
  7. __get_user_2:
  8. 2:ldrbtr2,[r0],#1
  9. 3:ldrbtr3,[r0]
  10. #ifndef__ARMEB__
  11. orrr2,r2,r3,lsl#8
  12. #else
  13. orrr2,r3,r2,lsl#8
  14. #endif
  15. movr0,#0
  16. movpc,lr
  17. .global__get_user_4
  18. __get_user_4:
  19. 4:ldrtr2,[r0]
  20. movr0,#0
  21. movpc,lr
  22. .global__get_user_8
  23. __get_user_8:
  24. 5:ldrtr2,[r0],#4
  25. 6:ldrtr3,[r0]
  26. movr0,#0
  27. movpc,lr
  28. __get_user_bad_8:
  29. movr3,#0
  30. __get_user_bad:
  31. movr2,#0
  32. movr0,#-EFAULT
  33. movpc,lr
  34. .section__ex_table,”a”
  35. .long1b,__get_user_bad
  36. .long2b,__get_user_bad
  37. .long3b,__get_user_bad
  38. .long4b,__get_user_bad
  39. .long5b,__get_user_bad_8
  40. .long6b,__get_user_bad_8
  41. .previous

这段代码都是单条汇编指令完结的内存操作,就不进行具体注解了。假如界说__ARMEB__宏,则是支撑EABI的大端格局代码(http://blog.csdn.net/ce123/article/details/8457491),关于大端形式和小端形式的具体介绍,能够参阅http://blog.csdn.net/ce123/article/details/6971544。这段代码在.section __ex_table, “a”之前都是惯例的内存复制操作,特别的当地在于后边界说“__ex_table”section 。

标号1,2,…,6处是内存拜访指令,假如mov的源地址坐落一个尚未被提交物理页面的空间中,将产生缺页反常,内核会调用do_page_fault函数处理这个反常,由于反常产生在内核空间,do_page_fault将调用search_exception_tables在“__ex_table”中查找反常指令的修正指令,在上面这段带面的最终,“__ex_table”section 中界说了如下数据:

[plain]view plaincopy

print?

  1. .section__ex_table,”a”
  2. .long1b,__get_user_bad//其间1b对应标号1处的指令,__get_user_bad是1处指令的修正指令。
  3. .long2b,__get_user_bad
  4. .long3b,__get_user_bad
  5. .long4b,__get_user_bad
  6. .long5b,__get_user_bad_8
  7. .long6b,__get_user_bad_8

当标号1处产生缺页反常时,体系将调用do_page_fault提交物理页面,然后跳到__get_user_bad持续履行。get_user函数假如效果履行则回来1,不然回来-EFAULT。

put_user用于将内核空间的一个简略类型变量x复制到p所指向的用户空间。该函数能够主动判别变量的类型,假如履行成功则回来0,不然回来-EFAULT。下面给出它们的界说(linux/include/asm-arm/uaccess.h)。

[plain]view plaincopy

print?

  1. externint__put_user_1(void*,unsignedint);
  2. externint__put_user_2(void*,unsignedint);
  3. externint__put_user_4(void*,unsignedint);
  4. externint__put_user_8(void*,unsignedlonglong);
  5. externint__put_user_bad(void);
  6. #define__put_user_x(__r2,__p,__e,__s)\
  7. __asm____volatile__(\
  8. __asmeq(“%0″,”r0”)__asmeq(“%2″,”r2”)\
  9. “bl__put_user_”#__s\
  10. :”=&r”(__e)\
  11. :”0″(__p),”r”(__r2)\
  12. :”ip”,”lr”,”cc”)
  13. #defineput_user(x,p)\
  14. ({\
  15. constregistertypeof(*(p))__r2asm(“r2”)=(x);\
  16. constregistertypeof(*(p))__user*__pasm(“r0”)=(p);\
  17. registerint__easm(“r0”);\
  18. switch(sizeof(*(__p))){\
  19. case1:\
  20. __put_user_x(__r2,__p,__e,1);\
  21. break;\
  22. case2:\
  23. __put_user_x(__r2,__p,__e,2);\
  24. break;\
  25. case4:\
  26. __put_user_x(__r2,__p,__e,4);\
  27. break;\
  28. case8:\
  29. __put_user_x(__r2,__p,__e,8);\
  30. break;\
  31. default:__e=__put_user_bad();break;\
  32. }\
  33. __e;\
  34. })

__put_user_1等函数的的界说如下(linux/arch/arm/lib/putuser.S)。

[plain]view plaincopy

print?

  1. .global__put_user_1
  2. __put_user_1:
  3. 1:strbtr2,[r0]
  4. movr0,#0
  5. movpc,lr
  6. .global__put_user_2
  7. __put_user_2:
  8. movip,r2,lsr#8
  9. #ifndef__ARMEB__
  10. 2:strbtr2,[r0],#1
  11. 3:strbtip,[r0]
  12. #else
  13. 2:strbtip,[r0],#1
  14. 3:strbtr2,[r0]
  15. #endif
  16. movr0,#0
  17. movpc,lr
  18. .global__put_user_4
  19. __put_user_4:
  20. 4:strtr2,[r0]
  21. movr0,#0
  22. movpc,lr
  23. .global__put_user_8
  24. __put_user_8:
  25. 5:strtr2,[r0],#4
  26. 6:strtr3,[r0]
  27. movr0,#0
  28. movpc,lr
  29. __put_user_bad:
  30. movr0,#-EFAULT
  31. movpc,lr
  32. .section__ex_table,”a”
  33. .long1b,__put_user_bad
  34. .long2b,__put_user_bad
  35. .long3b,__put_user_bad
  36. .long4b,__put_user_bad
  37. .long5b,__put_user_bad
  38. .long6b,__put_user_bad
  39. .previous

put_user函数就不具体剖析了。get_user和put_user仅能完结一些简略类型变量的复制使命,后边咱们将剖析copy_to_user和copy_from_user。

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/xinpin/yuanjian/262401.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部