Linux内核源码分析—从用户空间复制数据到内核空间
Linux内核源码分析—从用户空间复制数据到内核空间
本文主要参考《深入理解Linux内核》,结合2.6.11.1版的内核代码,分析从用户空间复制数据到内核空间函数。
1、不描述内核同步、错误处理、参数合法性验证相关的内容
2、源码摘自Linux内核2.6.11.1版
3、阅读本文请结合《深入理解Linux内核》第三版相关章节
4、本文会不定时更新
1、copy_from_user
函数功能:
从用户空间向内核空间复制数据
函数源码:
/**
* copy_from_user: - Copy a block of data fromuser space.
* @to: Destination address, in kernel space.
* @from: Source address, in user space.
* @n: Number of bytes to copy.
*
* Context: User context only. This function may sleep.
*
* Copy data from user space to kernel space.
*
* Returns number of bytes that could not becopied.
* On success, this will be zero.
*
* If some data could not be copied, thisfunction will pad the copied
* data to the requested size using zero bytes.
*/
unsigned long
copy_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);
else
memset(to,0, n);
returnn;
}
static inline unsigned long
__copy_from_user(void *to, const void__user *from, unsigned long n)
{
might_sleep();
return __copy_from_user_inatomic(to, from, n);
}
函数处理流程:
如果用户空间有读权限,调用__copy_from_user从用户空间复制数据到内核空间,__copy_from_user函数是__copy_from_user_inatomic函数的封装函数,__copy_from_user_inatomic的具体分析见本文;没有则把内核空间置0
2、__copy_from_user_inatomic
函数源码:
/**
* __copy_from_user: - Copy a block of datafrom user space, with less checking.
* @to: Destination address, in kernel space.
* @from: Source address, in user space.
* @n: Number of bytes to copy.
*
* Context: User context only. This function may sleep.
*
* Copy data from user space to kernelspace. Caller must check
* the specified block with access_ok() beforecalling this function.
*
* Returns number of bytes that could not becopied.
* On success, this will be zero.
*
* If some data could not be copied, thisfunction will pad the copied
* data to the requested size using zero bytes.
*/
static inline unsigned long
__copy_from_user_inatomic(void *to,const void __user *from, unsigned long n)
{
if(__builtin_constant_p(n)) {
unsignedlong ret;
switch(n) {
case1:
__get_user_size(*(u8*)to, from, 1, ret, 1);
returnret;
case2:
__get_user_size(*(u16*)to, from, 2, ret, 2);
returnret;
case4:
__get_user_size(*(u32*)to, from, 4, ret, 4);
returnret;
}
}
return__copy_from_user_ll(to, from, n);
}
函数处理流程:
1、__builtin_constant_p 是编译器gcc内置函数,用于判断一个值是否为编译时常量,如果是常数,函数返回1 ,否则返回0。
2、如果n是常量,这里先判断要拷贝的字节大小,如果是1,2,4字节的话,则调用函数__get_user_size来拷贝数据,具体分析参见本文
3、如果n不是常量,调用函数__copy_from_user_ll来拷贝数据,具体分析参见本文
4、__get_user_size
函数源码:
#define __get_user_size(x,ptr,size,retval,errret) \
do { \
retval= 0; \
__chk_user_ptr(ptr); \
switch(size) { \
case1:__get_user_asm(x,ptr,retval,"b","b","=q",errret);break; \
case2:__get_user_asm(x,ptr,retval,"w","w","=r",errret);break; \
case4: __get_user_asm(x,ptr,retval,"l","","=r",errret);break; \
default:(x) = __get_user_bad(); \
} \
} while (0)
函数处理流程:
根据size是1、2、4字节,用不同的参数调用函数__get_user_asm来拷贝数据,具体分析参见本文
5、__get_user_asm
函数参数:
x=to
addr=from
err=4
itype=”b”/”w”/”l”
rtype=”b”/”w”/””
ltype=”=q”/”=r”/”=r”
errret=4
函数源码:
#define __get_user_asm(x, addr, err,itype, rtype, ltype, errret) \
__asm____volatile__( \
/*movb/movw/movl addr, %b/w/“”1*/
"1: mov"itype"%2,%"rtype"1\n" \
/**/
"2:\n" \
/*把下面的代码放入.fixup 节中*/
".section.fixup,\"ax\"\n" \
/*err= errret */
"3: movl %3,%0\n" \
/*把reg1即x置0*/
" xor"itype"%"rtype"1,%"rtype"1\n" \
/**/
" jmp 2b\n" \
/*恢复编译到前面保存的节中*/
".previous\n" \
/*这里指定异常表项,参见“参考文章3”*/
".section__ex_table,\"a\"\n" \
/**/
" .align 4\n" \
/*1b地址的指令引起异常,就跳转到3b*/
" .long 1b,3b\n" \
/**/
".previous" \
:"=r"(err), ltype (x) \
:"m"(__m(addr)), "i"(errret), "0"(err))
函数处理流程:
输出部:
代码:: "=r"(err), ltype (x)
解释:
%0: err=r0
%1: x=寄存器 (ltype(=q/=r/=r))
输入部:
代码::"m"(__m(addr)), "i"(errret), "0"(err))
解释:
%2: addr内存单元
%3: errret直接操作数
%4: r0=err
损坏部:: 无
指令部:
1、具体指令含义参见代码注释
2、处理流程:执行1处的指令,成功则结束;失败,根据异常表项《.section __ex_table,\"a\"\n"》,跳转到3b处执行,设置寄存器值后跳转到2b处结束
注:关于异常表的介绍参见:
Linux异常表
http://www.cnblogs.com/chengxuyuancc/p/3428944.html
6、__copy_from_user_ll
函数源码:
unsigned long
__copy_from_user_ll(void *to, constvoid __user *from, unsigned long n)
{
BUG_ON((long)n< 0);
if(movsl_is_ok(to, from, n))
__copy_user_zeroing(to,from, n);
else
n= __copy_user_zeroing_intel(to, from, n);
returnn;
}
#define movsl_is_ok(a1,a2,n) \
__movsl_is_ok((unsignedlong)(a1),(unsigned long)(a2),(n))
static inline int__movsl_is_ok(unsigned long a1, unsigned long a2, unsigned long n)
{
#ifdef CONFIG_X86_INTEL_USERCOPY
if(n >= 64 && ((a1 ^ a2) & movsl_mask.mask))
return0;
#endif
return1;
}
函数处理流程:
这里没理解清楚CONFIG_X86_INTEL_USERCOPY和movsl_mask.mask的含义,待理解后补上
Linux内核源码分析—从用户空间复制数据到内核空间相关推荐
- v09.04 鸿蒙内核源码分析(调度故事) | 用故事说内核调度 | 百篇博客分析HarmonyOS源码
子曰:"吾与回言终日,不违如愚.退而省其私,亦足以发.回也,不愚."<论语>:为政篇 百篇博客系列篇.本篇为: v09.xx 鸿蒙内核源码分析(调度故事篇) | 用故事 ...
- v70.05 鸿蒙内核源码分析(管道文件) | 如何降低数据流动成本 | 百篇博客分析OpenHarmony源码
子曰:"其身正,不令而行:其身不正,虽令不从." <论语>:子路篇 百篇博客系列篇.本篇为: v70.xx 鸿蒙内核源码分析(管道文件篇) | 如何降低数据流动成本 文 ...
- Linux内核源码分析《进程管理》
Linux内核源码分析<进程管理> 前言 1. Linux 内核源码分析架构 2. 进程原理分析 2.1 进程基础知识 2.2 Linux进程四要素 2.3 进程描述符 task_stru ...
- Linux内核源码分析之内存管理
本文站的角度更底层,基本都是从Linux内核出发,会更深入.所以当你都读完,然后再次审视这些功能的实现和设计时,我相信你会有种豁然开朗的感觉. 1.页 内核把物理页作为内存管理的基本单元. 尽管处理器 ...
- Linux kernel 3.10内核源码分析--进程上下文切换
一.疑问 进程调度时,当被选中的next进程不是current进程时,需要进行上下文切换. 进行上下文切换时,有一些问题不太容易理解,比如: 1.进程上下文切换必然发生在内核态吗? 2.上下文切换后原 ...
- Linux内核源码分析方法
说明:这是一个刚接触内核三个月的同学,通过对一个内核特性的分析,总结出一套分析内核的方法. 一.内核源码之我见 Linux内核代码的庞大令不少人"望而生畏",也正因为如此,使得人们 ...
- Linux内核源码分析--内核启动之(4)Image内核启动(setup_arch函数)(Linux-3.0 ARMv7)【转】...
原文地址:Linux内核源码分析--内核启动之(4)Image内核启动(setup_arch函数)(Linux-3.0 ARMv7) 作者:tekkamanninja 转自:http://blog.c ...
- Linux内核源码分析方法—程序员进阶必备
一.内核源码之我见 Linux内核代码的庞大令不少人"望而生畏",也正因为如此,使得人们对Linux的了解仅处于泛泛的层次.如果想透析Linux,深入操作系统的本质,阅读内核源码是 ...
- iostat IO统计原理linux内核源码分析----基于单通道SATA盘
iostat IO统计原理linux内核源码分析----基于单通道SATA盘 先上一个IO发送submit_bio流程图,本文基本就是围绕该流程讲解. 内核版本 3.10.96 详细的源码注释:htt ...
最新文章
- html css网站开发兵书,程序员藏经阁--HTML+CSS网站开发兵书(附光盘)
- C语言学习笔记--预编译/宏定义/数组/参数传递/函数指针
- python3 多维数组 NumPy ndarray 简介
- 操作系统【逻辑空间、物理空间与页表大小的关系】【分页地址映射(方法+例题)】
- 400错误是什么原因_499错误是什么?499错误的原因及解决方法
- java并发编程之线程的基本介绍
- MYSQL索引创建与删除
- Hive 内嵌模式安装指导
- 《前端之路》之 JavaScript 高级技巧、高阶函数(一)
- 多视几何_计算两幅图像之间的基础矩阵F和一副图像上的点在另一福图像上的极线L
- 贪心算法详解(C++)
- Next主题美化博客
- 非参数统计:方法与应用(全书例题R语言实现)
- linux 文件名 序列号,在Linux中应如何查看系统硬件制造商、型号和序列号
- ffmpeg(七)合并音视频文件
- smartbi 安装教程
- zic - 时区编辑器
- 我的2016:做精彩的自己
- Office自定义功能区各功能图标间隔太大,与之前排版不一样,如何减少间隔距离?
- android画图之贝塞尔曲线讲解
热门文章
- APS54085 外围电路简单_调光无频闪 智能家居照明
- matlab里vSAS,科学网—【MATLAB】saveas和print保存图片的格式 - 叶瑞杰的博文
- mpvue 搭配 minui
- 磨金石教育摄影技能干货分享|那些酷炫的照片是怎么拍出来的?
- markdown 表情包大法
- Linux使用详解(进阶篇)
- android 动态、静态壁纸实现
- 怎么判断噎到没噎到_宝宝噎着的表现是什么 宝宝噎着症状
- tipask 3.5 出错get_class() expects parameter 1 to be object 解决方案及说明
- 《孙子兵法》中的企业领导艺术和方法