]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/Library/MtrrLib/MtrrLib.c
UefiCpuPkg MTRR Library: enhance MTRR Library.
[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 BOOLEAN CoveredByExistingMtrr;
481
482 FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCount ();
483
484 *OverwriteExistingMtrr = FALSE;
485 CoveredByExistingMtrr = FALSE;
486 EndAddress = *Base +*Length - 1;
487
488 for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) {
489
490 MtrrEnd = VariableMtrr[Index].BaseAddress + VariableMtrr[Index].Length - 1;
491 if (
492 !VariableMtrr[Index].Valid ||
493 (
494 *Base > (MtrrEnd) ||
495 (EndAddress < VariableMtrr[Index].BaseAddress)
496 )
497 ) {
498 continue;
499 }
500
501 //
502 // Combine same attribute MTRR range
503 //
504 if (Attributes == VariableMtrr[Index].Type) {
505 //
506 // if the Mtrr range contain the request range, set a flag, then continue to
507 // invalidate any MTRR of the same request range with higher priority cache type.
508 //
509 if (VariableMtrr[Index].BaseAddress <= *Base && MtrrEnd >= EndAddress) {
510 CoveredByExistingMtrr = TRUE;
511 continue;
512 }
513 //
514 // invalid this MTRR, and program the combine range
515 //
516 CombineStart =
517 (*Base) < VariableMtrr[Index].BaseAddress ?
518 (*Base) :
519 VariableMtrr[Index].BaseAddress;
520 CombineEnd = EndAddress > MtrrEnd ? EndAddress : MtrrEnd;
521
522 //
523 // Record the MTRR usage status in VariableMtrr array.
524 //
525 InvalidateShadowMtrr (Index, VariableMtrr, UsedMtrr);
526 *Base = CombineStart;
527 *Length = CombineEnd - CombineStart + 1;
528 EndAddress = CombineEnd;
529 *OverwriteExistingMtrr = TRUE;
530 continue;
531 } else {
532 //
533 // The cache type is different, but the range is convered by one MTRR
534 //
535 if (VariableMtrr[Index].BaseAddress == *Base && MtrrEnd == EndAddress) {
536 InvalidateShadowMtrr (Index, VariableMtrr, UsedMtrr);
537 continue;
538 }
539
540 }
541
542 if ((Attributes== MTRR_CACHE_WRITE_THROUGH &&
543 VariableMtrr[Index].Type == MTRR_CACHE_WRITE_BACK) ||
544 (Attributes == MTRR_CACHE_WRITE_BACK &&
545 VariableMtrr[Index].Type == MTRR_CACHE_WRITE_THROUGH) ||
546 (Attributes == MTRR_CACHE_UNCACHEABLE) ||
547 (VariableMtrr[Index].Type == MTRR_CACHE_UNCACHEABLE)
548 ) {
549 *OverwriteExistingMtrr = TRUE;
550 continue;
551 }
552 //
553 // Other type memory overlap is invalid
554 //
555 return RETURN_ACCESS_DENIED;
556 }
557
558 if (CoveredByExistingMtrr) {
559 *Length = 0;
560 }
561
562 return RETURN_SUCCESS;
563 }
564
565
566 /**
567 Calculate the maximum value which is a power of 2, but less the MemoryLength.
568
569 @param MemoryLength The number to pass in.
570 @return The maximum value which is align to power of 2 and less the MemoryLength
571
572 **/
573 UINT64
574 Power2MaxMemory (
575 IN UINT64 MemoryLength
576 )
577 {
578 UINT64 Result;
579
580 if (RShiftU64 (MemoryLength, 32) != 0) {
581 Result = LShiftU64 (
582 (UINT64) GetPowerOfTwo32 (
583 (UINT32) RShiftU64 (MemoryLength, 32)
584 ),
585 32
586 );
587 } else {
588 Result = (UINT64) GetPowerOfTwo32 ((UINT32) MemoryLength);
589 }
590
591 return Result;
592 }
593
594
595 /**
596 Determine the MTRR numbers used to program a memory range.
597
598 This function first checks the alignment of the base address. If the alignment of the base address <= Length,
599 cover the memory range (BaseAddress, alignment) by a MTRR, then BaseAddress += alignment and Length -= alignment.
600 Repeat the step until alignment > Length.
601
602 Then this function determines which direction of programming the variable MTRRs for the remaining length
603 will use fewer MTRRs.
604
605 @param BaseAddress Length of Memory to program MTRR
606 @param Length Length of Memory to program MTRR
607 @param MtrrNumber Pointer to the number of necessary MTRRs
608
609 @retval TRUE Positive direction is better.
610 FALSE Negtive direction is better.
611
612 **/
613 BOOLEAN
614 GetMtrrNumberAndDirection (
615 IN UINT64 BaseAddress,
616 IN UINT64 Length,
617 IN UINTN *MtrrNumber
618 )
619 {
620 UINT64 TempQword;
621 UINT64 Alignment;
622 UINT32 Positive;
623 UINT32 Subtractive;
624
625 *MtrrNumber = 0;
626
627 if (BaseAddress != 0) {
628 do {
629 //
630 // Calculate the alignment of the base address.
631 //
632 Alignment = LShiftU64 (1, (UINTN)LowBitSet64 (BaseAddress));
633
634 if (Alignment > Length) {
635 break;
636 }
637
638 (*MtrrNumber)++;
639 BaseAddress += Alignment;
640 Length -= Alignment;
641 } while (TRUE);
642
643 if (Length == 0) {
644 return TRUE;
645 }
646 }
647
648 TempQword = Length;
649 Positive = 0;
650 Subtractive = 0;
651
652 do {
653 TempQword -= Power2MaxMemory (TempQword);
654 Positive++;
655 } while (TempQword != 0);
656
657 TempQword = Power2MaxMemory (LShiftU64 (Length, 1)) - Length;
658 Subtractive++;
659 do {
660 TempQword -= Power2MaxMemory (TempQword);
661 Subtractive++;
662 } while (TempQword != 0);
663
664 if (Positive <= Subtractive) {
665 *MtrrNumber += Positive;
666 return TRUE;
667 } else {
668 *MtrrNumber += Subtractive;
669 return FALSE;
670 }
671 }
672
673 /**
674 Invalid variable MTRRs according to the value in the shadow array.
675
676 This function programs MTRRs according to the values specified
677 in the shadow array.
678
679 @param VariableMtrr The array to shadow variable MTRRs content
680
681 **/
682 VOID
683 InvalidateMtrr (
684 IN VARIABLE_MTRR *VariableMtrr
685 )
686 {
687 UINTN Index;
688 UINTN Cr4;
689 UINTN VariableMtrrCount;
690
691 Cr4 = PreMtrrChange ();
692 Index = 0;
693 VariableMtrrCount = GetVariableMtrrCount ();
694 while (Index < VariableMtrrCount) {
695 if (!VariableMtrr[Index].Valid && VariableMtrr[Index].Used) {
696 AsmWriteMsr64 (VariableMtrr[Index].Msr, 0);
697 AsmWriteMsr64 (VariableMtrr[Index].Msr + 1, 0);
698 VariableMtrr[Index].Used = FALSE;
699 }
700 Index ++;
701 }
702 PostMtrrChange (Cr4);
703 }
704
705
706 /**
707 Programs variable MTRRs
708
709 This function programs variable MTRRs
710
711 @param MtrrNumber Index of MTRR to program.
712 @param BaseAddress Base address of memory region.
713 @param Length Length of memory region.
714 @param MemoryCacheType Memory type to set.
715 @param MtrrValidAddressMask The valid address mask for MTRR
716
717 **/
718 VOID
719 ProgramVariableMtrr (
720 IN UINTN MtrrNumber,
721 IN PHYSICAL_ADDRESS BaseAddress,
722 IN UINT64 Length,
723 IN UINT64 MemoryCacheType,
724 IN UINT64 MtrrValidAddressMask
725 )
726 {
727 UINT64 TempQword;
728 UINTN Cr4;
729
730 Cr4 = PreMtrrChange ();
731
732 //
733 // MTRR Physical Base
734 //
735 TempQword = (BaseAddress & MtrrValidAddressMask) | MemoryCacheType;
736 AsmWriteMsr64 ((UINT32) MtrrNumber, TempQword);
737
738 //
739 // MTRR Physical Mask
740 //
741 TempQword = ~(Length - 1);
742 AsmWriteMsr64 (
743 (UINT32) (MtrrNumber + 1),
744 (TempQword & MtrrValidAddressMask) | MTRR_LIB_CACHE_MTRR_ENABLED
745 );
746
747 PostMtrrChange (Cr4);
748 }
749
750
751 /**
752 Convert the Memory attibute value to MTRR_MEMORY_CACHE_TYPE.
753
754 @param MtrrType MTRR memory type
755
756 @return The enum item in MTRR_MEMORY_CACHE_TYPE
757
758 **/
759 MTRR_MEMORY_CACHE_TYPE
760 GetMemoryCacheTypeFromMtrrType (
761 IN UINT64 MtrrType
762 )
763 {
764 switch (MtrrType) {
765 case MTRR_CACHE_UNCACHEABLE:
766 return CacheUncacheable;
767 case MTRR_CACHE_WRITE_COMBINING:
768 return CacheWriteCombining;
769 case MTRR_CACHE_WRITE_THROUGH:
770 return CacheWriteThrough;
771 case MTRR_CACHE_WRITE_PROTECTED:
772 return CacheWriteProtected;
773 case MTRR_CACHE_WRITE_BACK:
774 return CacheWriteBack;
775 default:
776 //
777 // MtrrType is MTRR_CACHE_INVALID_TYPE, that means
778 // no mtrr covers the range
779 //
780 return CacheUncacheable;
781 }
782 }
783
784 /**
785 Initializes the valid bits mask and valid address mask for MTRRs.
786
787 This function initializes the valid bits mask and valid address mask for MTRRs.
788
789 @param MtrrValidBitsMask The mask for the valid bit of the MTRR
790 @param MtrrValidAddressMask The valid address mask for the MTRR
791
792 **/
793 VOID
794 MtrrLibInitializeMtrrMask (
795 OUT UINT64 *MtrrValidBitsMask,
796 OUT UINT64 *MtrrValidAddressMask
797 )
798 {
799 UINT32 RegEax;
800 UINT8 PhysicalAddressBits;
801
802 AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
803
804 if (RegEax >= 0x80000008) {
805 AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);
806
807 PhysicalAddressBits = (UINT8) RegEax;
808
809 *MtrrValidBitsMask = LShiftU64 (1, PhysicalAddressBits) - 1;
810 *MtrrValidAddressMask = *MtrrValidBitsMask & 0xfffffffffffff000ULL;
811 } else {
812 *MtrrValidBitsMask = MTRR_LIB_CACHE_VALID_ADDRESS;
813 *MtrrValidAddressMask = 0xFFFFFFFF;
814 }
815 }
816
817
818 /**
819 Determing the real attribute of a memory range.
820
821 This function is to arbitrate the real attribute of the memory when
822 there are 2 MTRR covers the same memory range. For further details,
823 please refer the IA32 Software Developer's Manual, Volume 3,
824 Section 10.11.4.1.
825
826 @param MtrrType1 the first kind of Memory type
827 @param MtrrType2 the second kind of memory type
828
829 **/
830 UINT64
831 MtrrPrecedence (
832 UINT64 MtrrType1,
833 UINT64 MtrrType2
834 )
835 {
836 UINT64 MtrrType;
837
838 MtrrType = MTRR_CACHE_INVALID_TYPE;
839 switch (MtrrType1) {
840 case MTRR_CACHE_UNCACHEABLE:
841 MtrrType = MTRR_CACHE_UNCACHEABLE;
842 break;
843 case MTRR_CACHE_WRITE_COMBINING:
844 if (
845 MtrrType2==MTRR_CACHE_WRITE_COMBINING ||
846 MtrrType2==MTRR_CACHE_UNCACHEABLE
847 ) {
848 MtrrType = MtrrType2;
849 }
850 break;
851 case MTRR_CACHE_WRITE_THROUGH:
852 if (
853 MtrrType2==MTRR_CACHE_WRITE_THROUGH ||
854 MtrrType2==MTRR_CACHE_WRITE_BACK
855 ) {
856 MtrrType = MTRR_CACHE_WRITE_THROUGH;
857 } else if(MtrrType2==MTRR_CACHE_UNCACHEABLE) {
858 MtrrType = MTRR_CACHE_UNCACHEABLE;
859 }
860 break;
861 case MTRR_CACHE_WRITE_PROTECTED:
862 if (MtrrType2 == MTRR_CACHE_WRITE_PROTECTED ||
863 MtrrType2 == MTRR_CACHE_UNCACHEABLE) {
864 MtrrType = MtrrType2;
865 }
866 break;
867 case MTRR_CACHE_WRITE_BACK:
868 if (
869 MtrrType2== MTRR_CACHE_UNCACHEABLE ||
870 MtrrType2==MTRR_CACHE_WRITE_THROUGH ||
871 MtrrType2== MTRR_CACHE_WRITE_BACK
872 ) {
873 MtrrType = MtrrType2;
874 }
875 break;
876 case MTRR_CACHE_INVALID_TYPE:
877 MtrrType = MtrrType2;
878 break;
879 default:
880 break;
881 }
882
883 if (MtrrType2 == MTRR_CACHE_INVALID_TYPE) {
884 MtrrType = MtrrType1;
885 }
886 return MtrrType;
887 }
888
889
890 /**
891 This function attempts to set the attributes for a memory range.
892
893 @param BaseAddress The physical address that is the start
894 address of a memory region.
895 @param Length The size in bytes of the memory region.
896 @param Attributes The bit mask of attributes to set for the
897 memory region.
898
899 @retval RETURN_SUCCESS The attributes were set for the memory
900 region.
901 @retval RETURN_INVALID_PARAMETER Length is zero.
902 @retval RETURN_UNSUPPORTED The processor does not support one or
903 more bytes of the memory resource range
904 specified by BaseAddress and Length.
905 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support
906 for the memory resource range specified
907 by BaseAddress and Length.
908 @retval RETURN_ACCESS_DENIED The attributes for the memory resource
909 range specified by BaseAddress and Length
910 cannot be modified.
911 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to
912 modify the attributes of the memory
913 resource range.
914
915 **/
916 RETURN_STATUS
917 EFIAPI
918 MtrrSetMemoryAttribute (
919 IN PHYSICAL_ADDRESS BaseAddress,
920 IN UINT64 Length,
921 IN MTRR_MEMORY_CACHE_TYPE Attribute
922 )
923 {
924 UINT64 TempQword;
925 RETURN_STATUS Status;
926 UINT64 MemoryType;
927 UINT64 Alignment;
928 BOOLEAN OverLap;
929 BOOLEAN Positive;
930 UINT32 MsrNum;
931 UINTN MtrrNumber;
932 VARIABLE_MTRR VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];
933 UINT32 UsedMtrr;
934 UINT64 MtrrValidBitsMask;
935 UINT64 MtrrValidAddressMask;
936 UINTN Cr4;
937 BOOLEAN OverwriteExistingMtrr;
938 UINT32 FirmwareVariableMtrrCount;
939 UINT32 VariableMtrrEnd;
940
941 DEBUG((DEBUG_CACHE, "MtrrSetMemoryAttribute() %a:%016lx-%016lx\n", mMtrrMemoryCacheTypeShortName[Attribute], BaseAddress, Length));
942
943 if (!IsMtrrSupported ()) {
944 Status = RETURN_UNSUPPORTED;
945 goto Done;
946 }
947
948 FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCount ();
949 VariableMtrrEnd = MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (2 * GetVariableMtrrCount ()) - 1;
950
951 MtrrLibInitializeMtrrMask(&MtrrValidBitsMask, &MtrrValidAddressMask);
952
953 TempQword = 0;
954 MemoryType = (UINT64)Attribute;
955 OverwriteExistingMtrr = FALSE;
956
957 //
958 // Check for an invalid parameter
959 //
960 if (Length == 0) {
961 Status = RETURN_INVALID_PARAMETER;
962 goto Done;
963 }
964
965 if (
966 (BaseAddress & ~MtrrValidAddressMask) != 0 ||
967 (Length & ~MtrrValidAddressMask) != 0
968 ) {
969 Status = RETURN_UNSUPPORTED;
970 goto Done;
971 }
972
973 //
974 // Check if Fixed MTRR
975 //
976 Status = RETURN_SUCCESS;
977 while ((BaseAddress < BASE_1MB) && (Length > 0) && Status == RETURN_SUCCESS) {
978 Cr4 = PreMtrrChange ();
979 Status = ProgramFixedMtrr (MemoryType, &BaseAddress, &Length);
980 PostMtrrChange (Cr4);
981 if (RETURN_ERROR (Status)) {
982 goto Done;
983 }
984 }
985
986 if (Length == 0) {
987 //
988 // A Length of 0 can only make sense for fixed MTTR ranges.
989 // Since we just handled the fixed MTRRs, we can skip the
990 // variable MTRR section.
991 //
992 goto Done;
993 }
994
995 //
996 // Since memory ranges below 1MB will be overridden by the fixed MTRRs,
997 // we can set the base to 0 to save variable MTRRs.
998 //
999 if (BaseAddress == BASE_1MB) {
1000 BaseAddress = 0;
1001 Length += SIZE_1MB;
1002 }
1003
1004 //
1005 // Check for overlap
1006 //
1007 UsedMtrr = MtrrGetMemoryAttributeInVariableMtrr (MtrrValidBitsMask, MtrrValidAddressMask, VariableMtrr);
1008 OverLap = CheckMemoryAttributeOverlap (BaseAddress, BaseAddress + Length - 1, VariableMtrr);
1009 if (OverLap) {
1010 Status = CombineMemoryAttribute (MemoryType, &BaseAddress, &Length, VariableMtrr, &UsedMtrr, &OverwriteExistingMtrr);
1011 if (RETURN_ERROR (Status)) {
1012 goto Done;
1013 }
1014
1015 if (Length == 0) {
1016 //
1017 // Combined successfully, invalidate the now-unused MTRRs
1018 //
1019 InvalidateMtrr(VariableMtrr);
1020 Status = RETURN_SUCCESS;
1021 goto Done;
1022 }
1023 }
1024
1025 //
1026 // Program Variable MTRRs
1027 //
1028 // Avoid hardcode here and read data dynamically
1029 //
1030 if (UsedMtrr >= FirmwareVariableMtrrCount) {
1031 Status = RETURN_OUT_OF_RESOURCES;
1032 goto Done;
1033 }
1034
1035 //
1036 // The memory type is the same with the type specified by
1037 // MTRR_LIB_IA32_MTRR_DEF_TYPE.
1038 //
1039 if ((!OverwriteExistingMtrr) && (Attribute == GetMtrrDefaultMemoryType ())) {
1040 //
1041 // Invalidate the now-unused MTRRs
1042 //
1043 InvalidateMtrr(VariableMtrr);
1044 goto Done;
1045 }
1046
1047 Positive = GetMtrrNumberAndDirection (BaseAddress, Length, &MtrrNumber);
1048
1049 if ((UsedMtrr + MtrrNumber) > FirmwareVariableMtrrCount) {
1050 Status = RETURN_OUT_OF_RESOURCES;
1051 goto Done;
1052 }
1053
1054 //
1055 // Invalidate the now-unused MTRRs
1056 //
1057 InvalidateMtrr(VariableMtrr);
1058
1059 //
1060 // Find first unused MTRR
1061 //
1062 for (MsrNum = MTRR_LIB_IA32_VARIABLE_MTRR_BASE;
1063 MsrNum < VariableMtrrEnd;
1064 MsrNum += 2
1065 ) {
1066 if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {
1067 break;
1068 }
1069 }
1070
1071 if (BaseAddress != 0) {
1072 do {
1073 //
1074 // Calculate the alignment of the base address.
1075 //
1076 Alignment = LShiftU64 (1, (UINTN)LowBitSet64 (BaseAddress));
1077
1078 if (Alignment > Length) {
1079 break;
1080 }
1081
1082 //
1083 // Find unused MTRR
1084 //
1085 for (; MsrNum < VariableMtrrEnd; MsrNum += 2) {
1086 if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {
1087 break;
1088 }
1089 }
1090
1091 ProgramVariableMtrr (
1092 MsrNum,
1093 BaseAddress,
1094 Alignment,
1095 MemoryType,
1096 MtrrValidAddressMask
1097 );
1098 BaseAddress += Alignment;
1099 Length -= Alignment;
1100 } while (TRUE);
1101
1102 if (Length == 0) {
1103 goto Done;
1104 }
1105 }
1106
1107 TempQword = Length;
1108
1109 if (!Positive) {
1110 Length = Power2MaxMemory (LShiftU64 (TempQword, 1));
1111
1112 //
1113 // Find unused MTRR
1114 //
1115 for (; MsrNum < VariableMtrrEnd; MsrNum += 2) {
1116 if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {
1117 break;
1118 }
1119 }
1120
1121 ProgramVariableMtrr (
1122 MsrNum,
1123 BaseAddress,
1124 Length,
1125 MemoryType,
1126 MtrrValidAddressMask
1127 );
1128 BaseAddress += Length;
1129 TempQword = Length - TempQword;
1130 MemoryType = MTRR_CACHE_UNCACHEABLE;
1131 }
1132
1133 do {
1134 //
1135 // Find unused MTRR
1136 //
1137 for (; MsrNum < VariableMtrrEnd; MsrNum += 2) {
1138 if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {
1139 break;
1140 }
1141 }
1142
1143 Length = Power2MaxMemory (TempQword);
1144 if (!Positive) {
1145 BaseAddress -= Length;
1146 }
1147
1148 ProgramVariableMtrr (
1149 MsrNum,
1150 BaseAddress,
1151 Length,
1152 MemoryType,
1153 MtrrValidAddressMask
1154 );
1155
1156 if (Positive) {
1157 BaseAddress += Length;
1158 }
1159 TempQword -= Length;
1160
1161 } while (TempQword > 0);
1162
1163 Done:
1164 DEBUG((DEBUG_CACHE, " Status = %r\n", Status));
1165 if (!RETURN_ERROR (Status)) {
1166 MtrrDebugPrintAllMtrrs ();
1167 }
1168
1169 return Status;
1170 }
1171
1172
1173 /**
1174 This function will get the memory cache type of the specific address.
1175
1176 This function is mainly for debug purpose.
1177
1178 @param Address The specific address
1179
1180 @return Memory cache type of the sepcific address
1181
1182 **/
1183 MTRR_MEMORY_CACHE_TYPE
1184 EFIAPI
1185 MtrrGetMemoryAttribute (
1186 IN PHYSICAL_ADDRESS Address
1187 )
1188 {
1189 UINT64 TempQword;
1190 UINTN Index;
1191 UINTN SubIndex;
1192 UINT64 MtrrType;
1193 UINT64 TempMtrrType;
1194 MTRR_MEMORY_CACHE_TYPE CacheType;
1195 VARIABLE_MTRR VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];
1196 UINT64 MtrrValidBitsMask;
1197 UINT64 MtrrValidAddressMask;
1198 UINTN VariableMtrrCount;
1199
1200 if (!IsMtrrSupported ()) {
1201 return CacheUncacheable;
1202 }
1203
1204 //
1205 // Check if MTRR is enabled, if not, return UC as attribute
1206 //
1207 TempQword = AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE);
1208 MtrrType = MTRR_CACHE_INVALID_TYPE;
1209
1210 if ((TempQword & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {
1211 return CacheUncacheable;
1212 }
1213
1214 //
1215 // If address is less than 1M, then try to go through the fixed MTRR
1216 //
1217 if (Address < BASE_1MB) {
1218 if ((TempQword & MTRR_LIB_CACHE_FIXED_MTRR_ENABLED) != 0) {
1219 //
1220 // Go through the fixed MTRR
1221 //
1222 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
1223 if (Address >= mMtrrLibFixedMtrrTable[Index].BaseAddress &&
1224 Address < (
1225 mMtrrLibFixedMtrrTable[Index].BaseAddress +
1226 (mMtrrLibFixedMtrrTable[Index].Length * 8)
1227 )
1228 ) {
1229 SubIndex =
1230 ((UINTN)Address - mMtrrLibFixedMtrrTable[Index].BaseAddress) /
1231 mMtrrLibFixedMtrrTable[Index].Length;
1232 TempQword = AsmReadMsr64 (mMtrrLibFixedMtrrTable[Index].Msr);
1233 MtrrType = RShiftU64 (TempQword, SubIndex * 8) & 0xFF;
1234 return GetMemoryCacheTypeFromMtrrType (MtrrType);
1235 }
1236 }
1237 }
1238 }
1239 MtrrLibInitializeMtrrMask(&MtrrValidBitsMask, &MtrrValidAddressMask);
1240 MtrrGetMemoryAttributeInVariableMtrr(
1241 MtrrValidBitsMask,
1242 MtrrValidAddressMask,
1243 VariableMtrr
1244 );
1245
1246 //
1247 // Go through the variable MTRR
1248 //
1249 VariableMtrrCount = GetVariableMtrrCount ();
1250 ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);
1251
1252 for (Index = 0; Index < VariableMtrrCount; Index++) {
1253 if (VariableMtrr[Index].Valid) {
1254 if (Address >= VariableMtrr[Index].BaseAddress &&
1255 Address < VariableMtrr[Index].BaseAddress+VariableMtrr[Index].Length) {
1256 TempMtrrType = VariableMtrr[Index].Type;
1257 MtrrType = MtrrPrecedence (MtrrType, TempMtrrType);
1258 }
1259 }
1260 }
1261 CacheType = GetMemoryCacheTypeFromMtrrType (MtrrType);
1262
1263 return CacheType;
1264 }
1265
1266
1267 /**
1268 This function will get the raw value in variable MTRRs
1269
1270 @param VariableSettings A buffer to hold variable MTRRs content.
1271
1272 @return The VariableSettings input pointer
1273
1274 **/
1275 MTRR_VARIABLE_SETTINGS*
1276 EFIAPI
1277 MtrrGetVariableMtrr (
1278 OUT MTRR_VARIABLE_SETTINGS *VariableSettings
1279 )
1280 {
1281 UINT32 Index;
1282 UINT32 VariableMtrrCount;
1283
1284 if (!IsMtrrSupported ()) {
1285 return VariableSettings;
1286 }
1287
1288 VariableMtrrCount = GetVariableMtrrCount ();
1289 ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);
1290
1291 for (Index = 0; Index < VariableMtrrCount; Index++) {
1292 VariableSettings->Mtrr[Index].Base =
1293 AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1));
1294 VariableSettings->Mtrr[Index].Mask =
1295 AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1) + 1);
1296 }
1297
1298 return VariableSettings;
1299 }
1300
1301
1302 /**
1303 Worker function setting variable MTRRs
1304
1305 @param VariableSettings A buffer to hold variable MTRRs content.
1306
1307 **/
1308 VOID
1309 MtrrSetVariableMtrrWorker (
1310 IN MTRR_VARIABLE_SETTINGS *VariableSettings
1311 )
1312 {
1313 UINT32 Index;
1314 UINT32 VariableMtrrCount;
1315
1316 VariableMtrrCount = GetVariableMtrrCount ();
1317 ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);
1318
1319 for (Index = 0; Index < VariableMtrrCount; Index++) {
1320 AsmWriteMsr64 (
1321 MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1),
1322 VariableSettings->Mtrr[Index].Base
1323 );
1324 AsmWriteMsr64 (
1325 MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1) + 1,
1326 VariableSettings->Mtrr[Index].Mask
1327 );
1328 }
1329 }
1330
1331
1332 /**
1333 This function sets variable MTRRs
1334
1335 @param VariableSettings A buffer to hold variable MTRRs content.
1336
1337 @return The pointer of VariableSettings
1338
1339 **/
1340 MTRR_VARIABLE_SETTINGS*
1341 EFIAPI
1342 MtrrSetVariableMtrr (
1343 IN MTRR_VARIABLE_SETTINGS *VariableSettings
1344 )
1345 {
1346 UINTN Cr4;
1347
1348 if (!IsMtrrSupported ()) {
1349 return VariableSettings;
1350 }
1351
1352 Cr4 = PreMtrrChange ();
1353 MtrrSetVariableMtrrWorker (VariableSettings);
1354 PostMtrrChange (Cr4);
1355 return VariableSettings;
1356 }
1357
1358
1359 /**
1360 This function gets the content in fixed MTRRs
1361
1362 @param FixedSettings A buffer to hold fixed Mtrrs content.
1363
1364 @retval The pointer of FixedSettings
1365
1366 **/
1367 MTRR_FIXED_SETTINGS*
1368 EFIAPI
1369 MtrrGetFixedMtrr (
1370 OUT MTRR_FIXED_SETTINGS *FixedSettings
1371 )
1372 {
1373 UINT32 Index;
1374
1375 if (!IsMtrrSupported ()) {
1376 return FixedSettings;
1377 }
1378
1379 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
1380 FixedSettings->Mtrr[Index] =
1381 AsmReadMsr64 (mMtrrLibFixedMtrrTable[Index].Msr);
1382 };
1383
1384 return FixedSettings;
1385 }
1386
1387 /**
1388 Worker function setting fixed MTRRs
1389
1390 @param FixedSettings A buffer to hold fixed Mtrrs content.
1391
1392 **/
1393 VOID
1394 MtrrSetFixedMtrrWorker (
1395 IN MTRR_FIXED_SETTINGS *FixedSettings
1396 )
1397 {
1398 UINT32 Index;
1399
1400 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
1401 AsmWriteMsr64 (
1402 mMtrrLibFixedMtrrTable[Index].Msr,
1403 FixedSettings->Mtrr[Index]
1404 );
1405 }
1406 }
1407
1408
1409 /**
1410 This function sets fixed MTRRs
1411
1412 @param FixedSettings A buffer to hold fixed Mtrrs content.
1413
1414 @retval The pointer of FixedSettings
1415
1416 **/
1417 MTRR_FIXED_SETTINGS*
1418 EFIAPI
1419 MtrrSetFixedMtrr (
1420 IN MTRR_FIXED_SETTINGS *FixedSettings
1421 )
1422 {
1423 UINTN Cr4;
1424
1425 if (!IsMtrrSupported ()) {
1426 return FixedSettings;
1427 }
1428
1429 Cr4 = PreMtrrChange ();
1430 MtrrSetFixedMtrrWorker (FixedSettings);
1431 PostMtrrChange (Cr4);
1432
1433 return FixedSettings;
1434 }
1435
1436
1437 /**
1438 This function gets the content in all MTRRs (variable and fixed)
1439
1440 @param MtrrSetting A buffer to hold all Mtrrs content.
1441
1442 @retval the pointer of MtrrSetting
1443
1444 **/
1445 MTRR_SETTINGS *
1446 EFIAPI
1447 MtrrGetAllMtrrs (
1448 OUT MTRR_SETTINGS *MtrrSetting
1449 )
1450 {
1451 if (!IsMtrrSupported ()) {
1452 return MtrrSetting;
1453 }
1454
1455 //
1456 // Get fixed MTRRs
1457 //
1458 MtrrGetFixedMtrr (&MtrrSetting->Fixed);
1459
1460 //
1461 // Get variable MTRRs
1462 //
1463 MtrrGetVariableMtrr (&MtrrSetting->Variables);
1464
1465 //
1466 // Get MTRR_DEF_TYPE value
1467 //
1468 MtrrSetting->MtrrDefType = AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE);
1469
1470 return MtrrSetting;
1471 }
1472
1473
1474 /**
1475 This function sets all MTRRs (variable and fixed)
1476
1477 @param MtrrSetting A buffer holding all MTRRs content.
1478
1479 @retval The pointer of MtrrSetting
1480
1481 **/
1482 MTRR_SETTINGS *
1483 EFIAPI
1484 MtrrSetAllMtrrs (
1485 IN MTRR_SETTINGS *MtrrSetting
1486 )
1487 {
1488 UINTN Cr4;
1489
1490 if (!IsMtrrSupported ()) {
1491 return MtrrSetting;
1492 }
1493
1494 Cr4 = PreMtrrChange ();
1495
1496 //
1497 // Set fixed MTRRs
1498 //
1499 MtrrSetFixedMtrrWorker (&MtrrSetting->Fixed);
1500
1501 //
1502 // Set variable MTRRs
1503 //
1504 MtrrSetVariableMtrrWorker (&MtrrSetting->Variables);
1505
1506 //
1507 // Set MTRR_DEF_TYPE value
1508 //
1509 AsmWriteMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE, MtrrSetting->MtrrDefType);
1510
1511 PostMtrrChange (Cr4);
1512
1513 return MtrrSetting;
1514 }
1515
1516 /**
1517 This function prints all MTRRs for debugging.
1518 **/
1519 VOID
1520 EFIAPI
1521 MtrrDebugPrintAllMtrrs (
1522 VOID
1523 )
1524 {
1525 DEBUG_CODE (
1526 MTRR_SETTINGS MtrrSettings;
1527 UINTN Index;
1528 UINTN Index1;
1529 UINTN VariableMtrrCount;
1530 UINT64 Base;
1531 UINT64 Limit;
1532 UINT64 MtrrBase;
1533 UINT64 MtrrLimit;
1534 UINT64 RangeBase;
1535 UINT64 RangeLimit;
1536 UINT64 NoRangeBase;
1537 UINT64 NoRangeLimit;
1538 UINT32 RegEax;
1539 UINTN MemoryType;
1540 UINTN PreviousMemoryType;
1541 BOOLEAN Found;
1542
1543 if (!IsMtrrSupported ()) {
1544 return;
1545 }
1546
1547 DEBUG((DEBUG_CACHE, "MTRR Settings\n"));
1548 DEBUG((DEBUG_CACHE, "=============\n"));
1549
1550 MtrrGetAllMtrrs (&MtrrSettings);
1551 DEBUG((DEBUG_CACHE, "MTRR Default Type: %016lx\n", MtrrSettings.MtrrDefType));
1552 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
1553 DEBUG((DEBUG_CACHE, "Fixed MTRR[%02d] : %016lx\n", Index, MtrrSettings.Fixed.Mtrr[Index]));
1554 }
1555
1556 VariableMtrrCount = GetVariableMtrrCount ();
1557 for (Index = 0; Index < VariableMtrrCount; Index++) {
1558 DEBUG((DEBUG_CACHE, "Variable MTRR[%02d]: Base=%016lx Mask=%016lx\n",
1559 Index,
1560 MtrrSettings.Variables.Mtrr[Index].Base,
1561 MtrrSettings.Variables.Mtrr[Index].Mask
1562 ));
1563 }
1564 DEBUG((DEBUG_CACHE, "\n"));
1565 DEBUG((DEBUG_CACHE, "MTRR Ranges\n"));
1566 DEBUG((DEBUG_CACHE, "====================================\n"));
1567
1568 Base = 0;
1569 PreviousMemoryType = MTRR_CACHE_INVALID_TYPE;
1570 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
1571 Base = mMtrrLibFixedMtrrTable[Index].BaseAddress;
1572 for (Index1 = 0; Index1 < 8; Index1++) {
1573 MemoryType = (UINTN)(RShiftU64 (MtrrSettings.Fixed.Mtrr[Index], Index1 * 8) & 0xff);
1574 if (MemoryType > CacheWriteBack) {
1575 MemoryType = MTRR_CACHE_INVALID_TYPE;
1576 }
1577 if (MemoryType != PreviousMemoryType) {
1578 if (PreviousMemoryType != MTRR_CACHE_INVALID_TYPE) {
1579 DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));
1580 }
1581 PreviousMemoryType = MemoryType;
1582 DEBUG((DEBUG_CACHE, "%a:%016lx-", mMtrrMemoryCacheTypeShortName[MemoryType], Base));
1583 }
1584 Base += mMtrrLibFixedMtrrTable[Index].Length;
1585 }
1586 }
1587 DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));
1588
1589 VariableMtrrCount = GetVariableMtrrCount ();
1590
1591 Base = BASE_1MB;
1592 PreviousMemoryType = MTRR_CACHE_INVALID_TYPE;
1593 do {
1594 MemoryType = MtrrGetMemoryAttribute (Base);
1595 if (MemoryType > CacheWriteBack) {
1596 MemoryType = MTRR_CACHE_INVALID_TYPE;
1597 }
1598
1599 if (MemoryType != PreviousMemoryType) {
1600 if (PreviousMemoryType != MTRR_CACHE_INVALID_TYPE) {
1601 DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));
1602 }
1603 PreviousMemoryType = MemoryType;
1604 DEBUG((DEBUG_CACHE, "%a:%016lx-", mMtrrMemoryCacheTypeShortName[MemoryType], Base));
1605 }
1606
1607 RangeBase = BASE_1MB;
1608 NoRangeBase = BASE_1MB;
1609 Limit = BIT36 - 1;
1610 AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
1611 if (RegEax >= 0x80000008) {
1612 AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);
1613 Limit = LShiftU64 (1, RegEax & 0xff) - 1;
1614 }
1615 RangeLimit = Limit;
1616 NoRangeLimit = Limit;
1617
1618 for (Index = 0, Found = FALSE; Index < VariableMtrrCount; Index++) {
1619 if ((MtrrSettings.Variables.Mtrr[Index].Mask & BIT11) == 0) {
1620 //
1621 // If mask is not valid, then do not display range
1622 //
1623 continue;
1624 }
1625 MtrrBase = (MtrrSettings.Variables.Mtrr[Index].Base & (~(SIZE_4KB - 1)));
1626 MtrrLimit = MtrrBase + ((~(MtrrSettings.Variables.Mtrr[Index].Mask & (~(SIZE_4KB - 1)))) & Limit);
1627
1628 if (Base >= MtrrBase && Base < MtrrLimit) {
1629 Found = TRUE;
1630 }
1631
1632 if (Base >= MtrrBase && MtrrBase > RangeBase) {
1633 RangeBase = MtrrBase;
1634 }
1635 if (Base > MtrrLimit && MtrrLimit > RangeBase) {
1636 RangeBase = MtrrLimit + 1;
1637 }
1638 if (Base < MtrrBase && MtrrBase < RangeLimit) {
1639 RangeLimit = MtrrBase - 1;
1640 }
1641 if (Base < MtrrLimit && MtrrLimit <= RangeLimit) {
1642 RangeLimit = MtrrLimit;
1643 }
1644
1645 if (Base > MtrrLimit && NoRangeBase < MtrrLimit) {
1646 NoRangeBase = MtrrLimit + 1;
1647 }
1648 if (Base < MtrrBase && NoRangeLimit > MtrrBase) {
1649 NoRangeLimit = MtrrBase - 1;
1650 }
1651 }
1652
1653 if (Found) {
1654 Base = RangeLimit + 1;
1655 } else {
1656 Base = NoRangeLimit + 1;
1657 }
1658 } while (Found);
1659 DEBUG((DEBUG_CACHE, "%016lx\n\n", Base - 1));
1660 );
1661 }
1662
1663 /**
1664 Checks if MTRR is supported.
1665
1666 @retval TRUE MTRR is supported.
1667 @retval FALSE MTRR is not supported.
1668
1669 **/
1670 BOOLEAN
1671 EFIAPI
1672 IsMtrrSupported (
1673 VOID
1674 )
1675 {
1676 UINT32 RegEdx;
1677 UINT64 MtrrCap;
1678
1679 //
1680 // Check CPUID(1).EDX[12] for MTRR capability
1681 //
1682 AsmCpuid (1, NULL, NULL, NULL, &RegEdx);
1683 if (BitFieldRead32 (RegEdx, 12, 12) == 0) {
1684 return FALSE;
1685 }
1686
1687 //
1688 // Check IA32_MTRRCAP.[0..7] for number of variable MTRRs and IA32_MTRRCAP[8] for
1689 // fixed MTRRs existence. If number of variable MTRRs is zero, or fixed MTRRs do not
1690 // exist, return false.
1691 //
1692 MtrrCap = AsmReadMsr64 (MTRR_LIB_IA32_MTRR_CAP);
1693 if ((BitFieldRead64 (MtrrCap, 0, 7) == 0) || (BitFieldRead64 (MtrrCap, 8, 8) == 0)) {
1694 return FALSE;
1695 }
1696
1697 return TRUE;
1698 }