Make MTRR region 0xc0000-0x100000 be cached.
[seabios.git] / src / mtrr.c
1 // Initialize MTRRs - mostly useful on KVM.
2 //
3 // Copyright (C) 2006 Fabrice Bellard
4 //
5 // This file may be distributed under the terms of the GNU LGPLv3 license.
6
7 #include "util.h" // dprintf
8 #include "biosvar.h" // GET_EBDA
9
10 #define MSR_MTRRcap                    0x000000fe
11 #define MSR_MTRRfix64K_00000           0x00000250
12 #define MSR_MTRRfix16K_80000           0x00000258
13 #define MSR_MTRRfix16K_A0000           0x00000259
14 #define MSR_MTRRfix4K_C0000            0x00000268
15 #define MSR_MTRRfix4K_C8000            0x00000269
16 #define MSR_MTRRfix4K_D0000            0x0000026a
17 #define MSR_MTRRfix4K_D8000            0x0000026b
18 #define MSR_MTRRfix4K_E0000            0x0000026c
19 #define MSR_MTRRfix4K_E8000            0x0000026d
20 #define MSR_MTRRfix4K_F0000            0x0000026e
21 #define MSR_MTRRfix4K_F8000            0x0000026f
22 #define MSR_MTRRdefType                0x000002ff
23
24 #define MTRRphysBase_MSR(reg) (0x200 + 2 * (reg))
25 #define MTRRphysMask_MSR(reg) (0x200 + 2 * (reg) + 1)
26
27 #define MTRR_MEMTYPE_UC 0
28 #define MTRR_MEMTYPE_WC 1
29 #define MTRR_MEMTYPE_WT 4
30 #define MTRR_MEMTYPE_WP 5
31 #define MTRR_MEMTYPE_WB 6
32
33 void mtrr_setup(void)
34 {
35     if (CONFIG_COREBOOT)
36         return;
37
38     u32 eax, ebx, ecx, edx, cpuid_features;
39     cpuid(1, &eax, &ebx, &ecx, &cpuid_features);
40     if (!(cpuid_features & CPUID_MTRR))
41         return;
42     if (!(cpuid_features & CPUID_MSR))
43         return;
44
45     dprintf(3, "init mtrr\n");
46
47     u32 mtrr_cap = rdmsr(MSR_MTRRcap);
48     int vcnt = mtrr_cap & 0xff;
49     int fix = mtrr_cap & 0x100;
50     if (!vcnt || !fix)
51        return;
52
53     // Disable MTRRs
54     wrmsr_smp(MSR_MTRRdefType, 0);
55
56     // Set fixed MTRRs
57     union u64b {
58         u8 valb[8];
59         u64 val;
60     } u;
61     u.val = 0;
62     int i;
63     for (i = 0; i < 8; i++)
64         if (RamSize >= 65536 * (i + 1))
65             u.valb[i] = MTRR_MEMTYPE_WB;
66     wrmsr_smp(MSR_MTRRfix64K_00000, u.val);
67     u.val = 0;
68     for (i = 0; i < 8; i++)
69         if (RamSize >= 0x80000 + 16384 * (i + 1))
70             u.valb[i] = MTRR_MEMTYPE_WB;
71     wrmsr_smp(MSR_MTRRfix16K_80000, u.val);
72     wrmsr_smp(MSR_MTRRfix16K_A0000, 0);   // 0xA0000-0xC0000 is uncached
73     int j;
74     for (j = 0; j < 8; j++) {
75         u.val = 0;
76         for (i = 0; i < 8; i++)
77             if (RamSize >= 0xC0000 + j * 0x8000 + 4096 * (i + 1))
78                 u.valb[i] = MTRR_MEMTYPE_WP;
79         wrmsr_smp(MSR_MTRRfix4K_C0000 + j, u.val);
80     }
81
82     // Set variable MTRRs
83     int phys_bits = 36;
84     cpuid(0x80000000u, &eax, &ebx, &ecx, &edx);
85     if (eax >= 0x80000008) {
86             /* Get physical bits from leaf 0x80000008 (if available) */
87             cpuid(0x80000008u, &eax, &ebx, &ecx, &edx);
88             phys_bits = eax & 0xff;
89     }
90     u64 phys_mask = ((1ull << phys_bits) - 1);
91     for (i=0; i<vcnt; i++) {
92         wrmsr_smp(MTRRphysBase_MSR(i), 0);
93         wrmsr_smp(MTRRphysMask_MSR(i), 0);
94     }
95     /* Mark 3.5-4GB as UC, anything not specified defaults to WB */
96     wrmsr_smp(MTRRphysBase_MSR(0), BUILD_MAX_HIGHMEM | MTRR_MEMTYPE_UC);
97     wrmsr_smp(MTRRphysMask_MSR(0)
98               , (-((1ull<<32)-BUILD_MAX_HIGHMEM) & phys_mask) | 0x800);
99
100     // Enable fixed and variable MTRRs; set default type.
101     wrmsr_smp(MSR_MTRRdefType, 0xc00 | MTRR_MEMTYPE_WB);
102 }