Linux 内核中定义页面缓存模式(Page Cache Mode)的枚举类型。它用于控制 CPU 对特定内存区域的访问方式,在性能和硬件行为之间进行权衡。
不同的缓存模式会直接影响 CPU 如何通过其缓存层次结构来处理内存读写操作,并且在 x86 架构中,这些模式最终会被编码到页表条目(PTE)的特定标志位(如_PAGE_PAT、_PAGE_PCD、_PAGE_PWT)中。
📝 各缓存模式详解
下面是对这些模式工作原理和用途的解析:
| 模式 | 宏定义 | 含义与用途 |
|---|---|---|
| Write-Back (WB) | _PAGE_CACHE_MODE_WB | 写回。这是系统默认且最高效的模式。数据在写入时会先存于缓存,稍后才同步到主存。读操作也优先从缓存获取。适用于绝大多数普通内存。 |
| Write-Combining (WC) | _PAGE_CACHE_MODE_WC | 写合并。用于优化向某些设备(如显存)写入大量数据的场景。它会将多个较小的写操作合并为一次较大的突发传输,能显著提升 GPU 等 I/O 设备的性能。 |
| Uncached Minus (UC-) | _PAGE_CACHE_MODE_UC_MINUS | 强缓存禁用(弱化版)。完全禁用缓存,且不允许使用 WC 模式。通常用于需要严格顺序访问的 MMIO(内存映射 I/O)区域,但性能最差。 |
| Uncached (UC) | _PAGE_CACHE_MODE_UC | 缓存禁用。比 UC- 更严格,会强制使用最保守的访问策略。在 x86 架构中,它和 UC- 的具体行为差异与 MTRR(内存类型范围寄存器)的设置有关。 |
| Write-Through (WT) | _PAGE_CACHE_MODE_WT | 写通。数据写入时同时更新缓存和主存。能保证数据一致性,但性能通常不如 WB。在某些需要实时监控内存变化的场景下使用。 |
| Write-Protected (WP) | _PAGE_CACHE_MODE_WP | 写保护。允许读取缓存数据,但任何写入操作都会绕过缓存,直接访问主存。这个模式在目前的 x86 内核中较少被直接使用。 |
在页表中的编码与使用场景
在 x86-64 架构中,这些模式最终会被编码到 PTE(页表条目)的PCD(Cache Disable)、PWT(Write Through)和PAT(Page Attribute Table)标志位中。内核提供了如pgprot_writecombine()、pgprot_uncached()等辅助函数,方便驱动开发者根据需求设置正确的缓存模式。
需要注意的是,提供的枚举中,
_PAGE_CACHE_MODE_NUM = 8这个值表示该枚举的最大容量,它与实际可用的模式数量(6种)并不完全对应。
这些模式如何被使用?
驱动开发中是一个典型的应用场景。当驱动程序需要访问一段设备内存(如 PCIe 设备的 BAR 空间)时,通常会使用ioremap()或ioremap_wc()等函数。这些函数在底层会根据传入的参数,设置对应的缓存模式。
例如,在ioremap_wc()的流程中,最终会调用__set_memory_prot(),并在其中根据_PAGE_CACHE_MODE_WC来设置页表属性。