#include "util.h" // dprintf
#include "biosvar.h" // GET_EBDA
+#include "xen.h" // usingXen
#define MSR_MTRRcap 0x000000fe
#define MSR_MTRRfix64K_00000 0x00000250
#define MTRRphysBase_MSR(reg) (0x200 + 2 * (reg))
#define MTRRphysMask_MSR(reg) (0x200 + 2 * (reg) + 1)
+#define MTRR_MEMTYPE_UC 0
+#define MTRR_MEMTYPE_WC 1
+#define MTRR_MEMTYPE_WT 4
+#define MTRR_MEMTYPE_WP 5
+#define MTRR_MEMTYPE_WB 6
+
void mtrr_setup(void)
{
- if (CONFIG_COREBOOT)
+ if (!CONFIG_MTRR_INIT || CONFIG_COREBOOT || usingXen())
return;
u32 eax, ebx, ecx, edx, cpuid_features;
dprintf(3, "init mtrr\n");
- int i, vcnt, fix, wc;
- u32 ram_size = GET_GLOBAL(RamSize);
- u32 mtrr_cap;
- union {
+ u32 mtrr_cap = rdmsr(MSR_MTRRcap);
+ int vcnt = mtrr_cap & 0xff;
+ int fix = mtrr_cap & 0x100;
+ if (!vcnt || !fix)
+ return;
+
+ // Disable MTRRs
+ wrmsr_smp(MSR_MTRRdefType, 0);
+
+ // Set fixed MTRRs
+ union u64b {
u8 valb[8];
u64 val;
} u;
-
- mtrr_cap = rdmsr(MSR_MTRRcap);
- vcnt = mtrr_cap & 0xff;
- fix = mtrr_cap & 0x100;
- wc = mtrr_cap & 0x400;
- if (!vcnt || !fix)
- return;
u.val = 0;
- for (i = 0; i < 8; ++i)
- if (ram_size >= 65536 * (i + 1))
- u.valb[i] = 6;
+ int i;
+ for (i = 0; i < 8; i++)
+ if (RamSize >= 65536 * (i + 1))
+ u.valb[i] = MTRR_MEMTYPE_WB;
wrmsr_smp(MSR_MTRRfix64K_00000, u.val);
u.val = 0;
- for (i = 0; i < 8; ++i)
- if (ram_size >= 65536 * 8 + 16384 * (i + 1))
- u.valb[i] = 6;
+ for (i = 0; i < 8; i++)
+ if (RamSize >= 0x80000 + 16384 * (i + 1))
+ u.valb[i] = MTRR_MEMTYPE_WB;
wrmsr_smp(MSR_MTRRfix16K_80000, u.val);
- wrmsr_smp(MSR_MTRRfix16K_A0000, 0);
- wrmsr_smp(MSR_MTRRfix4K_C0000, 0);
- wrmsr_smp(MSR_MTRRfix4K_C8000, 0);
- wrmsr_smp(MSR_MTRRfix4K_D0000, 0);
- wrmsr_smp(MSR_MTRRfix4K_D8000, 0);
- wrmsr_smp(MSR_MTRRfix4K_E0000, 0);
- wrmsr_smp(MSR_MTRRfix4K_E8000, 0);
- wrmsr_smp(MSR_MTRRfix4K_F0000, 0);
- wrmsr_smp(MSR_MTRRfix4K_F8000, 0);
- /* Mark 3.5-4GB as UC, anything not specified defaults to WB */
- wrmsr_smp(MTRRphysBase_MSR(0), 0xe0000000ull | 0);
+ wrmsr_smp(MSR_MTRRfix16K_A0000, 0); // 0xA0000-0xC0000 is uncached
+ int j;
+ for (j = 0; j < 8; j++) {
+ u.val = 0;
+ for (i = 0; i < 8; i++)
+ if (RamSize >= 0xC0000 + j * 0x8000 + 4096 * (i + 1))
+ u.valb[i] = MTRR_MEMTYPE_WP;
+ wrmsr_smp(MSR_MTRRfix4K_C0000 + j, u.val);
+ }
+ // Set variable MTRRs
int phys_bits = 36;
cpuid(0x80000000u, &eax, &ebx, &ecx, &edx);
if (eax >= 0x80000008) {
phys_bits = eax & 0xff;
}
u64 phys_mask = ((1ull << phys_bits) - 1);
- wrmsr_smp(MTRRphysMask_MSR(0), (~(0x20000000ull - 1) & phys_mask) | 0x800);
+ for (i=0; i<vcnt; i++) {
+ wrmsr_smp(MTRRphysBase_MSR(i), 0);
+ wrmsr_smp(MTRRphysMask_MSR(i), 0);
+ }
+ /* Mark 3.5-4GB as UC, anything not specified defaults to WB */
+ wrmsr_smp(MTRRphysBase_MSR(0), BUILD_MAX_HIGHMEM | MTRR_MEMTYPE_UC);
+ wrmsr_smp(MTRRphysMask_MSR(0)
+ , (-((1ull<<32)-BUILD_MAX_HIGHMEM) & phys_mask) | 0x800);
- wrmsr_smp(MSR_MTRRdefType, 0xc06);
+ // Enable fixed and variable MTRRs; set default type.
+ wrmsr_smp(MSR_MTRRdefType, 0xc00 | MTRR_MEMTYPE_WB);
}