13. PAT(页属性表)¶
x86 页属性表 (PAT) 允许在页级别粒度上设置内存属性。PAT 是 MTRR 设置的补充,后者允许在物理地址范围上设置内存类型。但是,由于 PAT 能够在页级别设置属性,并且由于允许的此类属性设置的数量没有硬件限制,因此 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 在内部将该区域跟踪为 memtype 列表中的 UC 或 WC,以确保没有冲突的映射。
请注意,这组 API 仅适用于 IO(非 RAM)区域。如果驱动程序想要导出 RAM 区域,则必须在上面的步骤 0 中执行 set_memory_uc() 或 set_memory_wc(),并跟踪这些页面的使用情况,并在释放页面到可用池之前使用 set_memory_wb()。
13.3. MTRR 对 PAT/非 PAT 系统的影响¶
下表提供了在 x86 上对非 PAT 和 PAT 系统使用 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。PAT MSR 必须由 Linux 更新,以支持 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 存根 -> PAT 禁用
已禁用
BIOS
图例
E
CPU 中启用的特性
D
CPU 中禁用的/不支持的特性
np
指定了“nopat”引导选项
!P
CONFIG_X86_PAT 选项未设置
!M
CONFIG_MTRR 选项未设置
已启用
PAT 状态设置为已启用
已禁用
PAT 状态设置为已禁用
操作系统
PAT 使用操作系统设置初始化 PAT MSR
BIOS
PAT 将 PAT MSR 保留在 BIOS 设置中