基于ARM 构架(带MMU)的copy_from_user与copy_to_user详细分析
- static inline unsigned long __must_check copy_from_user(void *to, const void __user *from, unsigned long n)
- {
- if (access_ok(VERIFY_READ, from, n))
- n = __copy_from_user(to, from, n);
- else /* security hole - plug it */
- memset(to, 0, n);
- return n;
- }
- static inline unsigned long __must_check copy_to_user(void __user *to, const void *from, unsigned long n)
- {
- if (access_ok(VERIFY_WRITE, to, n))
- n = __copy_to_user(to, from, n);
- return n;
- }
- /*
- * 带有MMU的构架应该覆盖这两个函数
- */
- #ifndef __copy_from_user
- static inline __must_check long __copy_from_user(void *to,
- const void __user * from, unsigned long n)
- {
- if (__builtin_constant_p(n)) {
- switch(n) {
- case 1:
- *(u8 *)to = *(u8 __force *)from;
- return 0;
- case 2:
- *(u16 *)to = *(u16 __force *)from;
- return 0;
- case 4:
- *(u32 *)to = *(u32 __force *)from;
- return 0;
- #ifdef CONFIG_64BIT
- case 8:
- *(u64 *)to = *(u64 __force *)from;
- return 0;
- #endif
- default:
- break;
- }
- }
- memcpy(to, (const void __force *)from, n);
- return 0;
- }
- #endif
- #ifndef __copy_to_user
- static inline __must_check long __copy_to_user(void __user *to,
- const void *from, unsigned long n)
- {
- if (__builtin_constant_p(n)) {
- switch(n) {
- case 1:
- *(u8 __force *)to = *(u8 *)from;
- return 0;
- case 2:
- *(u16 __force *)to = *(u16 *)from;
- return 0;
- case 4:
- *(u32 __force *)to = *(u32 *)from;
- return 0;
- #ifdef CONFIG_64BIT
- case 8:
- *(u64 __force *)to = *(u64 *)from;
- return 0;
- #endif
- default:
- break;
- }
- }
- memcpy((void __force *)to, from, n);
- return 0;
- }
- #endif
点击(此处)折叠或打开
- GCC的内建函数 __builtin_constant_p 用于判断一个值是否为编译时常数,如果参数值是常数,函数返回 1,否则返回 0。
- #ifndef __HAVE_ARCH_MEMCPY
- /**
- * memcpy - Copy one area of memory to another
- * @dest: Where to copy to
- * @src: Where to copy from
- * @count: The size of the area.
- *
- * You should not use this function to access IO space, use memcpy_toio()
- * or memcpy_fromio() instead.
- */
- void *memcpy(void *dest, const void *src, size_t count)
- {
- char *tmp = dest;
- const char *s = src;
- while (count--)
- *tmp++ = *s++;
- return dest;
- }
- EXPORT_SYMBOL(memcpy);
- #endif
- /* We use 33-bit arithmetic here... */
- #define __range_ok(addr,size) ({ \
- unsigned long flag, roksum; \
- __chk_user_ptr(addr); \
- __asm__("adds %1, %2, %3; sbcccs %1, %1, %0; movcc %0, #0" \
- : "=&r" (flag), "=&r" (roksum) \
- : "r" (addr), "Ir" (size), "0" (current_thread_info()->addr_limit) \
- : "cc"); \
- flag; })
- ......
- #define access_ok(type,addr,size) (__range_ok(addr,size) == 0)
- ......
这个就比较麻烦了,涉及到了C语言中内联汇编,如果还不熟悉的朋友可以看看《ARM GCC 内嵌汇编手册》,我也不是很熟。
现在我们来仔细分析__range_ok这个宏:
(1)unsigned long flag, roksum;\\定义两个变量
- flag:保存结果的变量:非零代表地址无效,零代表地址可以访问。初始存放非零值(current_thread_info()->addr_limit),也就是当前进程的地址上限值。
- roksum:保存要访问的地址范围末端,用于和当前进程地址空间限制数据做比较
(2)__chk_user_ptr(addr);\\定义是一个空函数
但是这个函数涉及到__CHECKER__宏的判断,__CHECKER__宏在通过Sparse(Semantic Parser for C)工具对内核代码进行检查时会定义的。在使用make C=1或C=2时便会调用该工具,这个工具可以检查在代码中声明了sparse所能检查到的相关属性的内核函数和变量。
如果定义了__CHECKER__,在网上的资料中这样解释的:__chk_user_ptr和__chk_io_ptr在这里只声明函数,没有函数体,目的就是在编译过程中Sparse能够捕捉到编译错误,检查参数的类型。
如果没有定义__CHECKER__,这就是一个空函数。
(3)接下来的汇编,我适当地翻译如下:
adds %1, %2, %3
roksum = addr + size 这个操作影响状态位(目的是影响是进位标志C)
以下的两个指令都带有条件CC,也就是当C=0的时候才执行。
如果上面的加法指令进位了(C=1),则以下的指令都不执行,flag就为初始值current_thread_info()->addr_limit(非零值),并返回。
如果没有进位(C=0),就执行下面的指令
sbcccs %1, %1, %0
roksum = roksum - flag,也就是(addr + size)- (current_thread_info()->addr_limit),操作影响符号位。
如果(addr + size)>=(current_thread_info()->addr_limit),则C=1
如果(addr + size)<(current_thread_info()->addr_limit),则C=0
(4)flag;
返回flag值
综上所诉:__range_ok宏其实等价于:
如果(addr + size)>=(current_thread_info()->addr_limit),返回非零值
如果(addr + size)<(current_thread_info()->addr_limit),返回零
而access_ok就是检验将要操作的用户空间的地址范围是否在当前进程的用户地址空间限制中。这个宏的功能很简单,完全可以用C实现,不是必须使用汇编。个人理解:由于这两个函数使用频繁,就使用汇编来实现部分功能来增加效率。
从这里再次可以认识到,copy_from_user与copy_to_user的使用是结合进程上下文的,因为他们要访问“user”的内存空间,这个“user”必须是某个特定的进程。通过上面的源码就知道,其中使用了current_thread_info()来检查空间是否可以访问。如果在驱动中使用这两个函数,必须是在实现系统调用的函数中使用,不可在实现中断处理的函数中使用。如果在中断上下文中使用了,那代码就很可能操作了根本不相关的进程地址空间。
其次由于操作的页面可能被换出,这两个函数可能会休眠,所以同样不可在中断上下文中使用。
转载于:https://www.cnblogs.com/jiayy/p/4831844.html
基于ARM 构架(带MMU)的copy_from_user与copy_to_user详细分析相关推荐
- 麒麟处理器是基于arm的吗_麒麟芯片是基于ARM构架,如果得不到授权华为还能活吗?...
跟其他的国产公司相比,华为最大的特点就是拥有自研的一些技术,比如华为的麒麟芯片,毕竟友商OPPO.小米都在使用高通的骁龙,他们没有足够的能力研发强大的芯片,单单在这一方面华为人就已经足够自豪. 不过最 ...
- arm体系结构与编程_教程:如何学习嵌入式系统(基于ARM平台)
一.嵌入式系统的概念 着重理解"嵌入"的概念 主要从三个方面上来理解. 1.从硬件上,将基于CPU的处围器件,整合到CPU芯片内部,比如早期基于X86体系结构下的计算机,CPU只是 ...
- 如何学习嵌入式系统(基于ARM平台)
一.嵌入式系统的概念 着重理解"嵌入"的概念 主要从三个方面上来理解. 1.从硬件上,将基于CPU的处围器件,整合到CPU芯片内部,比如早期基于X86体系结构 ...
- 基于ARM处理器的LCD控制及触摸屏接口设计
作者:menuconfig 转自:http://blog.csdn.net/menuconfig/article/details/2621231 研究了一种基于ARM处理器的嵌入式网络收音机的设计方案 ...
- 瑞芯微RK3188规格说明,ARM构架
瑞芯微RK3188规格说明,ARM构架 RK3188是一款低功耗.高性能的个人手机处理器.移动互联网设备和其他数字多媒体应用,并集成四核Cortex-A9,带有单独的Neor和FPU协处理器. 更多的 ...
- 基于ARM的嵌入式Bootloader实现自动升级
摘要:本文阐述了ARM7嵌入式系统Bootloader的基本流程,重点分析了在Bootloader中通过CF存储卡或硬盘实现对内核或文件系统进行升级.并通过EM8624L在ARM+uClinux下实验 ...
- arm Linux 低成本方案,参赛作品《低成本基于ARM+Linux平台搭建web服务器的物联网学习板》...
[报名阶段需要填写的内容] 1. 参赛者姓名(必填项): 王徕泽 2. 单位或学校名称(选填项): 徕泽电子工作室 3. 当前职务或职称(选填项): 室长 4. 参赛作品的名字(必填项): 低成本基于 ...
- 基于ARM的嵌入式Linux移植真实体验(3)――操作系统
基于ARM的嵌入式Linux移植真实体验(3)――操作系统 宋宝华[email]21cnbao@21cn.com[/email] 出处:dev.yesky.com 在笔者撰写的<C语言嵌入式系统 ...
- 可复用的基于ARM的W5100底层驱动设计
摘要: 为了缩短基于ARM的网络化嵌入式应用开发周期.降低开发成本和提高产品质量,提出一种有别于传统利用操作系统开发嵌入式应用的模式.在该模式的框架下,对W5100网络芯片底层驱动进行编写.封装和测试 ...
最新文章
- python进度条 pyqt_Python高级进阶#015 pyqt5进度条QProgressBar结合使用qbasictimer
- MFC中CSliderCtrl的使用(收集)
- Visual Studio Code的Issue列表被黑产“攻陷”
- GAN生成对抗网络-CGAN原理与基本实现-条件生成对抗网络04
- java中四种线程池及poolSize、corePoolSize、maximumPoolSize
- .Net Micro Framework 快速入门
- 编制一个c语言成绩记录簿_C语言基础知识点模拟试题
- linux字符模式分辨率grub2,Deepin 15.8系统Grub菜单分辨率低的原因及解决方案
- django+uwsgi+nginx部署
- 计算机维护宝典,超齐全的维修宝典之电脑维修实例大全
- 工业物联网卡未来发展的优势和特点
- MFC开发环境搭建(顺便来个Helloworld)
- BUUCTF--[GUET-CTF2019]number_game
- Windows 文件、目录操作编程 常用API
- 同花顺数据获取思路及算法
- android系统构建系统_构建系统简介
- word2vec模型原理(附python实现代码)
- C语言实验——用*号输出字母C的图案
- WPF在mxs里引用图片资源并释放的方法
- Python--进程池与线程池
热门文章
- linux7自带haprox版本,CentOS7.4—构建最新版haproxy高可用群集
- python generator输出_python 高级特性:Generator(生成器)
- python学习-列表解析、字典解析
- js css加载器,webpack的CSS加载器的使用
- suse linux下交叉编译,阐述SUSE 10.1交叉编译环境构建方法
- python soup提取叶子标签_python 利用beautifulSoup提取页面多个标签的文本内容
- hbuilder打包ios_ios开发证书的作用及申请步骤
- 未来十年,Java 仍会是最受欢迎的编程语言吗?
- 如何测量程序运行时间?
- 关于硕士研究生的几点思考