【问题标题】:Can a page fault handler generate more page faults?页面错误处理程序可以生成更多页面错误吗?
【发布时间】:2019-09-21 14:37:42
【问题描述】:

当我们处于用户模式并发生页面错误时,我有点困惑。

IIRC,当 TLB 尝试将我的(用户空间)虚拟地址映射到物理地址并且失败时,将生成页面错误。

然后它会生成一个将由操作系统同步处理的异常。但现在的问题是:这个异常处理程序代码的地址及其相关数据很可能也不在 TLB 中!

这是递归的还是这个内核内存地址范围受不同规则的约束(例如,虚拟/物理内存之间的自动映射以避免需要使用 TLB?)

谢谢!

【问题讨论】:

  • 我认为你误解了TLB和页面错误之间的关系。在你说“TLB”的任何地方,你都应该说“页表[用于进程]”。 TLB 只是页表的缓存 - TLB 中的缺失不会导致页面错误(它会导致“页面遍历”),但页表中的缺失会。

标签: linux operating-system cpu-architecture tlb page-fault


【解决方案1】:

不,Linux 不会换出内核内存。(出于此和类似原因,例如确保页面错误处理程序不会在任何访问内存的随机指令之前运行)。

对内核内存进行分页的操作系统肯定需要将页面错误处理程序、页表和磁盘 I/O 代码保存在内存中......


此异常处理程序代码及其相关数据也不会出现在 TLB 中!

您将页面遍历(在 TLB 未命中时)与页面错误(虚拟页面的条目无效或权限不足,必要时在页面遍历之后进行)混为一谈。

在 x86 和大多数(?)其他 ISA 上,页面遍历是由硬件完成的。见What happens after a L2 TLB miss?

操作系统将顶级页表的物理地址提供给 CPU(例如在 x86 上使用 mov cr3, rax),然后 CPU 透明地处理其他所有事情。 (唯一的软件 TLB 管理是在修改内存中的页表条目后使可能缓存的条目失效。例如 x86 invlpg

硬件页表管理允许 CPU推测性地在数组上的循环接近页面边界时执行 TLB 遍历,而不是等到实际负载触及下一页。并且页面遍历延迟被乱序执行部分隐藏,还有很多好东西。 Skylake 甚至有 2 个 page-walk 单元,因此它可以并行处理 2 个 TLB 未命中(可能是投机性的,也可能是需求性的)。


在带有软件页面遍历的 ISA 上,TLB 未命中处理程序与页面错误处理程序是分开的。

例如,在 MIPS 上,有一个特殊的地址范围,其映射不同于正常的内核虚拟地址:

如果地址以0b100 [前 3 位] 开头,则转换为物理内存的底部 512 MB,并且不通过 TLB。 (缓存和未映射)。叫kseg0。用于内核指令和数据。

MIPS TLB 处理 - https://people.csail.mit.edu/rinard/teaching/osnotes/h11.html

(设置了高位的 MIPS 地址只能由内核代码使用,用户空间访问错误。即,high-half kernel 被嵌入用于 MIPS。)

这有点像将低物理内存的 512MiB 巨页映射烘焙到硬件中。显然,内核希望将其页面查找数据结构保持在该范围内,但它可以使用它想要的任何数据结构,例如基于开始/长度。

【讨论】:

  • 嗨。感谢您的详尽回答!在阅读“每个程序员都应该了解的内存”的 TLB 部分时,我花了所有时间回复您。
  • 我有几个问题:页面错误是否在这个循环中发生?我想当树遍历并得出页面已被交换的结论时会发生硬页面错误。那么软页面错误呢?
  • @devouredelysium:软页面错误是指页面存在于内存中但“连接”到硬件页表中(无效)。由页面错误处理程序使用内核的数据结构(通常是有效的基于开始/长度范围的映射列表,而不是硬件页表的基数树格式,每页始终有 1 个条目)进行排序。或写时复制映射:逻辑上该页面是可写的,但操作系统在页表中将其标记为只读。所以在重新运行写指令之前需要将页面复制到新分配的物理页面。
  • @devouredelysium:无论哪种方式,硬件只知道 PTE 无效/不存在或没有权限,例如在 x86 上引发 #PF 异常(一旦已知指令是非推测性的,即在无序后端中达到退休,而不是更早。这就是为什么 Meltdown 是一件事的部分原因:P)。硬件对交换空间一无所知,这只是软件可以用虚拟内存做的有趣的事情之一。延迟分配(在触及内存之前根本不创建 HW 页表条目)和写时复制是另外两件事。
  • 但是,在 Linux 内核中,同步 vmalloc 页表可能会发生第二个 #PF 异常。
【解决方案2】:

首先,在考虑软件时,您应该忘记 TLB。 TLB 是一个硬件组件。 TLB 中没有映射这一事实不会自动导致页面错误。

其次,在某些硬件上,多页错误很常见。当处理器允许对页表进行分页时,就会发生这种情况。因此,您可能会在页面上出现页面错误,并且在读取页表时会出现更多或更多的页面错误。支持这一点的处理器使用各种机制来解决可以创建分页表的先有鸡还是先有蛋的问题。

然后它会生成一个将由操作系统同步处理的异常。但现在的问题是:这个异常处理程序代码的地址及其相关数据很可能也不在 TLB 中!

任何操作系统都必须确保其页面错误处理程序保留在物理内存中。

这是递归的还是这个内核内存地址范围受不同规则的约束(例如,虚拟/物理内存之间的自动映射以避免需要使用 TLB?)

在某些处理器上,系统地址空间范围的映射不同于用户空间。这是避免分页页表鸡与蛋问题的方法之一。

【讨论】:

  • 这不是一个特定于 x86 的问题。在 MIPS 之类的架构中,TLB 未命中会导致软件异常。 (不过,与页面错误分开。)
  • 我没有想到英特尔应该显示的文本。注意最后一段。
  • 是的,最后一部分在架构中是有意义的,但你从“在考虑软件时应该忘记 TLB”开始。是的,它在逻辑上与页面错误处理是分开的,但是对于软件 TLB 处理,它是 TLB 未命中处理程序来检测访问是否是页面错误,对吗?或者硬件也可以直接分页错误以对只读 TLB 条目进行写访问?
  • 但是,是的,关于具有分页页表而不是多级嵌套页表的硬件的公平点,解决相同问题的 2 种不同方法,即覆盖 4GB 地址空间,每 4k 有 4 或 8 个字节条目页,如果完全填充且未分页,则会导致巨大的页表。
  • 除非您正在处理 MIPS(这是我能想到的唯一一个具有软件加载 TLB 的架构),否则您可以忘记 TLB 以了解事情是如何工作的。
猜你喜欢
  • 2016-05-05
  • 2012-09-10
  • 2013-05-03
  • 2015-02-03
  • 2017-05-25
  • 1970-01-01
  • 1970-01-01
  • 2017-04-05
  • 1970-01-01
相关资源
最近更新 更多