| 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_SYNCZX_VMO_OP_CACHE_INVALIDATEZX_VMO_OP_CACHE_CLEANZX_VMO_OP_CACHE_CLEAN_INVALIDATE
对非物理 VMO(即通过 zx_vmo_create、zx_vmo_create_contiguous、zx_vmo_create_child 或 zx_pager_create_vmo 创建的 VMO)执行的这些操作将保持不变,并且行为与之前相同。
这会导致物理 VMO 和分页 VMO 之间的 API 出现差异,这并不理想,因为代码可能需要容忍被赋予任一类型。不过,物理 VMO 并不常用,而且目前无法从所有 VMO 中移除缓存操作,因此需要支持任一类 VMO 的代码都必须确保它具有可用的映射。
实现
树中对物理 VMO 缓存操作的使用并不多,因为大多数需要缓存操作的位置都已使用首选的 zx_cache_flush。在现有 VMO 缓存操作的用法中,始终存在可用于 zx_cache_flush 的现有映射,从而使迁移变得非常简单。
然后,实施计划如下:
- 迁移任何触及物理 VMO 的现有 VMO 缓存操作使用情况。
- 停用物理 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 的范围可能非常大。
- 增加了内核复杂性,并继续允许用户对可能导致内核故障的无效范围执行缓存操作。
临时内核映射
通过仅在缓存操作代码路径中执行临时映射,可以缓解页表的开销。不过,与用户自行执行临时映射相比,这种方法的好处并不大,因此实际上并未改进原始提案。