MTRR

From OSDev Wiki
Jump to navigation Jump to search

MTRR, or Memory-Type Range Registers are a group of x86 Model Specific Registers providing a way to control access and cacheability of physical memory regions. These were introduced in the Intel Pentium Pro (P6) processor, intended to extend and enhance the memory type information provided by page tables (i.e. the write-through and cache disable bits).

The set of registers is provided in two groups: 11 registers for 88 fixed ranges and a number of base-mask pairs for custom range configuration. The exact number of the latter can be known by reading the capabilities register.

While this method is available in most new Intel and AMD processors, preference should be given to Page Attribute Tables instead, as many of the systems usually configure these during early boot from UEFI/BIOS and changing MTRRs which were set up by the firmware may lead to unexpected problems.

Memory types

There are 5 memory types defined for use in MTRRs:

Number Name Description
0 UC — Uncacheable All accesses are uncacheable. Write combining is not allowed. Speculative accesses are not allowed.
1 WC — Write-Combining All accesses are uncacheable. Write combining is allowed. Speculative reads are allowed.
4 WT — Writethrough Reads allocate cache lines on a cache miss. Cache lines are not allocated on a write miss.

Write hits update the cache and main memory.

5 WP — Write-Protect Reads allocate cache lines on a cache miss. All writes update main memory.

Cache lines are not allocated on a write miss. Write hits invalidate the cache line and update main memory.

6 WB — Writeback Reads allocate cache lines on a cache miss, and can allocate to either the shared,

exclusive, or modified state. Writes allocate to the modified state on a cache miss.

Accessing MTRRs

Before attempting reads/writes to MTRRs, the operating system should first check the availability of this feature by checking if CPUID.01h:EDX[bit 12] is set.

Once the feature is known to be available, the following MSRs can be used for configuration:

IA32_MTRRCAP (MSR 0xFE)

This register describes memory range types and count supported by the implementation. The register is read-only.

Bit(s) Label Description
63..11 - Reserved
10 WC Write-combining type is available
9 - Reserved
8 FIX All fixed-size MTRRs are available
7..0 VCNT Count of variable-size MTRRs supported

IA32_MTRRdefType (MSR 0x2FF)

Describes the default type used for physical addresses which are outside of any configured memory ranges, as well as whether MTRRs and fixed ranges are enabled.

Bit(s) Label Description
63..12 - Reserved
11 E MTRR enable
10 FE Fixed range enable
9..8 - Reserved
7..0 Type Default memory type

IA32_MTRRphysBasen and IA32_MTRRphysMaskn registers

These allow defining custom memory ranges using base-mask pairs and have the following addresses:

  • IA32_MTRRphysBasen = 0x200 + (n * 2)
  • IA32_MTRRphysMaskn = 0x201 + (n * 2)

Where n parameter ranges from 0 to IA32_MTRRdefType[VCNT].

Base register has the following bits:

Bit(s) Label Description
63..52 - Reserved
51..12 PhysBase Range base address
11..8 - Reserved
7..0 Type Range memory type

"Mask" registers use bits 51:12 to specify the region mask and bit 11 ("Valid" bit) tells if the region is enabled. If your CPU supports address widths of less than 52 bits, the remaining bits are reserved. Writing to these reserved bits will trigger a General Protection Fault.

The processor uses the following algorithm to check if an address is covered by an MTRR:

 MaskBase = PhysMask AND PhysBase
 MaskTarget = PhysMask AND Target_Address[51:12]
 IF MaskBase == MaskTarget
   target address is in range
 ELSE
   target address is not in range

The mask is calculated like this: ~(size - 1) & ((1 << ADDRESS_WIDTH) - 1) where ADDRESS WIDTH is the maximum supported address width of your CPU. Both the mask and base must be aligned to at least 4K boundary (thus must be shifted to the right by 12 to fit into the 51:12 range) and the size must be equal to the boundary, on which the range is aligned. So, in order to have, for example, a 6M-long range, one would need to set up two MTRRs, one 4M and the other 2M.

IA32_MTRRfixsize_base

If supported by implementation, the specification defines a set of 11 registers allowing the configuration of addresses in lowest 1M block.

