blob: ed239c81b1489b79f0b97709f8f1c6771dcb4623 [file] [log] [blame]
Kevin O'Connor7061eb62009-01-04 21:48:22 -05001// Initialize MTRRs - mostly useful on KVM.
2//
3// Copyright (C) 2006 Fabrice Bellard
4//
Kevin O'Connorb1b7c2a2009-01-15 20:52:58 -05005// This file may be distributed under the terms of the GNU LGPLv3 license.
Kevin O'Connor7061eb62009-01-04 21:48:22 -05006
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
Kevin O'Connorafc02da2009-12-23 21:24:27 -050027#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
Kevin O'Connor7061eb62009-01-04 21:48:22 -050033void mtrr_setup(void)
34{
Kevin O'Connore97ca7b2009-06-21 09:10:28 -040035 if (CONFIG_COREBOOT)
Kevin O'Connor7061eb62009-01-04 21:48:22 -050036 return;
Kevin O'Connore97ca7b2009-06-21 09:10:28 -040037
Kevin O'Connore622ff62009-11-09 19:30:17 -050038 u32 eax, ebx, ecx, edx, cpuid_features;
Kevin O'Connore97ca7b2009-06-21 09:10:28 -040039 cpuid(1, &eax, &ebx, &ecx, &cpuid_features);
40 if (!(cpuid_features & CPUID_MTRR))
41 return;
42 if (!(cpuid_features & CPUID_MSR))
43 return;
44
Kevin O'Connor7061eb62009-01-04 21:48:22 -050045 dprintf(3, "init mtrr\n");
46
Kevin O'Connor9a8609f2010-01-01 12:50:04 -050047 u32 mtrr_cap = rdmsr(MSR_MTRRcap);
48 int vcnt = mtrr_cap & 0xff;
49 int fix = mtrr_cap & 0x100;
Kevin O'Connor7061eb62009-01-04 21:48:22 -050050 if (!vcnt || !fix)
51 return;
Kevin O'Connorafc02da2009-12-23 21:24:27 -050052
Kevin O'Connor9a8609f2010-01-01 12:50:04 -050053 // 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;
Kevin O'Connor7061eb62009-01-04 21:48:22 -050061 u.val = 0;
Kevin O'Connor9a8609f2010-01-01 12:50:04 -050062 int i;
63 for (i = 0; i < 8; i++)
Kevin O'Connorafc02da2009-12-23 21:24:27 -050064 if (RamSize >= 65536 * (i + 1))
65 u.valb[i] = MTRR_MEMTYPE_WB;
Kevin O'Connor7061eb62009-01-04 21:48:22 -050066 wrmsr_smp(MSR_MTRRfix64K_00000, u.val);
67 u.val = 0;
Kevin O'Connor9a8609f2010-01-01 12:50:04 -050068 for (i = 0; i < 8; i++)
69 if (RamSize >= 0x80000 + 16384 * (i + 1))
Kevin O'Connorafc02da2009-12-23 21:24:27 -050070 u.valb[i] = MTRR_MEMTYPE_WB;
Kevin O'Connor7061eb62009-01-04 21:48:22 -050071 wrmsr_smp(MSR_MTRRfix16K_80000, u.val);
Kevin O'Connor9a8609f2010-01-01 12:50:04 -050072 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 }
Kevin O'Connore622ff62009-11-09 19:30:17 -050081
Kevin O'Connor9a8609f2010-01-01 12:50:04 -050082 // Set variable MTRRs
Kevin O'Connore622ff62009-11-09 19:30:17 -050083 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);
Kevin O'Connor9a8609f2010-01-01 12:50:04 -050091 for (i=0; i<vcnt; i++) {
92 wrmsr_smp(MTRRphysBase_MSR(i), 0);
93 wrmsr_smp(MTRRphysMask_MSR(i), 0);
94 }
Kevin O'Connorafc02da2009-12-23 21:24:27 -050095 /* 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);
Kevin O'Connore622ff62009-11-09 19:30:17 -050099
Kevin O'Connorafc02da2009-12-23 21:24:27 -0500100 // Enable fixed and variable MTRRs; set default type.
101 wrmsr_smp(MSR_MTRRdefType, 0xc00 | MTRR_MEMTYPE_WB);
Kevin O'Connor7061eb62009-01-04 21:48:22 -0500102}