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