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
Reviewers:
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_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
执行,因为它在尽可能的情况下更易于使用且更方便,从人体工学角度来看,它始终优于 VMO 操作。不过,如果映射尚不存在,则人体工学性会大大降低。
向后兼容性
这是一个 API 破坏性更改,但缓存操作由一小部分用户(通常是驱动程序等)执行,而拥有实体 VMO 的用户就更少了,因此现有代码的迁移应该不会很困难。
安全注意事项
此提案既会从内核中移除代码和逻辑,还会导致在特权模式下运行时,用户控制的缓存操作不会针对潜在的设备内存执行。因此,从安全角度来看,这对应用的影响介于中立和略微正面之间。
缺点、替代方案和未知情况
此提案的假设是,对实体 VMO 执行缓存操作的用户要么:
- 因此,如果已经有了映射,那么改为对其执行缓存操作可以提升性能,而不会带来任何负面影响。
- 没有映射,但可以在非性能关键的初始化部分创建映射。
- 没有映射,对性能没有关键影响,并且可以创建临时映射来执行缓存操作。
可能存在以下情况的用户:
- 没有映射。
- 没有可用于创建映射的非性能关键型初始化点。
- 否则,在执行缓存操作时,性能至关重要。
在考虑现有用户和不受支持的潜在用户的这些假设后,我们可以考虑一些完全移除缓存操作的替代方案。
为所有 VMO 移除
移除所有 VMO 的缓存操作将提供统一的 API,这将防止在之前仅预期分页 VMO 的情况下,代码在给定物理 VMO 时可能会失败的情况。
遗憾的是,在某些常见模式下,系统可能会向服务或驱动程序提供 VMO,而无需在固定并传递给底层硬件之前创建映射。在这种情况下,客户端写入的数据可能需要通过缓存操作清理到内存。不过,在 VMO 固定之前,其底层页面可能会被内核更改,导致之前的任何缓存清理操作都不足以清理 VMO。由于只有驱动程序(而非客户端)可以固定内存,这意味着驱动程序必须在固定内存后执行缓存操作。在这种情况下,如果需要映射才能执行此操作,则会给驱动程序增加不必要的开销。
为物理 VMO 提供单独的内核映射
内核可以为每个物理 VMO 创建单独的映射,而不是依赖于 physmap,并改为对此映射执行缓存操作。
这确实解决了 physmap 使用方面的直接问题,解除了所有相关的内核更改,并确保没有映射的假设性能关键用户不会受到影响。
缺点如下:
- 需要分配额外的页面表才能将其映射到内存中,如果用户已经有映射,则会浪费内存。物理 VMO 可能非常大。
- 增加了内核复杂性,并继续允许用户对可能导致内核出错的无效范围执行缓存操作。
临时内核映射
只在缓存操作代码路径中执行临时映射,可以减少页表开销。不过,与用户自行执行临时映射相比,这并没有太大的好处,因此实际上并未改进原始提案。