blob: ec3be4f3aa66fcf76eed22183ab87ce30ed92dbe [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
Ian Campbell74c78782011-06-01 11:00:29 +01009#include "xen.h" // usingXen
Kevin O'Connor7061eb62009-01-04 21:48:22 -050010
11#define MSR_MTRRcap 0x000000fe
12#define MSR_MTRRfix64K_00000 0x00000250
13#define MSR_MTRRfix16K_80000 0x00000258
14#define MSR_MTRRfix16K_A0000 0x00000259
15#define MSR_MTRRfix4K_C0000 0x00000268
16#define MSR_MTRRfix4K_C8000 0x00000269
17#define MSR_MTRRfix4K_D0000 0x0000026a
18#define MSR_MTRRfix4K_D8000 0x0000026b
19#define MSR_MTRRfix4K_E0000 0x0000026c
20#define MSR_MTRRfix4K_E8000 0x0000026d
21#define MSR_MTRRfix4K_F0000 0x0000026e
22#define MSR_MTRRfix4K_F8000 0x0000026f
23#define MSR_MTRRdefType 0x000002ff
24
25#define MTRRphysBase_MSR(reg) (0x200 + 2 * (reg))
26#define MTRRphysMask_MSR(reg) (0x200 + 2 * (reg) + 1)
27
Kevin O'Connorafc02da2009-12-23 21:24:27 -050028#define MTRR_MEMTYPE_UC 0
29#define MTRR_MEMTYPE_WC 1
30#define MTRR_MEMTYPE_WT 4
31#define MTRR_MEMTYPE_WP 5
32#define MTRR_MEMTYPE_WB 6
33
Kevin O'Connor7061eb62009-01-04 21:48:22 -050034void mtrr_setup(void)
35{
Ian Campbell74c78782011-06-01 11:00:29 +010036 if (!CONFIG_MTRR_INIT || CONFIG_COREBOOT || usingXen())
Kevin O'Connor7061eb62009-01-04 21:48:22 -050037 return;
Kevin O'Connore97ca7b2009-06-21 09:10:28 -040038
Kevin O'Connore622ff62009-11-09 19:30:17 -050039 u32 eax, ebx, ecx, edx, cpuid_features;
Kevin O'Connore97ca7b2009-06-21 09:10:28 -040040 cpuid(1, &eax, &ebx, &ecx, &cpuid_features);
41 if (!(cpuid_features & CPUID_MTRR))
42 return;
43 if (!(cpuid_features & CPUID_MSR))
44 return;
45
Kevin O'Connor7061eb62009-01-04 21:48:22 -050046 dprintf(3, "init mtrr\n");
47
Kevin O'Connor9a8609f2010-01-01 12:50:04 -050048 u32 mtrr_cap = rdmsr(MSR_MTRRcap);
49 int vcnt = mtrr_cap & 0xff;
50 int fix = mtrr_cap & 0x100;
Kevin O'Connor7061eb62009-01-04 21:48:22 -050051 if (!vcnt || !fix)
52 return;
Kevin O'Connorafc02da2009-12-23 21:24:27 -050053
Kevin O'Connor9a8609f2010-01-01 12:50:04 -050054 // Disable MTRRs
55 wrmsr_smp(MSR_MTRRdefType, 0);
56
57 // Set fixed MTRRs
58 union u64b {
59 u8 valb[8];
60 u64 val;
61 } u;
Kevin O'Connor7061eb62009-01-04 21:48:22 -050062 u.val = 0;
Kevin O'Connor9a8609f2010-01-01 12:50:04 -050063 int i;
64 for (i = 0; i < 8; i++)
Kevin O'Connorafc02da2009-12-23 21:24:27 -050065 if (RamSize >= 65536 * (i + 1))
66 u.valb[i] = MTRR_MEMTYPE_WB;
Kevin O'Connor7061eb62009-01-04 21:48:22 -050067 wrmsr_smp(MSR_MTRRfix64K_00000, u.val);
68 u.val = 0;
Kevin O'Connor9a8609f2010-01-01 12:50:04 -050069 for (i = 0; i < 8; i++)
70 if (RamSize >= 0x80000 + 16384 * (i + 1))
Kevin O'Connorafc02da2009-12-23 21:24:27 -050071 u.valb[i] = MTRR_MEMTYPE_WB;
Kevin O'Connor7061eb62009-01-04 21:48:22 -050072 wrmsr_smp(MSR_MTRRfix16K_80000, u.val);
Kevin O'Connor9a8609f2010-01-01 12:50:04 -050073 wrmsr_smp(MSR_MTRRfix16K_A0000, 0); // 0xA0000-0xC0000 is uncached
74 int j;
75 for (j = 0; j < 8; j++) {
76 u.val = 0;
77 for (i = 0; i < 8; i++)
78 if (RamSize >= 0xC0000 + j * 0x8000 + 4096 * (i + 1))
79 u.valb[i] = MTRR_MEMTYPE_WP;
80 wrmsr_smp(MSR_MTRRfix4K_C0000 + j, u.val);
81 }
Kevin O'Connore622ff62009-11-09 19:30:17 -050082
Kevin O'Connor9a8609f2010-01-01 12:50:04 -050083 // Set variable MTRRs
Kevin O'Connore622ff62009-11-09 19:30:17 -050084 int phys_bits = 36;
85 cpuid(0x80000000u, &eax, &ebx, &ecx, &edx);
86 if (eax >= 0x80000008) {
Kevin O'Connor9eb21002012-01-29 13:30:56 -050087 /* Get physical bits from leaf 0x80000008 (if available) */
88 cpuid(0x80000008u, &eax, &ebx, &ecx, &edx);
89 phys_bits = eax & 0xff;
Kevin O'Connore622ff62009-11-09 19:30:17 -050090 }
91 u64 phys_mask = ((1ull << phys_bits) - 1);
Kevin O'Connor9a8609f2010-01-01 12:50:04 -050092 for (i=0; i<vcnt; i++) {
93 wrmsr_smp(MTRRphysBase_MSR(i), 0);
94 wrmsr_smp(MTRRphysMask_MSR(i), 0);
95 }
Kevin O'Connorafc02da2009-12-23 21:24:27 -050096 /* Mark 3.5-4GB as UC, anything not specified defaults to WB */
97 wrmsr_smp(MTRRphysBase_MSR(0), BUILD_MAX_HIGHMEM | MTRR_MEMTYPE_UC);
98 wrmsr_smp(MTRRphysMask_MSR(0)
99 , (-((1ull<<32)-BUILD_MAX_HIGHMEM) & phys_mask) | 0x800);
Kevin O'Connore622ff62009-11-09 19:30:17 -0500100
Kevin O'Connorafc02da2009-12-23 21:24:27 -0500101 // Enable fixed and variable MTRRs; set default type.
102 wrmsr_smp(MSR_MTRRdefType, 0xc00 | MTRR_MEMTYPE_WB);
Kevin O'Connor7061eb62009-01-04 21:48:22 -0500103}