Detect CPUID instruction before using it.
[seabios.git] / src / mtrr.c
index 6bd0dba46bbbfce4562423e1cf988e0ed972f3bd..ec3be4f3aa66fcf76eed22183ab87ce30ed92dbe 100644 (file)
@@ -6,6 +6,7 @@
 
 #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;
@@ -38,51 +45,59 @@ void mtrr_setup(void)
 
     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) {
-            /* Get physical bits from leaf 0x80000008 (if available) */
-            cpuid(0x80000008u, &eax, &ebx, &ecx, &edx);
-            phys_bits = eax & 0xff;
+        /* Get physical bits from leaf 0x80000008 (if available) */
+        cpuid(0x80000008u, &eax, &ebx, &ecx, &edx);
+        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);
 }