1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
|
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef CPU_X86_MTRR_H
#define CPU_X86_MTRR_H
#ifndef __ASSEMBLER__
#include <cpu/x86/msr.h>
#include <arch/cpu.h>
#endif
#define MTRR_VERBOSE_LEVEL BIOS_NEVER
/* MTRRs are at a 4KiB granularity. */
#define RANGE_SHIFT 12
#define ADDR_SHIFT_TO_RANGE_SHIFT(x) \
(((x) > RANGE_SHIFT) ? ((x) - RANGE_SHIFT) : RANGE_SHIFT)
#define PHYS_TO_RANGE_ADDR(x) ((x) >> RANGE_SHIFT)
#define RANGE_TO_PHYS_ADDR(x) (((resource_t)(x)) << RANGE_SHIFT)
/* Helpful constants. */
#define RANGE_1MB PHYS_TO_RANGE_ADDR(1ULL << 20)
#define RANGE_4GB (1ULL << (ADDR_SHIFT_TO_RANGE_SHIFT(32)))
#define MTRR_ALGO_SHIFT (8)
#define MTRR_TAG_MASK ((1 << MTRR_ALGO_SHIFT) - 1)
/* These are the region types */
#define MTRR_TYPE_UNCACHEABLE 0
#define MTRR_TYPE_WRCOMB 1
#define MTRR_TYPE_WRTHROUGH 4
#define MTRR_TYPE_WRPROT 5
#define MTRR_TYPE_WRBACK 6
#define MTRR_NUM_TYPES 7
#define MTRR_CAP_MSR 0x0fe
#define MTRR_CAP_PRMRR (1 << 12)
#define MTRR_CAP_SMRR (1 << 11)
#define MTRR_CAP_WC (1 << 10)
#define MTRR_CAP_FIX (1 << 8)
#define MTRR_CAP_VCNT 0xff
#define MTRR_DEF_TYPE_MSR 0x2ff
#define MTRR_DEF_TYPE_MASK 0xff
#define MTRR_DEF_TYPE_EN (1 << 11)
#define MTRR_DEF_TYPE_FIX_EN (1 << 10)
#define IA32_SMRR_PHYS_BASE 0x1f2
#define IA32_SMRR_PHYS_MASK 0x1f3
#define SMRR_PHYS_MASK_LOCK (1 << 10)
/* Specific to model_6fx and model_1067x.
These are named MSR_SMRR_PHYSBASE in the SDM. */
#define CORE2_SMRR_PHYS_BASE 0xa0
#define CORE2_SMRR_PHYS_MASK 0xa1
#define MTRR_PHYS_BASE(reg) (0x200 + 2 * (reg))
#define MTRR_PHYS_MASK(reg) (MTRR_PHYS_BASE(reg) + 1)
#define MTRR_PHYS_MASK_VALID (1 << 11)
#define NUM_FIXED_RANGES 88
#define RANGES_PER_FIXED_MTRR 8
#define NUM_FIXED_MTRRS (NUM_FIXED_RANGES / RANGES_PER_FIXED_MTRR)
#define MTRR_FIX_64K_00000 0x250
#define MTRR_FIX_16K_80000 0x258
#define MTRR_FIX_16K_A0000 0x259
#define MTRR_FIX_4K_C0000 0x268
#define MTRR_FIX_4K_C8000 0x269
#define MTRR_FIX_4K_D0000 0x26a
#define MTRR_FIX_4K_D8000 0x26b
#define MTRR_FIX_4K_E0000 0x26c
#define MTRR_FIX_4K_E8000 0x26d
#define MTRR_FIX_4K_F0000 0x26e
#define MTRR_FIX_4K_F8000 0x26f
#if !defined(__ASSEMBLER__)
#include <stdint.h>
#include <stddef.h>
#include <lib.h>
/*
* The MTRR code has some side effects that the callers should be aware for.
* 1. The call sequence matters. x86_setup_mtrrs() calls
* x86_setup_fixed_mtrrs_no_enable() then enable_fixed_mtrrs() (equivalent
* of x86_setup_fixed_mtrrs()) then x86_setup_var_mtrrs(). If the callers
* want to call the components of x86_setup_mtrrs() because of other
* requirements the ordering should still preserved.
* 2. enable_fixed_mtrr() will enable both variable and fixed MTRRs because
* of the nature of the global MTRR enable flag. Therefore, all direct
* or indirect callers of enable_fixed_mtrr() should ensure that the
* variable MTRR MSRs do not contain bad ranges.
*
* Note that this function sets up MTRRs for addresses above 4GiB.
*/
void x86_setup_mtrrs(void);
/*
* x86_setup_mtrrs_with_detect() does the same thing as x86_setup_mtrrs(), but
* it always dynamically detects the number of variable MTRRs available.
*/
void x86_setup_mtrrs_with_detect(void);
void x86_setup_mtrrs_with_detect_no_above_4gb(void);
/*
* x86_setup_var_mtrrs() parameters:
* address_bits - number of physical address bits supported by cpu
* above4gb - if set setup MTRRs for addresses above 4GiB else ignore
* memory ranges above 4GiB
*/
void x86_setup_var_mtrrs(unsigned int address_bits, unsigned int above4gb);
void enable_fixed_mtrr(void);
/* Unhide Rd/WrDram bits and allow modification for AMD. */
void fixed_mtrrs_expose_amd_rwdram(void);
/* Hide Rd/WrDram bits and allow modification for AMD. */
void fixed_mtrrs_hide_amd_rwdram(void);
void x86_mtrr_check(void);
/* Insert a temporary MTRR range for the duration of coreboot's runtime.
* This function needs to be called after the first MTRR solution is derived. */
void mtrr_use_temp_range(uintptr_t begin, size_t size, int type);
static inline int get_var_mtrr_count(void)
{
return rdmsr(MTRR_CAP_MSR).lo & MTRR_CAP_VCNT;
}
void set_var_mtrr(unsigned int reg, unsigned int base, unsigned int size,
unsigned int type);
int get_free_var_mtrr(void);
void clear_all_var_mtrr(void);
asmlinkage void display_mtrrs(void);
struct var_mtrr_context {
uint32_t max_var_mtrrs;
uint32_t used_var_mtrrs;
struct {
msr_t base;
msr_t mask;
} mtrr[];
};
void var_mtrr_context_init(struct var_mtrr_context *ctx);
int var_mtrr_set(struct var_mtrr_context *ctx, uintptr_t addr, size_t size, int type);
void commit_mtrr_setup(const struct var_mtrr_context *ctx);
void postcar_mtrr_setup(void);
static inline uint64_t calculate_var_mtrr_size(uint64_t mask)
{
return 1 << (__ffs64(mask >> RANGE_SHIFT) + RANGE_SHIFT);
}
#endif /* !defined(__ASSEMBLER__) */
/* Align up/down to next power of 2, suitable for assembler
too. Range of result 256kB to 128MB is good enough here. */
#define _POW2_MASK(x) ((x>>1)|(x>>2)|(x>>3)|(x>>4)|(x>>5)| \
(x>>6)|(x>>7)|(x>>8)|((1<<18)-1))
#define _ALIGN_UP_POW2(x) ((x + _POW2_MASK(x)) & ~_POW2_MASK(x))
#define _ALIGN_DOWN_POW2(x) ((x) & ~_POW2_MASK(x))
/* Calculate `4GiB - x` (e.g. absolute address for offset from 4GiB) */
#define _FROM_4G_TOP(x) ((0xffffffff - (x)) + 1)
/* At the end of romstage, low RAM 0..CACHE_TM_RAMTOP may be set
* as write-back cacheable to speed up ramstage decompression.
* Note MTRR boundaries, must be power of two.
*/
#define CACHE_TMP_RAMTOP (16<<20)
/* For ROM caching, generally, try to use the next power of 2. */
#define OPTIMAL_CACHE_ROM_SIZE _ALIGN_UP_POW2(CONFIG_ROM_SIZE)
#define OPTIMAL_CACHE_ROM_BASE _FROM_4G_TOP(OPTIMAL_CACHE_ROM_SIZE)
#if (OPTIMAL_CACHE_ROM_SIZE < CONFIG_ROM_SIZE) || \
(OPTIMAL_CACHE_ROM_SIZE >= (2 * CONFIG_ROM_SIZE))
# error "Optimal CACHE_ROM_SIZE can't be derived, _POW2_MASK needs refinement."
#endif
/* Make sure it doesn't overlap CAR, though. If the gap between
CAR and 4GiB is too small, make it at most the size of this
gap. As we can't align up (might overlap again), align down
to get a power of 2 again, for a single MTRR. */
#define CAR_END (CONFIG_DCACHE_RAM_BASE + CONFIG_DCACHE_RAM_SIZE)
#if CAR_END > OPTIMAL_CACHE_ROM_BASE
# define CAR_CACHE_ROM_SIZE _ALIGN_DOWN_POW2(_FROM_4G_TOP(CAR_END))
#else
# define CAR_CACHE_ROM_SIZE OPTIMAL_CACHE_ROM_SIZE
#endif
#if ((CAR_CACHE_ROM_SIZE & (CAR_CACHE_ROM_SIZE - 1)) != 0)
# error "CAR CACHE_ROM_SIZE is not a power of 2, _POW2_MASK needs refinement."
#endif
/* Last but not least, most (if not all) chipsets have MMIO
between 0xfe000000 and 0xff000000, so limit to 16MiB. */
#if CAR_CACHE_ROM_SIZE >= 16 << 20
# define CACHE_ROM_SIZE (16 << 20)
#else
# define CACHE_ROM_SIZE CAR_CACHE_ROM_SIZE
#endif
#define CACHE_ROM_BASE _FROM_4G_TOP(CACHE_ROM_SIZE)
#endif /* CPU_X86_MTRR_H */
|