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