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