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