RFC-0252:无物理 VMO CacheOps

RFC-0252:无物理 VMO CacheOps
状态已接受
区域
  • 内核
说明

移除了对物理 VMO 的缓存操作。

Gerrit 更改
作者
审核人
提交日期(年-月-日)2024-06-12
审核日期(年-月-日)2024-07-18

摘要

移除了直接在物理 VMO 上执行缓存操作的功能。

设计初衷

目前,对物理 VMO 的缓存操作无法可靠地运行,因为它们依赖于 physmap。鉴于物理 VMO 只能通过映射进行操作,因此它们始终可以使用现有的 zx_cache_flush 操作。

物理 VMO 通常表示物理地址空间的非 RAM 区域,例如 MMIO 寄存器。执行缓存操作最好是无意义的,最坏是致命错误,具体取决于架构和硬件。虽然物理 VMO 已经需要受限资源才能创建,但尽可能减少用户可能会导致内核崩溃的方式仍然是一件好事。

利益相关方

辅导员

cpu@google.com

审核者

mcgrathr@google.com、hansens@google.com、jbauman@google.com

已咨询

共同化

在 Zircon 内核/虚拟机团队中讨论过。

设计

由于 zx_cache_flush 已经存在并已实现,因此无需为此提案构建任何新内容。因此,该提案只是要移除对物理 VMO(即由 zx_vmo_create_physical 创建的 VMO)的以下操作的支持:

  • ZX_VMO_OP_CACHE_SYNC
  • ZX_VMO_OP_CACHE_INVALIDATE
  • ZX_VMO_OP_CACHE_CLEAN
  • ZX_VMO_OP_CACHE_CLEAN_INVALIDATE

对非物理 VMO(即通过 zx_vmo_createzx_vmo_create_contiguouszx_vmo_create_childzx_pager_create_vmo 创建的 VMO)执行的这些操作将保持不变,并且行为与之前相同。

这会导致物理 VMO 和分页 VMO 之间的 API 出现差异,这并不理想,因为代码可能需要容忍被赋予任一类型。不过,物理 VMO 并不常用,而且目前无法从所有 VMO 中移除缓存操作,因此需要支持任一类 VMO 的代码都必须确保它具有可用的映射。

实现

树中对物理 VMO 缓存操作的使用并不多,因为大多数需要缓存操作的位置都已使用首选的 zx_cache_flush。在现有 VMO 缓存操作的用法中,始终存在可用于 zx_cache_flush 的现有映射,从而使迁移变得非常简单。

然后,实施计划如下:

  1. 迁移任何触及物理 VMO 的现有 VMO 缓存操作使用情况。
  2. 停用物理 VMO 上的缓存操作,并让它们返回 ZX_ERR_NOT_SUPPORTED

性能

使用 zx_cache_flush 执行缓存操作应该比执行系统调用更高效,因此这项更改通常会带来净性能提升。不过,如果需要创建映射,但物理 VMO 不常用,并且目前不存在此类情况,则此规则不适用。如果日后有需要,您可以重新考虑此决定。

工效学设计

目前,大多数缓存操作都已使用 zx_cache_flush 执行,因为在可能的情况下,使用 zx_cache_flush 更简单方便,从人体工程学角度来看,zx_cache_flush 也始终优于 VMO 操作。不过,如果映射尚不存在,这种方式的人体工程学效果会差很多。

向后兼容性

这是一项 API 破坏性更改,但缓存操作是由一小部分用户(通常是驱动程序和类似用户)完成的,而拥有物理 VMO 的用户更少,因此对于现有代码来说,迁移应该不会太困难。

安全注意事项

此提案既移除了内核中的代码和逻辑,又导致在以特权模式运行时,用户控制的缓存操作不会针对潜在的设备内存进行。因此,从安全角度来看,它属于中性或略微正面。

缺点、替代方案和未知因素

此提案的假设是,对物理 VMO 执行缓存操作的用户要么:

  • 因此,已有映射并切换到对其执行缓存操作是一种性能改进,没有任何缺点。
  • 没有映射,但可以在非性能关键的初始化部分中创建一个映射。
  • 没有映射,对性能要求不高,并且可以创建临时映射来执行缓存操作。

可能存在以下用户:

  • 没有映射。
  • 没有非性能关键型初始化点,无法在其中创建映射。
  • 在执行缓存操作时,否则性能至关重要。

考虑到现有用户和不受支持的潜在用户,我们可以检查一些替代方案,而不是完全移除缓存操作。

针对所有 VMO 移除

移除所有 VMO 的缓存操作将提供统一的 API,从而防止在以下情况下代码可能失败:之前只预期使用分页 VMO,但现在却获得了物理 VMO。

遗憾的是,在常见模式中,服务或驱动程序可能会获得 VMO,但无需在固定并传递给底层硬件之前创建映射。在此场景中,可能需要通过缓存操作将客户端写入的数据清理到内存。不过,在 VMO 固定之前,其底层页面可能会被内核更改,从而导致任何先前的缓存清理都不够充分。由于只有驱动程序(而非客户端)可以固定内存,这意味着驱动程序必须在固定后执行缓存操作。在这种情况下,要求进行映射会给驱动程序增加不必要的开销。

针对物理 VMO 的单独内核映射

内核可以为每个物理 VMO 创建单独的映射,并对该映射执行缓存操作,而不是依赖于 physmap。

这确实解决了 physmap 使用的直接问题,解锁了所有相关的内核更改,并确保了假设的性能关键用户(没有映射)不会受到影响。

缺点如下:

  • 需要分配额外的页面表才能保持此映射,如果用户无论如何都有映射,则会浪费内存。物理 VMO 的范围可能非常大。
  • 增加了内核复杂性,并继续允许用户对可能导致内核故障的无效范围执行缓存操作。

临时内核映射

通过仅在缓存操作代码路径中执行临时映射,可以缓解页表的开销。不过,与用户自行执行临时映射相比,这种方法的好处并不大,因此实际上并未改进原始提案。