PAT / MTRR / PTE 正是 ioremap_wc()、ioremap_cache() 等函数性能差异的底层原因
🧩三者的作用概览
| 名称 | 全称 | 层级 | 作用 | 典型设置接口 |
|---|---|---|---|---|
| MTRR | Memory Type Range Registers | CPU 全局级 | 为物理地址范围指定内存类型(WB/WC/UC 等) | BIOS、内核启动阶段 (/proc/mtrr) |
| PAT | Page Attribute Table | 每个 CPU 的全局表 | 定义 PTE 中 “memory type 编码” 的含义 | 内核初始化时设置(CR_PAT 寄存器) |
| PTE | Page Table Entry | 页表级 | 实际控制每个页的内存类型(通过 PAT + PWT/PCD 位编码) | 通过 ioremap_*() 等接口 |
🧠三者关系示意图
┌────────────────────────┐
│ 内核驱动映射调用 │
│ ioremap(), ioremap_wc()│
└──────────┬─────────────┘
│
▼
┌────────────────────────────┐
│ PTE:页表项 (Page Table) │
│ - PWT / PCD 位 │
│ - PAT 位 │
└──────────┬─────────────────┘
│ 组合编码索引
▼
┌────────────────────────────┐
│ PAT:页属性表 │
│ 索引出内存类型(WB/WC/UC)│
└──────────┬─────────────────┘
│
▼
┌────────────────────────────┐
│ MTRR:物理区间默认类型 │
│ 供 PAT 覆盖或 fallback 使用 │
└────────────────────────────┘
⚙️内存类型 (Memory Type) 对比
| 类型 | 含义 | 特性 | 用途 |
|---|---|---|---|
| UC (Uncacheable) | 不缓存 | 最慢,强制顺序访问 | MMIO 寄存器 |
| WC (Write Combining) | 写合并 | 连续写合并为 burst,提高显存吞吐 | GPU GDDR 映射 |
| WT (Write Through) | 写穿透 | 读缓存、写同时写内存 | 一般不用 |
| WB (Write Back) | 回写缓存 | 最快的普通内存类型 | 系统内存 |
| WP (Write Protected) | 只读缓存 | 特殊用途 | 调试或设备保护 |
🧩PTE 中的关键位
PTE 中有三个位控制缓存类型:
| 位 | 名称 | 含义 |
|---|---|---|
| PCD | Page Cache Disable | 1 = 禁止缓存 |
| PWT | Page Write Through | 1 = 写穿透模式 |
| PAT | Page Attribute Table | 选择 PAT 表中不同组合的 entry |
这三个位组成 3-bit 索引,共 8 种组合:
| PAT | PCD | PWT | 组合索引 | 默认类型(Intel 默认 PAT 表) |
|---|---|---|---|---|
| 0 | 0 | 0 | 0 | WB |
| 0 | 0 | 1 | 1 | WT |
| 0 | 1 | 0 | 2 | UC- |
| 0 | 1 | 1 | 3 | UC |
| 1 | 0 | 0 | 4 | WC |
| 1 | 0 | 1 | 5 | WP |
| 1 | 1 | 0 | 6 | UC |
| 1 | 1 | 1 | 7 | UC |
注:Linux 初始化时会重新写入 PAT 表,使得 WC 支持更方便。
⚖️优先级规则
CPU 最终确定内存类型时的优先级是:
1️⃣ 固定 MTRR(Fixed MTRR)
2️⃣ 可变 MTRR(Variable MTRR)
3️⃣ PAT(通过 PTE 编码)
在多个机制同时定义时:
| 组合情况 | 最终结果 |
|---|---|
| MTRR = UC | 无论 PAT/PTE,最终 UC |
| MTRR = WB 且 PTE = WC | 最终 WC |
| MTRR = WB 且 PTE = UC | 最终 UC |
| 无 MTRR 定义 | 使用 PAT 决定 |
也就是说:
-
MTRR 限制了物理区间的上限属性(全局);
-
PAT 决定每页的具体缓存策略(局部);
-
PTE 是 PAT 的载体。
🚀 与 ioremap_* 的对应关系
| 函数 | 设置的 PAT/PTE 位 | 结果类型 | 性能特征 |
|---|---|---|---|
| ioremap() | UC | 不缓存 | 最慢、最安全 |
| ioremap_nocache() | UC (同上) | 同上 | 已过时 |
| ioremap_wc() | PAT = 1 (WC) | 写合并 | 适合 GPU 显存 |
| ioremap_cache() | WB | 可缓存 | 普通 RAM 映射 |
| ioremap_prot() | 自定义 | 取决于保护属性 | 自定义用途 |
🧩 在 5.10+ 的优化背景
在 Linux 5.10+,ioremap_wc() 优化了 reserve_memtype() 的逻辑:
-
过去每次 ioremap_wc() 都会申请和合并 MTRR 区域(开销大);
-
新逻辑优先走 PAT-only 模式,不再频繁更新 MTRR;
-
只在 BIOS 没有开启 PAT 支持时回退到 MTRR。
这显著减少了:
-
全局锁 memtype_lock 的竞争;
-
映射延迟;
-
CPU 占用。
✅总结
| 层级 | 控制范围 | 功能 | 示例 |
|---|---|---|---|
| MTRR | 物理区间全局 | BIOS/固件设定默认类型 | “BAR2 映射为 WC” |
| PAT | CPU 层全局表 | 定义 PTE 编码的含义 | PAT[4] = WC |
| PTE | 每页设置 | 实际页表项,决定最终类型 | ioremap_wc() 设置为 PAT=1 |
🧠 最终访问性能 = MTRR(限制) + PAT(解释) + PTE(指令)

JINHU