- 1、原创力文档(book118)网站文档一经付费(服务费),不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。。
- 2、本站所有内容均由合作方或网友上传,本站不对文档的完整性、权威性及其观点立场正确性做任何保证或承诺!文档内容仅供研究参考,付费前请自行鉴别。如您付费,意味着您自己接受本站规则且自行承担风险,本站不退款、不进行额外附加服务;查看《如何避免下载的几个坑》。如果您已付费下载过本站文档,您可以点击 这里二次下载。
- 3、如文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“版权申诉”(推荐),也可以打举报电话:400-050-0827(电话支持时间:9:00-18:30)。
查看更多
* do_page_fault( )函数的首先是读取引起缺页的虚地址。如果没找到,则说明访问了非法虚地址,Linux会发信号终止进程(如果必要)。否则,检查缺页类型,如果是非法类型(越界错误,段权限错误等)同样会发信号终止进程。 缺页异常肯定要发生在内核态,如果发生在用户态,则必定是错误的,于是把相关信息保存在进程的PCB中。 对有效的虚地址,如果是缺页异常,Linux 必须区分页所在的位置,即判断页是在交换文件中,还是在可执行映像中。为此,Linux 通过页表项中的信息区分页所在的位置。如果该页的页表项非空,但对应的页不在内存,则说明该页处于交换文件中,操作系统要从交换文件装入页。 如果错误由写访问引起,该函数检查这个虚存区是否可写。如果不可写,则对这种错误进行相应的处理;如果可写,则采用“写时复制”技术。 如果错误由读或执行访问引起,该函数检查这一页是否已经存在于物理内存中。如果在,错误的发生就是由于进程试图访问用户态下的一个有特权的页面(页面的User/Supervisor标志被清除),因此函数跳到相应的错误处理代码处(实际上这种情况从不发生,因为内核根本不会给用户进程分配有特权的页面)。如果不在物理内存,函数还将检查这个虚存区是否可读或可执行。 如果这个虚存区的访问权限与引起缺页异常的访问类型相匹配,则调用handle_mm_fault( )函数,该函数确定如何给进程分配一个新的物理页面: (1)? 如果被访问的页不在内存,也就是说,这个页还没有被存放在任何一个物理页面中,那么,内核分配一个新的页面并适当地初始化;这种技术称为“请求调页”。 如果被访问的页在内存但是被标为只读,也就是说,它已经被存放在一个页面中,那么,内核分配一个新的页面,并把旧页面的数据拷贝到新页面来初始化它;这种技术称为”写时复制”。 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 当一个进程执行时,如果CPU访问到一个有效的虚地址,但是这个地址对应的页没有在内存,则CPU产生一个缺页异常,同时将这个虚地址存入CR2寄存器(参见第二章),然后调用缺页异常处理程序do_page_fault()。Linux的缺页异常处理程序必须对产生缺页的原因进行区分:是由编程错误所引起的异常,还是由访问进程用户空间的页但还尚未分配物理页面所引起的异常。 分页模型概述 分页单元负责将线性地址转换成物理地址 线性地址会被分组成页的形式,这些线性地址实际上都是连续的 —— 分页单元将这些连续的内存映射成对应的连续物理地址范围(称为 页框) X86分页机制 线性地址到对应物理位置的转换的过程包含两个步骤。第一步使用了一个称为页目录 (Page Directory) 的转换表(从页目录转换成页表),第二步使用了一个称为页表 (Page Table) 的转换表(即页表加偏移量再加页框) 存放页目录物理地址 Linux分页机制 Linux 采用的是一个体系结构无关的三级页表模型 例: //aa.cpp #include stdio.h Void printhello() { printf(“hello,world!\n”); } Void main() { printhello(); } 编译:gcc a.cpp –o aa objdump –d aa 第一步-段式映射 内核在建立进程时就会调用下列代码将CS的值设定好 (include/asm-i386/processor.h) #define start_thread(regs, new_eip, new_esp) do { \ __asm__(movl %0,%%fs ; movl %0,%%gs: :r (0)); \ set_fs(USER_DS); \ regs-xds = __USER_DS; \ regs-xes = __USER_DS; \ regs-xss = __USER_DS; \ regs-xcs = __USER_CS; \ regs-eip = new_eip; \ regs-esp = new_esp; \ } while (0) 段寄存器 因此0X8048328这个虚拟地址经过段式映射后得到线性地址,其值仍然为0X8048328 下面进入重要的页式映射阶段 0000 1000 0000 0100 1000 0011 0010 1000 线性地址032 72 0X740000 物理地址0X740328 PART 4.7 内核内存函数 伙伴关系也好、slab技术也好,从
文档评论(0)