]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/Library/MtrrLib/MtrrLib.c
Remove extra {} inside DEBUG_CODE() macro
[mirror_edk2.git] / UefiCpuPkg / Library / MtrrLib / MtrrLib.c
1 /** @file
2 MTRR setting library
3
4 Copyright (c) 2008 - 2011, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include <Base.h>
16
17 #include <Library/MtrrLib.h>
18 #include <Library/BaseLib.h>
19 #include <Library/CpuLib.h>
20 #include <Library/BaseMemoryLib.h>
21 #include <Library/DebugLib.h>
22
23 //
24 // This table defines the offset, base and length of the fixed MTRRs
25 //
26 CONST FIXED_MTRR mMtrrLibFixedMtrrTable[] = {
27 {
28 MTRR_LIB_IA32_MTRR_FIX64K_00000,
29 0,
30 SIZE_64KB
31 },
32 {
33 MTRR_LIB_IA32_MTRR_FIX16K_80000,
34 0x80000,
35 SIZE_16KB
36 },
37 {
38 MTRR_LIB_IA32_MTRR_FIX16K_A0000,
39 0xA0000,
40 SIZE_16KB
41 },
42 {
43 MTRR_LIB_IA32_MTRR_FIX4K_C0000,
44 0xC0000,
45 SIZE_4KB
46 },
47 {
48 MTRR_LIB_IA32_MTRR_FIX4K_C8000,
49 0xC8000,
50 SIZE_4KB
51 },
52 {
53 MTRR_LIB_IA32_MTRR_FIX4K_D0000,
54 0xD0000,
55 SIZE_4KB
56 },
57 {
58 MTRR_LIB_IA32_MTRR_FIX4K_D8000,
59 0xD8000,
60 SIZE_4KB
61 },
62 {
63 MTRR_LIB_IA32_MTRR_FIX4K_E0000,
64 0xE0000,
65 SIZE_4KB
66 },
67 {
68 MTRR_LIB_IA32_MTRR_FIX4K_E8000,
69 0xE8000,
70 SIZE_4KB
71 },
72 {
73 MTRR_LIB_IA32_MTRR_FIX4K_F0000,
74 0xF0000,
75 SIZE_4KB
76 },
77 {
78 MTRR_LIB_IA32_MTRR_FIX4K_F8000,
79 0xF8000,
80 SIZE_4KB
81 },
82 };
83
84 //
85 // Lookup table used to print MTRRs
86 //
87 GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 *mMtrrMemoryCacheTypeShortName[] = {
88 "UC", // CacheUncacheable
89 "WC", // CacheWriteCombining
90 "R*", // Invalid
91 "R*", // Invalid
92 "WT", // CacheWriteThrough
93 "WP", // CacheWriteProtected
94 "WB", // CacheWriteBack
95 "R*" // Invalid
96 };
97
98 /**
99 Returns the variable MTRR count for the CPU.
100
101 @return Variable MTRR count
102
103 **/
104 UINT32
105 EFIAPI
106 GetVariableMtrrCount (
107 VOID
108 )
109 {
110 UINT32 VariableMtrrCount;
111
112 if (!IsMtrrSupported ()) {
113 return 0;
114 }
115
116 VariableMtrrCount = (UINT32)(AsmReadMsr64 (MTRR_LIB_IA32_MTRR_CAP) & MTRR_LIB_IA32_MTRR_CAP_VCNT_MASK);
117 ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);
118
119 return VariableMtrrCount;
120 }
121
122 /**
123 Returns the firmware usable variable MTRR count for the CPU.
124
125 @return Firmware usable variable MTRR count
126
127 **/
128 UINT32
129 EFIAPI
130 GetFirmwareVariableMtrrCount (
131 VOID
132 )
133 {
134 UINT32 VariableMtrrCount;
135
136 VariableMtrrCount = GetVariableMtrrCount ();
137 if (VariableMtrrCount < RESERVED_FIRMWARE_VARIABLE_MTRR_NUMBER) {
138 return 0;
139 }
140
141 return VariableMtrrCount - RESERVED_FIRMWARE_VARIABLE_MTRR_NUMBER;
142 }
143
144 /**
145 Returns the default MTRR cache type for the system.
146
147 @return MTRR default type
148
149 **/
150 UINT64
151 GetMtrrDefaultMemoryType (
152 VOID
153 )
154 {
155 return (AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE) & 0xff);
156 }
157
158
159 /**
160 Preparation before programming MTRR.
161
162 This function will do some preparation for programming MTRRs:
163 disable cache, invalid cache and disable MTRR caching functionality
164
165 @return CR4 value before changing.
166
167 **/
168 UINTN
169 PreMtrrChange (
170 VOID
171 )
172 {
173 UINTN Value;
174
175 //
176 // Enter no fill cache mode, CD=1(Bit30), NW=0 (Bit29)
177 //
178 AsmDisableCache ();
179
180 //
181 // Save original CR4 value and clear PGE flag (Bit 7)
182 //
183 Value = AsmReadCr4 ();
184 AsmWriteCr4 (Value & (~BIT7));
185
186 //
187 // Flush all TLBs
188 //
189 CpuFlushTlb ();
190
191 //
192 // Disable Mtrrs
193 //
194 AsmMsrBitFieldWrite64 (MTRR_LIB_IA32_MTRR_DEF_TYPE, 10, 11, 0);
195
196 //
197 // Return original CR4 value
198 //
199 return Value;
200 }
201
202
203 /**
204 Cleaning up after programming MTRRs.
205
206 This function will do some clean up after programming MTRRs:
207 enable MTRR caching functionality, and enable cache
208
209 @param Cr4 CR4 value to restore
210
211 **/
212 VOID
213 PostMtrrChange (
214 UINTN Cr4
215 )
216 {
217 //
218 // Enable Cache MTRR
219 //
220 AsmMsrBitFieldWrite64 (MTRR_LIB_IA32_MTRR_DEF_TYPE, 10, 11, 3);
221
222 //
223 // Flush all TLBs
224 //
225 CpuFlushTlb ();
226
227 //
228 // Enable Normal Mode caching CD=NW=0, CD(Bit30), NW(Bit29)
229 //
230 AsmEnableCache ();
231
232 //
233 // Restore original CR4 value
234 //
235 AsmWriteCr4 (Cr4);
236 }
237
238
239 /**
240 Programs fixed MTRRs registers.
241
242 @param MemoryCacheType The memory type to set.
243 @param Base The base address of memory range.
244 @param Length The length of memory range.
245
246 @retval RETURN_SUCCESS The cache type was updated successfully
247 @retval RETURN_UNSUPPORTED The requested range or cache type was invalid
248 for the fixed MTRRs.
249
250 **/
251 RETURN_STATUS
252 ProgramFixedMtrr (
253 IN UINT64 MemoryCacheType,
254 IN OUT UINT64 *Base,
255 IN OUT UINT64 *Length
256 )
257 {
258 UINT32 MsrNum;
259 UINT32 ByteShift;
260 UINT64 TempQword;
261 UINT64 OrMask;
262 UINT64 ClearMask;
263
264 TempQword = 0;
265 OrMask = 0;
266 ClearMask = 0;
267
268 for (MsrNum = 0; MsrNum < MTRR_NUMBER_OF_FIXED_MTRR; MsrNum++) {
269 if ((*Base >= mMtrrLibFixedMtrrTable[MsrNum].BaseAddress) &&
270 (*Base <
271 (
272 mMtrrLibFixedMtrrTable[MsrNum].BaseAddress +
273 (8 * mMtrrLibFixedMtrrTable[MsrNum].Length)
274 )
275 )
276 ) {
277 break;
278 }
279 }
280
281 if (MsrNum == MTRR_NUMBER_OF_FIXED_MTRR) {
282 return RETURN_UNSUPPORTED;
283 }
284
285 //
286 // We found the fixed MTRR to be programmed
287 //
288 for (ByteShift = 0; ByteShift < 8; ByteShift++) {
289 if (*Base ==
290 (
291 mMtrrLibFixedMtrrTable[MsrNum].BaseAddress +
292 (ByteShift * mMtrrLibFixedMtrrTable[MsrNum].Length)
293 )
294 ) {
295 break;
296 }
297 }
298
299 if (ByteShift == 8) {
300 return RETURN_UNSUPPORTED;
301 }
302
303 for (
304 ;
305 ((ByteShift < 8) && (*Length >= mMtrrLibFixedMtrrTable[MsrNum].Length));
306 ByteShift++
307 ) {
308 OrMask |= LShiftU64 ((UINT64) MemoryCacheType, (UINT32) (ByteShift * 8));
309 ClearMask |= LShiftU64 ((UINT64) 0xFF, (UINT32) (ByteShift * 8));
310 *Length -= mMtrrLibFixedMtrrTable[MsrNum].Length;
311 *Base += mMtrrLibFixedMtrrTable[MsrNum].Length;
312 }
313
314 if (ByteShift < 8 && (*Length != 0)) {
315 return RETURN_UNSUPPORTED;
316 }
317
318 TempQword =
319 (AsmReadMsr64 (mMtrrLibFixedMtrrTable[MsrNum].Msr) & ~ClearMask) | OrMask;
320 AsmWriteMsr64 (mMtrrLibFixedMtrrTable[MsrNum].Msr, TempQword);
321 return RETURN_SUCCESS;
322 }
323
324
325 /**
326 Get the attribute of variable MTRRs.
327
328 This function shadows the content of variable MTRRs into an
329 internal array: VariableMtrr.
330
331 @param MtrrValidBitsMask The mask for the valid bit of the MTRR
332 @param MtrrValidAddressMask The valid address mask for MTRR
333 @param VariableMtrr The array to shadow variable MTRRs content
334
335 @return The return value of this paramter indicates the
336 number of MTRRs which has been used.
337
338 **/
339 UINT32
340 EFIAPI
341 MtrrGetMemoryAttributeInVariableMtrr (
342 IN UINT64 MtrrValidBitsMask,
343 IN UINT64 MtrrValidAddressMask,
344 OUT VARIABLE_MTRR *VariableMtrr
345 )
346 {
347 UINTN Index;
348 UINT32 MsrNum;
349 UINT32 UsedMtrr;
350 UINT32 FirmwareVariableMtrrCount;
351 UINT32 VariableMtrrEnd;
352
353 if (!IsMtrrSupported ()) {
354 return 0;
355 }
356
357 FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCount ();
358 VariableMtrrEnd = MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (2 * GetVariableMtrrCount ()) - 1;
359
360 ZeroMem (VariableMtrr, sizeof (VARIABLE_MTRR) * MTRR_NUMBER_OF_VARIABLE_MTRR);
361 UsedMtrr = 0;
362
363 for (MsrNum = MTRR_LIB_IA32_VARIABLE_MTRR_BASE, Index = 0;
364 (
365 (MsrNum < VariableMtrrEnd) &&
366 (Index < FirmwareVariableMtrrCount)
367 );
368 MsrNum += 2
369 ) {
370 if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) != 0) {
371 VariableMtrr[Index].Msr = MsrNum;
372 VariableMtrr[Index].BaseAddress = (AsmReadMsr64 (MsrNum) &
373 MtrrValidAddressMask);
374 VariableMtrr[Index].Length = ((~(AsmReadMsr64 (MsrNum + 1) &
375 MtrrValidAddressMask)
376 ) &
377 MtrrValidBitsMask
378 ) + 1;
379 VariableMtrr[Index].Type = (AsmReadMsr64 (MsrNum) & 0x0ff);
380 VariableMtrr[Index].Valid = TRUE;
381 VariableMtrr[Index].Used = TRUE;
382 UsedMtrr = UsedMtrr + 1;
383 Index++;
384 }
385 }
386 return UsedMtrr;
387 }
388
389
390 /**
391 Checks overlap between given memory range and MTRRs.
392
393 @param Start The start address of memory range.
394 @param End The end address of memory range.
395 @param VariableMtrr The array to shadow variable MTRRs content
396
397 @retval TRUE Overlap exists.
398 @retval FALSE No overlap.
399
400 **/
401 BOOLEAN
402 CheckMemoryAttributeOverlap (
403 IN PHYSICAL_ADDRESS Start,
404 IN PHYSICAL_ADDRESS End,
405 IN VARIABLE_MTRR *VariableMtrr
406 )
407 {
408 UINT32 Index;
409
410 for (Index = 0; Index < 6; Index++) {
411 if (
412 VariableMtrr[Index].Valid &&
413 !(
414 (Start > (VariableMtrr[Index].BaseAddress +
415 VariableMtrr[Index].Length - 1)
416 ) ||
417 (End < VariableMtrr[Index].BaseAddress)
418 )
419 ) {
420 return TRUE;
421 }
422 }
423
424 return FALSE;
425 }
426
427
428 /**
429 Marks a variable MTRR as non-valid.
430
431 @param Index The index of the array VariableMtrr to be invalidated
432 @param VariableMtrr The array to shadow variable MTRRs content
433 @param UsedMtrr The number of MTRRs which has already been used
434
435 **/
436 VOID
437 InvalidateShadowMtrr (
438 IN UINTN Index,
439 IN VARIABLE_MTRR *VariableMtrr,
440 OUT UINT32 *UsedMtrr
441 )
442 {
443 VariableMtrr[Index].Valid = FALSE;
444 *UsedMtrr = *UsedMtrr - 1;
445 }
446
447
448 /**
449 Combine memory attributes.
450
451 If overlap exists between given memory range and MTRRs, try to combine them.
452
453 @param Attributes The memory type to set.
454 @param Base The base address of memory range.
455 @param Length The length of memory range.
456 @param VariableMtrr The array to shadow variable MTRRs content
457 @param UsedMtrr The number of MTRRs which has already been used
458 @param OverwriteExistingMtrr Returns whether an existing MTRR was used
459
460 @retval EFI_SUCCESS Memory region successfully combined.
461 @retval EFI_ACCESS_DENIED Memory region cannot be combined.
462
463 **/
464 RETURN_STATUS
465 CombineMemoryAttribute (
466 IN UINT64 Attributes,
467 IN OUT UINT64 *Base,
468 IN OUT UINT64 *Length,
469 IN VARIABLE_MTRR *VariableMtrr,
470 IN OUT UINT32 *UsedMtrr,
471 OUT BOOLEAN *OverwriteExistingMtrr
472 )
473 {
474 UINT32 Index;
475 UINT64 CombineStart;
476 UINT64 CombineEnd;
477 UINT64 MtrrEnd;
478 UINT64 EndAddress;
479 UINT32 FirmwareVariableMtrrCount;
480
481 FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCount ();
482
483 *OverwriteExistingMtrr = FALSE;
484 EndAddress = *Base +*Length - 1;
485
486 for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) {
487
488 MtrrEnd = VariableMtrr[Index].BaseAddress + VariableMtrr[Index].Length - 1;
489 if (
490 !VariableMtrr[Index].Valid ||
491 (
492 *Base > (MtrrEnd) ||
493 (EndAddress < VariableMtrr[Index].BaseAddress)
494 )
495 ) {
496 continue;
497 }
498
499 //
500 // Combine same attribute MTRR range
501 //
502 if (Attributes == VariableMtrr[Index].Type) {
503 //
504 // if the Mtrr range contain the request range, return RETURN_SUCCESS
505 //
506 if (VariableMtrr[Index].BaseAddress <= *Base && MtrrEnd >= EndAddress) {
507 *Length = 0;
508 return RETURN_SUCCESS;
509 }
510 //
511 // invalid this MTRR, and program the combine range
512 //
513 CombineStart =
514 (*Base) < VariableMtrr[Index].BaseAddress ?
515 (*Base) :
516 VariableMtrr[Index].BaseAddress;
517 CombineEnd = EndAddress > MtrrEnd ? EndAddress : MtrrEnd;
518
519 //
520 // Record the MTRR usage status in VariableMtrr array.
521 //
522 InvalidateShadowMtrr (Index, VariableMtrr, UsedMtrr);
523 *Base = CombineStart;
524 *Length = CombineEnd - CombineStart + 1;
525 EndAddress = CombineEnd;
526 *OverwriteExistingMtrr = TRUE;
527 continue;
528 } else {
529 //
530 // The cache type is different, but the range is convered by one MTRR
531 //
532 if (VariableMtrr[Index].BaseAddress == *Base && MtrrEnd == EndAddress) {
533 InvalidateShadowMtrr (Index, VariableMtrr, UsedMtrr);
534 continue;
535 }
536
537 }
538
539 if ((Attributes== MTRR_CACHE_WRITE_THROUGH &&
540 VariableMtrr[Index].Type == MTRR_CACHE_WRITE_BACK) ||
541 (Attributes == MTRR_CACHE_WRITE_BACK &&
542 VariableMtrr[Index].Type == MTRR_CACHE_WRITE_THROUGH) ||
543 (Attributes == MTRR_CACHE_UNCACHEABLE) ||
544 (VariableMtrr[Index].Type == MTRR_CACHE_UNCACHEABLE)
545 ) {
546 *OverwriteExistingMtrr = TRUE;
547 continue;
548 }
549 //
550 // Other type memory overlap is invalid
551 //
552 return RETURN_ACCESS_DENIED;
553 }
554
555 return RETURN_SUCCESS;
556 }
557
558
559 /**
560 Calculate the maximum value which is a power of 2, but less the MemoryLength.
561
562 @param MemoryLength The number to pass in.
563 @return The maximum value which is align to power of 2 and less the MemoryLength
564
565 **/
566 UINT64
567 Power2MaxMemory (
568 IN UINT64 MemoryLength
569 )
570 {
571 UINT64 Result;
572
573 if (RShiftU64 (MemoryLength, 32) != 0) {
574 Result = LShiftU64 (
575 (UINT64) GetPowerOfTwo32 (
576 (UINT32) RShiftU64 (MemoryLength, 32)
577 ),
578 32
579 );
580 } else {
581 Result = (UINT64) GetPowerOfTwo32 ((UINT32) MemoryLength);
582 }
583
584 return Result;
585 }
586
587
588 /**
589 Check the direction to program variable MTRRs.
590
591 This function determines which direction of programming the variable
592 MTRRs will use fewer MTRRs.
593
594 @param Input Length of Memory to program MTRR
595 @param MtrrNumber Pointer to the number of necessary MTRRs
596
597 @retval TRUE Positive direction is better.
598 FALSE Negtive direction is better.
599
600 **/
601 BOOLEAN
602 GetDirection (
603 IN UINT64 Input,
604 IN UINTN *MtrrNumber
605 )
606 {
607 UINT64 TempQword;
608 UINT32 Positive;
609 UINT32 Subtractive;
610
611 TempQword = Input;
612 Positive = 0;
613 Subtractive = 0;
614
615 do {
616 TempQword -= Power2MaxMemory (TempQword);
617 Positive++;
618 } while (TempQword != 0);
619
620 TempQword = Power2MaxMemory (LShiftU64 (Input, 1)) - Input;
621 Subtractive++;
622 do {
623 TempQword -= Power2MaxMemory (TempQword);
624 Subtractive++;
625 } while (TempQword != 0);
626
627 if (Positive <= Subtractive) {
628 *MtrrNumber = Positive;
629 return TRUE;
630 } else {
631 *MtrrNumber = Subtractive;
632 return FALSE;
633 }
634 }
635
636 /**
637 Invalid variable MTRRs according to the value in the shadow array.
638
639 This function programs MTRRs according to the values specified
640 in the shadow array.
641
642 @param VariableMtrr The array to shadow variable MTRRs content
643
644 **/
645 VOID
646 InvalidateMtrr (
647 IN VARIABLE_MTRR *VariableMtrr
648 )
649 {
650 UINTN Index;
651 UINTN Cr4;
652 UINTN VariableMtrrCount;
653
654 Cr4 = PreMtrrChange ();
655 Index = 0;
656 VariableMtrrCount = GetVariableMtrrCount ();
657 while (Index < VariableMtrrCount) {
658 if (!VariableMtrr[Index].Valid && VariableMtrr[Index].Used) {
659 AsmWriteMsr64 (VariableMtrr[Index].Msr, 0);
660 AsmWriteMsr64 (VariableMtrr[Index].Msr + 1, 0);
661 VariableMtrr[Index].Used = FALSE;
662 }
663 Index ++;
664 }
665 PostMtrrChange (Cr4);
666 }
667
668
669 /**
670 Programs variable MTRRs
671
672 This function programs variable MTRRs
673
674 @param MtrrNumber Index of MTRR to program.
675 @param BaseAddress Base address of memory region.
676 @param Length Length of memory region.
677 @param MemoryCacheType Memory type to set.
678 @param MtrrValidAddressMask The valid address mask for MTRR
679
680 **/
681 VOID
682 ProgramVariableMtrr (
683 IN UINTN MtrrNumber,
684 IN PHYSICAL_ADDRESS BaseAddress,
685 IN UINT64 Length,
686 IN UINT64 MemoryCacheType,
687 IN UINT64 MtrrValidAddressMask
688 )
689 {
690 UINT64 TempQword;
691 UINTN Cr4;
692
693 Cr4 = PreMtrrChange ();
694
695 //
696 // MTRR Physical Base
697 //
698 TempQword = (BaseAddress & MtrrValidAddressMask) | MemoryCacheType;
699 AsmWriteMsr64 ((UINT32) MtrrNumber, TempQword);
700
701 //
702 // MTRR Physical Mask
703 //
704 TempQword = ~(Length - 1);
705 AsmWriteMsr64 (
706 (UINT32) (MtrrNumber + 1),
707 (TempQword & MtrrValidAddressMask) | MTRR_LIB_CACHE_MTRR_ENABLED
708 );
709
710 PostMtrrChange (Cr4);
711 }
712
713
714 /**
715 Convert the Memory attibute value to MTRR_MEMORY_CACHE_TYPE.
716
717 @param MtrrType MTRR memory type
718
719 @return The enum item in MTRR_MEMORY_CACHE_TYPE
720
721 **/
722 MTRR_MEMORY_CACHE_TYPE
723 GetMemoryCacheTypeFromMtrrType (
724 IN UINT64 MtrrType
725 )
726 {
727 switch (MtrrType) {
728 case MTRR_CACHE_UNCACHEABLE:
729 return CacheUncacheable;
730 case MTRR_CACHE_WRITE_COMBINING:
731 return CacheWriteCombining;
732 case MTRR_CACHE_WRITE_THROUGH:
733 return CacheWriteThrough;
734 case MTRR_CACHE_WRITE_PROTECTED:
735 return CacheWriteProtected;
736 case MTRR_CACHE_WRITE_BACK:
737 return CacheWriteBack;
738 default:
739 //
740 // MtrrType is MTRR_CACHE_INVALID_TYPE, that means
741 // no mtrr covers the range
742 //
743 return CacheUncacheable;
744 }
745 }
746
747 /**
748 Initializes the valid bits mask and valid address mask for MTRRs.
749
750 This function initializes the valid bits mask and valid address mask for MTRRs.
751
752 @param MtrrValidBitsMask The mask for the valid bit of the MTRR
753 @param MtrrValidAddressMask The valid address mask for the MTRR
754
755 **/
756 VOID
757 MtrrLibInitializeMtrrMask (
758 OUT UINT64 *MtrrValidBitsMask,
759 OUT UINT64 *MtrrValidAddressMask
760 )
761 {
762 UINT32 RegEax;
763 UINT8 PhysicalAddressBits;
764
765 AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
766
767 if (RegEax >= 0x80000008) {
768 AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);
769
770 PhysicalAddressBits = (UINT8) RegEax;
771
772 *MtrrValidBitsMask = LShiftU64 (1, PhysicalAddressBits) - 1;
773 *MtrrValidAddressMask = *MtrrValidBitsMask & 0xfffffffffffff000ULL;
774 } else {
775 *MtrrValidBitsMask = MTRR_LIB_CACHE_VALID_ADDRESS;
776 *MtrrValidAddressMask = 0xFFFFFFFF;
777 }
778 }
779
780
781 /**
782 Determing the real attribute of a memory range.
783
784 This function is to arbitrate the real attribute of the memory when
785 there are 2 MTRR covers the same memory range. For further details,
786 please refer the IA32 Software Developer's Manual, Volume 3,
787 Section 10.11.4.1.
788
789 @param MtrrType1 the first kind of Memory type
790 @param MtrrType2 the second kind of memory type
791
792 **/
793 UINT64
794 MtrrPrecedence (
795 UINT64 MtrrType1,
796 UINT64 MtrrType2
797 )
798 {
799 UINT64 MtrrType;
800
801 MtrrType = MTRR_CACHE_INVALID_TYPE;
802 switch (MtrrType1) {
803 case MTRR_CACHE_UNCACHEABLE:
804 MtrrType = MTRR_CACHE_UNCACHEABLE;
805 break;
806 case MTRR_CACHE_WRITE_COMBINING:
807 if (
808 MtrrType2==MTRR_CACHE_WRITE_COMBINING ||
809 MtrrType2==MTRR_CACHE_UNCACHEABLE
810 ) {
811 MtrrType = MtrrType2;
812 }
813 break;
814 case MTRR_CACHE_WRITE_THROUGH:
815 if (
816 MtrrType2==MTRR_CACHE_WRITE_THROUGH ||
817 MtrrType2==MTRR_CACHE_WRITE_BACK
818 ) {
819 MtrrType = MTRR_CACHE_WRITE_THROUGH;
820 } else if(MtrrType2==MTRR_CACHE_UNCACHEABLE) {
821 MtrrType = MTRR_CACHE_UNCACHEABLE;
822 }
823 break;
824 case MTRR_CACHE_WRITE_PROTECTED:
825 if (MtrrType2 == MTRR_CACHE_WRITE_PROTECTED ||
826 MtrrType2 == MTRR_CACHE_UNCACHEABLE) {
827 MtrrType = MtrrType2;
828 }
829 break;
830 case MTRR_CACHE_WRITE_BACK:
831 if (
832 MtrrType2== MTRR_CACHE_UNCACHEABLE ||
833 MtrrType2==MTRR_CACHE_WRITE_THROUGH ||
834 MtrrType2== MTRR_CACHE_WRITE_BACK
835 ) {
836 MtrrType = MtrrType2;
837 }
838 break;
839 case MTRR_CACHE_INVALID_TYPE:
840 MtrrType = MtrrType2;
841 break;
842 default:
843 break;
844 }
845
846 if (MtrrType2 == MTRR_CACHE_INVALID_TYPE) {
847 MtrrType = MtrrType1;
848 }
849 return MtrrType;
850 }
851
852
853 /**
854 This function attempts to set the attributes for a memory range.
855
856 @param BaseAddress The physical address that is the start
857 address of a memory region.
858 @param Length The size in bytes of the memory region.
859 @param Attributes The bit mask of attributes to set for the
860 memory region.
861
862 @retval RETURN_SUCCESS The attributes were set for the memory
863 region.
864 @retval RETURN_INVALID_PARAMETER Length is zero.
865 @retval RETURN_UNSUPPORTED The processor does not support one or
866 more bytes of the memory resource range
867 specified by BaseAddress and Length.
868 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support
869 for the memory resource range specified
870 by BaseAddress and Length.
871 @retval RETURN_ACCESS_DENIED The attributes for the memory resource
872 range specified by BaseAddress and Length
873 cannot be modified.
874 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to
875 modify the attributes of the memory
876 resource range.
877
878 **/
879 RETURN_STATUS
880 EFIAPI
881 MtrrSetMemoryAttribute (
882 IN PHYSICAL_ADDRESS BaseAddress,
883 IN UINT64 Length,
884 IN MTRR_MEMORY_CACHE_TYPE Attribute
885 )
886 {
887 UINT64 TempQword;
888 RETURN_STATUS Status;
889 UINT64 MemoryType;
890 UINT64 Remainder;
891 BOOLEAN OverLap;
892 BOOLEAN Positive;
893 UINT32 MsrNum;
894 UINTN MtrrNumber;
895 VARIABLE_MTRR VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];
896 UINT32 UsedMtrr;
897 UINT64 MtrrValidBitsMask;
898 UINT64 MtrrValidAddressMask;
899 UINTN Cr4;
900 BOOLEAN OverwriteExistingMtrr;
901 UINT32 FirmwareVariableMtrrCount;
902 UINT32 VariableMtrrEnd;
903
904 DEBUG((DEBUG_CACHE, "MtrrSetMemoryAttribute() %a:%016lx-%016lx\n", mMtrrMemoryCacheTypeShortName[Attribute], BaseAddress, Length));
905
906 if (!IsMtrrSupported ()) {
907 Status = RETURN_UNSUPPORTED;
908 goto Done;
909 }
910
911 FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCount ();
912 VariableMtrrEnd = MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (2 * GetVariableMtrrCount ()) - 1;
913
914 MtrrLibInitializeMtrrMask(&MtrrValidBitsMask, &MtrrValidAddressMask);
915
916 TempQword = 0;
917 MemoryType = (UINT64)Attribute;
918 OverwriteExistingMtrr = FALSE;
919
920 //
921 // Check for an invalid parameter
922 //
923 if (Length == 0) {
924 Status = RETURN_INVALID_PARAMETER;
925 goto Done;
926 }
927
928 if (
929 (BaseAddress & ~MtrrValidAddressMask) != 0 ||
930 (Length & ~MtrrValidAddressMask) != 0
931 ) {
932 Status = RETURN_UNSUPPORTED;
933 goto Done;
934 }
935
936 //
937 // Check if Fixed MTRR
938 //
939 Status = RETURN_SUCCESS;
940 while ((BaseAddress < BASE_1MB) && (Length > 0) && Status == RETURN_SUCCESS) {
941 Cr4 = PreMtrrChange ();
942 Status = ProgramFixedMtrr (MemoryType, &BaseAddress, &Length);
943 PostMtrrChange (Cr4);
944 if (RETURN_ERROR (Status)) {
945 goto Done;
946 }
947 }
948
949 if (Length == 0) {
950 //
951 // A Length of 0 can only make sense for fixed MTTR ranges.
952 // Since we just handled the fixed MTRRs, we can skip the
953 // variable MTRR section.
954 //
955 goto Done;
956 }
957
958 //
959 // Since memory ranges below 1MB will be overridden by the fixed MTRRs,
960 // we can set the base to 0 to save variable MTRRs.
961 //
962 if (BaseAddress == BASE_1MB) {
963 BaseAddress = 0;
964 Length += SIZE_1MB;
965 }
966
967 //
968 // Check memory base address alignment
969 //
970 DivU64x64Remainder (BaseAddress, Power2MaxMemory (LShiftU64 (Length, 1)), &Remainder);
971 if (Remainder != 0) {
972 DivU64x64Remainder (BaseAddress, Power2MaxMemory (Length), &Remainder);
973 if (Remainder != 0) {
974 Status = RETURN_UNSUPPORTED;
975 goto Done;
976 }
977 }
978
979 //
980 // Check for overlap
981 //
982 UsedMtrr = MtrrGetMemoryAttributeInVariableMtrr (MtrrValidBitsMask, MtrrValidAddressMask, VariableMtrr);
983 OverLap = CheckMemoryAttributeOverlap (BaseAddress, BaseAddress + Length - 1, VariableMtrr);
984 if (OverLap) {
985 Status = CombineMemoryAttribute (MemoryType, &BaseAddress, &Length, VariableMtrr, &UsedMtrr, &OverwriteExistingMtrr);
986 if (RETURN_ERROR (Status)) {
987 goto Done;
988 }
989
990 if (Length == 0) {
991 //
992 // Combined successfully
993 //
994 Status = RETURN_SUCCESS;
995 goto Done;
996 }
997 }
998
999 //
1000 // Program Variable MTRRs
1001 //
1002 // Avoid hardcode here and read data dynamically
1003 //
1004 if (UsedMtrr >= FirmwareVariableMtrrCount) {
1005 Status = RETURN_OUT_OF_RESOURCES;
1006 goto Done;
1007 }
1008
1009 //
1010 // The memory type is the same with the type specified by
1011 // MTRR_LIB_IA32_MTRR_DEF_TYPE.
1012 //
1013 if ((!OverwriteExistingMtrr) && (Attribute == GetMtrrDefaultMemoryType ())) {
1014 //
1015 // Invalidate the now-unused MTRRs
1016 //
1017 InvalidateMtrr(VariableMtrr);
1018 goto Done;
1019 }
1020
1021 TempQword = Length;
1022
1023
1024 if (TempQword == Power2MaxMemory (TempQword)) {
1025 //
1026 // Invalidate the now-unused MTRRs
1027 //
1028 InvalidateMtrr(VariableMtrr);
1029
1030 //
1031 // Find first unused MTRR
1032 //
1033 for (MsrNum = MTRR_LIB_IA32_VARIABLE_MTRR_BASE;
1034 MsrNum < VariableMtrrEnd;
1035 MsrNum += 2
1036 ) {
1037 if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {
1038 break;
1039 }
1040 }
1041
1042 ProgramVariableMtrr (
1043 MsrNum,
1044 BaseAddress,
1045 Length,
1046 MemoryType,
1047 MtrrValidAddressMask
1048 );
1049 } else {
1050
1051 Positive = GetDirection (TempQword, &MtrrNumber);
1052
1053 if ((UsedMtrr + MtrrNumber) > FirmwareVariableMtrrCount) {
1054 Status = RETURN_OUT_OF_RESOURCES;
1055 goto Done;
1056 }
1057
1058 //
1059 // Invalidate the now-unused MTRRs
1060 //
1061 InvalidateMtrr(VariableMtrr);
1062
1063 //
1064 // Find first unused MTRR
1065 //
1066 for (MsrNum = MTRR_LIB_IA32_VARIABLE_MTRR_BASE;
1067 MsrNum < VariableMtrrEnd;
1068 MsrNum += 2
1069 ) {
1070 if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {
1071 break;
1072 }
1073 }
1074
1075 if (!Positive) {
1076 Length = Power2MaxMemory (LShiftU64 (TempQword, 1));
1077 ProgramVariableMtrr (
1078 MsrNum,
1079 BaseAddress,
1080 Length,
1081 MemoryType,
1082 MtrrValidAddressMask
1083 );
1084 BaseAddress += Length;
1085 TempQword = Length - TempQword;
1086 MemoryType = MTRR_CACHE_UNCACHEABLE;
1087 }
1088
1089 do {
1090 //
1091 // Find unused MTRR
1092 //
1093 for (; MsrNum < VariableMtrrEnd; MsrNum += 2) {
1094 if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {
1095 break;
1096 }
1097 }
1098
1099 Length = Power2MaxMemory (TempQword);
1100 if (!Positive) {
1101 BaseAddress -= Length;
1102 }
1103
1104 ProgramVariableMtrr (
1105 MsrNum,
1106 BaseAddress,
1107 Length,
1108 MemoryType,
1109 MtrrValidAddressMask
1110 );
1111
1112 if (Positive) {
1113 BaseAddress += Length;
1114 }
1115 TempQword -= Length;
1116
1117 } while (TempQword > 0);
1118 }
1119
1120 Done:
1121 DEBUG((DEBUG_CACHE, " Status = %r\n", Status));
1122 if (!RETURN_ERROR (Status)) {
1123 MtrrDebugPrintAllMtrrs ();
1124 }
1125
1126 return Status;
1127 }
1128
1129
1130 /**
1131 This function will get the memory cache type of the specific address.
1132
1133 This function is mainly for debug purpose.
1134
1135 @param Address The specific address
1136
1137 @return Memory cache type of the sepcific address
1138
1139 **/
1140 MTRR_MEMORY_CACHE_TYPE
1141 EFIAPI
1142 MtrrGetMemoryAttribute (
1143 IN PHYSICAL_ADDRESS Address
1144 )
1145 {
1146 UINT64 TempQword;
1147 UINTN Index;
1148 UINTN SubIndex;
1149 UINT64 MtrrType;
1150 UINT64 TempMtrrType;
1151 MTRR_MEMORY_CACHE_TYPE CacheType;
1152 VARIABLE_MTRR VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];
1153 UINT64 MtrrValidBitsMask;
1154 UINT64 MtrrValidAddressMask;
1155 UINTN VariableMtrrCount;
1156
1157 if (!IsMtrrSupported ()) {
1158 return CacheUncacheable;
1159 }
1160
1161 //
1162 // Check if MTRR is enabled, if not, return UC as attribute
1163 //
1164 TempQword = AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE);
1165 MtrrType = MTRR_CACHE_INVALID_TYPE;
1166
1167 if ((TempQword & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {
1168 return CacheUncacheable;
1169 }
1170
1171 //
1172 // If address is less than 1M, then try to go through the fixed MTRR
1173 //
1174 if (Address < BASE_1MB) {
1175 if ((TempQword & MTRR_LIB_CACHE_FIXED_MTRR_ENABLED) != 0) {
1176 //
1177 // Go through the fixed MTRR
1178 //
1179 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
1180 if (Address >= mMtrrLibFixedMtrrTable[Index].BaseAddress &&
1181 Address < (
1182 mMtrrLibFixedMtrrTable[Index].BaseAddress +
1183 (mMtrrLibFixedMtrrTable[Index].Length * 8)
1184 )
1185 ) {
1186 SubIndex =
1187 ((UINTN)Address - mMtrrLibFixedMtrrTable[Index].BaseAddress) /
1188 mMtrrLibFixedMtrrTable[Index].Length;
1189 TempQword = AsmReadMsr64 (mMtrrLibFixedMtrrTable[Index].Msr);
1190 MtrrType = RShiftU64 (TempQword, SubIndex * 8) & 0xFF;
1191 return GetMemoryCacheTypeFromMtrrType (MtrrType);
1192 }
1193 }
1194 }
1195 }
1196 MtrrLibInitializeMtrrMask(&MtrrValidBitsMask, &MtrrValidAddressMask);
1197 MtrrGetMemoryAttributeInVariableMtrr(
1198 MtrrValidBitsMask,
1199 MtrrValidAddressMask,
1200 VariableMtrr
1201 );
1202
1203 //
1204 // Go through the variable MTRR
1205 //
1206 VariableMtrrCount = GetVariableMtrrCount ();
1207 ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);
1208
1209 for (Index = 0; Index < VariableMtrrCount; Index++) {
1210 if (VariableMtrr[Index].Valid) {
1211 if (Address >= VariableMtrr[Index].BaseAddress &&
1212 Address < VariableMtrr[Index].BaseAddress+VariableMtrr[Index].Length) {
1213 TempMtrrType = VariableMtrr[Index].Type;
1214 MtrrType = MtrrPrecedence (MtrrType, TempMtrrType);
1215 }
1216 }
1217 }
1218 CacheType = GetMemoryCacheTypeFromMtrrType (MtrrType);
1219
1220 return CacheType;
1221 }
1222
1223
1224 /**
1225 This function will get the raw value in variable MTRRs
1226
1227 @param VariableSettings A buffer to hold variable MTRRs content.
1228
1229 @return The VariableSettings input pointer
1230
1231 **/
1232 MTRR_VARIABLE_SETTINGS*
1233 EFIAPI
1234 MtrrGetVariableMtrr (
1235 OUT MTRR_VARIABLE_SETTINGS *VariableSettings
1236 )
1237 {
1238 UINT32 Index;
1239 UINT32 VariableMtrrCount;
1240
1241 if (!IsMtrrSupported ()) {
1242 return VariableSettings;
1243 }
1244
1245 VariableMtrrCount = GetVariableMtrrCount ();
1246 ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);
1247
1248 for (Index = 0; Index < VariableMtrrCount; Index++) {
1249 VariableSettings->Mtrr[Index].Base =
1250 AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1));
1251 VariableSettings->Mtrr[Index].Mask =
1252 AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1) + 1);
1253 }
1254
1255 return VariableSettings;
1256 }
1257
1258
1259 /**
1260 Worker function setting variable MTRRs
1261
1262 @param VariableSettings A buffer to hold variable MTRRs content.
1263
1264 **/
1265 VOID
1266 MtrrSetVariableMtrrWorker (
1267 IN MTRR_VARIABLE_SETTINGS *VariableSettings
1268 )
1269 {
1270 UINT32 Index;
1271 UINT32 VariableMtrrCount;
1272
1273 VariableMtrrCount = GetVariableMtrrCount ();
1274 ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);
1275
1276 for (Index = 0; Index < VariableMtrrCount; Index++) {
1277 AsmWriteMsr64 (
1278 MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1),
1279 VariableSettings->Mtrr[Index].Base
1280 );
1281 AsmWriteMsr64 (
1282 MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1) + 1,
1283 VariableSettings->Mtrr[Index].Mask
1284 );
1285 }
1286 }
1287
1288
1289 /**
1290 This function sets variable MTRRs
1291
1292 @param VariableSettings A buffer to hold variable MTRRs content.
1293
1294 @return The pointer of VariableSettings
1295
1296 **/
1297 MTRR_VARIABLE_SETTINGS*
1298 EFIAPI
1299 MtrrSetVariableMtrr (
1300 IN MTRR_VARIABLE_SETTINGS *VariableSettings
1301 )
1302 {
1303 UINTN Cr4;
1304
1305 if (!IsMtrrSupported ()) {
1306 return VariableSettings;
1307 }
1308
1309 Cr4 = PreMtrrChange ();
1310 MtrrSetVariableMtrrWorker (VariableSettings);
1311 PostMtrrChange (Cr4);
1312 return VariableSettings;
1313 }
1314
1315
1316 /**
1317 This function gets the content in fixed MTRRs
1318
1319 @param FixedSettings A buffer to hold fixed Mtrrs content.
1320
1321 @retval The pointer of FixedSettings
1322
1323 **/
1324 MTRR_FIXED_SETTINGS*
1325 EFIAPI
1326 MtrrGetFixedMtrr (
1327 OUT MTRR_FIXED_SETTINGS *FixedSettings
1328 )
1329 {
1330 UINT32 Index;
1331
1332 if (!IsMtrrSupported ()) {
1333 return FixedSettings;
1334 }
1335
1336 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
1337 FixedSettings->Mtrr[Index] =
1338 AsmReadMsr64 (mMtrrLibFixedMtrrTable[Index].Msr);
1339 };
1340
1341 return FixedSettings;
1342 }
1343
1344 /**
1345 Worker function setting fixed MTRRs
1346
1347 @param FixedSettings A buffer to hold fixed Mtrrs content.
1348
1349 **/
1350 VOID
1351 MtrrSetFixedMtrrWorker (
1352 IN MTRR_FIXED_SETTINGS *FixedSettings
1353 )
1354 {
1355 UINT32 Index;
1356
1357 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
1358 AsmWriteMsr64 (
1359 mMtrrLibFixedMtrrTable[Index].Msr,
1360 FixedSettings->Mtrr[Index]
1361 );
1362 }
1363 }
1364
1365
1366 /**
1367 This function sets fixed MTRRs
1368
1369 @param FixedSettings A buffer to hold fixed Mtrrs content.
1370
1371 @retval The pointer of FixedSettings
1372
1373 **/
1374 MTRR_FIXED_SETTINGS*
1375 EFIAPI
1376 MtrrSetFixedMtrr (
1377 IN MTRR_FIXED_SETTINGS *FixedSettings
1378 )
1379 {
1380 UINTN Cr4;
1381
1382 if (!IsMtrrSupported ()) {
1383 return FixedSettings;
1384 }
1385
1386 Cr4 = PreMtrrChange ();
1387 MtrrSetFixedMtrrWorker (FixedSettings);
1388 PostMtrrChange (Cr4);
1389
1390 return FixedSettings;
1391 }
1392
1393
1394 /**
1395 This function gets the content in all MTRRs (variable and fixed)
1396
1397 @param MtrrSetting A buffer to hold all Mtrrs content.
1398
1399 @retval the pointer of MtrrSetting
1400
1401 **/
1402 MTRR_SETTINGS *
1403 EFIAPI
1404 MtrrGetAllMtrrs (
1405 OUT MTRR_SETTINGS *MtrrSetting
1406 )
1407 {
1408 if (!IsMtrrSupported ()) {
1409 return MtrrSetting;
1410 }
1411
1412 //
1413 // Get fixed MTRRs
1414 //
1415 MtrrGetFixedMtrr (&MtrrSetting->Fixed);
1416
1417 //
1418 // Get variable MTRRs
1419 //
1420 MtrrGetVariableMtrr (&MtrrSetting->Variables);
1421
1422 //
1423 // Get MTRR_DEF_TYPE value
1424 //
1425 MtrrSetting->MtrrDefType = AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE);
1426
1427 return MtrrSetting;
1428 }
1429
1430
1431 /**
1432 This function sets all MTRRs (variable and fixed)
1433
1434 @param MtrrSetting A buffer holding all MTRRs content.
1435
1436 @retval The pointer of MtrrSetting
1437
1438 **/
1439 MTRR_SETTINGS *
1440 EFIAPI
1441 MtrrSetAllMtrrs (
1442 IN MTRR_SETTINGS *MtrrSetting
1443 )
1444 {
1445 UINTN Cr4;
1446
1447 if (!IsMtrrSupported ()) {
1448 return MtrrSetting;
1449 }
1450
1451 Cr4 = PreMtrrChange ();
1452
1453 //
1454 // Set fixed MTRRs
1455 //
1456 MtrrSetFixedMtrrWorker (&MtrrSetting->Fixed);
1457
1458 //
1459 // Set variable MTRRs
1460 //
1461 MtrrSetVariableMtrrWorker (&MtrrSetting->Variables);
1462
1463 //
1464 // Set MTRR_DEF_TYPE value
1465 //
1466 AsmWriteMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE, MtrrSetting->MtrrDefType);
1467
1468 PostMtrrChange (Cr4);
1469
1470 return MtrrSetting;
1471 }
1472
1473 /**
1474 This function prints all MTRRs for debugging.
1475 **/
1476 VOID
1477 EFIAPI
1478 MtrrDebugPrintAllMtrrs (
1479 VOID
1480 )
1481 {
1482 DEBUG_CODE (
1483 MTRR_SETTINGS MtrrSettings;
1484 UINTN Index;
1485 UINTN Index1;
1486 UINTN VariableMtrrCount;
1487 UINT64 Base;
1488 UINT64 Limit;
1489 UINT64 MtrrBase;
1490 UINT64 MtrrLimit;
1491 UINT64 RangeBase;
1492 UINT64 RangeLimit;
1493 UINT64 NoRangeBase;
1494 UINT64 NoRangeLimit;
1495 UINT32 RegEax;
1496 UINTN MemoryType;
1497 UINTN PreviousMemoryType;
1498 BOOLEAN Found;
1499
1500 if (!IsMtrrSupported ()) {
1501 return;
1502 }
1503
1504 DEBUG((DEBUG_CACHE, "MTRR Settings\n"));
1505 DEBUG((DEBUG_CACHE, "=============\n"));
1506
1507 MtrrGetAllMtrrs (&MtrrSettings);
1508 DEBUG((DEBUG_CACHE, "MTRR Default Type: %016lx\n", MtrrSettings.MtrrDefType));
1509 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
1510 DEBUG((DEBUG_CACHE, "Fixed MTRR[%02d] : %016lx\n", Index, MtrrSettings.Fixed.Mtrr[Index]));
1511 }
1512
1513 VariableMtrrCount = GetVariableMtrrCount ();
1514 for (Index = 0; Index < VariableMtrrCount; Index++) {
1515 DEBUG((DEBUG_CACHE, "Variable MTRR[%02d]: Base=%016lx Mask=%016lx\n",
1516 Index,
1517 MtrrSettings.Variables.Mtrr[Index].Base,
1518 MtrrSettings.Variables.Mtrr[Index].Mask
1519 ));
1520 }
1521 DEBUG((DEBUG_CACHE, "\n"));
1522 DEBUG((DEBUG_CACHE, "MTRR Ranges\n"));
1523 DEBUG((DEBUG_CACHE, "====================================\n"));
1524
1525 Base = 0;
1526 PreviousMemoryType = MTRR_CACHE_INVALID_TYPE;
1527 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
1528 Base = mMtrrLibFixedMtrrTable[Index].BaseAddress;
1529 for (Index1 = 0; Index1 < 8; Index1++) {
1530 MemoryType = (UINTN)(RShiftU64 (MtrrSettings.Fixed.Mtrr[Index], Index1 * 8) & 0xff);
1531 if (MemoryType > CacheWriteBack) {
1532 MemoryType = MTRR_CACHE_INVALID_TYPE;
1533 }
1534 if (MemoryType != PreviousMemoryType) {
1535 if (PreviousMemoryType != MTRR_CACHE_INVALID_TYPE) {
1536 DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));
1537 }
1538 PreviousMemoryType = MemoryType;
1539 DEBUG((DEBUG_CACHE, "%a:%016lx-", mMtrrMemoryCacheTypeShortName[MemoryType], Base));
1540 }
1541 Base += mMtrrLibFixedMtrrTable[Index].Length;
1542 }
1543 }
1544 DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));
1545
1546 VariableMtrrCount = GetVariableMtrrCount ();
1547
1548 Base = BASE_1MB;
1549 PreviousMemoryType = MTRR_CACHE_INVALID_TYPE;
1550 do {
1551 MemoryType = MtrrGetMemoryAttribute (Base);
1552 if (MemoryType > CacheWriteBack) {
1553 MemoryType = MTRR_CACHE_INVALID_TYPE;
1554 }
1555
1556 if (MemoryType != PreviousMemoryType) {
1557 if (PreviousMemoryType != MTRR_CACHE_INVALID_TYPE) {
1558 DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));
1559 }
1560 PreviousMemoryType = MemoryType;
1561 DEBUG((DEBUG_CACHE, "%a:%016lx-", mMtrrMemoryCacheTypeShortName[MemoryType], Base));
1562 }
1563
1564 RangeBase = BASE_1MB;
1565 NoRangeBase = BASE_1MB;
1566 Limit = BIT36 - 1;
1567 AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
1568 if (RegEax >= 0x80000008) {
1569 AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);
1570 Limit = LShiftU64 (1, RegEax & 0xff) - 1;
1571 }
1572 RangeLimit = Limit;
1573 NoRangeLimit = Limit;
1574
1575 for (Index = 0, Found = FALSE; Index < VariableMtrrCount; Index++) {
1576 if ((MtrrSettings.Variables.Mtrr[Index].Mask & BIT11) == 0) {
1577 //
1578 // If mask is not valid, then do not display range
1579 //
1580 continue;
1581 }
1582 MtrrBase = (MtrrSettings.Variables.Mtrr[Index].Base & (~(SIZE_4KB - 1)));
1583 MtrrLimit = MtrrBase + ((~(MtrrSettings.Variables.Mtrr[Index].Mask & (~(SIZE_4KB - 1)))) & Limit);
1584
1585 if (Base >= MtrrBase && Base < MtrrLimit) {
1586 Found = TRUE;
1587 }
1588
1589 if (Base >= MtrrBase && MtrrBase > RangeBase) {
1590 RangeBase = MtrrBase;
1591 }
1592 if (Base > MtrrLimit && MtrrLimit > RangeBase) {
1593 RangeBase = MtrrLimit + 1;
1594 }
1595 if (Base < MtrrBase && MtrrBase < RangeLimit) {
1596 RangeLimit = MtrrBase - 1;
1597 }
1598 if (Base < MtrrLimit && MtrrLimit <= RangeLimit) {
1599 RangeLimit = MtrrLimit;
1600 }
1601
1602 if (Base > MtrrLimit && NoRangeBase < MtrrLimit) {
1603 NoRangeBase = MtrrLimit + 1;
1604 }
1605 if (Base < MtrrBase && NoRangeLimit > MtrrBase) {
1606 NoRangeLimit = MtrrBase - 1;
1607 }
1608 }
1609
1610 if (Found) {
1611 Base = RangeLimit + 1;
1612 } else {
1613 Base = NoRangeLimit + 1;
1614 }
1615 } while (Found);
1616 DEBUG((DEBUG_CACHE, "%016lx\n\n", Base - 1));
1617 );
1618 }
1619
1620 /**
1621 Checks if MTRR is supported.
1622
1623 @retval TRUE MTRR is supported.
1624 @retval FALSE MTRR is not supported.
1625
1626 **/
1627 BOOLEAN
1628 EFIAPI
1629 IsMtrrSupported (
1630 VOID
1631 )
1632 {
1633 UINT32 RegEdx;
1634 UINT64 MtrrCap;
1635
1636 //
1637 // Check CPUID(1).EDX[12] for MTRR capability
1638 //
1639 AsmCpuid (1, NULL, NULL, NULL, &RegEdx);
1640 if (BitFieldRead32 (RegEdx, 12, 12) == 0) {
1641 return FALSE;
1642 }
1643
1644 //
1645 // Check IA32_MTRRCAP.[0..7] for number of variable MTRRs and IA32_MTRRCAP[8] for
1646 // fixed MTRRs existence. If number of variable MTRRs is zero, or fixed MTRRs do not
1647 // exist, return false.
1648 //
1649 MtrrCap = AsmReadMsr64 (MTRR_LIB_IA32_MTRR_CAP);
1650 if ((BitFieldRead64 (MtrrCap, 0, 7) == 0) || (BitFieldRead64 (MtrrCap, 8, 8) == 0)) {
1651 return FALSE;
1652 }
1653
1654 return TRUE;
1655 }