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-

(來自現有別名)

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 介面和以下組合來完成:

  1. pgprot_noncached()

  2. 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