分段故障如何在内部工作(内核/硬件)?

us2*_*012 15 c hardware memory-management linux-kernel

从广义上讲,我想知道内核(或CPU)如何知道进程试图访问它缺少权限的内存位置,以及称为MMU的神秘硬件如何帮助实现这一点.

特别是:在我看来,MMU对操作系统内核的内存管理模型(分页,内存区域,进程地址空间......)是不可知的(我认为Linux和Windows页面不完全相同,因为例如,如果我错了,请纠正我.但是,我的CPU如何确定当前代码是否可以访问位置x?它如何向内核发出信号?

twa*_*erg 12

这可能是一个太大的话题,无法在这里完全回答; 你会做得更好,搜索讨论虚拟内存实现背后的硬件的一些论文/文章/书籍(可能从特定的架构开始,因为例如x86,x86_64,sparc等之间存在显着差异......).

简而言之,硬件是通过页表处理这个问题.要求MMU处理的每个内存访问都通过页表结构进行验证.如果描述包含所请求地址的页面的页表条目未标记为允许所请求的访问类型(读/写/执行/ ...),则硬件会生成一个陷阱,Linux最终将其称为"分段错误" .其他操作系统以不同的名称命名(例如,一般保护错误,......).操作系统内核然后必须找出故障的原因以及是否可以对其进行任何操作(内核处理许多陷阱以从磁盘交换新页面,映射新的空页等,但有些,如空指针解引用,内核可以做的最好的事情是将它扔到应用程序上说"你做了坏事".

  • 页表结构由硬件决定 - 它们必须采用特定格式.通常,操作系统可以灵活地处理表的某些方面,但操作系统必须提供正确格式的页表供硬件使用.早期的操作系统没有使用分页,因为(a)硬件还没有支持它,或者(b)硬件支持它,但操作系统试图保持与旧系统的向后兼容性,因此实际上没有使用它即使硬件支持它. (2认同)
  • 并且,一旦表格为操作系统的进程设置一次,操作系统就不需要更改它们,除非您映射新内存段或取消映射旧内存段,或者需要处理页面输入/页面输出事件.每次内存访问(指令获取,数据读/写,堆栈等)都必须通过MMU,但是一旦表格设置正确,硬件就可以处理所有内容 - 您无需在每次访问时切换到内核. (2认同)

Chr*_*ton 8

MMU被配置(通过其内核设置的逻辑和/或选项位的设计)作为分页模型的实现的硬件部分.

MMU通常必须将逻辑地址转换为映射的物理地址; 当它不能这样做因为所请求的逻辑地址没有相应的物理地址时,它会产生一个故障(通常作为一种中断),它在内核中运行处理程序代码.

如果故障是尝试请求理论上存在的东西 - 比如映射文件的一部分 - 但是当前不存在于物理内存中,操作系统的虚拟内存实现可以通过分配一些物理内存并复制相应的磁盘块来解决问题进去.

但是,如果它是对不存在的东西的请求,则不能满足它并且必须作为程序错误处理.

写入不允许写入的内容的请求将以类似的方式处理.

在我的脑海中,我不确定是否在MMU中检测到执行非可执行信息的尝试或者在CPU本身中检测到更多信息.如果存在的指令缓存如何适应,也可能使事情复杂化.但是,最终结果将是类似的 - 内核发生非法执行尝试的错误条件,内核通常将其视为程序错误.

总之,模型是更简单的硬件层告诉内核发生了一些不寻常的事情,硬件无法使用其当前配置自行处理.然后,操作系统决定是否可以和应该发生的尝试 - 如果是,它会更新硬件配置以使其成为可能.或者,如果不允许尝试的内容,则声明程序错误.还有其他可能性,例如,虚拟化层可以决定模拟所请求的操作而不是字面上执行它,从而保留了与硬件的一些隔离.