Each fixed-size range register contains 8 eight-bit type fields and the address block is split in different sizes:

63-56 55-48 47-40 39-32 31-24 23-16 15-8 7-0 Register
Address range
70000-7FFFF 60000-6FFFF 50000-5FFFF 40000-4FFFF 30000-3FFFF 20000-2FFFF 10000-1FFFF 00000-0FFFF MTRRfix64K_00000
9C000-9FFFF 98000-9BFFF 94000-97FFF 90000-93FFF 8C000-8FFFF 88000-8BFFF 84000-87FFF 80000-83FFF MTRRfix16K_80000
BC000-BFFFF B8000-BBFFF B4000-B7FFF B0000-B3FFF AC000-AFFFF A8000-ABFFF A4000-A7FFF A0000-A3FFF MTRRfix16K_A0000
C7000-C7FFF C6000-C6FFF C5000-C5FFF C4000-C4FFF C3000-C3FFF C2000-C2FFF C1000-C1FFF C0000-C0FFF MTRRfix4K_C0000
CF000-CFFFF CE000-CEFFF CD000-CDFFF CC000-CCFFF CB000-CBFFF CA000-CAFFF C9000-C9FFF C8000-C8FFF MTRRfix4K_C8000
D7000-D7FFF D6000-D6FFF D5000-D5FFF D4000-D4FFF D3000-D3FFF D2000-D2FFF D1000-D1FFF D0000-D0FFF MTRRfix4K_D0000
DF000-DFFFF DE000-DEFFF DD000-DDFFF DC000-DCFFF DB000-DBFFF DA000-DAFFF D9000-D9FFF D8000-D8FFF MTRRfix4K_D8000
E7000-E7FFF E6000-E6FFF E5000-E5FFF E4000-E4FFF E3000-E3FFF E2000-E2FFF E1000-E1FFF E0000-E0FFF MTRRfix4K_E0000
EF000-EFFFF EE000-EEFFF ED000-EDFFF EC000-ECFFF EB000-EBFFF EA000-EAFFF E9000-E9FFF E8000-E8FFF MTRRfix4K_E8000
F7000-F7FFF F6000-F6FFF F5000-F5FFF F4000-F4FFF F3000-F3FFF F2000-F2FFF F1000-F1FFF F0000-F0FFF MTRRfix4K_F0000
FF000-FFFFF FE000-FEFFF FD000-FDFFF FC000-FCFFF FB000-FBFFF FA000-FAFFF F9000-F9FFF F8000-F8FFF MTRRfix4K_F8000

Fixed-size range registers have are:

  • MTRRfix64K_00000 — MSR 0x250
  • MTRRfix16K_80000 — MSR 0x258
  • MTRRfix16K_A0000 — MSR 0x259
  • MTRRfix4K_C0000 — MSR 0x268
  • MTRRfix4K_C8000 — MSR 0x269
  • MTRRfix4K_D0000 — MSR 0x26A
  • MTRRfix4K_D8000 — MSR 0x26B
  • MTRRfix4K_E0000 — MSR 0x26C
  • MTRRfix4K_E8000 — MSR 0x26D
  • MTRRfix4K_F0000 — MSR 0x26E
  • MTRRfix4K_F8000 — MSR 0x26F

Combining with page-level control

Both MTRR and Page Tables allow setting cache-disable and writethrough attributes for memory regions — there may be cases when such ranges overlap. How MTRR and page entry bits work in combination (if the PAT register wasn't modified):

Without PAT

MTRR type Page CD bit Page WT bit Resulting type
UC UC
WC 0 WC
1 0 WC (impl. dependent)
1 1 UC
WP 0 WP
1 UC
WT 0 WT
1 UC
WB 0 0 WB
0 1 WT
1 UC

With PAT

MTRR type PAT Entry Value Resulting type
UC UC UC
UC- UC
WC WC
WT UC
WB UC
WP UC
WC UC UC
UC- WC
WC WC
WT UC
WB WC
WP UC
WT UC UC
UC- UC
WC WC
WT WT
WB WT
WP WP
WB UC UC
UC- UC
WC WC
WT WT
WB WB
WP WP
WP UC UC
UC- WC
WC WC
WT WT
WB WP
WP WP