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