@@ -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
2230void 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
6874void 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
153154static 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
0 commit comments