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