内核中的page fault copy_from_user
内核态的page fault?
前段时间有同事问了个问题:内核中是否可能发生page fault?
一时没能给出准确答案,当即有种感觉:难道是对内核内存管理的理解还不够,之前在这方面还是比较自信的~
问题看似很简单,从之前的理解来看,以经典的32位X86为例,内核态低端地址都是线性映射的,页表都是事先(内核初始化时)创建好的,对于这段地址,应该不会发生page fault;但对于vmalloc区,是通过页表动态映射的,这部分显然是可能发生缺页的。
看似问题有答案了,但TX问的不是针对内核态地址发送的缺页,而是:在内核态下,对用户态地址的访问,是否发生page fault?
我追问了一句:什么情况下,内核态需要访问用户态地址? 回答:比如copy_from_user.
问题清晰了,这种情况下,可能发生缺页吗?
硬件层面
从硬件层面上来说,当CPU做访问操作时,MMU硬件会遍历页表,查找匹配的映射条目,如果没有找到,就会自动触发page fault。
所以,从这个角度看,只要copy_from_user参数中的用户态地址对应的页表项不存在,就会产生page fault。
不应该发生吧?
换个角度,内核要使用copy_from_user从用户态拷贝数据时,按理数据应该都已经准备好了吧,也就是说相应的内存(物理)应该都已经分配好了把,不应该发生page fault了吧?
正常情况下,的确如此,但万一内核非要访问未映射的用户态地址呢?万一用户态数据此时没有准备好呢?谁能保证?
所以,虽然不应该发生,但还是可能发送的。
有什么不一样么?
这种情况下,在内核中发生的page fault,与平常我们见到的在用户态发生的page fault有什么不同么?
在用户态时,发生缺页时,CPU硬件会切换到到特权模式(内核态),进行异常处理;在内核态时发生缺页,由于当前本来就出于内核态,所以处理方式肯定会有不同。这也许只是一方面,应该还有其它不同~
如何处理的?
在page fault的流程中针对Vmalloc区发生的缺页有专门的处理,可以参见vmalloc_fault函数。
那对于copy_from_user的情况呢?
肯定的。其实就是do_page_fault流程中exception table相关的处理,之前对这里的代码没有仔细理解清楚,原来就是用来处理这种情况的。
为什么要用copy_from_user?
还是回到老问题,为什么要用copy_from_user,按理解,拷贝数据,不就是从一个地址搬移数据到另一个地址,用memcpy不就好了?
就是因为可能发生page fault的情况,memcpy对这种情况没有任何的处理措施,可能引发不可知的后果。
而copy_from_user对这种情况进行了处理,处理方式就是在代码中增加了一个.fixup的段,该段在do_page_fault中会被读取,结合exception table进行相应的修正,具体修正方式,没时间深入研究了,感兴趣可以继续看看。
copy_from_user代码如下:
static unsigned long
__copy_user_intel(void __user *to, const void *from, unsigned long size)
{int d0, d1;__asm__ __volatile__(" .align 2,0x90\n""1: movl 32(%4), %%eax\n"" cmpl $67, %0\n"" jbe 3f\n""2: movl 64(%4), %%eax\n"" .align 2,0x90\n""3: movl 0(%4), %%eax\n""4: movl 4(%4), %%edx\n""5: movl %%eax, 0(%3)\n""6: movl %%edx, 4(%3)\n""7: movl 8(%4), %%eax\n""8: movl 12(%4),%%edx\n""9: movl %%eax, 8(%3)\n""10: movl %%edx, 12(%3)\n""11: movl 16(%4), %%eax\n""12: movl 20(%4), %%edx\n""13: movl %%eax, 16(%3)\n""14: movl %%edx, 20(%3)\n""15: movl 24(%4), %%eax\n""16: movl 28(%4), %%edx\n""17: movl %%eax, 24(%3)\n""18: movl %%edx, 28(%3)\n""19: movl 32(%4), %%eax\n""20: movl 36(%4), %%edx\n""21: movl %%eax, 32(%3)\n""22: movl %%edx, 36(%3)\n""23: movl 40(%4), %%eax\n""24: movl 44(%4), %%edx\n""25: movl %%eax, 40(%3)\n""26: movl %%edx, 44(%3)\n""27: movl 48(%4), %%eax\n""28: movl 52(%4), %%edx\n""29: movl %%eax, 48(%3)\n""30: movl %%edx, 52(%3)\n""31: movl 56(%4), %%eax\n""32: movl 60(%4), %%edx\n""33: movl %%eax, 56(%3)\n""34: movl %%edx, 60(%3)\n"" addl $-64, %0\n"" addl $64, %4\n"" addl $64, %3\n"" cmpl $63, %0\n"" ja 1b\n""35: movl %0, %%eax\n"" shrl $2, %0\n"" andl $3, %%eax\n"" cld\n""99: rep; movsl\n""36: movl %%eax, %0\n""37: rep; movsb\n""100:\n"".section .fixup,\"ax\"\n""101: lea 0(%%eax,%0,4),%0\n"" jmp 100b\n"".previous\n"_ASM_EXTABLE(1b,100b)_ASM_EXTABLE(2b,100b)_ASM_EXTABLE(3b,100b)_ASM_EXTABLE(4b,100b)_ASM_EXTABLE(5b,100b)_ASM_EXTABLE(6b,100b)_ASM_EXTABLE(7b,100b)_ASM_EXTABLE(8b,100b)_ASM_EXTABLE(9b,100b)_ASM_EXTABLE(10b,100b)_ASM_EXTABLE(11b,100b)_ASM_EXTABLE(12b,100b)_ASM_EXTABLE(13b,100b)_ASM_EXTABLE(14b,100b)_ASM_EXTABLE(15b,100b)_ASM_EXTABLE(16b,100b)_ASM_EXTABLE(17b,100b)_ASM_EXTABLE(18b,100b)_ASM_EXTABLE(19b,100b)_ASM_EXTABLE(20b,100b)_ASM_EXTABLE(21b,100b)_ASM_EXTABLE(22b,100b)_ASM_EXTABLE(23b,100b)_ASM_EXTABLE(24b,100b)_ASM_EXTABLE(25b,100b)_ASM_EXTABLE(26b,100b)_ASM_EXTABLE(27b,100b)_ASM_EXTABLE(28b,100b)_ASM_EXTABLE(29b,100b)_ASM_EXTABLE(30b,100b)_ASM_EXTABLE(31b,100b)_ASM_EXTABLE(32b,100b)_ASM_EXTABLE(33b,100b)_ASM_EXTABLE(34b,100b)_ASM_EXTABLE(35b,100b)_ASM_EXTABLE(36b,100b)_ASM_EXTABLE(37b,100b)_ASM_EXTABLE(99b,101b): "=&c"(size), "=&D" (d0), "=&S" (d1): "1"(to), "2"(from), "0"(size): "eax", "edx", "memory");return size;
}
代码整体上跟memcpy实现差不多,主要差别就是fixup段了,感兴趣的TX可以对比看看。
原文地址: http://happyseeker.github.io/kernel/2016/12/30/page-fault-in-kernel.html
内核中的page fault copy_from_user相关推荐
- linux内核中的copy_to_user和copy_from_user(一)
linux内核中的copy_to_user和copy_from_user(一) 2017年12月21日 20:07:32 prike 阅读数:4768 linux内核中的copy_to_user和co ...
- Linux内存page,【原创】(十四)Linux内存管理之page fault处理
背景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: Kernel版本: ...
- linux 内存管理 page fault带来的性能问题
Linux进程如何访问内存 Linux下,进程并不是直接访问物理内存,而是通过内存管理单元(MMU)来访问内存资源. 原因后面会讲到. 为什么需要虚拟内存地址空间 假设某个进程需要4MB的空间,内存假 ...
- 图解|什么是缺页错误Page Fault
1.号外号外 各位老铁,大家好! 上周大白有事停更1次,最近在想如何让大家在10分钟中有所收获,于是准备搞一个"什么是xxx"系列,写一些精悍的知识点. 先抛一道阿里面试题给大家热 ...
- linux 内存越界判断_虚拟内存 和 page fault 的解释
Linux 内核给每个进程都提供了一个独立的虚拟地址空间,并且这个地址空间是连续的.这样进程就可以很方便地访问内存,更确切地说是访问虚拟内存. 1.什么是虚拟内存 假设某个进程需要100MB的空间,而 ...
- linux那些事之page fault(AMD64架构)(user space)(2)
do_user_addr_fault 用户空间地址处理是page fault主要处理流程,x86 64位系统主要是do_user_addr_fault()函数 该处理部分是x86架构特有部分 即与架构 ...
- 趣味图解 | 什么是缺页错误 Page Fault?
来源 | 后端技术指南针 号外号外 各位老铁,大家好! 最近在想如何让大家在10分钟中有所收获,写一些精悍的知识点. 先抛一道阿里面试题给大家热热身,引出今天的主角-缺页异常Page Fault. 谈 ...
- [十月往昔]——Linux内核中的内存管理浅谈
为什么要叫做"十月往昔"呢,是为了纪念我的原博客,http://www.casual0402.cn. 不知道为什么,突然想来一个新的开始--而那个博客存活至今刚好十个月,也有十个月 ...
- 6.S081-6缺页异常 - lazy allocation - Page Fault
6.S081-6缺页异常Page Fault 这一节课,可以帮我们完成2个实验: 题目要求链接:Lab: xv6 lazy page allocation 对应做法链接:6.S081 Lab4 Laz ...
最新文章
- MySQL配置文件参数详解
- 【Android 逆向】ptrace 函数 ( ptrace 函数族 | 进程附着 | 进程脱离 | 进程数据读写权限 | 进程对应的主线程寄存器读写 | 单步调试 |ptrace 函数族状态转换 )
- edittext怎么输入默认内容覆盖_Linux Shell 输入与输出重定向
- docker入门与实践之【04-使用dockerfile定制镜像】
- 怎么设置班级文件服务器,如何开设论坛如题下学期老师组织学生开一个班级论坛有专用服务器接下 爱问知识人...
- HTML5 列表和表格
- Basic--Java基本语法
- Tomcat服务器搭建及测试教程,腾讯+华为+阿里面试真题分享
- Nmap简单使用教程
- 又一打包工具介绍:Installshield 打包安装包心得
- 宾馆客房管理系统——前后端分离
- Win11 系统安装事项,跳过微软账户登录,VMWare安装Win11
- 小米笔记本电脑设置u盘启动的方法教程
- 一文详解谷歌最新物联网操作系统 Android Things,话说还记得大明湖畔的Fuchsia吗?
- 这部纪录片带你重新认识中华神州大地,领略你不知道的中国
- 形式化方法(Formal Methods)
- Python Flask Web教程006:Flask HTTP方法
- ASP.NET动态网站开发学习实录(一)
- 功耗大好还是小好_热设计功耗高好还是低好 - 卡饭网
- 民俗杂事丨为什么说出轨女人的丈夫是被戴了“绿帽子”?