요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.
1. 요약·해설
원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.
2. 영어 원문 전체
번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.
원문 전체 펼치기
.. SPDX-License-Identifier: GPL-2.0
==========================
PAT (Page Attribute Table)
==========================
x86 Page Attribute Table (PAT) allows for setting the memory attribute at the
page level granularity. PAT is complementary to the MTRR settings which allows
for setting of memory types over physical address ranges. However, PAT is
more flexible than MTRR due to its capability to set attributes at page level
and also due to the fact that there are no hardware limitations on number of
such attribute settings allowed. Added flexibility comes with guidelines for
not having memory type aliasing for the same physical memory with multiple
virtual addresses.
PAT allows for different types of memory attributes. The most commonly used
ones that will be supported at this time are:
=== ==============
WB Write-back
UC Uncached
WC Write-combined
WT Write-through
UC- Uncached Minus
=== ==============
PAT APIs
========
There are many different APIs in the kernel that allows setting of memory
attributes at the page level. In order to avoid aliasing, these interfaces
should be used thoughtfully. Below is a table of interfaces available,
their intended usage and their memory attribute relationships. Internally,
these APIs use a reserve_memtype()/free_memtype() interface on the physical
address range to avoid any aliasing.
+------------------------+----------+--------------+------------------+
| API | RAM | ACPI,... | Reserved/Holes |
+------------------------+----------+--------------+------------------+
| ioremap | -- | UC- | UC- |
+------------------------+----------+--------------+------------------+
| ioremap_cache | -- | WB | WB |
+------------------------+----------+--------------+------------------+
| ioremap_uc | -- | UC | UC |
+------------------------+----------+--------------+------------------+
| ioremap_wc | -- | -- | WC |
+------------------------+----------+--------------+------------------+
| ioremap_wt | -- | -- | WT |
+------------------------+----------+--------------+------------------+
| set_memory_uc, | UC- | -- | -- |
| set_memory_wb | | | |
+------------------------+----------+--------------+------------------+
| set_memory_wc, | WC | -- | -- |
| set_memory_wb | | | |
+------------------------+----------+--------------+------------------+
| set_memory_wt, | WT | -- | -- |
| set_memory_wb | | | |
+------------------------+----------+--------------+------------------+
| pci sysfs resource | -- | -- | UC- |
+------------------------+----------+--------------+------------------+
| pci sysfs resource_wc | -- | -- | WC |
| is IORESOURCE_PREFETCH | | | |
+------------------------+----------+--------------+------------------+
| pci proc | -- | -- | UC- |
| !PCIIOC_WRITE_COMBINE | | | |
+------------------------+----------+--------------+------------------+
| pci proc | -- | -- | WC |
| PCIIOC_WRITE_COMBINE | | | |
+------------------------+----------+--------------+------------------+
| /dev/mem | -- | WB/WC/UC- | WB/WC/UC- |
| read-write | | | |
+------------------------+----------+--------------+------------------+
| /dev/mem | -- | UC- | UC- |
| mmap SYNC flag | | | |
+------------------------+----------+--------------+------------------+
| /dev/mem | -- | WB/WC/UC- | WB/WC/UC- |
| mmap !SYNC flag | | | |
| and | |(from existing| (from existing |
| any alias to this area | |alias) | alias) |
+------------------------+----------+--------------+------------------+
| /dev/mem | -- | WB | WB |
| mmap !SYNC flag | | | |
| no alias to this area | | | |
| and | | | |
| MTRR says WB | | | |
+------------------------+----------+--------------+------------------+
| /dev/mem | -- | -- | UC- |
| mmap !SYNC flag | | | |
| no alias to this area | | | |
| and | | | |
| MTRR says !WB | | | |
+------------------------+----------+--------------+------------------+
Advanced APIs for drivers
=========================
A. Exporting pages to users with remap_pfn_range, io_remap_pfn_range,
vmf_insert_pfn.
Drivers wanting to export some pages to userspace do it by using mmap
interface and a combination of:
1) pgprot_noncached()
2) io_remap_pfn_range() or remap_pfn_range() or vmf_insert_pfn()
With PAT support, a new API pgprot_writecombine is being added. So, drivers can
continue to use the above sequence, with either pgprot_noncached() or
pgprot_writecombine() in step 1, followed by step 2.
In addition, step 2 internally tracks the region as UC or WC in memtype
list in order to ensure no conflicting mapping.
Note that this set of APIs only works with IO (non RAM) regions. If driver
wants to export a RAM region, it has to do set_memory_uc() or set_memory_wc()
as step 0 above and also track the usage of those pages and use set_memory_wb()
before the page is freed to free pool.
MTRR effects on PAT / non-PAT systems
=====================================
The following table provides the effects of using write-combining MTRRs when
using ioremap*() calls on x86 for both non-PAT and PAT systems. Ideally
mtrr_add() usage will be phased out in favor of arch_phys_wc_add() which will
be a no-op on PAT enabled systems. The region over which a arch_phys_wc_add()
is made, should already have been ioremapped with WC attributes or PAT entries,
this can be done by using ioremap_wc() / set_memory_wc(). Devices which
combine areas of IO memory desired to remain uncacheable with areas where
write-combining is desirable should consider use of ioremap_uc() followed by
set_memory_wc() to white-list effective write-combined areas. Such use is
nevertheless discouraged as the effective memory type is considered
implementation defined, yet this strategy can be used as last resort on devices
with size-constrained regions where otherwise MTRR write-combining would
otherwise not be effective.
::
==== ======= === ========================= =====================
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
.. note:: -- in the above table mean "Not suggested usage for the API". Some
of the --'s are strictly enforced by the kernel. Some others are not really
enforced today, but may be enforced in future.
For ioremap and pci access through /sys or /proc - The actual type returned
can be more restrictive, in case of any existing aliasing for that address.
For example: If there is an existing uncached mapping, a new ioremap_wc can
return uncached mapping in place of write-combine requested.
set_memory_[uc|wc|wt] and set_memory_wb should be used in pairs, where driver
will first make a region uc, wc or wt and switch it back to wb after use.
Over time writes to /proc/mtrr will be deprecated in favor of using PAT based
interfaces. Users writing to /proc/mtrr are suggested to use above interfaces.
Drivers should use ioremap_[uc|wc] to access PCI BARs with [uc|wc] access
types.
Drivers should use set_memory_[uc|wc|wt] to set access type for RAM ranges.
PAT debugging
=============
With CONFIG_DEBUG_FS enabled, PAT memtype list can be examined by::
# 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
This list shows physical address ranges and various PAT settings used to
access those physical address ranges.
Another, more verbose way of getting PAT related debug messages is with
"debugpat" boot parameter. With this parameter, various debug messages are
printed to dmesg log.
PAT Initialization
==================
The following table describes how PAT is initialized under various
configurations. The PAT MSR must be updated by Linux in order to support WC
and WT attributes. Otherwise, the PAT MSR has the value programmed in it
by the firmware. Note, Xen enables WC attribute in the PAT MSR for guests.
==== ===== ========================== ========= =======
MTRR PAT Call Sequence PAT State PAT MSR
==== ===== ========================== ========= =======
E E MTRR -> PAT init Enabled OS
E D MTRR -> PAT init Disabled -
D E MTRR -> PAT disable Disabled BIOS
D D MTRR -> PAT disable Disabled -
- np/E PAT -> PAT disable Disabled BIOS
- np/D PAT -> PAT disable Disabled -
E !P/E MTRR -> PAT init Disabled BIOS
D !P/E MTRR -> PAT disable Disabled BIOS
!M !P/E MTRR stub -> PAT disable Disabled BIOS
==== ===== ========================== ========= =======
Legend
========= =======================================
E Feature enabled in CPU
D Feature disabled/unsupported in CPU
np "nopat" boot option specified
!P CONFIG_X86_PAT option unset
!M CONFIG_MTRR option unset
Enabled PAT state set to enabled
Disabled PAT state set to disabled
OS PAT initializes PAT MSR with OS setting
BIOS PAT keeps PAT MSR with BIOS setting
========= =======================================
3. 한국어 전문 번역
영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.
PAT 개요와 memory type
1-27이 문서는 `SPDX-License-Identifier: GPL-2.0`으로 배포됩니다. x86 Page Attribute Table(PAT)은 page 단위 granularity로 memory attribute를 설정합니다. physical address range에 memory type을 지정하는 MTRR과 상호 보완적입니다.
PAT는 page 단위로 attribute를 지정할 수 있고 설정 수에 hardware 제한이 없어 MTRR보다 유연합니다. 그러나 같은 physical memory를 여러 virtual address로 mapping할 때 memory type alias가 생기지 않도록 지침을 따라야 합니다.
현재 지원하는 가장 일반적인 memory attribute는 다음과 같습니다.
| 약어 | memory attribute |
|---|---|
| `WB` | Write-back |
| `UC` | Uncached |
| `WC` | Write-combined |
| `WT` | Write-through |
| `UC-` | Uncached Minus |
PAT API와 적용 영역
28-95kernel에는 page 단위 memory attribute를 설정하는 여러 API가 있습니다. aliasing을 피하려면 신중하게 사용해야 합니다. 내부적으로 이 API들은 physical address range에 `reserve_memtype()`/`free_memtype()` interface를 사용해 충돌하는 alias를 방지합니다.
| API | RAM | ACPI,... | Reserved/Holes |
|---|---|---|---|
| `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 `resource` | -- | -- | UC- |
| PCI sysfs `resource_wc`, `IORESOURCE_PREFETCH` 설정 | -- | -- | WC |
| PCI proc, `!PCIIOC_WRITE_COMBINE` | -- | -- | UC- |
| PCI proc, `PCIIOC_WRITE_COMBINE` | -- | -- | WC |
| `/dev/mem` read-write | -- | WB/WC/UC- | WB/WC/UC- |
| `/dev/mem` mmap `SYNC` flag | -- | UC- | UC- |
| `/dev/mem` mmap `!SYNC`, 해당 영역에 alias 존재 | -- | 기존 alias의 WB/WC/UC- | 기존 alias의 WB/WC/UC- |
| `/dev/mem` mmap `!SYNC`, alias 없음, MTRR은 WB | -- | WB | WB |
| `/dev/mem` mmap `!SYNC`, alias 없음, MTRR은 !WB | -- | -- | UC- |
driver를 위한 고급 API
96-119`remap_pfn_range`, `io_remap_pfn_range`, `vmf_insert_pfn`으로 page를 user에게 export할 수 있습니다. userspace에 page를 export하려는 driver는 mmap interface와 다음 순서를 조합합니다.
- 1단계: `pgprot_noncached()` 또는 PAT 지원 시 `pgprot_writecombine()`을 선택합니다.
- 2단계: `io_remap_pfn_range()`, `remap_pfn_range()`, `vmf_insert_pfn()` 가운데 하나를 호출합니다.
2단계는 충돌 mapping을 막기 위해 region을 memtype list의 UC 또는 WC로 내부 추적합니다.
이 API 집합은 IO, 즉 non-RAM region에서만 동작합니다. RAM region을 export하려면 위 순서의 0단계로 `set_memory_uc()` 또는 `set_memory_wc()`를 호출해야 합니다. page 사용도 추적하고 free pool로 반환하기 전에 `set_memory_wb()`를 호출해야 합니다.
PAT·non-PAT system에서 MTRR 효과
120-173다음 표는 x86에서 `ioremap*()`을 호출할 때 write-combining MTRR이 non-PAT 및 PAT system에 미치는 영향을 보여 줍니다. `mtrr_add()`는 PAT system에서 no-op인 `arch_phys_wc_add()`로 단계적으로 대체하는 것이 바람직합니다.
`arch_phys_wc_add()` 대상 region은 `ioremap_wc()` 또는 `set_memory_wc()`를 사용해 이미 WC attribute나 PAT entry로 ioremap되어 있어야 합니다.
uncacheable로 유지할 IO memory와 write-combining이 필요한 영역이 섞인 device는 `ioremap_uc()` 뒤 `set_memory_wc()`를 사용해 effective WC 영역을 white-list할 수 있습니다. effective memory type이 implementation-defined이므로 권장하지 않지만, 크기 제약 때문에 MTRR write-combining이 달리 효과를 내지 못하는 device에서는 최후 수단으로 사용할 수 있습니다.
MTRR이 WC일 때 PCD/PWT와 PAT entry 조합별 Linux mapping 값과 실제 memory type을 비교합니다.
`*`는 implementation-defined이며 사용을 권장하지 않음을 뜻합니다. API 표의 `--`는 권장하지 않는 사용을 뜻합니다. 일부는 kernel이 엄격히 막고, 일부는 현재 막지 않지만 향후 강제될 수 있습니다.
`ioremap`과 `/sys` 또는 `/proc`를 통한 PCI access에서는 해당 address에 기존 alias가 있으면 실제 반환 type이 더 restrictive할 수 있습니다. 예를 들어 기존 uncached mapping이 있으면 새 `ioremap_wc`가 요청한 write-combine 대신 uncached mapping을 반환할 수 있습니다.
`set_memory_[uc|wc|wt]`와 `set_memory_wb`는 쌍으로 사용해야 합니다. driver가 region을 UC, WC, WT로 바꿨다가 사용 뒤 WB로 되돌립니다.
`/proc/mtrr` write는 시간이 지나며 PAT 기반 interface로 폐지될 예정입니다. PCI BAR에 UC/WC로 access할 driver는 `ioremap_[uc|wc]`를 사용하고, RAM range의 access type에는 `set_memory_[uc|wc|wt]`를 사용해야 합니다.
PAT debugging
174-204`CONFIG_DEBUG_FS`가 활성화되어 있으면 다음과 같이 PAT memtype list를 확인할 수 있습니다.
# 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
이 list는 physical address range와 그 range에 access할 때 사용하는 여러 PAT 설정을 보여 줍니다.
더 자세한 PAT debug message가 필요하면 `debugpat` boot parameter를 사용합니다. 여러 debug message가 dmesg log에 출력됩니다.
PAT 초기화
205-240WC와 WT attribute를 지원하려면 Linux가 PAT MSR을 update해야 합니다. 그렇지 않으면 PAT MSR은 firmware가 programming한 값을 유지합니다. Xen은 guest의 PAT MSR에서 WC attribute를 활성화합니다.
| MTRR | PAT | call sequence | PAT state | PAT MSR |
|---|---|---|---|---|
| E | E | MTRR → PAT init | Enabled | OS |
| E | D | MTRR → PAT init | Disabled | - |
| D | E | MTRR → PAT disable | Disabled | BIOS |
| D | D | MTRR → PAT disable | Disabled | - |
| - | np/E | PAT → PAT disable | Disabled | BIOS |
| - | np/D | PAT → PAT disable | Disabled | - |
| E | !P/E | MTRR → PAT init | Disabled | BIOS |
| D | !P/E | MTRR → PAT disable | Disabled | BIOS |
| !M | !P/E | MTRR stub → PAT disable | Disabled | BIOS |
| 표기 | 의미 |
|---|---|
| E | CPU에서 feature enabled |
| D | CPU에서 feature disabled/unsupported |
| np | `nopat` boot option 지정 |
| !P | `CONFIG_X86_PAT` option unset |
| !M | `CONFIG_MTRR` option unset |
| Enabled | PAT state를 enabled로 설정 |
| Disabled | PAT state를 disabled로 설정 |
| OS | PAT가 OS 설정으로 PAT MSR 초기화 |
| BIOS | PAT가 BIOS 설정의 PAT MSR 유지 |
요약과 해설
pat.rst:1-240PAT는 page 단위로 WB·UC·WC·WT·UC-를 지정하지만 같은 physical memory의 virtual alias가 서로 다른 type을 갖지 않도록 해야 합니다. kernel mapping API는 `reserve_memtype()`과 `free_memtype()`으로 이를 추적합니다.
driver는 IO region에 `ioremap_[uc|wc]`, RAM range에 `set_memory_[uc|wc|wt]`와 복구용 `set_memory_wb()`를 사용해야 합니다. `arch_phys_wc_add()`는 non-PAT system의 MTRR 효과와 PAT system의 no-op을 통합합니다.