13. PAT (页属性表)¶
x86 页属性表 (PAT) 允许在页级别粒度上设置内存属性。 PAT 是对 MTRR 设置的补充,MTRR 允许在物理地址范围上设置内存类型。 但是,PAT 比 MTRR 更灵活,因为它能够在页级别设置属性,而且由于允许的此类属性设置数量没有硬件限制。 增加的灵活性带来了一些指导原则,即对于具有多个虚拟地址的同一物理内存,不要进行内存类型别名。
PAT 允许不同类型的内存属性。 此时将支持的最常用的属性是
WB |
写回 |
UC |
非缓存 |
WC |
写合并 |
WT |
写透 |
UC- |
非缓存减 |
13.1. PAT API¶
内核中有许多不同的 API 允许在页级别设置内存属性。 为了避免别名,应谨慎使用这些接口。 下面是一个可用接口、其预期用途及其内存属性关系的表。 在内部,这些 API 在物理地址范围上使用 reserve_memtype()/free_memtype() 接口来避免任何别名。
API |
RAM |
ACPI,... |
保留/空洞 |
ioremap |
-- |
UC- |
UC- |
ioremap_cache |
-- |
WB |
WB |
ioremap_uc |
-- |
UC |
UC |
ioremap_wc |
-- |
-- |
WC |
ioremap_wt |
-- |
-- |
WT |
set_memory_uc, set_memory_wb |
UC- |
-- |
-- |
set_memory_wc, set_memory_wb |
WC |
-- |
-- |
set_memory_wt, set_memory_wb |
WT |
-- |
-- |
pci sysfs 资源 |
-- |
-- |
UC- |
pci sysfs resource_wc 是 IORESOURCE_PREFETCH |
-- |
-- |
WC |
pci proc !PCIIOC_WRITE_COMBINE |
-- |
-- |
UC- |
pci proc PCIIOC_WRITE_COMBINE |
-- |
-- |
WC |
/dev/mem 读写 |
-- |
WB/WC/UC- |
WB/WC/UC- |
/dev/mem mmap SYNC 标志 |
-- |
UC- |
UC- |
/dev/mem mmap !SYNC 标志以及此区域的任何别名 |
-- |
(来自现有别名) |
WB/WC/UC- (来自现有别名) |
/dev/mem mmap !SYNC 标志,此区域没有别名,并且 MTRR 指出 WB |
-- |
WB |
WB |
/dev/mem mmap !SYNC 标志,此区域没有别名,并且 MTRR 指出 !WB |
-- |
-- |
UC- |
13.2. 驱动程序的高级 API¶
A. 使用 remap_pfn_range、io_remap_pfn_range、vmf_insert_pfn 将页面导出给用户。
希望将某些页面导出到用户空间的驱动程序通过使用 mmap 接口和以下组合来完成:
pgprot_noncached()
io_remap_pfn_range() 或
remap_pfn_range()
或vmf_insert_pfn()
通过 PAT 支持,正在添加一个新的 API pgprot_writecombine。 因此,驱动程序可以继续使用上述序列,在步骤 1 中使用 pgprot_noncached() 或 pgprot_writecombine(),然后在步骤 2 中使用。
此外,步骤 2 在内部将该区域作为 UC 或 WC 跟踪在 memtype 列表中,以确保没有冲突的映射。
请注意,这组 API 仅适用于 IO(非 RAM)区域。 如果驱动程序想要导出 RAM 区域,则必须执行 set_memory_uc() 或 set_memory_wc() 作为上面的步骤 0,并且还跟踪这些页面的使用情况,并在将页面释放到空闲池之前使用 set_memory_wb()。
13.3. MTRR 对 PAT / 非 PAT 系统的影响¶
下表提供了在非 PAT 和 PAT 系统上为 x86 使用 ioremap*() 调用时使用写合并 MTRR 的影响。 理想情况下,mtrr_add() 的使用将在 arch_phys_wc_add()
的支持下逐步淘汰,这将是在启用 PAT 的系统上的空操作。 进行 arch_phys_wc_add()
的区域应已使用 WC 属性或 PAT 条目进行 ioremap,这可以通过使用 ioremap_wc() / set_memory_wc() 来完成。 将希望保持不可缓存的 IO 内存区域与希望进行写合并的区域组合在一起的设备应考虑使用 ioremap_uc(),然后使用 set_memory_wc() 将有效的写合并区域列入白名单。 然而,不鼓励这种使用,因为有效的内存类型被认为是实现定义的,但这种策略可以用作在尺寸受限的区域中设备的最后手段,否则 MTRR 写合并将无效。
==== ======= === ========================= =====================
MTRR Non-PAT PAT Linux ioremap value Effective memory type
==== ======= === ========================= =====================
PAT Non-PAT | PAT
|PCD |
||PWT |
||| |
WC 000 WB _PAGE_CACHE_MODE_WB WC | WC
WC 001 WC _PAGE_CACHE_MODE_WC WC* | WC
WC 010 UC- _PAGE_CACHE_MODE_UC_MINUS WC* | UC
WC 011 UC _PAGE_CACHE_MODE_UC UC | UC
==== ======= === ========================= =====================
(*) denotes implementation defined and is discouraged
注意
-- 在上表中表示 “不建议用于 API”。 一些 --’s 由内核严格执行。 其他一些今天并没有真正执行,但将来可能会执行。
对于通过 /sys 或 /proc 进行的 ioremap 和 pci 访问 - 如果该地址有任何现有别名,则返回的实际类型可能会受到更多限制。 例如:如果存在现有的非缓存映射,则新的 ioremap_wc 可以返回非缓存映射来代替请求的写合并。
set_memory_[uc|wc|wt] 和 set_memory_wb 应该成对使用,驱动程序首先将区域设置为 uc、wc 或 wt,然后在使用后将其切换回 wb。
随着时间的推移,写入 /proc/mtrr 将被弃用,取而代之的是使用基于 PAT 的接口。 建议写入 /proc/mtrr 的用户使用上面的接口。
驱动程序应使用 ioremap_[uc|wc] 来访问具有 [uc|wc] 访问类型的 PCI BAR。
驱动程序应使用 set_memory_[uc|wc|wt] 来设置 RAM 范围的访问类型。
13.4. PAT 调试¶
启用 CONFIG_DEBUG_FS 后,可以通过以下方式检查 PAT memtype 列表:
# mount -t debugfs debugfs /sys/kernel/debug
# cat /sys/kernel/debug/x86/pat_memtype_list
PAT memtype list:
uncached-minus @ 0x7fadf000-0x7fae0000
uncached-minus @ 0x7fb19000-0x7fb1a000
uncached-minus @ 0x7fb1a000-0x7fb1b000
uncached-minus @ 0x7fb1b000-0x7fb1c000
uncached-minus @ 0x7fb1c000-0x7fb1d000
uncached-minus @ 0x7fb1d000-0x7fb1e000
uncached-minus @ 0x7fb1e000-0x7fb25000
uncached-minus @ 0x7fb25000-0x7fb26000
uncached-minus @ 0x7fb26000-0x7fb27000
uncached-minus @ 0x7fb27000-0x7fb28000
uncached-minus @ 0x7fb28000-0x7fb2e000
uncached-minus @ 0x7fb2e000-0x7fb2f000
uncached-minus @ 0x7fb2f000-0x7fb30000
uncached-minus @ 0x7fb31000-0x7fb32000
uncached-minus @ 0x80000000-0x90000000
此列表显示物理地址范围和用于访问这些物理地址范围的各种 PAT 设置。
另一种获取与 PAT 相关的调试消息的更详细的方法是使用 “debugpat” 启动参数。 使用此参数,各种调试消息将打印到 dmesg 日志。
13.5. PAT 初始化¶
下表描述了在各种配置下如何初始化 PAT。 必须由 Linux 更新 PAT MSR,才能支持 WC 和 WT 属性。 否则,PAT MSR 具有固件编程到其中的值。 请注意,Xen 在 PAT MSR 中为访客启用 WC 属性。
MTRR
PAT
调用序列
PAT 状态
PAT MSR
E
E
MTRR -> PAT 初始化
已启用
操作系统
E
D
MTRR -> PAT 初始化
已禁用
D
E
MTRR -> PAT 禁用
已禁用
BIOS
D
D
MTRR -> PAT 禁用
已禁用
np/E
PAT -> PAT 禁用
已禁用
BIOS
np/D
PAT -> PAT 禁用
已禁用
E
!P/E
MTRR -> PAT 初始化
已禁用
BIOS
D
!P/E
MTRR -> PAT 禁用
已禁用
BIOS
!M
!P/E
MTRR stub -> PAT 禁用
已禁用
BIOS
图例
E
CPU 中启用的特性
D
CPU 中禁用/不支持的特性
np
指定的 “nopat” 启动选项
!P
未设置 CONFIG_X86_PAT 选项
!M
未设置 CONFIG_MTRR 选项
已启用
PAT 状态设置为已启用
已禁用
PAT 状态设置为已禁用
操作系统
PAT 使用操作系统设置初始化 PAT MSR
BIOS
PAT 使用 BIOS 设置保留 PAT MSR