Skip to content

Commit 529fc81

Browse files
committed
mm/mtrr: Reuse mtrr_save/mtrr_restore for WC FB undo
1 parent 68ff52f commit 529fc81

3 files changed

Lines changed: 22 additions & 73 deletions

File tree

common/lib/term.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ void term_notready(bool preserve_screen) {
3333
}
3434

3535
#if defined (__i386__) || defined (__x86_64__)
36-
mtrr_wc_clear_fb_ranges();
36+
mtrr_restore();
3737
#endif
3838

3939
for (size_t i = 0; i < terms_i; i++) {

common/mm/mtrr.c

Lines changed: 21 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,20 @@ static bool mtrr_supported(void) {
1717
return !!(edx & (1 << 12));
1818
}
1919

20-
uint64_t *saved_mtrrs = NULL;
20+
// Sized for the architectural maximum MTRRCAP.VCNT (8 bits -> 256), plus the
21+
// 11 fixed-range MTRRs and the default-type MSR. .no_unwind so the snapshot
22+
// survives a panic-rewind: the MSR state we mutated persists across the
23+
// rewind, and so does the data we need to undo it.
24+
#define SAVED_MTRRS_MAX (256 * 2 + 11 + 1)
25+
26+
no_unwind uint64_t saved_mtrrs[SAVED_MTRRS_MAX];
27+
static no_unwind uint8_t saved_mtrrs_var_count = 0;
28+
static no_unwind bool saved_mtrrs_valid = false;
2129

2230
void mtrr_save(void) {
31+
if (saved_mtrrs_valid) {
32+
return;
33+
}
2334
if (!mtrr_supported()) {
2435
return;
2536
}
@@ -29,14 +40,6 @@ void mtrr_save(void) {
2940
uint8_t var_reg_count = ia32_mtrrcap & 0xff;
3041
bool fix_supported = !!(ia32_mtrrcap & ((uint64_t)1 << 8));
3142

32-
if (saved_mtrrs == NULL) {
33-
saved_mtrrs = ext_mem_alloc((
34-
(var_reg_count * 2) /* variable MTRRs, 2 MSRs each */
35-
+ 11 /* 11 fixed MTRRs */
36-
+ 1 /* 1 default type MTRR */
37-
) * sizeof(uint64_t));
38-
}
39-
4043
/* save variable range MTRRs */
4144
for (uint8_t i = 0; i < var_reg_count * 2; i += 2) {
4245
saved_mtrrs[i] = rdmsr(0x200 + i);
@@ -63,22 +66,25 @@ void mtrr_save(void) {
6366

6467
/* make sure that the saved MTRR default has MTRRs off */
6568
saved_mtrrs[var_reg_count * 2 + 11] &= ~((uint64_t)1 << 11);
69+
70+
saved_mtrrs_var_count = var_reg_count;
71+
saved_mtrrs_valid = true;
6672
}
6773

6874
void mtrr_restore(void) {
6975
if (!mtrr_supported()) {
7076
return;
7177
}
7278

79+
if (!saved_mtrrs_valid) {
80+
return;
81+
}
82+
7383
uint64_t ia32_mtrrcap = rdmsr(0xfe);
7484

75-
uint8_t var_reg_count = ia32_mtrrcap & 0xff;
85+
uint8_t var_reg_count = saved_mtrrs_var_count;
7686
bool fix_supported = !!(ia32_mtrrcap & ((uint64_t)1 << 8));
7787

78-
if (saved_mtrrs == NULL) {
79-
panic(true, "mtrr: Attempted restore without prior save");
80-
}
81-
8288
/* according to the Intel SDM 12.11.7.2 "MemTypeSet() Function",
8389
we need to follow this procedure before changing MTRR set up */
8490

@@ -144,11 +150,6 @@ void mtrr_restore(void) {
144150
}
145151

146152
#define MTRR_TYPE_WC 1
147-
#define MTRR_VAR_MAX 256
148-
149-
static no_unwind uint64_t wc_full_saved_var[MTRR_VAR_MAX * 2];
150-
static no_unwind uint8_t wc_full_saved_var_i = 0;
151-
static no_unwind bool wc_full_saved_valid = false;
152153

153154
static bool wc_add_mtrr(uint64_t base, uint64_t size, uint8_t type,
154155
uint8_t maxphysaddr, uint8_t var_reg_count) {
@@ -223,14 +224,7 @@ bool mtrr_wc_add_fb_range(uint64_t base, uint64_t size) {
223224
}
224225
}
225226

226-
if (!wc_full_saved_valid) {
227-
for (uint8_t i = 0; i < var_reg_count; i++) {
228-
wc_full_saved_var[i * 2] = rdmsr(0x200 + i * 2);
229-
wc_full_saved_var[i * 2 + 1] = rdmsr(0x200 + i * 2 + 1);
230-
}
231-
wc_full_saved_var_i = var_reg_count;
232-
wc_full_saved_valid = true;
233-
}
227+
mtrr_save();
234228

235229
#if defined (UEFI)
236230
asm volatile ("cli");
@@ -265,48 +259,4 @@ bool mtrr_wc_add_fb_range(uint64_t base, uint64_t size) {
265259
return ok;
266260
}
267261

268-
void mtrr_wc_clear_fb_ranges(void) {
269-
if (!wc_full_saved_valid) {
270-
return;
271-
}
272-
if (!mtrr_supported()) {
273-
wc_full_saved_valid = false;
274-
return;
275-
}
276-
277-
#if defined (UEFI)
278-
asm volatile ("cli");
279-
#endif
280-
281-
uintptr_t old_cr0;
282-
asm volatile ("mov %%cr0, %0" : "=r"(old_cr0) :: "memory");
283-
uintptr_t new_cr0 = (old_cr0 | (1U << 30)) & ~((uintptr_t)1 << 29);
284-
asm volatile ("mov %0, %%cr0" :: "r"(new_cr0) : "memory");
285-
asm volatile ("wbinvd" ::: "memory");
286-
287-
uintptr_t cr3;
288-
asm volatile ("mov %%cr3, %0" : "=r"(cr3) :: "memory");
289-
asm volatile ("mov %0, %%cr3" :: "r"(cr3) : "memory");
290-
291-
uint64_t mtrr_def = rdmsr(0x2ff);
292-
wrmsr(0x2ff, mtrr_def & ~((uint64_t)1 << 11));
293-
294-
for (uint8_t i = 0; i < wc_full_saved_var_i; i++) {
295-
wrmsr(0x200 + i * 2, wc_full_saved_var[i * 2]);
296-
wrmsr(0x200 + i * 2 + 1, wc_full_saved_var[i * 2 + 1]);
297-
}
298-
wrmsr(0x2ff, mtrr_def);
299-
300-
asm volatile ("mov %%cr3, %0" : "=r"(cr3) :: "memory");
301-
asm volatile ("mov %0, %%cr3" :: "r"(cr3) : "memory");
302-
asm volatile ("wbinvd" ::: "memory");
303-
asm volatile ("mov %0, %%cr0" :: "r"(old_cr0) : "memory");
304-
305-
#if defined (UEFI)
306-
asm volatile ("sti");
307-
#endif
308-
309-
wc_full_saved_valid = false;
310-
}
311-
312262
#endif

common/mm/mtrr.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ void mtrr_save(void);
1010
void mtrr_restore(void);
1111

1212
bool mtrr_wc_add_fb_range(uint64_t base, uint64_t size);
13-
void mtrr_wc_clear_fb_ranges(void);
1413

1514
#endif
1615

0 commit comments

Comments
 (0)