]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/Library/MtrrLib/MtrrLib.c
UefiCpuPkg/MtrrLib: Use a better algorithm to calculate MTRR
[mirror_edk2.git] / UefiCpuPkg / Library / MtrrLib / MtrrLib.c
1 /** @file
2 MTRR setting library
3
4 @par Note:
5 Most of services in this library instance are suggested to be invoked by BSP only,
6 except for MtrrSetAllMtrrs() which is used to sync BSP's MTRR setting to APs.
7
8 Copyright (c) 2008 - 2017, Intel Corporation. All rights reserved.<BR>
9 This program and the accompanying materials
10 are licensed and made available under the terms and conditions of the BSD License
11 which accompanies this distribution. The full text of the license may be found at
12 http://opensource.org/licenses/bsd-license.php
13
14 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
15 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16
17 **/
18
19 #include <Base.h>
20
21 #include <Register/Cpuid.h>
22 #include <Register/Msr.h>
23
24 #include <Library/MtrrLib.h>
25 #include <Library/BaseLib.h>
26 #include <Library/CpuLib.h>
27 #include <Library/BaseMemoryLib.h>
28 #include <Library/DebugLib.h>
29
30 #define OR_SEED 0x0101010101010101ull
31 #define CLEAR_SEED 0xFFFFFFFFFFFFFFFFull
32
33 #define MTRR_LIB_ASSERT_ALIGNED(B, L) ASSERT ((B & ~(L - 1)) == B);
34 //
35 // Context to save and restore when MTRRs are programmed
36 //
37 typedef struct {
38 UINTN Cr4;
39 BOOLEAN InterruptState;
40 } MTRR_CONTEXT;
41
42 typedef struct {
43 UINT64 BaseAddress;
44 UINT64 Length;
45 MTRR_MEMORY_CACHE_TYPE Type;
46 } MEMORY_RANGE;
47
48 //
49 // This table defines the offset, base and length of the fixed MTRRs
50 //
51 CONST FIXED_MTRR mMtrrLibFixedMtrrTable[] = {
52 {
53 MTRR_LIB_IA32_MTRR_FIX64K_00000,
54 0,
55 SIZE_64KB
56 },
57 {
58 MTRR_LIB_IA32_MTRR_FIX16K_80000,
59 0x80000,
60 SIZE_16KB
61 },
62 {
63 MTRR_LIB_IA32_MTRR_FIX16K_A0000,
64 0xA0000,
65 SIZE_16KB
66 },
67 {
68 MTRR_LIB_IA32_MTRR_FIX4K_C0000,
69 0xC0000,
70 SIZE_4KB
71 },
72 {
73 MTRR_LIB_IA32_MTRR_FIX4K_C8000,
74 0xC8000,
75 SIZE_4KB
76 },
77 {
78 MTRR_LIB_IA32_MTRR_FIX4K_D0000,
79 0xD0000,
80 SIZE_4KB
81 },
82 {
83 MTRR_LIB_IA32_MTRR_FIX4K_D8000,
84 0xD8000,
85 SIZE_4KB
86 },
87 {
88 MTRR_LIB_IA32_MTRR_FIX4K_E0000,
89 0xE0000,
90 SIZE_4KB
91 },
92 {
93 MTRR_LIB_IA32_MTRR_FIX4K_E8000,
94 0xE8000,
95 SIZE_4KB
96 },
97 {
98 MTRR_LIB_IA32_MTRR_FIX4K_F0000,
99 0xF0000,
100 SIZE_4KB
101 },
102 {
103 MTRR_LIB_IA32_MTRR_FIX4K_F8000,
104 0xF8000,
105 SIZE_4KB
106 }
107 };
108
109 //
110 // Lookup table used to print MTRRs
111 //
112 GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 *mMtrrMemoryCacheTypeShortName[] = {
113 "UC", // CacheUncacheable
114 "WC", // CacheWriteCombining
115 "R*", // Invalid
116 "R*", // Invalid
117 "WT", // CacheWriteThrough
118 "WP", // CacheWriteProtected
119 "WB", // CacheWriteBack
120 "R*" // Invalid
121 };
122
123 /**
124 Worker function returns the variable MTRR count for the CPU.
125
126 @return Variable MTRR count
127
128 **/
129 UINT32
130 GetVariableMtrrCountWorker (
131 VOID
132 )
133 {
134 MSR_IA32_MTRRCAP_REGISTER MtrrCap;
135
136 MtrrCap.Uint64 = AsmReadMsr64 (MSR_IA32_MTRRCAP);
137 ASSERT (MtrrCap.Bits.VCNT <= MTRR_NUMBER_OF_VARIABLE_MTRR);
138 return MtrrCap.Bits.VCNT;
139 }
140
141 /**
142 Returns the variable MTRR count for the CPU.
143
144 @return Variable MTRR count
145
146 **/
147 UINT32
148 EFIAPI
149 GetVariableMtrrCount (
150 VOID
151 )
152 {
153 if (!IsMtrrSupported ()) {
154 return 0;
155 }
156 return GetVariableMtrrCountWorker ();
157 }
158
159 /**
160 Worker function returns the firmware usable variable MTRR count for the CPU.
161
162 @return Firmware usable variable MTRR count
163
164 **/
165 UINT32
166 GetFirmwareVariableMtrrCountWorker (
167 VOID
168 )
169 {
170 UINT32 VariableMtrrCount;
171 UINT32 ReservedMtrrNumber;
172
173 VariableMtrrCount = GetVariableMtrrCountWorker ();
174 ReservedMtrrNumber = PcdGet32 (PcdCpuNumberOfReservedVariableMtrrs);
175 if (VariableMtrrCount < ReservedMtrrNumber) {
176 return 0;
177 }
178
179 return VariableMtrrCount - ReservedMtrrNumber;
180 }
181
182 /**
183 Returns the firmware usable variable MTRR count for the CPU.
184
185 @return Firmware usable variable MTRR count
186
187 **/
188 UINT32
189 EFIAPI
190 GetFirmwareVariableMtrrCount (
191 VOID
192 )
193 {
194 if (!IsMtrrSupported ()) {
195 return 0;
196 }
197 return GetFirmwareVariableMtrrCountWorker ();
198 }
199
200 /**
201 Worker function returns the default MTRR cache type for the system.
202
203 If MtrrSetting is not NULL, returns the default MTRR cache type from input
204 MTRR settings buffer.
205 If MtrrSetting is NULL, returns the default MTRR cache type from MSR.
206
207 @param[in] MtrrSetting A buffer holding all MTRRs content.
208
209 @return The default MTRR cache type.
210
211 **/
212 MTRR_MEMORY_CACHE_TYPE
213 MtrrGetDefaultMemoryTypeWorker (
214 IN MTRR_SETTINGS *MtrrSetting
215 )
216 {
217 if (MtrrSetting == NULL) {
218 return (MTRR_MEMORY_CACHE_TYPE) (AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE) & 0x7);
219 } else {
220 return (MTRR_MEMORY_CACHE_TYPE) (MtrrSetting->MtrrDefType & 0x7);
221 }
222 }
223
224
225 /**
226 Returns the default MTRR cache type for the system.
227
228 @return The default MTRR cache type.
229
230 **/
231 MTRR_MEMORY_CACHE_TYPE
232 EFIAPI
233 MtrrGetDefaultMemoryType (
234 VOID
235 )
236 {
237 if (!IsMtrrSupported ()) {
238 return CacheUncacheable;
239 }
240 return MtrrGetDefaultMemoryTypeWorker (NULL);
241 }
242
243 /**
244 Preparation before programming MTRR.
245
246 This function will do some preparation for programming MTRRs:
247 disable cache, invalid cache and disable MTRR caching functionality
248
249 @param[out] MtrrContext Pointer to context to save
250
251 **/
252 VOID
253 MtrrLibPreMtrrChange (
254 OUT MTRR_CONTEXT *MtrrContext
255 )
256 {
257 //
258 // Disable interrupts and save current interrupt state
259 //
260 MtrrContext->InterruptState = SaveAndDisableInterrupts();
261
262 //
263 // Enter no fill cache mode, CD=1(Bit30), NW=0 (Bit29)
264 //
265 AsmDisableCache ();
266
267 //
268 // Save original CR4 value and clear PGE flag (Bit 7)
269 //
270 MtrrContext->Cr4 = AsmReadCr4 ();
271 AsmWriteCr4 (MtrrContext->Cr4 & (~BIT7));
272
273 //
274 // Flush all TLBs
275 //
276 CpuFlushTlb ();
277
278 //
279 // Disable MTRRs
280 //
281 AsmMsrBitFieldWrite64 (MTRR_LIB_IA32_MTRR_DEF_TYPE, 10, 11, 0);
282 }
283
284 /**
285 Cleaning up after programming MTRRs.
286
287 This function will do some clean up after programming MTRRs:
288 Flush all TLBs, re-enable caching, restore CR4.
289
290 @param[in] MtrrContext Pointer to context to restore
291
292 **/
293 VOID
294 MtrrLibPostMtrrChangeEnableCache (
295 IN MTRR_CONTEXT *MtrrContext
296 )
297 {
298 //
299 // Flush all TLBs
300 //
301 CpuFlushTlb ();
302
303 //
304 // Enable Normal Mode caching CD=NW=0, CD(Bit30), NW(Bit29)
305 //
306 AsmEnableCache ();
307
308 //
309 // Restore original CR4 value
310 //
311 AsmWriteCr4 (MtrrContext->Cr4);
312
313 //
314 // Restore original interrupt state
315 //
316 SetInterruptState (MtrrContext->InterruptState);
317 }
318
319 /**
320 Cleaning up after programming MTRRs.
321
322 This function will do some clean up after programming MTRRs:
323 enable MTRR caching functionality, and enable cache
324
325 @param[in] MtrrContext Pointer to context to restore
326
327 **/
328 VOID
329 MtrrLibPostMtrrChange (
330 IN MTRR_CONTEXT *MtrrContext
331 )
332 {
333 //
334 // Enable Cache MTRR
335 //
336 AsmMsrBitFieldWrite64 (MTRR_LIB_IA32_MTRR_DEF_TYPE, 10, 11, 3);
337
338 MtrrLibPostMtrrChangeEnableCache (MtrrContext);
339 }
340
341 /**
342 Worker function gets the content in fixed MTRRs
343
344 @param[out] FixedSettings A buffer to hold fixed MTRRs content.
345
346 @retval The pointer of FixedSettings
347
348 **/
349 MTRR_FIXED_SETTINGS*
350 MtrrGetFixedMtrrWorker (
351 OUT MTRR_FIXED_SETTINGS *FixedSettings
352 )
353 {
354 UINT32 Index;
355
356 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
357 FixedSettings->Mtrr[Index] =
358 AsmReadMsr64 (mMtrrLibFixedMtrrTable[Index].Msr);
359 }
360
361 return FixedSettings;
362 }
363
364
365 /**
366 This function gets the content in fixed MTRRs
367
368 @param[out] FixedSettings A buffer to hold fixed MTRRs content.
369
370 @retval The pointer of FixedSettings
371
372 **/
373 MTRR_FIXED_SETTINGS*
374 EFIAPI
375 MtrrGetFixedMtrr (
376 OUT MTRR_FIXED_SETTINGS *FixedSettings
377 )
378 {
379 if (!IsMtrrSupported ()) {
380 return FixedSettings;
381 }
382
383 return MtrrGetFixedMtrrWorker (FixedSettings);
384 }
385
386
387 /**
388 Worker function will get the raw value in variable MTRRs
389
390 If MtrrSetting is not NULL, gets the variable MTRRs raw value from input
391 MTRR settings buffer.
392 If MtrrSetting is NULL, gets the variable MTRRs raw value from MTRRs.
393
394 @param[in] MtrrSetting A buffer holding all MTRRs content.
395 @param[in] VariableMtrrCount Number of variable MTRRs.
396 @param[out] VariableSettings A buffer to hold variable MTRRs content.
397
398 @return The VariableSettings input pointer
399
400 **/
401 MTRR_VARIABLE_SETTINGS*
402 MtrrGetVariableMtrrWorker (
403 IN MTRR_SETTINGS *MtrrSetting,
404 IN UINT32 VariableMtrrCount,
405 OUT MTRR_VARIABLE_SETTINGS *VariableSettings
406 )
407 {
408 UINT32 Index;
409
410 ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);
411
412 for (Index = 0; Index < VariableMtrrCount; Index++) {
413 if (MtrrSetting == NULL) {
414 VariableSettings->Mtrr[Index].Base =
415 AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1));
416 VariableSettings->Mtrr[Index].Mask =
417 AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1) + 1);
418 } else {
419 VariableSettings->Mtrr[Index].Base = MtrrSetting->Variables.Mtrr[Index].Base;
420 VariableSettings->Mtrr[Index].Mask = MtrrSetting->Variables.Mtrr[Index].Mask;
421 }
422 }
423
424 return VariableSettings;
425 }
426
427 /**
428 This function will get the raw value in variable MTRRs
429
430 @param[out] VariableSettings A buffer to hold variable MTRRs content.
431
432 @return The VariableSettings input pointer
433
434 **/
435 MTRR_VARIABLE_SETTINGS*
436 EFIAPI
437 MtrrGetVariableMtrr (
438 OUT MTRR_VARIABLE_SETTINGS *VariableSettings
439 )
440 {
441 if (!IsMtrrSupported ()) {
442 return VariableSettings;
443 }
444
445 return MtrrGetVariableMtrrWorker (
446 NULL,
447 GetVariableMtrrCountWorker (),
448 VariableSettings
449 );
450 }
451
452 /**
453 Programs fixed MTRRs registers.
454
455 @param[in] Type The memory type to set.
456 @param[in, out] Base The base address of memory range.
457 @param[in, out] Length The length of memory range.
458 @param[in, out] LastMsrNum On input, the last index of the fixed MTRR MSR to program.
459 On return, the current index of the fixed MTRR MSR to program.
460 @param[out] ReturnClearMask The bits to clear in the fixed MTRR MSR.
461 @param[out] ReturnOrMask The bits to set in the fixed MTRR MSR.
462
463 @retval RETURN_SUCCESS The cache type was updated successfully
464 @retval RETURN_UNSUPPORTED The requested range or cache type was invalid
465 for the fixed MTRRs.
466
467 **/
468 RETURN_STATUS
469 MtrrLibProgramFixedMtrr (
470 IN MTRR_MEMORY_CACHE_TYPE Type,
471 IN OUT UINT64 *Base,
472 IN OUT UINT64 *Length,
473 IN OUT UINT32 *LastMsrNum,
474 OUT UINT64 *ReturnClearMask,
475 OUT UINT64 *ReturnOrMask
476 )
477 {
478 UINT32 MsrNum;
479 UINT32 LeftByteShift;
480 UINT32 RightByteShift;
481 UINT64 OrMask;
482 UINT64 ClearMask;
483 UINT64 SubLength;
484
485 //
486 // Find the fixed MTRR index to be programmed
487 //
488 for (MsrNum = *LastMsrNum + 1; MsrNum < MTRR_NUMBER_OF_FIXED_MTRR; MsrNum++) {
489 if ((*Base >= mMtrrLibFixedMtrrTable[MsrNum].BaseAddress) &&
490 (*Base <
491 (
492 mMtrrLibFixedMtrrTable[MsrNum].BaseAddress +
493 (8 * mMtrrLibFixedMtrrTable[MsrNum].Length)
494 )
495 )
496 ) {
497 break;
498 }
499 }
500
501 if (MsrNum == MTRR_NUMBER_OF_FIXED_MTRR) {
502 return RETURN_UNSUPPORTED;
503 }
504
505 //
506 // Find the begin offset in fixed MTRR and calculate byte offset of left shift
507 //
508 LeftByteShift = ((UINT32)*Base - mMtrrLibFixedMtrrTable[MsrNum].BaseAddress)
509 / mMtrrLibFixedMtrrTable[MsrNum].Length;
510
511 if (LeftByteShift >= 8) {
512 return RETURN_UNSUPPORTED;
513 }
514
515 //
516 // Find the end offset in fixed MTRR and calculate byte offset of right shift
517 //
518 SubLength = mMtrrLibFixedMtrrTable[MsrNum].Length * (8 - LeftByteShift);
519 if (*Length >= SubLength) {
520 RightByteShift = 0;
521 } else {
522 RightByteShift = 8 - LeftByteShift -
523 (UINT32)(*Length) / mMtrrLibFixedMtrrTable[MsrNum].Length;
524 if ((LeftByteShift >= 8) ||
525 (((UINT32)(*Length) % mMtrrLibFixedMtrrTable[MsrNum].Length) != 0)
526 ) {
527 return RETURN_UNSUPPORTED;
528 }
529 //
530 // Update SubLength by actual length
531 //
532 SubLength = *Length;
533 }
534
535 ClearMask = CLEAR_SEED;
536 OrMask = MultU64x32 (OR_SEED, (UINT32) Type);
537
538 if (LeftByteShift != 0) {
539 //
540 // Clear the low bits by LeftByteShift
541 //
542 ClearMask &= LShiftU64 (ClearMask, LeftByteShift * 8);
543 OrMask &= LShiftU64 (OrMask, LeftByteShift * 8);
544 }
545
546 if (RightByteShift != 0) {
547 //
548 // Clear the high bits by RightByteShift
549 //
550 ClearMask &= RShiftU64 (ClearMask, RightByteShift * 8);
551 OrMask &= RShiftU64 (OrMask, RightByteShift * 8);
552 }
553
554 *Length -= SubLength;
555 *Base += SubLength;
556
557 *LastMsrNum = MsrNum;
558 *ReturnClearMask = ClearMask;
559 *ReturnOrMask = OrMask;
560
561 return RETURN_SUCCESS;
562 }
563
564
565 /**
566 Worker function gets the attribute of variable MTRRs.
567
568 This function shadows the content of variable MTRRs into an
569 internal array: VariableMtrr.
570
571 @param[in] VariableSettings The variable MTRR values to shadow
572 @param[in] FirmwareVariableMtrrCount The number of variable MTRRs available to firmware
573 @param[in] MtrrValidBitsMask The mask for the valid bit of the MTRR
574 @param[in] MtrrValidAddressMask The valid address mask for MTRR
575 @param[out] VariableMtrr The array to shadow variable MTRRs content
576
577 @return The return value of this parameter indicates the
578 number of MTRRs which has been used.
579
580 **/
581 UINT32
582 MtrrGetMemoryAttributeInVariableMtrrWorker (
583 IN MTRR_VARIABLE_SETTINGS *VariableSettings,
584 IN UINTN FirmwareVariableMtrrCount,
585 IN UINT64 MtrrValidBitsMask,
586 IN UINT64 MtrrValidAddressMask,
587 OUT VARIABLE_MTRR *VariableMtrr
588 )
589 {
590 UINTN Index;
591 UINT32 UsedMtrr;
592
593 ZeroMem (VariableMtrr, sizeof (VARIABLE_MTRR) * MTRR_NUMBER_OF_VARIABLE_MTRR);
594 for (Index = 0, UsedMtrr = 0; Index < FirmwareVariableMtrrCount; Index++) {
595 if ((VariableSettings->Mtrr[Index].Mask & MTRR_LIB_CACHE_MTRR_ENABLED) != 0) {
596 VariableMtrr[Index].Msr = (UINT32)Index;
597 VariableMtrr[Index].BaseAddress = (VariableSettings->Mtrr[Index].Base & MtrrValidAddressMask);
598 VariableMtrr[Index].Length = ((~(VariableSettings->Mtrr[Index].Mask & MtrrValidAddressMask)) & MtrrValidBitsMask) + 1;
599 VariableMtrr[Index].Type = (VariableSettings->Mtrr[Index].Base & 0x0ff);
600 VariableMtrr[Index].Valid = TRUE;
601 VariableMtrr[Index].Used = TRUE;
602 UsedMtrr++;
603 }
604 }
605 return UsedMtrr;
606 }
607
608
609 /**
610 Gets the attribute of variable MTRRs.
611
612 This function shadows the content of variable MTRRs into an
613 internal array: VariableMtrr.
614
615 @param[in] MtrrValidBitsMask The mask for the valid bit of the MTRR
616 @param[in] MtrrValidAddressMask The valid address mask for MTRR
617 @param[out] VariableMtrr The array to shadow variable MTRRs content
618
619 @return The return value of this parameter indicates the
620 number of MTRRs which has been used.
621
622 **/
623 UINT32
624 EFIAPI
625 MtrrGetMemoryAttributeInVariableMtrr (
626 IN UINT64 MtrrValidBitsMask,
627 IN UINT64 MtrrValidAddressMask,
628 OUT VARIABLE_MTRR *VariableMtrr
629 )
630 {
631 MTRR_VARIABLE_SETTINGS VariableSettings;
632
633 if (!IsMtrrSupported ()) {
634 return 0;
635 }
636
637 MtrrGetVariableMtrrWorker (
638 NULL,
639 GetVariableMtrrCountWorker (),
640 &VariableSettings
641 );
642
643 return MtrrGetMemoryAttributeInVariableMtrrWorker (
644 &VariableSettings,
645 GetFirmwareVariableMtrrCountWorker (),
646 MtrrValidBitsMask,
647 MtrrValidAddressMask,
648 VariableMtrr
649 );
650 }
651
652 /**
653 Return the least alignment of address.
654
655 @param Address The address to return the alignment.
656 @param Alignment0 The alignment to return when Address is 0.
657
658 @return The least alignment of the Address.
659 **/
660 UINT64
661 MtrrLibLeastAlignment (
662 UINT64 Address,
663 UINT64 Alignment0
664 )
665 {
666 if (Address == 0) {
667 return Alignment0;
668 }
669
670 return LShiftU64 (1, (UINTN) LowBitSet64 (Address));
671 }
672
673 /**
674 Return the number of required variable MTRRs to positively cover the
675 specified range.
676
677 @param BaseAddress Base address of the range.
678 @param Length Length of the range.
679 @param Alignment0 Alignment of 0.
680
681 @return The number of the required variable MTRRs.
682 **/
683 UINT32
684 MtrrLibGetPositiveMtrrNumber (
685 IN UINT64 BaseAddress,
686 IN UINT64 Length,
687 IN UINT64 Alignment0
688 )
689 {
690 UINT64 SubLength;
691 UINT32 MtrrNumber;
692 BOOLEAN UseLeastAlignment;
693
694 UseLeastAlignment = TRUE;
695
696 //
697 // Calculate the alignment of the base address.
698 //
699 for (MtrrNumber = 0; Length != 0; MtrrNumber++) {
700 if (UseLeastAlignment) {
701 SubLength = MtrrLibLeastAlignment (BaseAddress, Alignment0);
702
703 if (SubLength > Length) {
704 //
705 // Set a flag when remaining length is too small
706 // so that MtrrLibLeastAlignment() is not called in following loops.
707 //
708 UseLeastAlignment = FALSE;
709 }
710 }
711
712 if (!UseLeastAlignment) {
713 SubLength = GetPowerOfTwo64 (Length);
714 }
715
716 BaseAddress += SubLength;
717 Length -= SubLength;
718 }
719
720 return MtrrNumber;
721 }
722
723 /**
724 Return whether the left MTRR type precedes the right MTRR type.
725
726 The MTRR type precedence rules are:
727 1. UC precedes any other type
728 2. WT precedes WB
729
730 @param Left The left MTRR type.
731 @param Right The right MTRR type.
732
733 @retval TRUE Left precedes Right.
734 @retval FALSE Left doesn't precede Right.
735 **/
736 BOOLEAN
737 MtrrLibTypeLeftPrecedeRight (
738 IN MTRR_MEMORY_CACHE_TYPE Left,
739 IN MTRR_MEMORY_CACHE_TYPE Right
740 )
741 {
742 return (BOOLEAN) (Left == CacheUncacheable || (Left == CacheWriteThrough && Right == CacheWriteBack));
743 }
744
745
746 /**
747 Return whether the type of the specified range can precede the specified type.
748
749 @param Ranges Memory range array holding memory type settings for all
750 the memory address.
751 @param RangeCount Count of memory ranges.
752 @param Type Type to check precedence.
753 @param SubBase Base address of the specified range.
754 @param SubLength Length of the specified range.
755
756 @retval TRUE The type of the specified range can precede the Type.
757 @retval FALSE The type of the specified range cannot precede the Type.
758 So the subtraction is not applicable.
759 **/
760 BOOLEAN
761 MtrrLibSubstractable (
762 IN CONST MEMORY_RANGE *Ranges,
763 IN UINT32 RangeCount,
764 IN MTRR_MEMORY_CACHE_TYPE Type,
765 IN UINT64 SubBase,
766 IN UINT64 SubLength
767 )
768 {
769 UINT32 Index;
770 UINT64 Length;
771 // WT > WB
772 // UC > *
773 for (Index = 0; Index < RangeCount; Index++) {
774 if (Ranges[Index].BaseAddress <= SubBase && SubBase < Ranges[Index].BaseAddress + Ranges[Index].Length) {
775
776 if (Ranges[Index].BaseAddress + Ranges[Index].Length >= SubBase + SubLength) {
777 return MtrrLibTypeLeftPrecedeRight (Ranges[Index].Type, Type);
778
779 } else {
780 if (!MtrrLibTypeLeftPrecedeRight (Ranges[Index].Type, Type)) {
781 return FALSE;
782 }
783
784 Length = Ranges[Index].BaseAddress + Ranges[Index].Length - SubBase;
785 SubBase += Length;
786 SubLength -= Length;
787 }
788 }
789 }
790
791 ASSERT (FALSE);
792 return FALSE;
793 }
794
795 /**
796 Return the number of required variable MTRRs to cover the specified range.
797
798 The routine considers subtraction in the both side of the range to find out
799 the most optimal solution (which uses the least MTRRs).
800
801 @param Ranges Array holding memory type settings of all memory
802 address.
803 @param RangeCount Count of memory ranges.
804 @param VariableMtrr Array holding allocated variable MTRRs.
805 @param VariableMtrrCount Count of allocated variable MTRRs.
806 @param BaseAddress Base address of the specified range.
807 @param Length Length of the specified range.
808 @param Type MTRR type of the specified range.
809 @param Alignment0 Alignment of 0.
810 @param SubLeft Return the count of left subtraction.
811 @param SubRight Return the count of right subtraction.
812
813 @return Number of required variable MTRRs.
814 **/
815 UINT32
816 MtrrLibGetMtrrNumber (
817 IN CONST MEMORY_RANGE *Ranges,
818 IN UINT32 RangeCount,
819 IN CONST VARIABLE_MTRR *VariableMtrr,
820 IN UINT32 VariableMtrrCount,
821 IN UINT64 BaseAddress,
822 IN UINT64 Length,
823 IN MTRR_MEMORY_CACHE_TYPE Type,
824 IN UINT64 Alignment0,
825 OUT UINT32 *SubLeft, // subtractive from BaseAddress to get more aligned address, to save MTRR
826 OUT UINT32 *SubRight // subtractive from BaseAddress + Length, to save MTRR
827 )
828 {
829 UINT64 Alignment;
830 UINT32 LeastLeftMtrrNumber;
831 UINT32 MiddleMtrrNumber;
832 UINT32 LeastRightMtrrNumber;
833 UINT32 CurrentMtrrNumber;
834 UINT32 SubtractiveCount;
835 UINT32 SubtractiveMtrrNumber;
836 UINT32 LeastSubtractiveMtrrNumber;
837 UINT64 SubtractiveBaseAddress;
838 UINT64 SubtractiveLength;
839 UINT64 BaseAlignment;
840 UINT32 Index;
841
842 *SubLeft = 0;
843 *SubRight = 0;
844 LeastSubtractiveMtrrNumber = 0;
845
846 //
847 // Get the optimal left subtraction solution.
848 //
849 if (BaseAddress != 0) {
850 //
851 // Get the MTRR number needed without left subtraction.
852 //
853 LeastLeftMtrrNumber = MtrrLibGetPositiveMtrrNumber (BaseAddress, Length, Alignment0);
854
855 //
856 // Left subtraction bit by bit, to find the optimal left subtraction solution.
857 //
858 for (SubtractiveMtrrNumber = 0, SubtractiveCount = 1; BaseAddress != 0; SubtractiveCount++) {
859 Alignment = MtrrLibLeastAlignment (BaseAddress, Alignment0);
860
861 //
862 // Check whether the memory type of [BaseAddress - Alignment, BaseAddress) can override Type.
863 // IA32 Manual defines the following override rules:
864 // WT > WB
865 // UC > * (any)
866 //
867 if (!MtrrLibSubstractable (Ranges, RangeCount, Type, BaseAddress - Alignment, Alignment)) {
868 break;
869 }
870
871 for (Index = 0; Index < VariableMtrrCount; Index++) {
872 if ((VariableMtrr[Index].BaseAddress == BaseAddress - Alignment) &&
873 (VariableMtrr[Index].Length == Alignment)) {
874 break;
875 }
876 }
877 if (Index == VariableMtrrCount) {
878 //
879 // Increment SubtractiveMtrrNumber when [BaseAddress - Alignment, BaseAddress) is not be planed as a MTRR
880 //
881 SubtractiveMtrrNumber++;
882 }
883
884 BaseAddress -= Alignment;
885 Length += Alignment;
886
887 CurrentMtrrNumber = SubtractiveMtrrNumber + MtrrLibGetPositiveMtrrNumber (BaseAddress, Length, Alignment0);
888 if (CurrentMtrrNumber <= LeastLeftMtrrNumber) {
889 LeastLeftMtrrNumber = CurrentMtrrNumber;
890 LeastSubtractiveMtrrNumber = SubtractiveMtrrNumber;
891 *SubLeft = SubtractiveCount;
892 SubtractiveBaseAddress = BaseAddress;
893 SubtractiveLength = Length;
894 }
895 }
896
897 //
898 // If left subtraction is better, subtract BaseAddress to left, and enlarge Length
899 //
900 if (*SubLeft != 0) {
901 BaseAddress = SubtractiveBaseAddress;
902 Length = SubtractiveLength;
903 }
904 }
905
906 //
907 // Increment BaseAddress greedily until (BaseAddress + Alignment) exceeds (BaseAddress + Length)
908 //
909 MiddleMtrrNumber = 0;
910 while (Length != 0) {
911 BaseAlignment = MtrrLibLeastAlignment (BaseAddress, Alignment0);
912 if (BaseAlignment > Length) {
913 break;
914 }
915 BaseAddress += BaseAlignment;
916 Length -= BaseAlignment;
917 MiddleMtrrNumber++;
918 }
919
920
921 if (Length == 0) {
922 return LeastSubtractiveMtrrNumber + MiddleMtrrNumber;
923 }
924
925
926 //
927 // Get the optimal right subtraction solution.
928 //
929
930 //
931 // Get the MTRR number needed without right subtraction.
932 //
933 LeastRightMtrrNumber = MtrrLibGetPositiveMtrrNumber (BaseAddress, Length, Alignment0);
934
935 for (SubtractiveCount = 1; Length < BaseAlignment; SubtractiveCount++) {
936 Alignment = MtrrLibLeastAlignment (BaseAddress + Length, Alignment0);
937 if (!MtrrLibSubstractable (Ranges, RangeCount, Type, BaseAddress + Length, Alignment)) {
938 break;
939 }
940
941 Length += Alignment;
942
943 //
944 // SubtractiveCount = Number of MTRRs used for subtraction
945 //
946 CurrentMtrrNumber = SubtractiveCount + MtrrLibGetPositiveMtrrNumber (BaseAddress, Length, Alignment0);
947 if (CurrentMtrrNumber <= LeastRightMtrrNumber) {
948 LeastRightMtrrNumber = CurrentMtrrNumber;
949 *SubRight = SubtractiveCount;
950 SubtractiveLength = Length;
951 }
952 }
953
954 return LeastSubtractiveMtrrNumber + MiddleMtrrNumber + LeastRightMtrrNumber;
955 }
956
957
958 /**
959 Converts the Memory attribute value to MTRR_MEMORY_CACHE_TYPE.
960
961 If MtrrSetting is not NULL, gets the default memory attribute from input
962 MTRR settings buffer.
963 If MtrrSetting is NULL, gets the default memory attribute from MSR.
964
965 @param[in] MtrrSetting A buffer holding all MTRRs content.
966 @param[in] MtrrType MTRR memory type
967
968 @return The enum item in MTRR_MEMORY_CACHE_TYPE
969
970 **/
971 MTRR_MEMORY_CACHE_TYPE
972 GetMemoryCacheTypeFromMtrrType (
973 IN MTRR_SETTINGS *MtrrSetting,
974 IN UINT64 MtrrType
975 )
976 {
977 switch (MtrrType) {
978 case MTRR_CACHE_UNCACHEABLE:
979 return CacheUncacheable;
980 case MTRR_CACHE_WRITE_COMBINING:
981 return CacheWriteCombining;
982 case MTRR_CACHE_WRITE_THROUGH:
983 return CacheWriteThrough;
984 case MTRR_CACHE_WRITE_PROTECTED:
985 return CacheWriteProtected;
986 case MTRR_CACHE_WRITE_BACK:
987 return CacheWriteBack;
988 default:
989 //
990 // MtrrType is MTRR_CACHE_INVALID_TYPE, that means
991 // no MTRR covers the range
992 //
993 return MtrrGetDefaultMemoryTypeWorker (MtrrSetting);
994 }
995 }
996
997 /**
998 Initializes the valid bits mask and valid address mask for MTRRs.
999
1000 This function initializes the valid bits mask and valid address mask for MTRRs.
1001
1002 @param[out] MtrrValidBitsMask The mask for the valid bit of the MTRR
1003 @param[out] MtrrValidAddressMask The valid address mask for the MTRR
1004
1005 **/
1006 VOID
1007 MtrrLibInitializeMtrrMask (
1008 OUT UINT64 *MtrrValidBitsMask,
1009 OUT UINT64 *MtrrValidAddressMask
1010 )
1011 {
1012 UINT32 MaxExtendedFunction;
1013 CPUID_VIR_PHY_ADDRESS_SIZE_EAX VirPhyAddressSize;
1014
1015
1016 AsmCpuid (CPUID_EXTENDED_FUNCTION, &MaxExtendedFunction, NULL, NULL, NULL);
1017
1018 if (MaxExtendedFunction >= CPUID_VIR_PHY_ADDRESS_SIZE) {
1019 AsmCpuid (CPUID_VIR_PHY_ADDRESS_SIZE, &VirPhyAddressSize.Uint32, NULL, NULL, NULL);
1020 } else {
1021 VirPhyAddressSize.Bits.PhysicalAddressBits = 36;
1022 }
1023
1024 *MtrrValidBitsMask = LShiftU64 (1, VirPhyAddressSize.Bits.PhysicalAddressBits) - 1;
1025 *MtrrValidAddressMask = *MtrrValidBitsMask & 0xfffffffffffff000ULL;
1026 }
1027
1028
1029 /**
1030 Determines the real attribute of a memory range.
1031
1032 This function is to arbitrate the real attribute of the memory when
1033 there are 2 MTRRs covers the same memory range. For further details,
1034 please refer the IA32 Software Developer's Manual, Volume 3,
1035 Section 10.11.4.1.
1036
1037 @param[in] MtrrType1 The first kind of Memory type
1038 @param[in] MtrrType2 The second kind of memory type
1039
1040 **/
1041 UINT64
1042 MtrrLibPrecedence (
1043 IN UINT64 MtrrType1,
1044 IN UINT64 MtrrType2
1045 )
1046 {
1047 UINT64 MtrrType;
1048
1049 MtrrType = MTRR_CACHE_INVALID_TYPE;
1050 switch (MtrrType1) {
1051 case MTRR_CACHE_UNCACHEABLE:
1052 MtrrType = MTRR_CACHE_UNCACHEABLE;
1053 break;
1054 case MTRR_CACHE_WRITE_COMBINING:
1055 if (
1056 MtrrType2==MTRR_CACHE_WRITE_COMBINING ||
1057 MtrrType2==MTRR_CACHE_UNCACHEABLE
1058 ) {
1059 MtrrType = MtrrType2;
1060 }
1061 break;
1062 case MTRR_CACHE_WRITE_THROUGH:
1063 if (
1064 MtrrType2==MTRR_CACHE_WRITE_THROUGH ||
1065 MtrrType2==MTRR_CACHE_WRITE_BACK
1066 ) {
1067 MtrrType = MTRR_CACHE_WRITE_THROUGH;
1068 } else if(MtrrType2==MTRR_CACHE_UNCACHEABLE) {
1069 MtrrType = MTRR_CACHE_UNCACHEABLE;
1070 }
1071 break;
1072 case MTRR_CACHE_WRITE_PROTECTED:
1073 if (MtrrType2 == MTRR_CACHE_WRITE_PROTECTED ||
1074 MtrrType2 == MTRR_CACHE_UNCACHEABLE) {
1075 MtrrType = MtrrType2;
1076 }
1077 break;
1078 case MTRR_CACHE_WRITE_BACK:
1079 if (
1080 MtrrType2== MTRR_CACHE_UNCACHEABLE ||
1081 MtrrType2==MTRR_CACHE_WRITE_THROUGH ||
1082 MtrrType2== MTRR_CACHE_WRITE_BACK
1083 ) {
1084 MtrrType = MtrrType2;
1085 }
1086 break;
1087 case MTRR_CACHE_INVALID_TYPE:
1088 MtrrType = MtrrType2;
1089 break;
1090 default:
1091 break;
1092 }
1093
1094 if (MtrrType2 == MTRR_CACHE_INVALID_TYPE) {
1095 MtrrType = MtrrType1;
1096 }
1097 return MtrrType;
1098 }
1099
1100 /**
1101 Worker function will get the memory cache type of the specific address.
1102
1103 If MtrrSetting is not NULL, gets the memory cache type from input
1104 MTRR settings buffer.
1105 If MtrrSetting is NULL, gets the memory cache type from MTRRs.
1106
1107 @param[in] MtrrSetting A buffer holding all MTRRs content.
1108 @param[in] Address The specific address
1109
1110 @return Memory cache type of the specific address
1111
1112 **/
1113 MTRR_MEMORY_CACHE_TYPE
1114 MtrrGetMemoryAttributeByAddressWorker (
1115 IN MTRR_SETTINGS *MtrrSetting,
1116 IN PHYSICAL_ADDRESS Address
1117 )
1118 {
1119 UINT64 TempQword;
1120 UINTN Index;
1121 UINTN SubIndex;
1122 UINT64 MtrrType;
1123 UINT64 TempMtrrType;
1124 MTRR_MEMORY_CACHE_TYPE CacheType;
1125 VARIABLE_MTRR VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];
1126 UINT64 MtrrValidBitsMask;
1127 UINT64 MtrrValidAddressMask;
1128 UINTN VariableMtrrCount;
1129 MTRR_VARIABLE_SETTINGS VariableSettings;
1130
1131 //
1132 // Check if MTRR is enabled, if not, return UC as attribute
1133 //
1134 if (MtrrSetting == NULL) {
1135 TempQword = AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE);
1136 } else {
1137 TempQword = MtrrSetting->MtrrDefType;
1138 }
1139 MtrrType = MTRR_CACHE_INVALID_TYPE;
1140
1141 if ((TempQword & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {
1142 return CacheUncacheable;
1143 }
1144
1145 //
1146 // If address is less than 1M, then try to go through the fixed MTRR
1147 //
1148 if (Address < BASE_1MB) {
1149 if ((TempQword & MTRR_LIB_CACHE_FIXED_MTRR_ENABLED) != 0) {
1150 //
1151 // Go through the fixed MTRR
1152 //
1153 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
1154 if (Address >= mMtrrLibFixedMtrrTable[Index].BaseAddress &&
1155 Address < (
1156 mMtrrLibFixedMtrrTable[Index].BaseAddress +
1157 (mMtrrLibFixedMtrrTable[Index].Length * 8)
1158 )
1159 ) {
1160 SubIndex =
1161 ((UINTN)Address - mMtrrLibFixedMtrrTable[Index].BaseAddress) /
1162 mMtrrLibFixedMtrrTable[Index].Length;
1163 if (MtrrSetting == NULL) {
1164 TempQword = AsmReadMsr64 (mMtrrLibFixedMtrrTable[Index].Msr);
1165 } else {
1166 TempQword = MtrrSetting->Fixed.Mtrr[Index];
1167 }
1168 MtrrType = RShiftU64 (TempQword, SubIndex * 8) & 0xFF;
1169 return GetMemoryCacheTypeFromMtrrType (MtrrSetting, MtrrType);
1170 }
1171 }
1172 }
1173 }
1174 MtrrLibInitializeMtrrMask(&MtrrValidBitsMask, &MtrrValidAddressMask);
1175
1176 MtrrGetVariableMtrrWorker (
1177 MtrrSetting,
1178 GetVariableMtrrCountWorker (),
1179 &VariableSettings
1180 );
1181
1182 MtrrGetMemoryAttributeInVariableMtrrWorker (
1183 &VariableSettings,
1184 GetFirmwareVariableMtrrCountWorker (),
1185 MtrrValidBitsMask,
1186 MtrrValidAddressMask,
1187 VariableMtrr
1188 );
1189
1190 //
1191 // Go through the variable MTRR
1192 //
1193 VariableMtrrCount = GetVariableMtrrCountWorker ();
1194 ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);
1195
1196 for (Index = 0; Index < VariableMtrrCount; Index++) {
1197 if (VariableMtrr[Index].Valid) {
1198 if (Address >= VariableMtrr[Index].BaseAddress &&
1199 Address < VariableMtrr[Index].BaseAddress+VariableMtrr[Index].Length) {
1200 TempMtrrType = VariableMtrr[Index].Type;
1201 MtrrType = MtrrLibPrecedence (MtrrType, TempMtrrType);
1202 }
1203 }
1204 }
1205 CacheType = GetMemoryCacheTypeFromMtrrType (MtrrSetting, MtrrType);
1206
1207 return CacheType;
1208 }
1209
1210
1211 /**
1212 This function will get the memory cache type of the specific address.
1213
1214 This function is mainly for debug purpose.
1215
1216 @param[in] Address The specific address
1217
1218 @return Memory cache type of the specific address
1219
1220 **/
1221 MTRR_MEMORY_CACHE_TYPE
1222 EFIAPI
1223 MtrrGetMemoryAttribute (
1224 IN PHYSICAL_ADDRESS Address
1225 )
1226 {
1227 if (!IsMtrrSupported ()) {
1228 return CacheUncacheable;
1229 }
1230
1231 return MtrrGetMemoryAttributeByAddressWorker (NULL, Address);
1232 }
1233
1234 /**
1235 Worker function prints all MTRRs for debugging.
1236
1237 If MtrrSetting is not NULL, print MTRR settings from input MTRR
1238 settings buffer.
1239 If MtrrSetting is NULL, print MTRR settings from MTRRs.
1240
1241 @param MtrrSetting A buffer holding all MTRRs content.
1242 **/
1243 VOID
1244 MtrrDebugPrintAllMtrrsWorker (
1245 IN MTRR_SETTINGS *MtrrSetting
1246 )
1247 {
1248 DEBUG_CODE (
1249 MTRR_SETTINGS LocalMtrrs;
1250 MTRR_SETTINGS *Mtrrs;
1251 UINTN Index;
1252 UINTN Index1;
1253 UINTN VariableMtrrCount;
1254 UINT64 Base;
1255 UINT64 Limit;
1256 UINT64 MtrrBase;
1257 UINT64 MtrrLimit;
1258 UINT64 RangeBase;
1259 UINT64 RangeLimit;
1260 UINT64 NoRangeBase;
1261 UINT64 NoRangeLimit;
1262 UINT32 RegEax;
1263 UINTN MemoryType;
1264 UINTN PreviousMemoryType;
1265 BOOLEAN Found;
1266
1267 if (!IsMtrrSupported ()) {
1268 return;
1269 }
1270
1271 DEBUG((DEBUG_CACHE, "MTRR Settings\n"));
1272 DEBUG((DEBUG_CACHE, "=============\n"));
1273
1274 if (MtrrSetting != NULL) {
1275 Mtrrs = MtrrSetting;
1276 } else {
1277 MtrrGetAllMtrrs (&LocalMtrrs);
1278 Mtrrs = &LocalMtrrs;
1279 }
1280
1281 DEBUG((DEBUG_CACHE, "MTRR Default Type: %016lx\n", Mtrrs->MtrrDefType));
1282 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
1283 DEBUG((DEBUG_CACHE, "Fixed MTRR[%02d] : %016lx\n", Index, Mtrrs->Fixed.Mtrr[Index]));
1284 }
1285
1286 VariableMtrrCount = GetVariableMtrrCount ();
1287 for (Index = 0; Index < VariableMtrrCount; Index++) {
1288 DEBUG((DEBUG_CACHE, "Variable MTRR[%02d]: Base=%016lx Mask=%016lx\n",
1289 Index,
1290 Mtrrs->Variables.Mtrr[Index].Base,
1291 Mtrrs->Variables.Mtrr[Index].Mask
1292 ));
1293 }
1294 DEBUG((DEBUG_CACHE, "\n"));
1295 DEBUG((DEBUG_CACHE, "MTRR Ranges\n"));
1296 DEBUG((DEBUG_CACHE, "====================================\n"));
1297
1298 Base = 0;
1299 PreviousMemoryType = MTRR_CACHE_INVALID_TYPE;
1300 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
1301 Base = mMtrrLibFixedMtrrTable[Index].BaseAddress;
1302 for (Index1 = 0; Index1 < 8; Index1++) {
1303 MemoryType = (UINTN)(RShiftU64 (Mtrrs->Fixed.Mtrr[Index], Index1 * 8) & 0xff);
1304 if (MemoryType > CacheWriteBack) {
1305 MemoryType = MTRR_CACHE_INVALID_TYPE;
1306 }
1307 if (MemoryType != PreviousMemoryType) {
1308 if (PreviousMemoryType != MTRR_CACHE_INVALID_TYPE) {
1309 DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));
1310 }
1311 PreviousMemoryType = MemoryType;
1312 DEBUG((DEBUG_CACHE, "%a:%016lx-", mMtrrMemoryCacheTypeShortName[MemoryType], Base));
1313 }
1314 Base += mMtrrLibFixedMtrrTable[Index].Length;
1315 }
1316 }
1317 DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));
1318
1319 VariableMtrrCount = GetVariableMtrrCount ();
1320
1321 Limit = BIT36 - 1;
1322 AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
1323 if (RegEax >= 0x80000008) {
1324 AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);
1325 Limit = LShiftU64 (1, RegEax & 0xff) - 1;
1326 }
1327 Base = BASE_1MB;
1328 PreviousMemoryType = MTRR_CACHE_INVALID_TYPE;
1329 do {
1330 MemoryType = MtrrGetMemoryAttributeByAddressWorker (Mtrrs, Base);
1331 if (MemoryType > CacheWriteBack) {
1332 MemoryType = MTRR_CACHE_INVALID_TYPE;
1333 }
1334
1335 if (MemoryType != PreviousMemoryType) {
1336 if (PreviousMemoryType != MTRR_CACHE_INVALID_TYPE) {
1337 DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));
1338 }
1339 PreviousMemoryType = MemoryType;
1340 DEBUG((DEBUG_CACHE, "%a:%016lx-", mMtrrMemoryCacheTypeShortName[MemoryType], Base));
1341 }
1342
1343 RangeBase = BASE_1MB;
1344 NoRangeBase = BASE_1MB;
1345 RangeLimit = Limit;
1346 NoRangeLimit = Limit;
1347
1348 for (Index = 0, Found = FALSE; Index < VariableMtrrCount; Index++) {
1349 if ((Mtrrs->Variables.Mtrr[Index].Mask & BIT11) == 0) {
1350 //
1351 // If mask is not valid, then do not display range
1352 //
1353 continue;
1354 }
1355 MtrrBase = (Mtrrs->Variables.Mtrr[Index].Base & (~(SIZE_4KB - 1)));
1356 MtrrLimit = MtrrBase + ((~(Mtrrs->Variables.Mtrr[Index].Mask & (~(SIZE_4KB - 1)))) & Limit);
1357
1358 if (Base >= MtrrBase && Base < MtrrLimit) {
1359 Found = TRUE;
1360 }
1361
1362 if (Base >= MtrrBase && MtrrBase > RangeBase) {
1363 RangeBase = MtrrBase;
1364 }
1365 if (Base > MtrrLimit && MtrrLimit > RangeBase) {
1366 RangeBase = MtrrLimit + 1;
1367 }
1368 if (Base < MtrrBase && MtrrBase < RangeLimit) {
1369 RangeLimit = MtrrBase - 1;
1370 }
1371 if (Base < MtrrLimit && MtrrLimit <= RangeLimit) {
1372 RangeLimit = MtrrLimit;
1373 }
1374
1375 if (Base > MtrrLimit && NoRangeBase < MtrrLimit) {
1376 NoRangeBase = MtrrLimit + 1;
1377 }
1378 if (Base < MtrrBase && NoRangeLimit > MtrrBase) {
1379 NoRangeLimit = MtrrBase - 1;
1380 }
1381 }
1382
1383 if (Found) {
1384 Base = RangeLimit + 1;
1385 } else {
1386 Base = NoRangeLimit + 1;
1387 }
1388 } while (Base < Limit);
1389 DEBUG((DEBUG_CACHE, "%016lx\n\n", Base - 1));
1390 );
1391 }
1392
1393
1394 /**
1395 This function prints all MTRRs for debugging.
1396 **/
1397 VOID
1398 EFIAPI
1399 MtrrDebugPrintAllMtrrs (
1400 VOID
1401 )
1402 {
1403 MtrrDebugPrintAllMtrrsWorker (NULL);
1404 }
1405
1406 /**
1407 Update the Ranges array to change the specified range identified by
1408 BaseAddress and Length to Type.
1409
1410 @param Ranges Array holding memory type settings for all memory regions.
1411 @param Capacity The maximum count of memory ranges the array can hold.
1412 @param Count Return the new memory range count in the array.
1413 @param BaseAddress The base address of the memory range to change type.
1414 @param Length The length of the memory range to change type.
1415 @param Type The new type of the specified memory range.
1416
1417 @retval RETURN_SUCCESS The type of the specified memory range is
1418 changed successfully.
1419 @retval RETURN_OUT_OF_RESOURCES The new type set causes the count of memory
1420 range exceeds capacity.
1421 **/
1422 RETURN_STATUS
1423 MtrrLibSetMemoryType (
1424 IN MEMORY_RANGE *Ranges,
1425 IN UINT32 Capacity,
1426 IN OUT UINT32 *Count,
1427 IN UINT64 BaseAddress,
1428 IN UINT64 Length,
1429 IN MTRR_MEMORY_CACHE_TYPE Type
1430 )
1431 {
1432 UINT32 Index;
1433 UINT64 Limit;
1434 UINT64 LengthLeft;
1435 UINT64 LengthRight;
1436 UINT32 StartIndex;
1437 UINT32 EndIndex;
1438 UINT32 DeltaCount;
1439
1440 Limit = BaseAddress + Length;
1441 StartIndex = *Count;
1442 EndIndex = *Count;
1443 for (Index = 0; Index < *Count; Index++) {
1444 if ((StartIndex == *Count) &&
1445 (Ranges[Index].BaseAddress <= BaseAddress) &&
1446 (BaseAddress < Ranges[Index].BaseAddress + Ranges[Index].Length)) {
1447 StartIndex = Index;
1448 LengthLeft = BaseAddress - Ranges[Index].BaseAddress;
1449 }
1450
1451 if ((EndIndex == *Count) &&
1452 (Ranges[Index].BaseAddress < Limit) &&
1453 (Limit <= Ranges[Index].BaseAddress + Ranges[Index].Length)) {
1454 EndIndex = Index;
1455 LengthRight = Ranges[Index].BaseAddress + Ranges[Index].Length - Limit;
1456 break;
1457 }
1458 }
1459
1460 ASSERT (StartIndex != *Count && EndIndex != *Count);
1461 if (StartIndex == EndIndex && Ranges[StartIndex].Type == Type) {
1462 return RETURN_SUCCESS;
1463 }
1464
1465 //
1466 // The type change may cause merging with previous range or next range.
1467 // Update the StartIndex, EndIndex, BaseAddress, Length so that following
1468 // logic doesn't need to consider merging.
1469 //
1470 if (StartIndex != 0) {
1471 if (LengthLeft == 0 && Ranges[StartIndex - 1].Type == Type) {
1472 StartIndex--;
1473 Length += Ranges[StartIndex].Length;
1474 BaseAddress -= Ranges[StartIndex].Length;
1475 }
1476 }
1477 if (EndIndex != (*Count) - 1) {
1478 if (LengthRight == 0 && Ranges[EndIndex + 1].Type == Type) {
1479 EndIndex++;
1480 Length += Ranges[EndIndex].Length;
1481 }
1482 }
1483
1484 //
1485 // |- 0 -|- 1 -|- 2 -|- 3 -| StartIndex EndIndex DeltaCount Count (Count = 4)
1486 // |++++++++++++++++++| 0 3 1=3-0-2 3
1487 // |+++++++| 0 1 -1=1-0-2 5
1488 // |+| 0 0 -2=0-0-2 6
1489 // |+++| 0 0 -1=0-0-2+1 5
1490 //
1491 //
1492 DeltaCount = EndIndex - StartIndex - 2;
1493 if (LengthLeft == 0) {
1494 DeltaCount++;
1495 }
1496 if (LengthRight == 0) {
1497 DeltaCount++;
1498 }
1499 if (*Count - DeltaCount > Capacity) {
1500 return RETURN_OUT_OF_RESOURCES;
1501 }
1502
1503 //
1504 // Reserve (-DeltaCount) space
1505 //
1506 CopyMem (&Ranges[EndIndex + 1 - DeltaCount], &Ranges[EndIndex + 1], (*Count - EndIndex - 1) * sizeof (Ranges[0]));
1507 *Count -= DeltaCount;
1508
1509 if (LengthLeft != 0) {
1510 Ranges[StartIndex].Length = LengthLeft;
1511 StartIndex++;
1512 }
1513 if (LengthRight != 0) {
1514 Ranges[EndIndex - DeltaCount].BaseAddress = BaseAddress + Length;
1515 Ranges[EndIndex - DeltaCount].Length = LengthRight;
1516 Ranges[EndIndex - DeltaCount].Type = Ranges[EndIndex].Type;
1517 }
1518 Ranges[StartIndex].BaseAddress = BaseAddress;
1519 Ranges[StartIndex].Length = Length;
1520 Ranges[StartIndex].Type = Type;
1521 return RETURN_SUCCESS;
1522 }
1523
1524 /**
1525 Allocate one or more variable MTRR to cover the range identified by
1526 BaseAddress and Length.
1527
1528 @param Ranges Memory range array holding the memory type
1529 settings for all memory address.
1530 @param RangeCount Count of memory ranges.
1531 @param VariableMtrr Variable MTRR array.
1532 @param VariableMtrrCapacity Capacity of variable MTRR array.
1533 @param VariableMtrrCount Count of variable MTRR.
1534 @param BaseAddress Base address of the memory range.
1535 @param Length Length of the memory range.
1536 @param Type MTRR type of the memory range.
1537 @param Alignment0 Alignment of 0.
1538
1539 @retval RETURN_SUCCESS Variable MTRRs are allocated successfully.
1540 @retval RETURN_OUT_OF_RESOURCES Count of variable MTRRs exceeds capacity.
1541 **/
1542 RETURN_STATUS
1543 MtrrLibSetMemoryAttributeInVariableMtrr (
1544 IN CONST MEMORY_RANGE *Ranges,
1545 IN UINT32 RangeCount,
1546 IN OUT VARIABLE_MTRR *VariableMtrr,
1547 IN UINT32 VariableMtrrCapacity,
1548 IN OUT UINT32 *VariableMtrrCount,
1549 IN UINT64 BaseAddress,
1550 IN UINT64 Length,
1551 IN MTRR_MEMORY_CACHE_TYPE Type,
1552 IN UINT64 Alignment0
1553 );
1554
1555 /**
1556 Allocate one or more variable MTRR to cover the range identified by
1557 BaseAddress and Length.
1558
1559 The routine recursively calls MtrrLibSetMemoryAttributeInVariableMtrr()
1560 to allocate variable MTRRs when the range contains several sub-ranges
1561 with different attributes.
1562
1563 @param Ranges Memory range array holding the memory type
1564 settings for all memory address.
1565 @param RangeCount Count of memory ranges.
1566 @param VariableMtrr Variable MTRR array.
1567 @param VariableMtrrCapacity Capacity of variable MTRR array.
1568 @param VariableMtrrCount Count of variable MTRR.
1569 @param BaseAddress Base address of the memory range.
1570 @param Length Length of the memory range.
1571 @param Type MTRR type of the range.
1572 If it's CacheInvalid, the memory range may
1573 contains several sub-ranges with different
1574 attributes.
1575 @param Alignment0 Alignment of 0.
1576
1577 @retval RETURN_SUCCESS Variable MTRRs are allocated successfully.
1578 @retval RETURN_OUT_OF_RESOURCES Count of variable MTRRs exceeds capacity.
1579 **/
1580 RETURN_STATUS
1581 MtrrLibAddVariableMtrr (
1582 IN CONST MEMORY_RANGE *Ranges,
1583 IN UINT32 RangeCount,
1584 IN OUT VARIABLE_MTRR *VariableMtrr,
1585 IN UINT32 VariableMtrrCapacity,
1586 IN OUT UINT32 *VariableMtrrCount,
1587 IN PHYSICAL_ADDRESS BaseAddress,
1588 IN UINT64 Length,
1589 IN MTRR_MEMORY_CACHE_TYPE Type,
1590 IN UINT64 Alignment0
1591 )
1592 {
1593 RETURN_STATUS Status;
1594 UINT32 Index;
1595 UINT64 SubLength;
1596
1597 MTRR_LIB_ASSERT_ALIGNED (BaseAddress, Length);
1598 if (Type == CacheInvalid) {
1599 for (Index = 0; Index < RangeCount; Index++) {
1600 if (Ranges[Index].BaseAddress <= BaseAddress && BaseAddress < Ranges[Index].BaseAddress + Ranges[Index].Length) {
1601
1602 //
1603 // Because the Length may not be aligned to BaseAddress, below code calls
1604 // MtrrLibSetMemoryAttributeInVariableMtrr() instead of itself.
1605 // MtrrLibSetMemoryAttributeInVariableMtrr() splits the range to several
1606 // aligned ranges.
1607 //
1608 if (Ranges[Index].BaseAddress + Ranges[Index].Length >= BaseAddress + Length) {
1609 return MtrrLibSetMemoryAttributeInVariableMtrr (
1610 Ranges, RangeCount, VariableMtrr, VariableMtrrCapacity, VariableMtrrCount,
1611 BaseAddress, Length, Ranges[Index].Type, Alignment0
1612 );
1613 } else {
1614 SubLength = Ranges[Index].BaseAddress + Ranges[Index].Length - BaseAddress;
1615 Status = MtrrLibSetMemoryAttributeInVariableMtrr (
1616 Ranges, RangeCount, VariableMtrr, VariableMtrrCapacity, VariableMtrrCount,
1617 BaseAddress, SubLength, Ranges[Index].Type, Alignment0
1618 );
1619 if (RETURN_ERROR (Status)) {
1620 return Status;
1621 }
1622 BaseAddress += SubLength;
1623 Length -= SubLength;
1624 }
1625 }
1626 }
1627
1628 //
1629 // Because memory ranges cover all the memory addresses, it's impossible to be here.
1630 //
1631 ASSERT (FALSE);
1632 return RETURN_DEVICE_ERROR;
1633 } else {
1634 for (Index = 0; Index < *VariableMtrrCount; Index++) {
1635 if (VariableMtrr[Index].BaseAddress == BaseAddress && VariableMtrr[Index].Length == Length) {
1636 ASSERT (VariableMtrr[Index].Type == Type);
1637 break;
1638 }
1639 }
1640 if (Index == *VariableMtrrCount) {
1641 if (*VariableMtrrCount == VariableMtrrCapacity) {
1642 return RETURN_OUT_OF_RESOURCES;
1643 }
1644 VariableMtrr[Index].BaseAddress = BaseAddress;
1645 VariableMtrr[Index].Length = Length;
1646 VariableMtrr[Index].Type = Type;
1647 VariableMtrr[Index].Valid = TRUE;
1648 VariableMtrr[Index].Used = TRUE;
1649 (*VariableMtrrCount)++;
1650 }
1651 return RETURN_SUCCESS;
1652 }
1653 }
1654
1655 /**
1656 Allocate one or more variable MTRR to cover the range identified by
1657 BaseAddress and Length.
1658
1659 @param Ranges Memory range array holding the memory type
1660 settings for all memory address.
1661 @param RangeCount Count of memory ranges.
1662 @param VariableMtrr Variable MTRR array.
1663 @param VariableMtrrCapacity Capacity of variable MTRR array.
1664 @param VariableMtrrCount Count of variable MTRR.
1665 @param BaseAddress Base address of the memory range.
1666 @param Length Length of the memory range.
1667 @param Type MTRR type of the memory range.
1668 @param Alignment0 Alignment of 0.
1669
1670 @retval RETURN_SUCCESS Variable MTRRs are allocated successfully.
1671 @retval RETURN_OUT_OF_RESOURCES Count of variable MTRRs exceeds capacity.
1672 **/
1673 RETURN_STATUS
1674 MtrrLibSetMemoryAttributeInVariableMtrr (
1675 IN CONST MEMORY_RANGE *Ranges,
1676 IN UINT32 RangeCount,
1677 IN OUT VARIABLE_MTRR *VariableMtrr,
1678 IN UINT32 VariableMtrrCapacity,
1679 IN OUT UINT32 *VariableMtrrCount,
1680 IN UINT64 BaseAddress,
1681 IN UINT64 Length,
1682 IN MTRR_MEMORY_CACHE_TYPE Type,
1683 IN UINT64 Alignment0
1684 )
1685 {
1686 UINT64 Alignment;
1687 UINT32 MtrrNumber;
1688 UINT32 SubtractiveLeft;
1689 UINT32 SubtractiveRight;
1690 BOOLEAN UseLeastAlignment;
1691
1692 MtrrNumber = MtrrLibGetMtrrNumber (Ranges, RangeCount, VariableMtrr, *VariableMtrrCount,
1693 BaseAddress, Length, Type, Alignment0, &SubtractiveLeft, &SubtractiveRight);
1694
1695 if (MtrrNumber + *VariableMtrrCount > VariableMtrrCapacity) {
1696 return RETURN_OUT_OF_RESOURCES;
1697 }
1698
1699 while (SubtractiveLeft-- != 0) {
1700 Alignment = MtrrLibLeastAlignment (BaseAddress, Alignment0);
1701 ASSERT (Alignment <= Length);
1702
1703 MtrrLibAddVariableMtrr (Ranges, RangeCount, VariableMtrr, VariableMtrrCapacity, VariableMtrrCount,
1704 BaseAddress - Alignment, Alignment, CacheInvalid, Alignment0);
1705 BaseAddress -= Alignment;
1706 Length += Alignment;
1707 }
1708
1709 while (Length != 0) {
1710 Alignment = MtrrLibLeastAlignment (BaseAddress, Alignment0);
1711 if (Alignment > Length) {
1712 break;
1713 }
1714 MtrrLibAddVariableMtrr (NULL, 0, VariableMtrr, VariableMtrrCapacity, VariableMtrrCount,
1715 BaseAddress, Alignment, Type, Alignment0);
1716 BaseAddress += Alignment;
1717 Length -= Alignment;
1718 }
1719
1720 while (SubtractiveRight-- != 0) {
1721 Alignment = MtrrLibLeastAlignment (BaseAddress + Length, Alignment0);
1722 MtrrLibAddVariableMtrr (Ranges, RangeCount, VariableMtrr, VariableMtrrCapacity, VariableMtrrCount,
1723 BaseAddress + Length, Alignment, CacheInvalid, Alignment0);
1724 Length += Alignment;
1725 }
1726
1727 UseLeastAlignment = TRUE;
1728 while (Length != 0) {
1729 if (UseLeastAlignment) {
1730 Alignment = MtrrLibLeastAlignment (BaseAddress, Alignment0);
1731 if (Alignment > Length) {
1732 UseLeastAlignment = FALSE;
1733 }
1734 }
1735
1736 if (!UseLeastAlignment) {
1737 Alignment = GetPowerOfTwo64 (Length);
1738 }
1739
1740 MtrrLibAddVariableMtrr (NULL, 0, VariableMtrr, VariableMtrrCapacity, VariableMtrrCount,
1741 BaseAddress, Alignment, Type, Alignment0);
1742 BaseAddress += Alignment;
1743 Length -= Alignment;
1744 }
1745 return RETURN_SUCCESS;
1746 }
1747
1748 /**
1749 Return an array of memory ranges holding memory type settings for all memory
1750 address.
1751
1752 @param DefaultType The default memory type.
1753 @param TotalLength The total length of the memory.
1754 @param VariableMtrr The variable MTRR array.
1755 @param VariableMtrrCount The count of variable MTRRs.
1756 @param Ranges Return the memory range array holding memory type
1757 settings for all memory address.
1758 @param RangeCapacity The capacity of memory range array.
1759 @param RangeCount Return the count of memory range.
1760
1761 @retval RETURN_SUCCESS The memory range array is returned successfully.
1762 @retval RETURN_OUT_OF_RESOURCES The count of memory ranges exceeds capacity.
1763 **/
1764 RETURN_STATUS
1765 MtrrLibGetMemoryTypes (
1766 IN MTRR_MEMORY_CACHE_TYPE DefaultType,
1767 IN UINT64 TotalLength,
1768 IN CONST VARIABLE_MTRR *VariableMtrr,
1769 IN UINT32 VariableMtrrCount,
1770 OUT MEMORY_RANGE *Ranges,
1771 IN UINT32 RangeCapacity,
1772 OUT UINT32 *RangeCount
1773 )
1774 {
1775 RETURN_STATUS Status;
1776 UINTN Index;
1777
1778 //
1779 // WT > WB
1780 // UC > *
1781 // UC > * (except WB, UC) > WB
1782 //
1783
1784 //
1785 // 0. Set whole range as DefaultType
1786 //
1787 *RangeCount = 1;
1788 Ranges[0].BaseAddress = 0;
1789 Ranges[0].Length = TotalLength;
1790 Ranges[0].Type = DefaultType;
1791
1792 //
1793 // 1. Set WB
1794 //
1795 for (Index = 0; Index < VariableMtrrCount; Index++) {
1796 if (VariableMtrr[Index].Valid && VariableMtrr[Index].Type == CacheWriteBack) {
1797 Status = MtrrLibSetMemoryType (
1798 Ranges, RangeCapacity, RangeCount,
1799 VariableMtrr[Index].BaseAddress, VariableMtrr[Index].Length, (MTRR_MEMORY_CACHE_TYPE) VariableMtrr[Index].Type
1800 );
1801 if (RETURN_ERROR (Status)) {
1802 return Status;
1803 }
1804 }
1805 }
1806
1807 //
1808 // 2. Set other types than WB or UC
1809 //
1810 for (Index = 0; Index < VariableMtrrCount; Index++) {
1811 if (VariableMtrr[Index].Valid && VariableMtrr[Index].Type != CacheWriteBack && VariableMtrr[Index].Type != CacheUncacheable) {
1812 Status = MtrrLibSetMemoryType (
1813 Ranges, RangeCapacity, RangeCount,
1814 VariableMtrr[Index].BaseAddress, VariableMtrr[Index].Length, (MTRR_MEMORY_CACHE_TYPE) VariableMtrr[Index].Type
1815 );
1816 if (RETURN_ERROR (Status)) {
1817 return Status;
1818 }
1819 }
1820 }
1821
1822 //
1823 // 3. Set UC
1824 //
1825 for (Index = 0; Index < VariableMtrrCount; Index++) {
1826 if (VariableMtrr[Index].Valid && VariableMtrr[Index].Type == CacheUncacheable) {
1827 Status = MtrrLibSetMemoryType (
1828 Ranges, RangeCapacity, RangeCount,
1829 VariableMtrr[Index].BaseAddress, VariableMtrr[Index].Length, (MTRR_MEMORY_CACHE_TYPE) VariableMtrr[Index].Type
1830 );
1831 if (RETURN_ERROR (Status)) {
1832 return Status;
1833 }
1834 }
1835 }
1836 return RETURN_SUCCESS;
1837 }
1838
1839 /**
1840 Worker function attempts to set the attributes for a memory range.
1841
1842 If MtrrSetting is not NULL, set the attributes into the input MTRR
1843 settings buffer.
1844 If MtrrSetting is NULL, set the attributes into MTRRs registers.
1845
1846 @param[in, out] MtrrSetting A buffer holding all MTRRs content.
1847 @param[in] BaseAddress The physical address that is the start
1848 address of a memory range.
1849 @param[in] Length The size in bytes of the memory range.
1850 @param[in] Type The MTRR type to set for the memory range.
1851
1852 @retval RETURN_SUCCESS The attributes were set for the memory
1853 range.
1854 @retval RETURN_INVALID_PARAMETER Length is zero.
1855 @retval RETURN_UNSUPPORTED The processor does not support one or
1856 more bytes of the memory resource range
1857 specified by BaseAddress and Length.
1858 @retval RETURN_UNSUPPORTED The MTRR type is not support for the
1859 memory resource range specified
1860 by BaseAddress and Length.
1861 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to
1862 modify the attributes of the memory
1863 resource range.
1864
1865 **/
1866 RETURN_STATUS
1867 MtrrSetMemoryAttributeWorker (
1868 IN OUT MTRR_SETTINGS *MtrrSetting,
1869 IN PHYSICAL_ADDRESS BaseAddress,
1870 IN UINT64 Length,
1871 IN MTRR_MEMORY_CACHE_TYPE Type
1872 )
1873 {
1874 RETURN_STATUS Status;
1875 UINT32 Index;
1876 UINT32 WorkingIndex;
1877 //
1878 // N variable MTRRs can maximumly separate (2N + 1) Ranges, plus 1 range for [0, 1M).
1879 //
1880 MEMORY_RANGE Ranges[MTRR_NUMBER_OF_VARIABLE_MTRR * 2 + 2];
1881 UINT32 RangeCount;
1882 UINT64 MtrrValidBitsMask;
1883 UINT64 MtrrValidAddressMask;
1884 UINT64 Alignment0;
1885 MTRR_CONTEXT MtrrContext;
1886 BOOLEAN MtrrContextValid;
1887
1888 MTRR_MEMORY_CACHE_TYPE DefaultType;
1889
1890 UINT32 MsrIndex;
1891 UINT64 ClearMask;
1892 UINT64 OrMask;
1893 UINT64 NewValue;
1894 BOOLEAN FixedSettingsValid[MTRR_NUMBER_OF_FIXED_MTRR];
1895 BOOLEAN FixedSettingsModified[MTRR_NUMBER_OF_FIXED_MTRR];
1896 MTRR_FIXED_SETTINGS WorkingFixedSettings;
1897
1898 UINT32 FirmwareVariableMtrrCount;
1899 MTRR_VARIABLE_SETTINGS *VariableSettings;
1900 MTRR_VARIABLE_SETTINGS OriginalVariableSettings;
1901 UINT32 OriginalVariableMtrrCount;
1902 VARIABLE_MTRR OriginalVariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];
1903 UINT32 WorkingVariableMtrrCount;
1904 VARIABLE_MTRR WorkingVariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];
1905 BOOLEAN VariableSettingModified[MTRR_NUMBER_OF_VARIABLE_MTRR];
1906 UINTN FreeVariableMtrrCount;
1907
1908 if (Length == 0) {
1909 return RETURN_INVALID_PARAMETER;
1910 }
1911
1912 MtrrLibInitializeMtrrMask (&MtrrValidBitsMask, &MtrrValidAddressMask);
1913 if (((BaseAddress & ~MtrrValidAddressMask) != 0) || (Length & ~MtrrValidAddressMask) != 0) {
1914 return RETURN_UNSUPPORTED;
1915 }
1916
1917 ZeroMem (&WorkingFixedSettings, sizeof (WorkingFixedSettings));
1918 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
1919 FixedSettingsValid[Index] = FALSE;
1920 FixedSettingsModified[Index] = FALSE;
1921 }
1922
1923 //
1924 // Check if Fixed MTRR
1925 //
1926 if (BaseAddress < BASE_1MB) {
1927 MsrIndex = (UINT32)-1;
1928 while ((BaseAddress < BASE_1MB) && (Length != 0)) {
1929 Status = MtrrLibProgramFixedMtrr (Type, &BaseAddress, &Length, &MsrIndex, &ClearMask, &OrMask);
1930 if (RETURN_ERROR (Status)) {
1931 return Status;
1932 }
1933 if (MtrrSetting != NULL) {
1934 MtrrSetting->Fixed.Mtrr[MsrIndex] = (MtrrSetting->Fixed.Mtrr[MsrIndex] & ~ClearMask) | OrMask;
1935 ((MSR_IA32_MTRR_DEF_TYPE_REGISTER *) &MtrrSetting->MtrrDefType)->Bits.FE = 1;
1936 } else {
1937 if (!FixedSettingsValid[MsrIndex]) {
1938 WorkingFixedSettings.Mtrr[MsrIndex] = AsmReadMsr64 (mMtrrLibFixedMtrrTable[MsrIndex].Msr);
1939 FixedSettingsValid[MsrIndex] = TRUE;
1940 }
1941 NewValue = (WorkingFixedSettings.Mtrr[MsrIndex] & ~ClearMask) | OrMask;
1942 if (WorkingFixedSettings.Mtrr[MsrIndex] != NewValue) {
1943 WorkingFixedSettings.Mtrr[MsrIndex] = NewValue;
1944 FixedSettingsModified[MsrIndex] = TRUE;
1945 }
1946 }
1947 }
1948
1949 if (Length == 0) {
1950 //
1951 // A Length of 0 can only make sense for fixed MTTR ranges.
1952 // Since we just handled the fixed MTRRs, we can skip the
1953 // variable MTRR section.
1954 //
1955 goto Done;
1956 }
1957 }
1958
1959 //
1960 // Read the default MTRR type
1961 //
1962 DefaultType = MtrrGetDefaultMemoryTypeWorker (MtrrSetting);
1963
1964 //
1965 // Read all variable MTRRs and convert to Ranges.
1966 //
1967 OriginalVariableMtrrCount = GetVariableMtrrCountWorker ();
1968 if (MtrrSetting == NULL) {
1969 ZeroMem (&OriginalVariableSettings, sizeof (OriginalVariableSettings));
1970 MtrrGetVariableMtrrWorker (NULL, OriginalVariableMtrrCount, &OriginalVariableSettings);
1971 VariableSettings = &OriginalVariableSettings;
1972 } else {
1973 VariableSettings = &MtrrSetting->Variables;
1974 }
1975 MtrrGetMemoryAttributeInVariableMtrrWorker (VariableSettings, OriginalVariableMtrrCount, MtrrValidBitsMask, MtrrValidAddressMask, OriginalVariableMtrr);
1976
1977 Status = MtrrLibGetMemoryTypes (
1978 DefaultType, MtrrValidBitsMask + 1, OriginalVariableMtrr, OriginalVariableMtrrCount,
1979 Ranges, 2 * OriginalVariableMtrrCount + 1, &RangeCount
1980 );
1981 ASSERT (Status == RETURN_SUCCESS);
1982
1983 FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCountWorker ();
1984 ASSERT (RangeCount <= 2 * FirmwareVariableMtrrCount + 1);
1985
1986 //
1987 // Force [0, 1M) to UC, so that it doesn't impact left subtraction algorithm.
1988 //
1989 Status = MtrrLibSetMemoryType (Ranges, 2 * FirmwareVariableMtrrCount + 2, &RangeCount, 0, SIZE_1MB, CacheUncacheable);
1990 ASSERT (Status == RETURN_SUCCESS);
1991 //
1992 // Apply Type to [BaseAddress, BaseAddress + Length)
1993 //
1994 Status = MtrrLibSetMemoryType (Ranges, 2 * FirmwareVariableMtrrCount + 2, &RangeCount, BaseAddress, Length, Type);
1995 if (RETURN_ERROR (Status)) {
1996 return Status;
1997 }
1998
1999 Alignment0 = LShiftU64 (1, (UINTN) HighBitSet64 (MtrrValidBitsMask));
2000 WorkingVariableMtrrCount = 0;
2001 ZeroMem (&WorkingVariableMtrr, sizeof (WorkingVariableMtrr));
2002 for (Index = 0; Index < RangeCount; Index++) {
2003 if (Ranges[Index].Type != DefaultType) {
2004 //
2005 // Maximum allowed MTRR count is (FirmwareVariableMtrrCount + 1)
2006 // Because potentially the range [0, 1MB) is not merged, but can be ignored because fixed MTRR covers that
2007 //
2008 Status = MtrrLibSetMemoryAttributeInVariableMtrr (
2009 Ranges, RangeCount,
2010 WorkingVariableMtrr, FirmwareVariableMtrrCount + 1, &WorkingVariableMtrrCount,
2011 Ranges[Index].BaseAddress, Ranges[Index].Length,
2012 Ranges[Index].Type, Alignment0
2013 );
2014 if (RETURN_ERROR (Status)) {
2015 return Status;
2016 }
2017 }
2018 }
2019
2020 //
2021 // Remove the [0, 1MB) MTRR if it still exists (not merged with other range)
2022 //
2023 if (WorkingVariableMtrr[0].BaseAddress == 0 && WorkingVariableMtrr[0].Length == SIZE_1MB) {
2024 ASSERT (WorkingVariableMtrr[0].Type == CacheUncacheable);
2025 WorkingVariableMtrrCount--;
2026 CopyMem (&WorkingVariableMtrr[0], &WorkingVariableMtrr[1], WorkingVariableMtrrCount * sizeof (VARIABLE_MTRR));
2027 }
2028
2029 if (WorkingVariableMtrrCount > FirmwareVariableMtrrCount) {
2030 return RETURN_OUT_OF_RESOURCES;
2031 }
2032
2033 for (Index = 0; Index < OriginalVariableMtrrCount; Index++) {
2034 VariableSettingModified[Index] = FALSE;
2035
2036 if (!OriginalVariableMtrr[Index].Valid) {
2037 continue;
2038 }
2039 for (WorkingIndex = 0; WorkingIndex < WorkingVariableMtrrCount; WorkingIndex++) {
2040 if (OriginalVariableMtrr[Index].BaseAddress == WorkingVariableMtrr[WorkingIndex].BaseAddress &&
2041 OriginalVariableMtrr[Index].Length == WorkingVariableMtrr[WorkingIndex].Length &&
2042 OriginalVariableMtrr[Index].Type == WorkingVariableMtrr[WorkingIndex].Type) {
2043 break;
2044 }
2045 }
2046
2047 if (WorkingIndex == WorkingVariableMtrrCount) {
2048 //
2049 // Remove the one from OriginalVariableMtrr which is not in WorkingVariableMtrr
2050 //
2051 OriginalVariableMtrr[Index].Valid = FALSE;
2052 VariableSettingModified[Index] = TRUE;
2053 } else {
2054 //
2055 // Remove the one from WorkingVariableMtrr which is also in OriginalVariableMtrr
2056 //
2057 WorkingVariableMtrr[WorkingIndex].Valid = FALSE;
2058 }
2059 //
2060 // The above two operations cause that valid MTRR only exists in either OriginalVariableMtrr or WorkingVariableMtrr.
2061 //
2062 }
2063
2064 //
2065 // Merge remaining MTRRs from WorkingVariableMtrr to OriginalVariableMtrr
2066 //
2067 for (FreeVariableMtrrCount = 0, WorkingIndex = 0, Index = 0; Index < OriginalVariableMtrrCount; Index++) {
2068 if (!OriginalVariableMtrr[Index].Valid) {
2069 for (; WorkingIndex < WorkingVariableMtrrCount; WorkingIndex++) {
2070 if (WorkingVariableMtrr[WorkingIndex].Valid) {
2071 break;
2072 }
2073 }
2074 if (WorkingIndex == WorkingVariableMtrrCount) {
2075 FreeVariableMtrrCount++;
2076 } else {
2077 CopyMem (&OriginalVariableMtrr[Index], &WorkingVariableMtrr[WorkingIndex], sizeof (VARIABLE_MTRR));
2078 VariableSettingModified[Index] = TRUE;
2079 WorkingIndex++;
2080 }
2081 }
2082 }
2083 ASSERT (OriginalVariableMtrrCount - FreeVariableMtrrCount <= FirmwareVariableMtrrCount);
2084
2085 //
2086 // Move MTRRs after the FirmwraeVariableMtrrCount position to beginning
2087 //
2088 WorkingIndex = FirmwareVariableMtrrCount;
2089 for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) {
2090 if (!OriginalVariableMtrr[Index].Valid) {
2091 //
2092 // Found an empty MTRR in WorkingIndex position
2093 //
2094 for (; WorkingIndex < OriginalVariableMtrrCount; WorkingIndex++) {
2095 if (OriginalVariableMtrr[WorkingIndex].Valid) {
2096 break;
2097 }
2098 }
2099
2100 if (WorkingIndex != OriginalVariableMtrrCount) {
2101 CopyMem (&OriginalVariableMtrr[Index], &OriginalVariableMtrr[WorkingIndex], sizeof (VARIABLE_MTRR));
2102 VariableSettingModified[Index] = TRUE;
2103 VariableSettingModified[WorkingIndex] = TRUE;
2104 OriginalVariableMtrr[WorkingIndex].Valid = FALSE;
2105 }
2106 }
2107 }
2108
2109 //
2110 // Convert OriginalVariableMtrr to VariableSettings
2111 // NOTE: MTRR from FirmwareVariableMtrr to OriginalVariableMtrr need to update as well.
2112 //
2113 for (Index = 0; Index < OriginalVariableMtrrCount; Index++) {
2114 if (VariableSettingModified[Index]) {
2115 if (OriginalVariableMtrr[Index].Valid) {
2116 VariableSettings->Mtrr[Index].Base = (OriginalVariableMtrr[Index].BaseAddress & MtrrValidAddressMask) | (UINT8) OriginalVariableMtrr[Index].Type;
2117 VariableSettings->Mtrr[Index].Mask = (~(OriginalVariableMtrr[Index].Length - 1)) & MtrrValidAddressMask | BIT11;
2118 } else {
2119 VariableSettings->Mtrr[Index].Base = 0;
2120 VariableSettings->Mtrr[Index].Mask = 0;
2121 }
2122 }
2123 }
2124
2125 Done:
2126 if (MtrrSetting != NULL) {
2127 ((MSR_IA32_MTRR_DEF_TYPE_REGISTER *) &MtrrSetting->MtrrDefType)->Bits.E = 1;
2128 return RETURN_SUCCESS;
2129 }
2130
2131 MtrrContextValid = FALSE;
2132 //
2133 // Write fixed MTRRs that have been modified
2134 //
2135 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
2136 if (FixedSettingsModified[Index]) {
2137 if (!MtrrContextValid) {
2138 MtrrLibPreMtrrChange (&MtrrContext);
2139 MtrrContextValid = TRUE;
2140 }
2141 AsmWriteMsr64 (
2142 mMtrrLibFixedMtrrTable[Index].Msr,
2143 WorkingFixedSettings.Mtrr[Index]
2144 );
2145 }
2146 }
2147
2148 //
2149 // Write variable MTRRs
2150 //
2151 for (Index = 0; Index < OriginalVariableMtrrCount; Index++) {
2152 if (VariableSettingModified[Index]) {
2153 if (!MtrrContextValid) {
2154 MtrrLibPreMtrrChange (&MtrrContext);
2155 MtrrContextValid = TRUE;
2156 }
2157 AsmWriteMsr64 (
2158 MSR_IA32_MTRR_PHYSBASE0 + (Index << 1),
2159 VariableSettings->Mtrr[Index].Base
2160 );
2161 AsmWriteMsr64 (
2162 MSR_IA32_MTRR_PHYSMASK0 + (Index << 1),
2163 VariableSettings->Mtrr[Index].Mask
2164 );
2165 }
2166 }
2167 if (MtrrContextValid) {
2168 MtrrLibPostMtrrChange (&MtrrContext);
2169 }
2170
2171 return Status;
2172 }
2173
2174 /**
2175 This function attempts to set the attributes for a memory range.
2176
2177 @param[in] BaseAddress The physical address that is the start
2178 address of a memory range.
2179 @param[in] Length The size in bytes of the memory range.
2180 @param[in] Attributes The bit mask of attributes to set for the
2181 memory range.
2182
2183 @retval RETURN_SUCCESS The attributes were set for the memory
2184 range.
2185 @retval RETURN_INVALID_PARAMETER Length is zero.
2186 @retval RETURN_UNSUPPORTED The processor does not support one or
2187 more bytes of the memory resource range
2188 specified by BaseAddress and Length.
2189 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support
2190 for the memory resource range specified
2191 by BaseAddress and Length.
2192 @retval RETURN_ACCESS_DENIED The attributes for the memory resource
2193 range specified by BaseAddress and Length
2194 cannot be modified.
2195 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to
2196 modify the attributes of the memory
2197 resource range.
2198
2199 **/
2200 RETURN_STATUS
2201 EFIAPI
2202 MtrrSetMemoryAttribute (
2203 IN PHYSICAL_ADDRESS BaseAddress,
2204 IN UINT64 Length,
2205 IN MTRR_MEMORY_CACHE_TYPE Attribute
2206 )
2207 {
2208 RETURN_STATUS Status;
2209
2210 if (!IsMtrrSupported ()) {
2211 return RETURN_UNSUPPORTED;
2212 }
2213
2214 Status = MtrrSetMemoryAttributeWorker (NULL, BaseAddress, Length, Attribute);
2215 DEBUG ((DEBUG_CACHE, "MtrrSetMemoryAttribute() %a: [%016lx, %016lx) - %r\n",
2216 mMtrrMemoryCacheTypeShortName[Attribute], BaseAddress, BaseAddress + Length, Status));
2217
2218 if (!RETURN_ERROR (Status)) {
2219 MtrrDebugPrintAllMtrrsWorker (NULL);
2220 }
2221 return Status;
2222 }
2223
2224 /**
2225 This function attempts to set the attributes into MTRR setting buffer for a memory range.
2226
2227 @param[in, out] MtrrSetting MTRR setting buffer to be set.
2228 @param[in] BaseAddress The physical address that is the start address
2229 of a memory range.
2230 @param[in] Length The size in bytes of the memory range.
2231 @param[in] Attribute The bit mask of attributes to set for the
2232 memory range.
2233
2234 @retval RETURN_SUCCESS The attributes were set for the memory range.
2235 @retval RETURN_INVALID_PARAMETER Length is zero.
2236 @retval RETURN_UNSUPPORTED The processor does not support one or more bytes of the
2237 memory resource range specified by BaseAddress and Length.
2238 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support for the memory resource
2239 range specified by BaseAddress and Length.
2240 @retval RETURN_ACCESS_DENIED The attributes for the memory resource range specified by
2241 BaseAddress and Length cannot be modified.
2242 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
2243 the memory resource range.
2244
2245 **/
2246 RETURN_STATUS
2247 EFIAPI
2248 MtrrSetMemoryAttributeInMtrrSettings (
2249 IN OUT MTRR_SETTINGS *MtrrSetting,
2250 IN PHYSICAL_ADDRESS BaseAddress,
2251 IN UINT64 Length,
2252 IN MTRR_MEMORY_CACHE_TYPE Attribute
2253 )
2254 {
2255 RETURN_STATUS Status;
2256 Status = MtrrSetMemoryAttributeWorker (MtrrSetting, BaseAddress, Length, Attribute);
2257 DEBUG((DEBUG_CACHE, "MtrrSetMemoryAttributeMtrrSettings(%p) %a: [%016lx, %016lx) - %r\n",
2258 MtrrSetting, mMtrrMemoryCacheTypeShortName[Attribute], BaseAddress, BaseAddress + Length, Status));
2259
2260 if (!RETURN_ERROR (Status)) {
2261 MtrrDebugPrintAllMtrrsWorker (MtrrSetting);
2262 }
2263
2264 return Status;
2265 }
2266
2267 /**
2268 Worker function setting variable MTRRs
2269
2270 @param[in] VariableSettings A buffer to hold variable MTRRs content.
2271
2272 **/
2273 VOID
2274 MtrrSetVariableMtrrWorker (
2275 IN MTRR_VARIABLE_SETTINGS *VariableSettings
2276 )
2277 {
2278 UINT32 Index;
2279 UINT32 VariableMtrrCount;
2280
2281 VariableMtrrCount = GetVariableMtrrCountWorker ();
2282 ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);
2283
2284 for (Index = 0; Index < VariableMtrrCount; Index++) {
2285 AsmWriteMsr64 (
2286 MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1),
2287 VariableSettings->Mtrr[Index].Base
2288 );
2289 AsmWriteMsr64 (
2290 MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1) + 1,
2291 VariableSettings->Mtrr[Index].Mask
2292 );
2293 }
2294 }
2295
2296
2297 /**
2298 This function sets variable MTRRs
2299
2300 @param[in] VariableSettings A buffer to hold variable MTRRs content.
2301
2302 @return The pointer of VariableSettings
2303
2304 **/
2305 MTRR_VARIABLE_SETTINGS*
2306 EFIAPI
2307 MtrrSetVariableMtrr (
2308 IN MTRR_VARIABLE_SETTINGS *VariableSettings
2309 )
2310 {
2311 MTRR_CONTEXT MtrrContext;
2312
2313 if (!IsMtrrSupported ()) {
2314 return VariableSettings;
2315 }
2316
2317 MtrrLibPreMtrrChange (&MtrrContext);
2318 MtrrSetVariableMtrrWorker (VariableSettings);
2319 MtrrLibPostMtrrChange (&MtrrContext);
2320 MtrrDebugPrintAllMtrrs ();
2321
2322 return VariableSettings;
2323 }
2324
2325 /**
2326 Worker function setting fixed MTRRs
2327
2328 @param[in] FixedSettings A buffer to hold fixed MTRRs content.
2329
2330 **/
2331 VOID
2332 MtrrSetFixedMtrrWorker (
2333 IN MTRR_FIXED_SETTINGS *FixedSettings
2334 )
2335 {
2336 UINT32 Index;
2337
2338 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
2339 AsmWriteMsr64 (
2340 mMtrrLibFixedMtrrTable[Index].Msr,
2341 FixedSettings->Mtrr[Index]
2342 );
2343 }
2344 }
2345
2346
2347 /**
2348 This function sets fixed MTRRs
2349
2350 @param[in] FixedSettings A buffer to hold fixed MTRRs content.
2351
2352 @retval The pointer of FixedSettings
2353
2354 **/
2355 MTRR_FIXED_SETTINGS*
2356 EFIAPI
2357 MtrrSetFixedMtrr (
2358 IN MTRR_FIXED_SETTINGS *FixedSettings
2359 )
2360 {
2361 MTRR_CONTEXT MtrrContext;
2362
2363 if (!IsMtrrSupported ()) {
2364 return FixedSettings;
2365 }
2366
2367 MtrrLibPreMtrrChange (&MtrrContext);
2368 MtrrSetFixedMtrrWorker (FixedSettings);
2369 MtrrLibPostMtrrChange (&MtrrContext);
2370 MtrrDebugPrintAllMtrrs ();
2371
2372 return FixedSettings;
2373 }
2374
2375
2376 /**
2377 This function gets the content in all MTRRs (variable and fixed)
2378
2379 @param[out] MtrrSetting A buffer to hold all MTRRs content.
2380
2381 @retval the pointer of MtrrSetting
2382
2383 **/
2384 MTRR_SETTINGS *
2385 EFIAPI
2386 MtrrGetAllMtrrs (
2387 OUT MTRR_SETTINGS *MtrrSetting
2388 )
2389 {
2390 if (!IsMtrrSupported ()) {
2391 return MtrrSetting;
2392 }
2393
2394 //
2395 // Get fixed MTRRs
2396 //
2397 MtrrGetFixedMtrrWorker (&MtrrSetting->Fixed);
2398
2399 //
2400 // Get variable MTRRs
2401 //
2402 MtrrGetVariableMtrrWorker (
2403 NULL,
2404 GetVariableMtrrCountWorker (),
2405 &MtrrSetting->Variables
2406 );
2407
2408 //
2409 // Get MTRR_DEF_TYPE value
2410 //
2411 MtrrSetting->MtrrDefType = AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE);
2412
2413 return MtrrSetting;
2414 }
2415
2416
2417 /**
2418 This function sets all MTRRs (variable and fixed)
2419
2420 @param[in] MtrrSetting A buffer holding all MTRRs content.
2421
2422 @retval The pointer of MtrrSetting
2423
2424 **/
2425 MTRR_SETTINGS *
2426 EFIAPI
2427 MtrrSetAllMtrrs (
2428 IN MTRR_SETTINGS *MtrrSetting
2429 )
2430 {
2431 MTRR_CONTEXT MtrrContext;
2432
2433 if (!IsMtrrSupported ()) {
2434 return MtrrSetting;
2435 }
2436
2437 MtrrLibPreMtrrChange (&MtrrContext);
2438
2439 //
2440 // Set fixed MTRRs
2441 //
2442 MtrrSetFixedMtrrWorker (&MtrrSetting->Fixed);
2443
2444 //
2445 // Set variable MTRRs
2446 //
2447 MtrrSetVariableMtrrWorker (&MtrrSetting->Variables);
2448
2449 //
2450 // Set MTRR_DEF_TYPE value
2451 //
2452 AsmWriteMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE, MtrrSetting->MtrrDefType);
2453
2454 MtrrLibPostMtrrChangeEnableCache (&MtrrContext);
2455
2456 return MtrrSetting;
2457 }
2458
2459
2460 /**
2461 Checks if MTRR is supported.
2462
2463 @retval TRUE MTRR is supported.
2464 @retval FALSE MTRR is not supported.
2465
2466 **/
2467 BOOLEAN
2468 EFIAPI
2469 IsMtrrSupported (
2470 VOID
2471 )
2472 {
2473 CPUID_VERSION_INFO_EDX Edx;
2474 MSR_IA32_MTRRCAP_REGISTER MtrrCap;
2475
2476 //
2477 // Check CPUID(1).EDX[12] for MTRR capability
2478 //
2479 AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &Edx.Uint32);
2480 if (Edx.Bits.MTRR == 0) {
2481 return FALSE;
2482 }
2483
2484 //
2485 // Check number of variable MTRRs and fixed MTRRs existence.
2486 // If number of variable MTRRs is zero, or fixed MTRRs do not
2487 // exist, return false.
2488 //
2489 MtrrCap.Uint64 = AsmReadMsr64 (MSR_IA32_MTRRCAP);
2490 if ((MtrrCap.Bits.VCNT == 0) || (MtrrCap.Bits.FIX == 0)) {
2491 return FALSE;
2492 }
2493 return TRUE;
2494 }
2495