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