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