]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/Library/MtrrLib/MtrrLib.c
fca9258ed7aef8142f484813969c8fd433a9f841
[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 UINT32 VariableMtrrCount;
97
98 if (!IsMtrrSupported ()) {
99 return 0;
100 }
101
102 VariableMtrrCount = (UINT32)(AsmReadMsr64 (MTRR_LIB_IA32_MTRR_CAP) & MTRR_LIB_IA32_MTRR_CAP_VCNT_MASK);
103 ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);
104
105 return VariableMtrrCount;
106 }
107
108 /**
109 Returns the firmware usable variable MTRR count for the CPU.
110
111 @return Firmware usable variable MTRR count
112
113 **/
114 UINT32
115 EFIAPI
116 GetFirmwareVariableMtrrCount (
117 VOID
118 )
119 {
120 UINT32 VariableMtrrCount;
121
122 VariableMtrrCount = GetVariableMtrrCount ();
123 if (VariableMtrrCount < RESERVED_FIRMWARE_VARIABLE_MTRR_NUMBER) {
124 return 0;
125 }
126
127 return VariableMtrrCount - RESERVED_FIRMWARE_VARIABLE_MTRR_NUMBER;
128 }
129
130 /**
131 Returns the default MTRR cache type for the system.
132
133 @return MTRR default type
134
135 **/
136 UINT64
137 GetMtrrDefaultMemoryType (
138 VOID
139 )
140 {
141 return (AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE) & 0xff);
142 }
143
144
145 /**
146 Preparation before programming MTRR.
147
148 This function will do some preparation for programming MTRRs:
149 disable cache, invalid cache and disable MTRR caching functionality
150
151 @return CR4 value before changing.
152
153 **/
154 UINTN
155 PreMtrrChange (
156 VOID
157 )
158 {
159 UINTN Value;
160
161 //
162 // Enter no fill cache mode, CD=1(Bit30), NW=0 (Bit29)
163 //
164 AsmDisableCache ();
165
166 //
167 // Save original CR4 value and clear PGE flag (Bit 7)
168 //
169 Value = AsmReadCr4 ();
170 AsmWriteCr4 (Value & (~BIT7));
171
172 //
173 // Flush all TLBs
174 //
175 CpuFlushTlb ();
176
177 //
178 // Disable Mtrrs
179 //
180 AsmMsrBitFieldWrite64 (MTRR_LIB_IA32_MTRR_DEF_TYPE, 10, 11, 0);
181
182 //
183 // Return original CR4 value
184 //
185 return Value;
186 }
187
188
189 /**
190 Cleaning up after programming MTRRs.
191
192 This function will do some clean up after programming MTRRs:
193 enable MTRR caching functionality, and enable cache
194
195 @param Cr4 CR4 value to restore
196
197 **/
198 VOID
199 PostMtrrChange (
200 UINTN Cr4
201 )
202 {
203 //
204 // Enable Cache MTRR
205 //
206 AsmMsrBitFieldWrite64 (MTRR_LIB_IA32_MTRR_DEF_TYPE, 10, 11, 3);
207
208 //
209 // Flush all TLBs
210 //
211 CpuFlushTlb ();
212
213 //
214 // Enable Normal Mode caching CD=NW=0, CD(Bit30), NW(Bit29)
215 //
216 AsmEnableCache ();
217
218 //
219 // Restore original CR4 value
220 //
221 AsmWriteCr4 (Cr4);
222 }
223
224
225 /**
226 Programs fixed MTRRs registers.
227
228 @param MemoryCacheType The memory type to set.
229 @param Base The base address of memory range.
230 @param Length The length of memory range.
231
232 @retval RETURN_SUCCESS The cache type was updated successfully
233 @retval RETURN_UNSUPPORTED The requested range or cache type was invalid
234 for the fixed MTRRs.
235
236 **/
237 RETURN_STATUS
238 ProgramFixedMtrr (
239 IN UINT64 MemoryCacheType,
240 IN OUT UINT64 *Base,
241 IN OUT UINT64 *Length
242 )
243 {
244 UINT32 MsrNum;
245 UINT32 ByteShift;
246 UINT64 TempQword;
247 UINT64 OrMask;
248 UINT64 ClearMask;
249
250 TempQword = 0;
251 OrMask = 0;
252 ClearMask = 0;
253
254 for (MsrNum = 0; MsrNum < MTRR_NUMBER_OF_FIXED_MTRR; MsrNum++) {
255 if ((*Base >= MtrrLibFixedMtrrTable[MsrNum].BaseAddress) &&
256 (*Base <
257 (
258 MtrrLibFixedMtrrTable[MsrNum].BaseAddress +
259 (8 * MtrrLibFixedMtrrTable[MsrNum].Length)
260 )
261 )
262 ) {
263 break;
264 }
265 }
266
267 if (MsrNum == MTRR_NUMBER_OF_FIXED_MTRR) {
268 return RETURN_UNSUPPORTED;
269 }
270
271 //
272 // We found the fixed MTRR to be programmed
273 //
274 for (ByteShift = 0; ByteShift < 8; ByteShift++) {
275 if (*Base ==
276 (
277 MtrrLibFixedMtrrTable[MsrNum].BaseAddress +
278 (ByteShift * MtrrLibFixedMtrrTable[MsrNum].Length)
279 )
280 ) {
281 break;
282 }
283 }
284
285 if (ByteShift == 8) {
286 return RETURN_UNSUPPORTED;
287 }
288
289 for (
290 ;
291 ((ByteShift < 8) && (*Length >= MtrrLibFixedMtrrTable[MsrNum].Length));
292 ByteShift++
293 ) {
294 OrMask |= LShiftU64 ((UINT64) MemoryCacheType, (UINT32) (ByteShift * 8));
295 ClearMask |= LShiftU64 ((UINT64) 0xFF, (UINT32) (ByteShift * 8));
296 *Length -= MtrrLibFixedMtrrTable[MsrNum].Length;
297 *Base += MtrrLibFixedMtrrTable[MsrNum].Length;
298 }
299
300 if (ByteShift < 8 && (*Length != 0)) {
301 return RETURN_UNSUPPORTED;
302 }
303
304 TempQword =
305 (AsmReadMsr64 (MtrrLibFixedMtrrTable[MsrNum].Msr) & ~ClearMask) | OrMask;
306 AsmWriteMsr64 (MtrrLibFixedMtrrTable[MsrNum].Msr, TempQword);
307 return RETURN_SUCCESS;
308 }
309
310
311 /**
312 Get the attribute of variable MTRRs.
313
314 This function shadows the content of variable MTRRs into an
315 internal array: VariableMtrr.
316
317 @param MtrrValidBitsMask The mask for the valid bit of the MTRR
318 @param MtrrValidAddressMask The valid address mask for MTRR
319 @param VariableMtrr The array to shadow variable MTRRs content
320
321 @return The return value of this paramter indicates the
322 number of MTRRs which has been used.
323
324 **/
325 UINT32
326 EFIAPI
327 MtrrGetMemoryAttributeInVariableMtrr (
328 IN UINT64 MtrrValidBitsMask,
329 IN UINT64 MtrrValidAddressMask,
330 OUT VARIABLE_MTRR *VariableMtrr
331 )
332 {
333 UINTN Index;
334 UINT32 MsrNum;
335 UINT32 UsedMtrr;
336 UINT32 FirmwareVariableMtrrCount;
337 UINT32 VariableMtrrEnd;
338
339 if (!IsMtrrSupported ()) {
340 return 0;
341 }
342
343 FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCount ();
344 VariableMtrrEnd = MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (2 * GetVariableMtrrCount ()) - 1;
345
346 ZeroMem (VariableMtrr, sizeof (VARIABLE_MTRR) * MTRR_NUMBER_OF_VARIABLE_MTRR);
347 UsedMtrr = 0;
348
349 for (MsrNum = MTRR_LIB_IA32_VARIABLE_MTRR_BASE, Index = 0;
350 (
351 (MsrNum < VariableMtrrEnd) &&
352 (Index < FirmwareVariableMtrrCount)
353 );
354 MsrNum += 2
355 ) {
356 if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) != 0) {
357 VariableMtrr[Index].Msr = MsrNum;
358 VariableMtrr[Index].BaseAddress = (AsmReadMsr64 (MsrNum) &
359 MtrrValidAddressMask);
360 VariableMtrr[Index].Length = ((~(AsmReadMsr64 (MsrNum + 1) &
361 MtrrValidAddressMask)
362 ) &
363 MtrrValidBitsMask
364 ) + 1;
365 VariableMtrr[Index].Type = (AsmReadMsr64 (MsrNum) & 0x0ff);
366 VariableMtrr[Index].Valid = TRUE;
367 VariableMtrr[Index].Used = TRUE;
368 UsedMtrr = UsedMtrr + 1;
369 Index++;
370 }
371 }
372 return UsedMtrr;
373 }
374
375
376 /**
377 Checks overlap between given memory range and MTRRs.
378
379 @param Start The start address of memory range.
380 @param End The end address of memory range.
381 @param VariableMtrr The array to shadow variable MTRRs content
382
383 @retval TRUE Overlap exists.
384 @retval FALSE No overlap.
385
386 **/
387 BOOLEAN
388 CheckMemoryAttributeOverlap (
389 IN PHYSICAL_ADDRESS Start,
390 IN PHYSICAL_ADDRESS End,
391 IN VARIABLE_MTRR *VariableMtrr
392 )
393 {
394 UINT32 Index;
395
396 for (Index = 0; Index < 6; Index++) {
397 if (
398 VariableMtrr[Index].Valid &&
399 !(
400 (Start > (VariableMtrr[Index].BaseAddress +
401 VariableMtrr[Index].Length - 1)
402 ) ||
403 (End < VariableMtrr[Index].BaseAddress)
404 )
405 ) {
406 return TRUE;
407 }
408 }
409
410 return FALSE;
411 }
412
413
414 /**
415 Marks a variable MTRR as non-valid.
416
417 @param Index The index of the array VariableMtrr to be invalidated
418 @param VariableMtrr The array to shadow variable MTRRs content
419 @param UsedMtrr The number of MTRRs which has already been used
420
421 **/
422 VOID
423 InvalidateShadowMtrr (
424 IN UINTN Index,
425 IN VARIABLE_MTRR *VariableMtrr,
426 OUT UINT32 *UsedMtrr
427 )
428 {
429 VariableMtrr[Index].Valid = FALSE;
430 *UsedMtrr = *UsedMtrr - 1;
431 }
432
433
434 /**
435 Combine memory attributes.
436
437 If overlap exists between given memory range and MTRRs, try to combine them.
438
439 @param Attributes The memory type to set.
440 @param Base The base address of memory range.
441 @param Length The length of memory range.
442 @param VariableMtrr The array to shadow variable MTRRs content
443 @param UsedMtrr The number of MTRRs which has already been used
444 @param OverwriteExistingMtrr Returns whether an existing MTRR was used
445
446 @retval EFI_SUCCESS Memory region successfully combined.
447 @retval EFI_ACCESS_DENIED Memory region cannot be combined.
448
449 **/
450 RETURN_STATUS
451 CombineMemoryAttribute (
452 IN UINT64 Attributes,
453 IN OUT UINT64 *Base,
454 IN OUT UINT64 *Length,
455 IN VARIABLE_MTRR *VariableMtrr,
456 IN OUT UINT32 *UsedMtrr,
457 OUT BOOLEAN *OverwriteExistingMtrr
458 )
459 {
460 UINT32 Index;
461 UINT64 CombineStart;
462 UINT64 CombineEnd;
463 UINT64 MtrrEnd;
464 UINT64 EndAddress;
465 UINT32 FirmwareVariableMtrrCount;
466
467 FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCount ();
468
469 *OverwriteExistingMtrr = FALSE;
470 EndAddress = *Base +*Length - 1;
471
472 for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) {
473
474 MtrrEnd = VariableMtrr[Index].BaseAddress + VariableMtrr[Index].Length - 1;
475 if (
476 !VariableMtrr[Index].Valid ||
477 (
478 *Base > (MtrrEnd) ||
479 (EndAddress < VariableMtrr[Index].BaseAddress)
480 )
481 ) {
482 continue;
483 }
484
485 //
486 // Combine same attribute MTRR range
487 //
488 if (Attributes == VariableMtrr[Index].Type) {
489 //
490 // if the Mtrr range contain the request range, return RETURN_SUCCESS
491 //
492 if (VariableMtrr[Index].BaseAddress <= *Base && MtrrEnd >= EndAddress) {
493 *Length = 0;
494 return RETURN_SUCCESS;
495 }
496 //
497 // invalid this MTRR, and program the combine range
498 //
499 CombineStart =
500 (*Base) < VariableMtrr[Index].BaseAddress ?
501 (*Base) :
502 VariableMtrr[Index].BaseAddress;
503 CombineEnd = EndAddress > MtrrEnd ? EndAddress : MtrrEnd;
504
505 //
506 // Record the MTRR usage status in VariableMtrr array.
507 //
508 InvalidateShadowMtrr (Index, VariableMtrr, UsedMtrr);
509 *Base = CombineStart;
510 *Length = CombineEnd - CombineStart + 1;
511 EndAddress = CombineEnd;
512 *OverwriteExistingMtrr = TRUE;
513 continue;
514 } else {
515 //
516 // The cache type is different, but the range is convered by one MTRR
517 //
518 if (VariableMtrr[Index].BaseAddress == *Base && MtrrEnd == EndAddress) {
519 InvalidateShadowMtrr (Index, VariableMtrr, UsedMtrr);
520 continue;
521 }
522
523 }
524
525 if ((Attributes== MTRR_CACHE_WRITE_THROUGH &&
526 VariableMtrr[Index].Type == MTRR_CACHE_WRITE_BACK) ||
527 (Attributes == MTRR_CACHE_WRITE_BACK &&
528 VariableMtrr[Index].Type == MTRR_CACHE_WRITE_THROUGH) ||
529 (Attributes == MTRR_CACHE_UNCACHEABLE) ||
530 (VariableMtrr[Index].Type == MTRR_CACHE_UNCACHEABLE)
531 ) {
532 *OverwriteExistingMtrr = TRUE;
533 continue;
534 }
535 //
536 // Other type memory overlap is invalid
537 //
538 return RETURN_ACCESS_DENIED;
539 }
540
541 return RETURN_SUCCESS;
542 }
543
544
545 /**
546 Calculate the maximum value which is a power of 2, but less the MemoryLength.
547
548 @param MemoryLength The number to pass in.
549 @return The maximum value which is align to power of 2 and less the MemoryLength
550
551 **/
552 UINT64
553 Power2MaxMemory (
554 IN UINT64 MemoryLength
555 )
556 {
557 UINT64 Result;
558
559 if (RShiftU64 (MemoryLength, 32) != 0) {
560 Result = LShiftU64 (
561 (UINT64) GetPowerOfTwo32 (
562 (UINT32) RShiftU64 (MemoryLength, 32)
563 ),
564 32
565 );
566 } else {
567 Result = (UINT64) GetPowerOfTwo32 ((UINT32) MemoryLength);
568 }
569
570 return Result;
571 }
572
573
574 /**
575 Check the direction to program variable MTRRs.
576
577 This function determines which direction of programming the variable
578 MTRRs will use fewer MTRRs.
579
580 @param Input Length of Memory to program MTRR
581 @param MtrrNumber Pointer to the number of necessary MTRRs
582
583 @retval TRUE Positive direction is better.
584 FALSE Negtive direction is better.
585
586 **/
587 BOOLEAN
588 GetDirection (
589 IN UINT64 Input,
590 IN UINTN *MtrrNumber
591 )
592 {
593 UINT64 TempQword;
594 UINT32 Positive;
595 UINT32 Subtractive;
596
597 TempQword = Input;
598 Positive = 0;
599 Subtractive = 0;
600
601 do {
602 TempQword -= Power2MaxMemory (TempQword);
603 Positive++;
604 } while (TempQword != 0);
605
606 TempQword = Power2MaxMemory (LShiftU64 (Input, 1)) - Input;
607 Subtractive++;
608 do {
609 TempQword -= Power2MaxMemory (TempQword);
610 Subtractive++;
611 } while (TempQword != 0);
612
613 if (Positive <= Subtractive) {
614 *MtrrNumber = Positive;
615 return TRUE;
616 } else {
617 *MtrrNumber = Subtractive;
618 return FALSE;
619 }
620 }
621
622 /**
623 Invalid variable MTRRs according to the value in the shadow array.
624
625 This function programs MTRRs according to the values specified
626 in the shadow array.
627
628 @param VariableMtrr The array to shadow variable MTRRs content
629
630 **/
631 VOID
632 InvalidateMtrr (
633 IN VARIABLE_MTRR *VariableMtrr
634 )
635 {
636 UINTN Index;
637 UINTN Cr4;
638 UINTN VariableMtrrCount;
639
640 Cr4 = PreMtrrChange ();
641 Index = 0;
642 VariableMtrrCount = GetVariableMtrrCount ();
643 while (Index < VariableMtrrCount) {
644 if (!VariableMtrr[Index].Valid && VariableMtrr[Index].Used) {
645 AsmWriteMsr64 (VariableMtrr[Index].Msr, 0);
646 AsmWriteMsr64 (VariableMtrr[Index].Msr + 1, 0);
647 VariableMtrr[Index].Used = FALSE;
648 }
649 Index ++;
650 }
651 PostMtrrChange (Cr4);
652 }
653
654
655 /**
656 Programs variable MTRRs
657
658 This function programs variable MTRRs
659
660 @param MtrrNumber Index of MTRR to program.
661 @param BaseAddress Base address of memory region.
662 @param Length Length of memory region.
663 @param MemoryCacheType Memory type to set.
664 @param MtrrValidAddressMask The valid address mask for MTRR
665
666 **/
667 VOID
668 ProgramVariableMtrr (
669 IN UINTN MtrrNumber,
670 IN PHYSICAL_ADDRESS BaseAddress,
671 IN UINT64 Length,
672 IN UINT64 MemoryCacheType,
673 IN UINT64 MtrrValidAddressMask
674 )
675 {
676 UINT64 TempQword;
677 UINTN Cr4;
678
679 Cr4 = PreMtrrChange ();
680
681 //
682 // MTRR Physical Base
683 //
684 TempQword = (BaseAddress & MtrrValidAddressMask) | MemoryCacheType;
685 AsmWriteMsr64 ((UINT32) MtrrNumber, TempQword);
686
687 //
688 // MTRR Physical Mask
689 //
690 TempQword = ~(Length - 1);
691 AsmWriteMsr64 (
692 (UINT32) (MtrrNumber + 1),
693 (TempQword & MtrrValidAddressMask) | MTRR_LIB_CACHE_MTRR_ENABLED
694 );
695
696 PostMtrrChange (Cr4);
697 }
698
699
700 /**
701 Convert the Memory attibute value to MTRR_MEMORY_CACHE_TYPE.
702
703 @param MtrrType MTRR memory type
704
705 @return The enum item in MTRR_MEMORY_CACHE_TYPE
706
707 **/
708 MTRR_MEMORY_CACHE_TYPE
709 GetMemoryCacheTypeFromMtrrType (
710 IN UINT64 MtrrType
711 )
712 {
713 switch (MtrrType) {
714 case MTRR_CACHE_UNCACHEABLE:
715 return CacheUncacheable;
716 case MTRR_CACHE_WRITE_COMBINING:
717 return CacheWriteCombining;
718 case MTRR_CACHE_WRITE_THROUGH:
719 return CacheWriteThrough;
720 case MTRR_CACHE_WRITE_PROTECTED:
721 return CacheWriteProtected;
722 case MTRR_CACHE_WRITE_BACK:
723 return CacheWriteBack;
724 default:
725 //
726 // MtrrType is MTRR_CACHE_INVALID_TYPE, that means
727 // no mtrr covers the range
728 //
729 return CacheUncacheable;
730 }
731 }
732
733 /**
734 Initializes the valid bits mask and valid address mask for MTRRs.
735
736 This function initializes the valid bits mask and valid address mask for MTRRs.
737
738 @param MtrrValidBitsMask The mask for the valid bit of the MTRR
739 @param MtrrValidAddressMask The valid address mask for the MTRR
740
741 **/
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 EFIAPI
1456 MtrrDebugPrintAllMtrrs (
1457 VOID
1458 )
1459 {
1460 DEBUG_CODE (
1461 {
1462 MTRR_SETTINGS MtrrSettings;
1463 UINTN Index;
1464 UINTN VariableMtrrCount;
1465
1466 if (!IsMtrrSupported ()) {
1467 return;
1468 }
1469
1470 MtrrGetAllMtrrs (&MtrrSettings);
1471 DEBUG((EFI_D_ERROR, "DefaultType = %016lx\n", MtrrSettings.MtrrDefType));
1472 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
1473 DEBUG((
1474 EFI_D_ERROR, "Fixed[%02d] = %016lx\n",
1475 Index,
1476 MtrrSettings.Fixed.Mtrr[Index]
1477 ));
1478 }
1479
1480 VariableMtrrCount = GetVariableMtrrCount ();
1481 for (Index = 0; Index < VariableMtrrCount; Index++) {
1482 DEBUG((
1483 EFI_D_ERROR, "Variable[%02d] = %016lx, %016lx\n",
1484 Index,
1485 MtrrSettings.Variables.Mtrr[Index].Base,
1486 MtrrSettings.Variables.Mtrr[Index].Mask
1487 ));
1488 }
1489 }
1490 );
1491 }
1492
1493 /**
1494 Checks if MTRR is supported.
1495
1496 @retval TRUE MTRR is supported.
1497 @retval FALSE MTRR is not supported.
1498
1499 **/
1500 BOOLEAN
1501 EFIAPI
1502 IsMtrrSupported (
1503 VOID
1504 )
1505 {
1506 UINT32 RegEdx;
1507 UINT64 MtrrCap;
1508
1509 //
1510 // Check CPUID(1).EDX[12] for MTRR capability
1511 //
1512 AsmCpuid (1, NULL, NULL, NULL, &RegEdx);
1513 if (BitFieldRead32 (RegEdx, 12, 12) == 0) {
1514 return FALSE;
1515 }
1516
1517 //
1518 // Check IA32_MTRRCAP.[0..7] for number of variable MTRRs and IA32_MTRRCAP[8] for
1519 // fixed MTRRs existence. If number of variable MTRRs is zero, or fixed MTRRs do not
1520 // exist, return false.
1521 //
1522 MtrrCap = AsmReadMsr64 (MTRR_LIB_IA32_MTRR_CAP);
1523 if ((BitFieldRead64 (MtrrCap, 0, 7) == 0) || (BitFieldRead64 (MtrrCap, 8, 8) == 0)) {
1524 return FALSE;
1525 }
1526
1527 return TRUE;
1528 }