页错误后会发生什么?

Jor*_*gos 8 memory interrupt

当 Linux 系统中发生页面错误时,中断处理程序必须找出页面错误发生的原因。但是怎么样?

  • 有什么特别的号码吗!?如果是,该号码记录在哪里?
  • 在引发异常之前是否有可能知道页面错误的原因?
    例如。
    • Step-1
      通过 CPU 查找原因
    • 步骤 2
      引发异常

Gil*_*il' 13

当内存访问失败时会发生页面错误,因为 MMU 对虚拟地址的查找以无效描述符结束或以指示缺乏权限的描述符(例如,对只读页面的写入尝试)结束。当页面错误发生时,处理器执行一些动作;细节特定于每个处理器架构,但要点是相同的:

  • 切换到特权模式(例如内核模式)。
  • 设置一些寄存器以至少指示故障的性质,以及故障点的程序计数器和处理器模式。
  • 跳转到内存中的特定地址,由寄存器或本身在内存中的特定位置指示:页面错误处理程序的地址。

举个例子,在(32位)ARM处理器上:

  • dfsr寄存器被设置为描述故障的值(无论是由于读还是写、处理器指令或 DMA 等)。
  • dfar寄存器设置为作为导致故障的访问目标的虚拟地址。
  • 处理器切换到中止模式(内核级特权模式之一)。
  • lr寄存器在发生故障时被设置为程序计数器,并且该spsr寄存器在发生故障时被设置为程序状态寄存器(cpsr包含模式位的寄存器)。
  • spcpsr寄存器被编组:它们从值恢复最后一组在中止模式。
  • 执行跳转到异常向量之一的异常向量中止向量

页错误处理程序的代码是操作系统内核的一部分。它的工作是分析故障原因并对其采取措施。它可以查询提供有关故障性质信息的专用寄存器,如果需要,它还可以检查程序正在执行的指令。它还可以在 MMU 表中查找描述符;无效描述符有时可以编码信息,例如交换空间中页面的位置。内核通过查看它在每次上下文切换时更新的全局变量或寄存器的值来知道当前正在执行哪个任务。以下是页面错误的一些常见行为:

  • 有关进程内存映射的数据表明该页面处于交换状态。内核找到一个空闲的物理页面,或者通过删除包含磁盘缓存的页面来获得一个,或者通过首先将其内容保存到交换来获得一个。然后它将数据从交换加载到这个物理页,并更改 MMU 表,以便导致错误的虚拟地址现在附加到进程的 MMU 映射中的那个物理页。最后,内核安排在导致故障的指令点切换回进程;这一次指令将被成功执行。
  • 有关进程内存映射的数据表明该页是写时复制页,并且已尝试进行写访问。与前一种情况类似,内核获得一个空闲的物理页面,将数据复制到它(这里是从只读页面),更改 MMU 描述符,并安排进程再次执行指令。
  • 有关进程内存映射的数据表明该页面未映射,或者它没有必要的权限。在这种情况下,内核会向进程发送 SIGSEGV 信号(分段错误):进程的执行在信号处理程序处而不是在原始位置恢复,但原始位置保存在堆栈中。如果进程没有 SIGSEGV 的处理程序,它就会被终止。

通常无法确定异常即将发生,除非了解虚拟内存配置并在访问内存之前进行检查。正常的操作流程是在页面错误发生时处理器记录页面错误的原因。