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