目录
给定一个虚拟内存区域vma,函数filemap_fault读文件页的方法如下:
什么是缺页异常?
在取指令或数据的时候,处理器的内存管理单元需要把虚拟地址转换成物理地址。如果虚拟也没有找到物理页时,或者没有访问权限,处理器将生成页错误异常。通常情况下称为缺页异常
大概有以下情况:
- 访问用户栈的时候,超出了当前用户栈的范围,需要扩大用户栈
- 当进程申请虚拟内存区域的时候,通常没有分配物理页,进程第一次访问的时候触发页错误异常。
- 内存不足的时候,内核把进程的匿名页换出到交换区
- 一个文件页被映射到进程的虚拟地址空间,内存不足时,内核回收这个文件页,在进程的页表中删除这个文件的映射
- 程序错误,访问没有分配给进程的虚拟内存区域,将会发出SIGSEGV信号将进程杀死。
没有访问权限,有以下两种情况:
- 可能是软件有意造成的,如写时复制:子进程和父进程以只读的方式共享私有的匿名页和文件页。当其中一个进程试图写只读页时,触发页错误异常,页错误异常处理程序分配新的物理页,把旧的物理页数据复制到新的物理页,然后把虚拟页映射到新的物理页。
- 程序错误,如试图写只读的代码段所在的物理页。
不同处理器架构的页面错误异常不同,页错误异常处理程的前面一部分是各处理器架构自定义部分,后面函数handle_mm_fault开始是共同架构。
处理器特定部分
生成页错误异常
ARM64处理器在取指令或数据的时候,需要把虚拟地址换成物理地址,分为两种情况:
1)如果虚拟地址的高16位不全是1或全0,是非法地址,生成页错误异常。
2,处理页错误异常高16位全是1或全0,内存管理单元根据关键字{地址空间标识符,虚拟地址}查找TLB。
如果命中了TLB选项,从TLB表项读取访问权限,检查访问权限,如果没有访问权限则生成页错误异常。
如果没有命中TLB选项,内存管理单元将会查询内存中的页表,称为转换遍历。
- 如果虚拟地址的高16位全是1,说明是内核虚拟地址,应该查询内核的页表,从寄存器TTBR1_EL1取内核的页全局目录的物理地址。
- 如果虚拟地址的高16位全是0,说明是用户虚拟地址,应该查询进程的页表,从寄存器TTBR0_L1取进程的页全局目录的物理地址。
处理页错误异常
在ARM64架构中,用户程序在异常级别0运行,内核在异常级别1运行。
ARM64定义了一个异常向量表,起始地址是vectors(arch/arm64/kernel/entry.S)每个异常向量表的长度是128字节,但是在linux内核中每个异常只存在一条指令,跳转到对应的处理程序。异常向量表的虚拟地址放在异常级别1的向量基准地址寄存器(VBAR_EL1)中。
匿名页的缺页异常
发生情况
- 函数的局部变量比较大,或者函数调用层次比较深,导致当前栈不够用,需要扩大栈;
- 进程调用malloc,从堆申请了内存块,只分配虚拟内存区域,还没有映射到物理页,第一次访问时触发缺页异常
- 进程直接调用mmap,创建匿名的内存映射,只分配了虚拟内存区域,还没有映射到物理页,第一次访问时触发缺页异常。
缺页异常函数 do_anonymous_page处理私有匿名的缺页异常。
文件的缺页异常
发生情况
- 启动程序的时候,内核为程序的代码段和数据段创建私有文件映射,映射到进程的虚拟地址空间,第一次访问的时候,触发问你件页的缺页异常。
- 进程使用mmap创建文件映射,把文件的一个区间映射到进程的虚拟地址空间,第一次访问的时候,触发文件页的缺页异常。
处理函数 __do_fault()
处理文件页错误,具体处理读文件页错误的方法:
- 把文件页从存储设备上的文件系统读到文件缓存(每个文件有一个缓存,因为以页为单位,所以称为页缓存)中
- 设置检测的页表项,把虚拟页映射到文件页缓存的物理页。
函数do_read_fault()
给定一个虚拟内存区域vma,函数filemap_fault读文件页的方法如下:
- 根据vma->vm_file得到文件的打开实例file
- 根据file->f_mapping得到文件的地址空间mapping
- 使用地址空间操作集合中的readpage方法(mapping->a_ops->readpage)把文件页读到内存中
- 函数finish_fault 负责设备项页表,把主要工作委托给函数alloc_set_pte,执行流程及源码分析
文件写私有文件页错误的方法:
- 把文件页从存储设备上的文件系统读到文件的页缓存中;
- 执行写时复制,为文件的页缓存中的物理页创建一个副本,这个副本是进程的私有匿名页和文件脱离系统,修改副本不会导致文件变化;
- 设备进程的页表项,把虚拟页映射到副本;
函数do_cow_falut处理写私有文件页错误
文件写共享文件页错误的方法如下:
- 把文件页从存储设备上的文件系统读到文件的也缓存中
- 设备进程的页表项,把虚拟地址映射到文件的页缓存中的物理页
函数do_shared_fault处理写共享文件页错误
参考链接
https://course.0voice.com/v1/course/intro?courseId=2&agentId=0