]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/Library/MtrrLib/MtrrLib.c
UefiCpuPkg/MtrrLib: Add MtrrSetMemoryAttributeInMtrrSettings()
[mirror_edk2.git] / UefiCpuPkg / Library / MtrrLib / MtrrLib.c
1 /** @file
2 MTRR setting library
3
4 Copyright (c) 2008 - 2015, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include <Base.h>
16
17 #include <Library/MtrrLib.h>
18 #include <Library/BaseLib.h>
19 #include <Library/CpuLib.h>
20 #include <Library/BaseMemoryLib.h>
21 #include <Library/DebugLib.h>
22
23 //
24 // Context to save and restore when MTRRs are programmed
25 //
26 typedef struct {
27 UINTN Cr4;
28 BOOLEAN InterruptState;
29 } MTRR_CONTEXT;
30
31 //
32 // This table defines the offset, base and length of the fixed MTRRs
33 //
34 CONST FIXED_MTRR mMtrrLibFixedMtrrTable[] = {
35 {
36 MTRR_LIB_IA32_MTRR_FIX64K_00000,
37 0,
38 SIZE_64KB
39 },
40 {
41 MTRR_LIB_IA32_MTRR_FIX16K_80000,
42 0x80000,
43 SIZE_16KB
44 },
45 {
46 MTRR_LIB_IA32_MTRR_FIX16K_A0000,
47 0xA0000,
48 SIZE_16KB
49 },
50 {
51 MTRR_LIB_IA32_MTRR_FIX4K_C0000,
52 0xC0000,
53 SIZE_4KB
54 },
55 {
56 MTRR_LIB_IA32_MTRR_FIX4K_C8000,
57 0xC8000,
58 SIZE_4KB
59 },
60 {
61 MTRR_LIB_IA32_MTRR_FIX4K_D0000,
62 0xD0000,
63 SIZE_4KB
64 },
65 {
66 MTRR_LIB_IA32_MTRR_FIX4K_D8000,
67 0xD8000,
68 SIZE_4KB
69 },
70 {
71 MTRR_LIB_IA32_MTRR_FIX4K_E0000,
72 0xE0000,
73 SIZE_4KB
74 },
75 {
76 MTRR_LIB_IA32_MTRR_FIX4K_E8000,
77 0xE8000,
78 SIZE_4KB
79 },
80 {
81 MTRR_LIB_IA32_MTRR_FIX4K_F0000,
82 0xF0000,
83 SIZE_4KB
84 },
85 {
86 MTRR_LIB_IA32_MTRR_FIX4K_F8000,
87 0xF8000,
88 SIZE_4KB
89 }
90 };
91
92 //
93 // Lookup table used to print MTRRs
94 //
95 GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 *mMtrrMemoryCacheTypeShortName[] = {
96 "UC", // CacheUncacheable
97 "WC", // CacheWriteCombining
98 "R*", // Invalid
99 "R*", // Invalid
100 "WT", // CacheWriteThrough
101 "WP", // CacheWriteProtected
102 "WB", // CacheWriteBack
103 "R*" // Invalid
104 };
105
106 /**
107 Worker function returns the variable MTRR count for the CPU.
108
109 @return Variable MTRR count
110
111 **/
112 UINT32
113 GetVariableMtrrCountWorker (
114 VOID
115 )
116 {
117 UINT32 VariableMtrrCount;
118
119 VariableMtrrCount = (UINT32)(AsmReadMsr64 (MTRR_LIB_IA32_MTRR_CAP) & MTRR_LIB_IA32_MTRR_CAP_VCNT_MASK);
120 ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);
121 return VariableMtrrCount;
122 }
123
124 /**
125 Returns the variable MTRR count for the CPU.
126
127 @return Variable MTRR count
128
129 **/
130 UINT32
131 EFIAPI
132 GetVariableMtrrCount (
133 VOID
134 )
135 {
136 if (!IsMtrrSupported ()) {
137 return 0;
138 }
139 return GetVariableMtrrCountWorker ();
140 }
141
142 /**
143 Worker function returns the firmware usable variable MTRR count for the CPU.
144
145 @return Firmware usable variable MTRR count
146
147 **/
148 UINT32
149 GetFirmwareVariableMtrrCountWorker (
150 VOID
151 )
152 {
153 UINT32 VariableMtrrCount;
154 UINT32 ReservedMtrrNumber;
155
156 VariableMtrrCount = GetVariableMtrrCountWorker ();
157 ReservedMtrrNumber = PcdGet32 (PcdCpuNumberOfReservedVariableMtrrs);
158 if (VariableMtrrCount < ReservedMtrrNumber) {
159 return 0;
160 }
161
162 return VariableMtrrCount - ReservedMtrrNumber;
163 }
164
165 /**
166 Returns the firmware usable variable MTRR count for the CPU.
167
168 @return Firmware usable variable MTRR count
169
170 **/
171 UINT32
172 EFIAPI
173 GetFirmwareVariableMtrrCount (
174 VOID
175 )
176 {
177 if (!IsMtrrSupported ()) {
178 return 0;
179 }
180 return GetFirmwareVariableMtrrCountWorker ();
181 }
182
183 /**
184 Worker function returns the default MTRR cache type for the system.
185
186 If MtrrSetting is not NULL, returns the default MTRR cache type from input
187 MTRR settings buffer.
188 If MtrrSetting is NULL, returns the default MTRR cache type from MSR.
189
190 @param[in] MtrrSetting A buffer holding all MTRRs content.
191
192 @return The default MTRR cache type.
193
194 **/
195 MTRR_MEMORY_CACHE_TYPE
196 MtrrGetDefaultMemoryTypeWorker (
197 IN MTRR_SETTINGS *MtrrSetting
198 )
199 {
200 if (MtrrSetting == NULL) {
201 return (MTRR_MEMORY_CACHE_TYPE) (AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE) & 0x7);
202 } else {
203 return (MTRR_MEMORY_CACHE_TYPE) (MtrrSetting->MtrrDefType & 0x7);
204 }
205 }
206
207
208 /**
209 Returns the default MTRR cache type for the system.
210
211 @return The default MTRR cache type.
212
213 **/
214 MTRR_MEMORY_CACHE_TYPE
215 EFIAPI
216 MtrrGetDefaultMemoryType (
217 VOID
218 )
219 {
220 if (!IsMtrrSupported ()) {
221 return CacheUncacheable;
222 }
223 return MtrrGetDefaultMemoryTypeWorker (NULL);
224 }
225
226 /**
227 Preparation before programming MTRR.
228
229 This function will do some preparation for programming MTRRs:
230 disable cache, invalid cache and disable MTRR caching functionality
231
232 @param[out] MtrrContext Pointer to context to save
233
234 **/
235 VOID
236 PreMtrrChange (
237 OUT MTRR_CONTEXT *MtrrContext
238 )
239 {
240 //
241 // Disable interrupts and save current interrupt state
242 //
243 MtrrContext->InterruptState = SaveAndDisableInterrupts();
244
245 //
246 // Enter no fill cache mode, CD=1(Bit30), NW=0 (Bit29)
247 //
248 AsmDisableCache ();
249
250 //
251 // Save original CR4 value and clear PGE flag (Bit 7)
252 //
253 MtrrContext->Cr4 = AsmReadCr4 ();
254 AsmWriteCr4 (MtrrContext->Cr4 & (~BIT7));
255
256 //
257 // Flush all TLBs
258 //
259 CpuFlushTlb ();
260
261 //
262 // Disable MTRRs
263 //
264 AsmMsrBitFieldWrite64 (MTRR_LIB_IA32_MTRR_DEF_TYPE, 10, 11, 0);
265 }
266
267 /**
268 Cleaning up after programming MTRRs.
269
270 This function will do some clean up after programming MTRRs:
271 Flush all TLBs, re-enable caching, restore CR4.
272
273 @param[in] MtrrContext Pointer to context to restore
274
275 **/
276 VOID
277 PostMtrrChangeEnableCache (
278 IN MTRR_CONTEXT *MtrrContext
279 )
280 {
281 //
282 // Flush all TLBs
283 //
284 CpuFlushTlb ();
285
286 //
287 // Enable Normal Mode caching CD=NW=0, CD(Bit30), NW(Bit29)
288 //
289 AsmEnableCache ();
290
291 //
292 // Restore original CR4 value
293 //
294 AsmWriteCr4 (MtrrContext->Cr4);
295
296 //
297 // Restore original interrupt state
298 //
299 SetInterruptState (MtrrContext->InterruptState);
300 }
301
302 /**
303 Cleaning up after programming MTRRs.
304
305 This function will do some clean up after programming MTRRs:
306 enable MTRR caching functionality, and enable cache
307
308 @param[in] MtrrContext Pointer to context to restore
309
310 **/
311 VOID
312 PostMtrrChange (
313 IN MTRR_CONTEXT *MtrrContext
314 )
315 {
316 //
317 // Enable Cache MTRR
318 //
319 AsmMsrBitFieldWrite64 (MTRR_LIB_IA32_MTRR_DEF_TYPE, 10, 11, 3);
320
321 PostMtrrChangeEnableCache (MtrrContext);
322 }
323
324 /**
325 Worker function gets the content in fixed MTRRs
326
327 @param[out] FixedSettings A buffer to hold fixed MTRRs content.
328
329 @retval The pointer of FixedSettings
330
331 **/
332 MTRR_FIXED_SETTINGS*
333 MtrrGetFixedMtrrWorker (
334 OUT MTRR_FIXED_SETTINGS *FixedSettings
335 )
336 {
337 UINT32 Index;
338
339 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
340 FixedSettings->Mtrr[Index] =
341 AsmReadMsr64 (mMtrrLibFixedMtrrTable[Index].Msr);
342 }
343
344 return FixedSettings;
345 }
346
347
348 /**
349 This function gets the content in fixed MTRRs
350
351 @param[out] FixedSettings A buffer to hold fixed MTRRs content.
352
353 @retval The pointer of FixedSettings
354
355 **/
356 MTRR_FIXED_SETTINGS*
357 EFIAPI
358 MtrrGetFixedMtrr (
359 OUT MTRR_FIXED_SETTINGS *FixedSettings
360 )
361 {
362 if (!IsMtrrSupported ()) {
363 return FixedSettings;
364 }
365
366 return MtrrGetFixedMtrrWorker (FixedSettings);
367 }
368
369
370 /**
371 Worker function will get the raw value in variable MTRRs
372
373 If MtrrSetting is not NULL, gets the variable MTRRs raw value from input
374 MTRR settings buffer.
375 If MtrrSetting is NULL, gets the variable MTRRs raw value from MTRRs.
376
377 @param[in] MtrrSetting A buffer holding all MTRRs content.
378 @param[in] VariableMtrrCount Number of variable MTRRs.
379 @param[out] VariableSettings A buffer to hold variable MTRRs content.
380
381 @return The VariableSettings input pointer
382
383 **/
384 MTRR_VARIABLE_SETTINGS*
385 MtrrGetVariableMtrrWorker (
386 IN MTRR_SETTINGS *MtrrSetting,
387 IN UINT32 VariableMtrrCount,
388 OUT MTRR_VARIABLE_SETTINGS *VariableSettings
389 )
390 {
391 UINT32 Index;
392
393 ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);
394
395 for (Index = 0; Index < VariableMtrrCount; Index++) {
396 if (MtrrSetting == NULL) {
397 VariableSettings->Mtrr[Index].Base =
398 AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1));
399 VariableSettings->Mtrr[Index].Mask =
400 AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1) + 1);
401 } else {
402 VariableSettings->Mtrr[Index].Base = MtrrSetting->Variables.Mtrr[Index].Base;
403 VariableSettings->Mtrr[Index].Mask = MtrrSetting->Variables.Mtrr[Index].Mask;
404 }
405 }
406
407 return VariableSettings;
408 }
409
410 /**
411 This function will get the raw value in variable MTRRs
412
413 @param[out] VariableSettings A buffer to hold variable MTRRs content.
414
415 @return The VariableSettings input pointer
416
417 **/
418 MTRR_VARIABLE_SETTINGS*
419 EFIAPI
420 MtrrGetVariableMtrr (
421 OUT MTRR_VARIABLE_SETTINGS *VariableSettings
422 )
423 {
424 if (!IsMtrrSupported ()) {
425 return VariableSettings;
426 }
427
428 return MtrrGetVariableMtrrWorker (
429 NULL,
430 GetVariableMtrrCountWorker (),
431 VariableSettings
432 );
433 }
434
435 /**
436 Programs fixed MTRRs registers.
437
438 @param[in] MemoryCacheType The memory type to set.
439 @param[in, out] Base The base address of memory range.
440 @param[in, out] Length The length of memory range.
441 @param[out] ReturnMsrNum The index of the fixed MTRR MSR to program.
442 @param[out] ReturnClearMask The bits to clear in the fixed MTRR MSR.
443 @param[out] ReturnOrMask The bits to set in the fixed MTRR MSR.
444
445 @retval RETURN_SUCCESS The cache type was updated successfully
446 @retval RETURN_UNSUPPORTED The requested range or cache type was invalid
447 for the fixed MTRRs.
448
449 **/
450 RETURN_STATUS
451 ProgramFixedMtrr (
452 IN UINT64 MemoryCacheType,
453 IN OUT UINT64 *Base,
454 IN OUT UINT64 *Length,
455 OUT UINT32 *ReturnMsrNum,
456 OUT UINT64 *ReturnClearMask,
457 OUT UINT64 *ReturnOrMask
458 )
459 {
460 UINT32 MsrNum;
461 UINT32 ByteShift;
462 UINT64 TempQword;
463 UINT64 OrMask;
464 UINT64 ClearMask;
465
466 TempQword = 0;
467 OrMask = 0;
468 ClearMask = 0;
469
470 for (MsrNum = 0; MsrNum < MTRR_NUMBER_OF_FIXED_MTRR; MsrNum++) {
471 if ((*Base >= mMtrrLibFixedMtrrTable[MsrNum].BaseAddress) &&
472 (*Base <
473 (
474 mMtrrLibFixedMtrrTable[MsrNum].BaseAddress +
475 (8 * mMtrrLibFixedMtrrTable[MsrNum].Length)
476 )
477 )
478 ) {
479 break;
480 }
481 }
482
483 if (MsrNum == MTRR_NUMBER_OF_FIXED_MTRR) {
484 return RETURN_UNSUPPORTED;
485 }
486
487 //
488 // We found the fixed MTRR to be programmed
489 //
490 for (ByteShift = 0; ByteShift < 8; ByteShift++) {
491 if (*Base ==
492 (
493 mMtrrLibFixedMtrrTable[MsrNum].BaseAddress +
494 (ByteShift * mMtrrLibFixedMtrrTable[MsrNum].Length)
495 )
496 ) {
497 break;
498 }
499 }
500
501 if (ByteShift == 8) {
502 return RETURN_UNSUPPORTED;
503 }
504
505 for (
506 ;
507 ((ByteShift < 8) && (*Length >= mMtrrLibFixedMtrrTable[MsrNum].Length));
508 ByteShift++
509 ) {
510 OrMask |= LShiftU64 ((UINT64) MemoryCacheType, (UINT32) (ByteShift * 8));
511 ClearMask |= LShiftU64 ((UINT64) 0xFF, (UINT32) (ByteShift * 8));
512 *Length -= mMtrrLibFixedMtrrTable[MsrNum].Length;
513 *Base += mMtrrLibFixedMtrrTable[MsrNum].Length;
514 }
515
516 if (ByteShift < 8 && (*Length != 0)) {
517 return RETURN_UNSUPPORTED;
518 }
519
520 *ReturnMsrNum = MsrNum;
521 *ReturnClearMask = ClearMask;
522 *ReturnOrMask = OrMask;
523
524 return RETURN_SUCCESS;
525 }
526
527
528 /**
529 Worker function gets the attribute of variable MTRRs.
530
531 This function shadows the content of variable MTRRs into an
532 internal array: VariableMtrr.
533
534 @param[in] VariableSettings The variable MTRR values to shadow
535 @param[in] FirmwareVariableMtrrCount The number of variable MTRRs available to firmware
536 @param[in] MtrrValidBitsMask The mask for the valid bit of the MTRR
537 @param[in] MtrrValidAddressMask The valid address mask for MTRR
538 @param[out] VariableMtrr The array to shadow variable MTRRs content
539
540 @return The return value of this parameter indicates the
541 number of MTRRs which has been used.
542
543 **/
544 UINT32
545 MtrrGetMemoryAttributeInVariableMtrrWorker (
546 IN MTRR_VARIABLE_SETTINGS *VariableSettings,
547 IN UINTN FirmwareVariableMtrrCount,
548 IN UINT64 MtrrValidBitsMask,
549 IN UINT64 MtrrValidAddressMask,
550 OUT VARIABLE_MTRR *VariableMtrr
551 )
552 {
553 UINTN Index;
554 UINT32 UsedMtrr;
555
556 ZeroMem (VariableMtrr, sizeof (VARIABLE_MTRR) * MTRR_NUMBER_OF_VARIABLE_MTRR);
557 for (Index = 0, UsedMtrr = 0; Index < FirmwareVariableMtrrCount; Index++) {
558 if ((VariableSettings->Mtrr[Index].Mask & MTRR_LIB_CACHE_MTRR_ENABLED) != 0) {
559 VariableMtrr[Index].Msr = (UINT32)Index;
560 VariableMtrr[Index].BaseAddress = (VariableSettings->Mtrr[Index].Base & MtrrValidAddressMask);
561 VariableMtrr[Index].Length = ((~(VariableSettings->Mtrr[Index].Mask & MtrrValidAddressMask)) & MtrrValidBitsMask) + 1;
562 VariableMtrr[Index].Type = (VariableSettings->Mtrr[Index].Base & 0x0ff);
563 VariableMtrr[Index].Valid = TRUE;
564 VariableMtrr[Index].Used = TRUE;
565 UsedMtrr++;
566 }
567 }
568 return UsedMtrr;
569 }
570
571
572 /**
573 Gets the attribute of variable MTRRs.
574
575 This function shadows the content of variable MTRRs into an
576 internal array: VariableMtrr.
577
578 @param[in] MtrrValidBitsMask The mask for the valid bit of the MTRR
579 @param[in] MtrrValidAddressMask The valid address mask for MTRR
580 @param[out] VariableMtrr The array to shadow variable MTRRs content
581
582 @return The return value of this paramter indicates the
583 number of MTRRs which has been used.
584
585 **/
586 UINT32
587 EFIAPI
588 MtrrGetMemoryAttributeInVariableMtrr (
589 IN UINT64 MtrrValidBitsMask,
590 IN UINT64 MtrrValidAddressMask,
591 OUT VARIABLE_MTRR *VariableMtrr
592 )
593 {
594 MTRR_VARIABLE_SETTINGS VariableSettings;
595
596 if (!IsMtrrSupported ()) {
597 return 0;
598 }
599
600 MtrrGetVariableMtrrWorker (
601 NULL,
602 GetVariableMtrrCountWorker (),
603 &VariableSettings
604 );
605
606 return MtrrGetMemoryAttributeInVariableMtrrWorker (
607 &VariableSettings,
608 GetFirmwareVariableMtrrCountWorker (),
609 MtrrValidBitsMask,
610 MtrrValidAddressMask,
611 VariableMtrr
612 );
613 }
614
615
616 /**
617 Checks overlap between given memory range and MTRRs.
618
619 @param[in] FirmwareVariableMtrrCount The number of variable MTRRs available
620 to firmware.
621 @param[in] Start The start address of memory range.
622 @param[in] End The end address of memory range.
623 @param[in] VariableMtrr The array to shadow variable MTRRs content
624
625 @retval TRUE Overlap exists.
626 @retval FALSE No overlap.
627
628 **/
629 BOOLEAN
630 CheckMemoryAttributeOverlap (
631 IN UINTN FirmwareVariableMtrrCount,
632 IN PHYSICAL_ADDRESS Start,
633 IN PHYSICAL_ADDRESS End,
634 IN VARIABLE_MTRR *VariableMtrr
635 )
636 {
637 UINT32 Index;
638
639 for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) {
640 if (
641 VariableMtrr[Index].Valid &&
642 !(
643 (Start > (VariableMtrr[Index].BaseAddress +
644 VariableMtrr[Index].Length - 1)
645 ) ||
646 (End < VariableMtrr[Index].BaseAddress)
647 )
648 ) {
649 return TRUE;
650 }
651 }
652
653 return FALSE;
654 }
655
656
657 /**
658 Marks a variable MTRR as non-valid.
659
660 @param[in] Index The index of the array VariableMtrr to be invalidated
661 @param[in] VariableMtrr The array to shadow variable MTRRs content
662 @param[out] UsedMtrr The number of MTRRs which has already been used
663
664 **/
665 VOID
666 InvalidateShadowMtrr (
667 IN UINTN Index,
668 IN VARIABLE_MTRR *VariableMtrr,
669 OUT UINT32 *UsedMtrr
670 )
671 {
672 VariableMtrr[Index].Valid = FALSE;
673 *UsedMtrr = *UsedMtrr - 1;
674 }
675
676
677 /**
678 Combines memory attributes.
679
680 If overlap exists between given memory range and MTRRs, try to combine them.
681
682 @param[in] FirmwareVariableMtrrCount The number of variable MTRRs
683 available to firmware.
684 @param[in] Attributes The memory type to set.
685 @param[in, out] Base The base address of memory range.
686 @param[in, out] Length The length of memory range.
687 @param[in] VariableMtrr The array to shadow variable MTRRs content
688 @param[in, out] UsedMtrr The number of MTRRs which has already been used
689 @param[out] OverwriteExistingMtrr Returns whether an existing MTRR was used
690
691 @retval EFI_SUCCESS Memory region successfully combined.
692 @retval EFI_ACCESS_DENIED Memory region cannot be combined.
693
694 **/
695 RETURN_STATUS
696 CombineMemoryAttribute (
697 IN UINT32 FirmwareVariableMtrrCount,
698 IN UINT64 Attributes,
699 IN OUT UINT64 *Base,
700 IN OUT UINT64 *Length,
701 IN VARIABLE_MTRR *VariableMtrr,
702 IN OUT UINT32 *UsedMtrr,
703 OUT BOOLEAN *OverwriteExistingMtrr
704 )
705 {
706 UINT32 Index;
707 UINT64 CombineStart;
708 UINT64 CombineEnd;
709 UINT64 MtrrEnd;
710 UINT64 EndAddress;
711 BOOLEAN CoveredByExistingMtrr;
712
713 *OverwriteExistingMtrr = FALSE;
714 CoveredByExistingMtrr = FALSE;
715 EndAddress = *Base +*Length - 1;
716
717 for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) {
718
719 MtrrEnd = VariableMtrr[Index].BaseAddress + VariableMtrr[Index].Length - 1;
720 if (
721 !VariableMtrr[Index].Valid ||
722 (
723 *Base > (MtrrEnd) ||
724 (EndAddress < VariableMtrr[Index].BaseAddress)
725 )
726 ) {
727 continue;
728 }
729
730 //
731 // Combine same attribute MTRR range
732 //
733 if (Attributes == VariableMtrr[Index].Type) {
734 //
735 // if the MTRR range contain the request range, set a flag, then continue to
736 // invalidate any MTRR of the same request range with higher priority cache type.
737 //
738 if (VariableMtrr[Index].BaseAddress <= *Base && MtrrEnd >= EndAddress) {
739 CoveredByExistingMtrr = TRUE;
740 continue;
741 }
742 //
743 // invalid this MTRR, and program the combine range
744 //
745 CombineStart =
746 (*Base) < VariableMtrr[Index].BaseAddress ?
747 (*Base) :
748 VariableMtrr[Index].BaseAddress;
749 CombineEnd = EndAddress > MtrrEnd ? EndAddress : MtrrEnd;
750
751 //
752 // Record the MTRR usage status in VariableMtrr array.
753 //
754 InvalidateShadowMtrr (Index, VariableMtrr, UsedMtrr);
755 *Base = CombineStart;
756 *Length = CombineEnd - CombineStart + 1;
757 EndAddress = CombineEnd;
758 *OverwriteExistingMtrr = TRUE;
759 continue;
760 } else {
761 //
762 // The cache type is different, but the range is convered by one MTRR
763 //
764 if (VariableMtrr[Index].BaseAddress == *Base && MtrrEnd == EndAddress) {
765 InvalidateShadowMtrr (Index, VariableMtrr, UsedMtrr);
766 continue;
767 }
768
769 }
770
771 if ((Attributes== MTRR_CACHE_WRITE_THROUGH &&
772 VariableMtrr[Index].Type == MTRR_CACHE_WRITE_BACK) ||
773 (Attributes == MTRR_CACHE_WRITE_BACK &&
774 VariableMtrr[Index].Type == MTRR_CACHE_WRITE_THROUGH) ||
775 (Attributes == MTRR_CACHE_UNCACHEABLE) ||
776 (VariableMtrr[Index].Type == MTRR_CACHE_UNCACHEABLE)
777 ) {
778 *OverwriteExistingMtrr = TRUE;
779 continue;
780 }
781 //
782 // Other type memory overlap is invalid
783 //
784 return RETURN_ACCESS_DENIED;
785 }
786
787 if (CoveredByExistingMtrr) {
788 *Length = 0;
789 }
790
791 return RETURN_SUCCESS;
792 }
793
794
795 /**
796 Calculates the maximum value which is a power of 2, but less the MemoryLength.
797
798 @param[in] MemoryLength The number to pass in.
799
800 @return The maximum value which is align to power of 2 and less the MemoryLength
801
802 **/
803 UINT64
804 Power2MaxMemory (
805 IN UINT64 MemoryLength
806 )
807 {
808 UINT64 Result;
809
810 if (RShiftU64 (MemoryLength, 32) != 0) {
811 Result = LShiftU64 (
812 (UINT64) GetPowerOfTwo32 (
813 (UINT32) RShiftU64 (MemoryLength, 32)
814 ),
815 32
816 );
817 } else {
818 Result = (UINT64) GetPowerOfTwo32 ((UINT32) MemoryLength);
819 }
820
821 return Result;
822 }
823
824
825 /**
826 Determines the MTRR numbers used to program a memory range.
827
828 This function first checks the alignment of the base address.
829 If the alignment of the base address <= Length, cover the memory range
830 (BaseAddress, alignment) by a MTRR, then BaseAddress += alignment and
831 Length -= alignment. Repeat the step until alignment > Length.
832
833 Then this function determines which direction of programming the variable
834 MTRRs for the remaining length will use fewer MTRRs.
835
836 @param[in] BaseAddress Length of Memory to program MTRR
837 @param[in] Length Length of Memory to program MTRR
838 @param[in] MtrrNumber Pointer to the number of necessary MTRRs
839
840 @retval TRUE Positive direction is better.
841 FALSE Negative direction is better.
842
843 **/
844 BOOLEAN
845 GetMtrrNumberAndDirection (
846 IN UINT64 BaseAddress,
847 IN UINT64 Length,
848 IN UINTN *MtrrNumber
849 )
850 {
851 UINT64 TempQword;
852 UINT64 Alignment;
853 UINT32 Positive;
854 UINT32 Subtractive;
855
856 *MtrrNumber = 0;
857
858 if (BaseAddress != 0) {
859 do {
860 //
861 // Calculate the alignment of the base address.
862 //
863 Alignment = LShiftU64 (1, (UINTN)LowBitSet64 (BaseAddress));
864
865 if (Alignment > Length) {
866 break;
867 }
868
869 (*MtrrNumber)++;
870 BaseAddress += Alignment;
871 Length -= Alignment;
872 } while (TRUE);
873
874 if (Length == 0) {
875 return TRUE;
876 }
877 }
878
879 TempQword = Length;
880 Positive = 0;
881 Subtractive = 0;
882
883 do {
884 TempQword -= Power2MaxMemory (TempQword);
885 Positive++;
886 } while (TempQword != 0);
887
888 TempQword = Power2MaxMemory (LShiftU64 (Length, 1)) - Length;
889 Subtractive++;
890 do {
891 TempQword -= Power2MaxMemory (TempQword);
892 Subtractive++;
893 } while (TempQword != 0);
894
895 if (Positive <= Subtractive) {
896 *MtrrNumber += Positive;
897 return TRUE;
898 } else {
899 *MtrrNumber += Subtractive;
900 return FALSE;
901 }
902 }
903
904 /**
905 Invalid variable MTRRs according to the value in the shadow array.
906
907 This function programs MTRRs according to the values specified
908 in the shadow array.
909
910 @param[in, out] VariableSettings Variable MTRR settings
911 @param[in] VariableMtrrCount Number of variable MTRRs
912 @param[in, out] VariableMtrr Shadow of variable MTRR contents
913
914 **/
915 VOID
916 InvalidateMtrr (
917 IN OUT MTRR_VARIABLE_SETTINGS *VariableSettings,
918 IN UINTN VariableMtrrCount,
919 IN OUT VARIABLE_MTRR *VariableMtrr
920 )
921 {
922 UINTN Index;
923
924 for (Index = 0; Index < VariableMtrrCount; Index++) {
925 if (!VariableMtrr[Index].Valid && VariableMtrr[Index].Used) {
926 VariableSettings->Mtrr[Index].Base = 0;
927 VariableSettings->Mtrr[Index].Mask = 0;
928 VariableMtrr[Index].Used = FALSE;
929 }
930 }
931 }
932
933
934 /**
935 Programs variable MTRRs
936
937 This function programs variable MTRRs
938
939 @param[in, out] VariableSettings Variable MTRR settings.
940 @param[in] MtrrNumber Index of MTRR to program.
941 @param[in] BaseAddress Base address of memory region.
942 @param[in] Length Length of memory region.
943 @param[in] MemoryCacheType Memory type to set.
944 @param[in] MtrrValidAddressMask The valid address mask for MTRR
945
946 **/
947 VOID
948 ProgramVariableMtrr (
949 IN OUT MTRR_VARIABLE_SETTINGS *VariableSettings,
950 IN UINTN MtrrNumber,
951 IN PHYSICAL_ADDRESS BaseAddress,
952 IN UINT64 Length,
953 IN UINT64 MemoryCacheType,
954 IN UINT64 MtrrValidAddressMask
955 )
956 {
957 UINT64 TempQword;
958
959 //
960 // MTRR Physical Base
961 //
962 TempQword = (BaseAddress & MtrrValidAddressMask) | MemoryCacheType;
963 VariableSettings->Mtrr[MtrrNumber].Base = TempQword;
964
965 //
966 // MTRR Physical Mask
967 //
968 TempQword = ~(Length - 1);
969 VariableSettings->Mtrr[MtrrNumber].Mask = (TempQword & MtrrValidAddressMask) | MTRR_LIB_CACHE_MTRR_ENABLED;
970 }
971
972
973 /**
974 Converts the Memory attribute value to MTRR_MEMORY_CACHE_TYPE.
975
976 If MtrrSetting is not NULL, gets the default memory attribute from input
977 MTRR settings buffer.
978 If MtrrSetting is NULL, gets the default memory attribute from MSR.
979
980 @param[in] MtrrSetting A buffer holding all MTRRs content.
981 @param[in] MtrrType MTRR memory type
982
983 @return The enum item in MTRR_MEMORY_CACHE_TYPE
984
985 **/
986 MTRR_MEMORY_CACHE_TYPE
987 GetMemoryCacheTypeFromMtrrType (
988 IN MTRR_SETTINGS *MtrrSetting,
989 IN UINT64 MtrrType
990 )
991 {
992 switch (MtrrType) {
993 case MTRR_CACHE_UNCACHEABLE:
994 return CacheUncacheable;
995 case MTRR_CACHE_WRITE_COMBINING:
996 return CacheWriteCombining;
997 case MTRR_CACHE_WRITE_THROUGH:
998 return CacheWriteThrough;
999 case MTRR_CACHE_WRITE_PROTECTED:
1000 return CacheWriteProtected;
1001 case MTRR_CACHE_WRITE_BACK:
1002 return CacheWriteBack;
1003 default:
1004 //
1005 // MtrrType is MTRR_CACHE_INVALID_TYPE, that means
1006 // no MTRR covers the range
1007 //
1008 return MtrrGetDefaultMemoryTypeWorker (MtrrSetting);
1009 }
1010 }
1011
1012 /**
1013 Initializes the valid bits mask and valid address mask for MTRRs.
1014
1015 This function initializes the valid bits mask and valid address mask for MTRRs.
1016
1017 @param[out] MtrrValidBitsMask The mask for the valid bit of the MTRR
1018 @param[out] MtrrValidAddressMask The valid address mask for the MTRR
1019
1020 **/
1021 VOID
1022 MtrrLibInitializeMtrrMask (
1023 OUT UINT64 *MtrrValidBitsMask,
1024 OUT UINT64 *MtrrValidAddressMask
1025 )
1026 {
1027 UINT32 RegEax;
1028 UINT8 PhysicalAddressBits;
1029
1030 AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
1031
1032 if (RegEax >= 0x80000008) {
1033 AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);
1034
1035 PhysicalAddressBits = (UINT8) RegEax;
1036
1037 *MtrrValidBitsMask = LShiftU64 (1, PhysicalAddressBits) - 1;
1038 *MtrrValidAddressMask = *MtrrValidBitsMask & 0xfffffffffffff000ULL;
1039 } else {
1040 *MtrrValidBitsMask = MTRR_LIB_MSR_VALID_MASK;
1041 *MtrrValidAddressMask = MTRR_LIB_CACHE_VALID_ADDRESS;
1042 }
1043 }
1044
1045
1046 /**
1047 Determines the real attribute of a memory range.
1048
1049 This function is to arbitrate the real attribute of the memory when
1050 there are 2 MTRRs covers the same memory range. For further details,
1051 please refer the IA32 Software Developer's Manual, Volume 3,
1052 Section 10.11.4.1.
1053
1054 @param[in] MtrrType1 The first kind of Memory type
1055 @param[in] MtrrType2 The second kind of memory type
1056
1057 **/
1058 UINT64
1059 MtrrPrecedence (
1060 IN UINT64 MtrrType1,
1061 IN UINT64 MtrrType2
1062 )
1063 {
1064 UINT64 MtrrType;
1065
1066 MtrrType = MTRR_CACHE_INVALID_TYPE;
1067 switch (MtrrType1) {
1068 case MTRR_CACHE_UNCACHEABLE:
1069 MtrrType = MTRR_CACHE_UNCACHEABLE;
1070 break;
1071 case MTRR_CACHE_WRITE_COMBINING:
1072 if (
1073 MtrrType2==MTRR_CACHE_WRITE_COMBINING ||
1074 MtrrType2==MTRR_CACHE_UNCACHEABLE
1075 ) {
1076 MtrrType = MtrrType2;
1077 }
1078 break;
1079 case MTRR_CACHE_WRITE_THROUGH:
1080 if (
1081 MtrrType2==MTRR_CACHE_WRITE_THROUGH ||
1082 MtrrType2==MTRR_CACHE_WRITE_BACK
1083 ) {
1084 MtrrType = MTRR_CACHE_WRITE_THROUGH;
1085 } else if(MtrrType2==MTRR_CACHE_UNCACHEABLE) {
1086 MtrrType = MTRR_CACHE_UNCACHEABLE;
1087 }
1088 break;
1089 case MTRR_CACHE_WRITE_PROTECTED:
1090 if (MtrrType2 == MTRR_CACHE_WRITE_PROTECTED ||
1091 MtrrType2 == MTRR_CACHE_UNCACHEABLE) {
1092 MtrrType = MtrrType2;
1093 }
1094 break;
1095 case MTRR_CACHE_WRITE_BACK:
1096 if (
1097 MtrrType2== MTRR_CACHE_UNCACHEABLE ||
1098 MtrrType2==MTRR_CACHE_WRITE_THROUGH ||
1099 MtrrType2== MTRR_CACHE_WRITE_BACK
1100 ) {
1101 MtrrType = MtrrType2;
1102 }
1103 break;
1104 case MTRR_CACHE_INVALID_TYPE:
1105 MtrrType = MtrrType2;
1106 break;
1107 default:
1108 break;
1109 }
1110
1111 if (MtrrType2 == MTRR_CACHE_INVALID_TYPE) {
1112 MtrrType = MtrrType1;
1113 }
1114 return MtrrType;
1115 }
1116
1117 /**
1118 Worker function will get the memory cache type of the specific address.
1119
1120 If MtrrSetting is not NULL, gets the memory cache type from input
1121 MTRR settings buffer.
1122 If MtrrSetting is NULL, gets the memory cache type from MTRRs.
1123
1124 @param[in] MtrrSetting A buffer holding all MTRRs content.
1125 @param[in] Address The specific address
1126
1127 @return Memory cache type of the specific address
1128
1129 **/
1130 MTRR_MEMORY_CACHE_TYPE
1131 MtrrGetMemoryAttributeByAddressWorker (
1132 IN MTRR_SETTINGS *MtrrSetting,
1133 IN PHYSICAL_ADDRESS Address
1134 )
1135 {
1136 UINT64 TempQword;
1137 UINTN Index;
1138 UINTN SubIndex;
1139 UINT64 MtrrType;
1140 UINT64 TempMtrrType;
1141 MTRR_MEMORY_CACHE_TYPE CacheType;
1142 VARIABLE_MTRR VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];
1143 UINT64 MtrrValidBitsMask;
1144 UINT64 MtrrValidAddressMask;
1145 UINTN VariableMtrrCount;
1146 MTRR_VARIABLE_SETTINGS VariableSettings;
1147
1148 //
1149 // Check if MTRR is enabled, if not, return UC as attribute
1150 //
1151 if (MtrrSetting == NULL) {
1152 TempQword = AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE);
1153 } else {
1154 TempQword = MtrrSetting->MtrrDefType;
1155 }
1156 MtrrType = MTRR_CACHE_INVALID_TYPE;
1157
1158 if ((TempQword & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {
1159 return CacheUncacheable;
1160 }
1161
1162 //
1163 // If address is less than 1M, then try to go through the fixed MTRR
1164 //
1165 if (Address < BASE_1MB) {
1166 if ((TempQword & MTRR_LIB_CACHE_FIXED_MTRR_ENABLED) != 0) {
1167 //
1168 // Go through the fixed MTRR
1169 //
1170 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
1171 if (Address >= mMtrrLibFixedMtrrTable[Index].BaseAddress &&
1172 Address < (
1173 mMtrrLibFixedMtrrTable[Index].BaseAddress +
1174 (mMtrrLibFixedMtrrTable[Index].Length * 8)
1175 )
1176 ) {
1177 SubIndex =
1178 ((UINTN)Address - mMtrrLibFixedMtrrTable[Index].BaseAddress) /
1179 mMtrrLibFixedMtrrTable[Index].Length;
1180 if (MtrrSetting == NULL) {
1181 TempQword = AsmReadMsr64 (mMtrrLibFixedMtrrTable[Index].Msr);
1182 } else {
1183 TempQword = MtrrSetting->Fixed.Mtrr[Index];
1184 }
1185 MtrrType = RShiftU64 (TempQword, SubIndex * 8) & 0xFF;
1186 return GetMemoryCacheTypeFromMtrrType (MtrrSetting, MtrrType);
1187 }
1188 }
1189 }
1190 }
1191 MtrrLibInitializeMtrrMask(&MtrrValidBitsMask, &MtrrValidAddressMask);
1192
1193 MtrrGetVariableMtrrWorker (
1194 MtrrSetting,
1195 GetVariableMtrrCountWorker (),
1196 &VariableSettings
1197 );
1198
1199 MtrrGetMemoryAttributeInVariableMtrrWorker (
1200 &VariableSettings,
1201 GetFirmwareVariableMtrrCountWorker (),
1202 MtrrValidBitsMask,
1203 MtrrValidAddressMask,
1204 VariableMtrr
1205 );
1206
1207 //
1208 // Go through the variable MTRR
1209 //
1210 VariableMtrrCount = GetVariableMtrrCountWorker ();
1211 ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);
1212
1213 for (Index = 0; Index < VariableMtrrCount; Index++) {
1214 if (VariableMtrr[Index].Valid) {
1215 if (Address >= VariableMtrr[Index].BaseAddress &&
1216 Address < VariableMtrr[Index].BaseAddress+VariableMtrr[Index].Length) {
1217 TempMtrrType = VariableMtrr[Index].Type;
1218 MtrrType = MtrrPrecedence (MtrrType, TempMtrrType);
1219 }
1220 }
1221 }
1222 CacheType = GetMemoryCacheTypeFromMtrrType (MtrrSetting, MtrrType);
1223
1224 return CacheType;
1225 }
1226
1227
1228 /**
1229 This function will get the memory cache type of the specific address.
1230
1231 This function is mainly for debug purpose.
1232
1233 @param[in] Address The specific address
1234
1235 @return Memory cache type of the specific address
1236
1237 **/
1238 MTRR_MEMORY_CACHE_TYPE
1239 EFIAPI
1240 MtrrGetMemoryAttribute (
1241 IN PHYSICAL_ADDRESS Address
1242 )
1243 {
1244 if (!IsMtrrSupported ()) {
1245 return CacheUncacheable;
1246 }
1247
1248 return MtrrGetMemoryAttributeByAddressWorker (NULL, Address);
1249 }
1250
1251 /**
1252 Worker function prints all MTRRs for debugging.
1253
1254 If MtrrSetting is not NULL, print MTRR settings from from input MTRR
1255 settings buffer.
1256 If MtrrSetting is NULL, print MTRR settings from MTRRs.
1257
1258 @param MtrrSetting A buffer holding all MTRRs content.
1259 **/
1260 VOID
1261 MtrrDebugPrintAllMtrrsWorker (
1262 IN MTRR_SETTINGS *MtrrSetting
1263 )
1264 {
1265 DEBUG_CODE (
1266 MTRR_SETTINGS LocalMtrrs;
1267 MTRR_SETTINGS *Mtrrs;
1268 UINTN Index;
1269 UINTN Index1;
1270 UINTN VariableMtrrCount;
1271 UINT64 Base;
1272 UINT64 Limit;
1273 UINT64 MtrrBase;
1274 UINT64 MtrrLimit;
1275 UINT64 RangeBase;
1276 UINT64 RangeLimit;
1277 UINT64 NoRangeBase;
1278 UINT64 NoRangeLimit;
1279 UINT32 RegEax;
1280 UINTN MemoryType;
1281 UINTN PreviousMemoryType;
1282 BOOLEAN Found;
1283
1284 if (!IsMtrrSupported ()) {
1285 return;
1286 }
1287
1288 DEBUG((DEBUG_CACHE, "MTRR Settings\n"));
1289 DEBUG((DEBUG_CACHE, "=============\n"));
1290
1291 if (MtrrSetting != NULL) {
1292 Mtrrs = MtrrSetting;
1293 } else {
1294 MtrrGetAllMtrrs (&LocalMtrrs);
1295 Mtrrs = &LocalMtrrs;
1296 }
1297
1298 DEBUG((DEBUG_CACHE, "MTRR Default Type: %016lx\n", Mtrrs->MtrrDefType));
1299 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
1300 DEBUG((DEBUG_CACHE, "Fixed MTRR[%02d] : %016lx\n", Index, Mtrrs->Fixed.Mtrr[Index]));
1301 }
1302
1303 VariableMtrrCount = GetVariableMtrrCount ();
1304 for (Index = 0; Index < VariableMtrrCount; Index++) {
1305 DEBUG((DEBUG_CACHE, "Variable MTRR[%02d]: Base=%016lx Mask=%016lx\n",
1306 Index,
1307 Mtrrs->Variables.Mtrr[Index].Base,
1308 Mtrrs->Variables.Mtrr[Index].Mask
1309 ));
1310 }
1311 DEBUG((DEBUG_CACHE, "\n"));
1312 DEBUG((DEBUG_CACHE, "MTRR Ranges\n"));
1313 DEBUG((DEBUG_CACHE, "====================================\n"));
1314
1315 Base = 0;
1316 PreviousMemoryType = MTRR_CACHE_INVALID_TYPE;
1317 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
1318 Base = mMtrrLibFixedMtrrTable[Index].BaseAddress;
1319 for (Index1 = 0; Index1 < 8; Index1++) {
1320 MemoryType = (UINTN)(RShiftU64 (Mtrrs->Fixed.Mtrr[Index], Index1 * 8) & 0xff);
1321 if (MemoryType > CacheWriteBack) {
1322 MemoryType = MTRR_CACHE_INVALID_TYPE;
1323 }
1324 if (MemoryType != PreviousMemoryType) {
1325 if (PreviousMemoryType != MTRR_CACHE_INVALID_TYPE) {
1326 DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));
1327 }
1328 PreviousMemoryType = MemoryType;
1329 DEBUG((DEBUG_CACHE, "%a:%016lx-", mMtrrMemoryCacheTypeShortName[MemoryType], Base));
1330 }
1331 Base += mMtrrLibFixedMtrrTable[Index].Length;
1332 }
1333 }
1334 DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));
1335
1336 VariableMtrrCount = GetVariableMtrrCount ();
1337
1338 Limit = BIT36 - 1;
1339 AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
1340 if (RegEax >= 0x80000008) {
1341 AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);
1342 Limit = LShiftU64 (1, RegEax & 0xff) - 1;
1343 }
1344 Base = BASE_1MB;
1345 PreviousMemoryType = MTRR_CACHE_INVALID_TYPE;
1346 do {
1347 MemoryType = MtrrGetMemoryAttributeByAddressWorker (Mtrrs, Base);
1348 if (MemoryType > CacheWriteBack) {
1349 MemoryType = MTRR_CACHE_INVALID_TYPE;
1350 }
1351
1352 if (MemoryType != PreviousMemoryType) {
1353 if (PreviousMemoryType != MTRR_CACHE_INVALID_TYPE) {
1354 DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));
1355 }
1356 PreviousMemoryType = MemoryType;
1357 DEBUG((DEBUG_CACHE, "%a:%016lx-", mMtrrMemoryCacheTypeShortName[MemoryType], Base));
1358 }
1359
1360 RangeBase = BASE_1MB;
1361 NoRangeBase = BASE_1MB;
1362 RangeLimit = Limit;
1363 NoRangeLimit = Limit;
1364
1365 for (Index = 0, Found = FALSE; Index < VariableMtrrCount; Index++) {
1366 if ((Mtrrs->Variables.Mtrr[Index].Mask & BIT11) == 0) {
1367 //
1368 // If mask is not valid, then do not display range
1369 //
1370 continue;
1371 }
1372 MtrrBase = (Mtrrs->Variables.Mtrr[Index].Base & (~(SIZE_4KB - 1)));
1373 MtrrLimit = MtrrBase + ((~(Mtrrs->Variables.Mtrr[Index].Mask & (~(SIZE_4KB - 1)))) & Limit);
1374
1375 if (Base >= MtrrBase && Base < MtrrLimit) {
1376 Found = TRUE;
1377 }
1378
1379 if (Base >= MtrrBase && MtrrBase > RangeBase) {
1380 RangeBase = MtrrBase;
1381 }
1382 if (Base > MtrrLimit && MtrrLimit > RangeBase) {
1383 RangeBase = MtrrLimit + 1;
1384 }
1385 if (Base < MtrrBase && MtrrBase < RangeLimit) {
1386 RangeLimit = MtrrBase - 1;
1387 }
1388 if (Base < MtrrLimit && MtrrLimit <= RangeLimit) {
1389 RangeLimit = MtrrLimit;
1390 }
1391
1392 if (Base > MtrrLimit && NoRangeBase < MtrrLimit) {
1393 NoRangeBase = MtrrLimit + 1;
1394 }
1395 if (Base < MtrrBase && NoRangeLimit > MtrrBase) {
1396 NoRangeLimit = MtrrBase - 1;
1397 }
1398 }
1399
1400 if (Found) {
1401 Base = RangeLimit + 1;
1402 } else {
1403 Base = NoRangeLimit + 1;
1404 }
1405 } while (Base < Limit);
1406 DEBUG((DEBUG_CACHE, "%016lx\n\n", Base - 1));
1407 );
1408 }
1409
1410
1411 /**
1412 This function prints all MTRRs for debugging.
1413 **/
1414 VOID
1415 EFIAPI
1416 MtrrDebugPrintAllMtrrs (
1417 VOID
1418 )
1419 {
1420 MtrrDebugPrintAllMtrrsWorker (NULL);
1421 }
1422
1423
1424 /**
1425 Worker function attempts to set the attributes for a memory range.
1426
1427 If MtrrSettings is not NULL, set the attributes into the input MTRR
1428 settings buffer.
1429 If MtrrSettings is NULL, set the attributes into MTRRs registers.
1430
1431 @param[in, out] MtrrSetting A buffer holding all MTRRs content.
1432 @param[in] BaseAddress The physical address that is the start
1433 address of a memory region.
1434 @param[in] Length The size in bytes of the memory region.
1435 @param[in] Attribute The bit mask of attributes to set for the
1436 memory region.
1437
1438 @retval RETURN_SUCCESS The attributes were set for the memory
1439 region.
1440 @retval RETURN_INVALID_PARAMETER Length is zero.
1441 @retval RETURN_UNSUPPORTED The processor does not support one or
1442 more bytes of the memory resource range
1443 specified by BaseAddress and Length.
1444 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support
1445 for the memory resource range specified
1446 by BaseAddress and Length.
1447 @retval RETURN_ACCESS_DENIED The attributes for the memory resource
1448 range specified by BaseAddress and Length
1449 cannot be modified.
1450 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to
1451 modify the attributes of the memory
1452 resource range.
1453
1454 **/
1455 RETURN_STATUS
1456 MtrrSetMemoryAttributeWorker (
1457 IN OUT MTRR_SETTINGS *MtrrSetting,
1458 IN PHYSICAL_ADDRESS BaseAddress,
1459 IN UINT64 Length,
1460 IN MTRR_MEMORY_CACHE_TYPE Attribute
1461 )
1462 {
1463 UINT64 TempQword;
1464 RETURN_STATUS Status;
1465 UINT64 MemoryType;
1466 UINT64 Alignment;
1467 BOOLEAN OverLap;
1468 BOOLEAN Positive;
1469 UINT32 MsrNum;
1470 UINTN MtrrNumber;
1471 VARIABLE_MTRR VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];
1472 UINT32 UsedMtrr;
1473 UINT64 MtrrValidBitsMask;
1474 UINT64 MtrrValidAddressMask;
1475 BOOLEAN OverwriteExistingMtrr;
1476 UINT32 FirmwareVariableMtrrCount;
1477 MTRR_CONTEXT MtrrContext;
1478 BOOLEAN MtrrContextValid;
1479 BOOLEAN FixedSettingsValid[MTRR_NUMBER_OF_FIXED_MTRR];
1480 BOOLEAN FixedSettingsModified[MTRR_NUMBER_OF_FIXED_MTRR];
1481 MTRR_FIXED_SETTINGS WorkingFixedSettings;
1482 UINT32 VariableMtrrCount;
1483 MTRR_VARIABLE_SETTINGS OriginalVariableSettings;
1484 BOOLEAN ProgramVariableSettings;
1485 MTRR_VARIABLE_SETTINGS WorkingVariableSettings;
1486 UINT32 Index;
1487 UINT64 ClearMask;
1488 UINT64 OrMask;
1489 UINT64 NewValue;
1490 MTRR_VARIABLE_SETTINGS *VariableSettings;
1491
1492 MtrrContextValid = FALSE;
1493 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
1494 FixedSettingsValid[Index] = FALSE;
1495 FixedSettingsModified[Index] = FALSE;
1496 }
1497 ProgramVariableSettings = FALSE;
1498
1499 if (!IsMtrrSupported ()) {
1500 Status = RETURN_UNSUPPORTED;
1501 goto Done;
1502 }
1503
1504 MtrrLibInitializeMtrrMask (&MtrrValidBitsMask, &MtrrValidAddressMask);
1505
1506 TempQword = 0;
1507 MemoryType = (UINT64)Attribute;
1508 OverwriteExistingMtrr = FALSE;
1509
1510 //
1511 // Check for an invalid parameter
1512 //
1513 if (Length == 0) {
1514 Status = RETURN_INVALID_PARAMETER;
1515 goto Done;
1516 }
1517
1518 if (
1519 (BaseAddress & ~MtrrValidAddressMask) != 0 ||
1520 (Length & ~MtrrValidAddressMask) != 0
1521 ) {
1522 Status = RETURN_UNSUPPORTED;
1523 goto Done;
1524 }
1525
1526 //
1527 // Check if Fixed MTRR
1528 //
1529 Status = RETURN_SUCCESS;
1530 if (BaseAddress < BASE_1MB) {
1531 while ((BaseAddress < BASE_1MB) && (Length > 0) && Status == RETURN_SUCCESS) {
1532 Status = ProgramFixedMtrr (MemoryType, &BaseAddress, &Length, &MsrNum, &ClearMask, &OrMask);
1533 if (RETURN_ERROR (Status)) {
1534 goto Done;
1535 }
1536 if (MtrrSetting != NULL) {
1537 MtrrSetting->Fixed.Mtrr[MsrNum] = (MtrrSetting->Fixed.Mtrr[MsrNum] & ~ClearMask) | OrMask;
1538 MtrrSetting->MtrrDefType |= MTRR_LIB_CACHE_FIXED_MTRR_ENABLED;
1539 } else {
1540 if (!FixedSettingsValid[MsrNum]) {
1541 WorkingFixedSettings.Mtrr[MsrNum] = AsmReadMsr64 (mMtrrLibFixedMtrrTable[MsrNum].Msr);
1542 FixedSettingsValid[MsrNum] = TRUE;
1543 }
1544 NewValue = (WorkingFixedSettings.Mtrr[MsrNum] & ~ClearMask) | OrMask;
1545 if (WorkingFixedSettings.Mtrr[MsrNum] != NewValue) {
1546 WorkingFixedSettings.Mtrr[MsrNum] = NewValue;
1547 FixedSettingsModified[MsrNum] = TRUE;
1548 }
1549 }
1550 }
1551
1552 if (Length == 0) {
1553 //
1554 // A Length of 0 can only make sense for fixed MTTR ranges.
1555 // Since we just handled the fixed MTRRs, we can skip the
1556 // variable MTRR section.
1557 //
1558 goto Done;
1559 }
1560 }
1561
1562 //
1563 // Since memory ranges below 1MB will be overridden by the fixed MTRRs,
1564 // we can set the base to 0 to save variable MTRRs.
1565 //
1566 if (BaseAddress == BASE_1MB) {
1567 BaseAddress = 0;
1568 Length += SIZE_1MB;
1569 }
1570
1571 //
1572 // Read all variable MTRRs
1573 //
1574 VariableMtrrCount = GetVariableMtrrCountWorker ();
1575 FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCountWorker ();
1576 if (MtrrSetting != NULL) {
1577 VariableSettings = &MtrrSetting->Variables;
1578 } else {
1579 MtrrGetVariableMtrrWorker (NULL, VariableMtrrCount, &OriginalVariableSettings);
1580 CopyMem (&WorkingVariableSettings, &OriginalVariableSettings, sizeof (WorkingVariableSettings));
1581 ProgramVariableSettings = TRUE;
1582 VariableSettings = &WorkingVariableSettings;
1583 }
1584
1585 //
1586 // Check for overlap
1587 //
1588 UsedMtrr = MtrrGetMemoryAttributeInVariableMtrrWorker (
1589 VariableSettings,
1590 FirmwareVariableMtrrCount,
1591 MtrrValidBitsMask,
1592 MtrrValidAddressMask,
1593 VariableMtrr
1594 );
1595 OverLap = CheckMemoryAttributeOverlap (
1596 FirmwareVariableMtrrCount,
1597 BaseAddress,
1598 BaseAddress + Length - 1,
1599 VariableMtrr
1600 );
1601 if (OverLap) {
1602 Status = CombineMemoryAttribute (
1603 FirmwareVariableMtrrCount,
1604 MemoryType,
1605 &BaseAddress,
1606 &Length,
1607 VariableMtrr,
1608 &UsedMtrr,
1609 &OverwriteExistingMtrr
1610 );
1611 if (RETURN_ERROR (Status)) {
1612 goto Done;
1613 }
1614
1615 if (Length == 0) {
1616 //
1617 // Combined successfully, invalidate the now-unused MTRRs
1618 //
1619 InvalidateMtrr (VariableSettings, VariableMtrrCount, VariableMtrr);
1620 Status = RETURN_SUCCESS;
1621 goto Done;
1622 }
1623 }
1624
1625 //
1626 // The memory type is the same with the type specified by
1627 // MTRR_LIB_IA32_MTRR_DEF_TYPE.
1628 //
1629 if ((!OverwriteExistingMtrr) && (Attribute == MtrrGetDefaultMemoryTypeWorker (MtrrSetting))) {
1630 //
1631 // Invalidate the now-unused MTRRs
1632 //
1633 InvalidateMtrr (VariableSettings, VariableMtrrCount, VariableMtrr);
1634 goto Done;
1635 }
1636
1637 Positive = GetMtrrNumberAndDirection (BaseAddress, Length, &MtrrNumber);
1638
1639 if ((UsedMtrr + MtrrNumber) > FirmwareVariableMtrrCount) {
1640 Status = RETURN_OUT_OF_RESOURCES;
1641 goto Done;
1642 }
1643
1644 //
1645 // Invalidate the now-unused MTRRs
1646 //
1647 InvalidateMtrr (VariableSettings, VariableMtrrCount, VariableMtrr);
1648
1649 //
1650 // Find first unused MTRR
1651 //
1652 for (MsrNum = 0; MsrNum < VariableMtrrCount; MsrNum++) {
1653 if ((VariableSettings->Mtrr[MsrNum].Mask & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {
1654 break;
1655 }
1656 }
1657
1658 if (BaseAddress != 0) {
1659 do {
1660 //
1661 // Calculate the alignment of the base address.
1662 //
1663 Alignment = LShiftU64 (1, (UINTN)LowBitSet64 (BaseAddress));
1664
1665 if (Alignment > Length) {
1666 break;
1667 }
1668
1669 //
1670 // Find unused MTRR
1671 //
1672 for (; MsrNum < VariableMtrrCount; MsrNum++) {
1673 if ((VariableSettings->Mtrr[MsrNum].Mask & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {
1674 break;
1675 }
1676 }
1677
1678 ProgramVariableMtrr (
1679 VariableSettings,
1680 MsrNum,
1681 BaseAddress,
1682 Alignment,
1683 MemoryType,
1684 MtrrValidAddressMask
1685 );
1686 BaseAddress += Alignment;
1687 Length -= Alignment;
1688 } while (TRUE);
1689
1690 if (Length == 0) {
1691 goto Done;
1692 }
1693 }
1694
1695 TempQword = Length;
1696
1697 if (!Positive) {
1698 Length = Power2MaxMemory (LShiftU64 (TempQword, 1));
1699
1700 //
1701 // Find unused MTRR
1702 //
1703 for (; MsrNum < VariableMtrrCount; MsrNum++) {
1704 if ((VariableSettings->Mtrr[MsrNum].Mask & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {
1705 break;
1706 }
1707 }
1708
1709 ProgramVariableMtrr (
1710 VariableSettings,
1711 MsrNum,
1712 BaseAddress,
1713 Length,
1714 MemoryType,
1715 MtrrValidAddressMask
1716 );
1717 BaseAddress += Length;
1718 TempQword = Length - TempQword;
1719 MemoryType = MTRR_CACHE_UNCACHEABLE;
1720 }
1721
1722 do {
1723 //
1724 // Find unused MTRR
1725 //
1726 for (; MsrNum < VariableMtrrCount; MsrNum++) {
1727 if ((VariableSettings->Mtrr[MsrNum].Mask & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {
1728 break;
1729 }
1730 }
1731
1732 Length = Power2MaxMemory (TempQword);
1733 if (!Positive) {
1734 BaseAddress -= Length;
1735 }
1736
1737 ProgramVariableMtrr (
1738 VariableSettings,
1739 MsrNum,
1740 BaseAddress,
1741 Length,
1742 MemoryType,
1743 MtrrValidAddressMask
1744 );
1745
1746 if (Positive) {
1747 BaseAddress += Length;
1748 }
1749 TempQword -= Length;
1750
1751 } while (TempQword > 0);
1752
1753 Done:
1754
1755 //
1756 // Write fixed MTRRs that have been modified
1757 //
1758 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
1759 if (FixedSettingsModified[Index]) {
1760 if (!MtrrContextValid) {
1761 PreMtrrChange (&MtrrContext);
1762 MtrrContextValid = TRUE;
1763 }
1764 AsmWriteMsr64 (
1765 mMtrrLibFixedMtrrTable[Index].Msr,
1766 WorkingFixedSettings.Mtrr[Index]
1767 );
1768 }
1769 }
1770
1771 //
1772 // Write variable MTRRs
1773 //
1774 if (ProgramVariableSettings) {
1775 for (Index = 0; Index < VariableMtrrCount; Index++) {
1776 if (WorkingVariableSettings.Mtrr[Index].Base != OriginalVariableSettings.Mtrr[Index].Base ||
1777 WorkingVariableSettings.Mtrr[Index].Mask != OriginalVariableSettings.Mtrr[Index].Mask ) {
1778 if (!MtrrContextValid) {
1779 PreMtrrChange (&MtrrContext);
1780 MtrrContextValid = TRUE;
1781 }
1782 AsmWriteMsr64 (
1783 MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1),
1784 WorkingVariableSettings.Mtrr[Index].Base
1785 );
1786 AsmWriteMsr64 (
1787 MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1) + 1,
1788 WorkingVariableSettings.Mtrr[Index].Mask
1789 );
1790 }
1791 }
1792 }
1793 if (MtrrContextValid) {
1794 PostMtrrChange (&MtrrContext);
1795 }
1796
1797 DEBUG((DEBUG_CACHE, " Status = %r\n", Status));
1798 if (!RETURN_ERROR (Status)) {
1799 if (MtrrSetting != NULL) {
1800 MtrrSetting->MtrrDefType |= MTRR_LIB_CACHE_MTRR_ENABLED;
1801 }
1802 MtrrDebugPrintAllMtrrsWorker (MtrrSetting);
1803 }
1804
1805 return Status;
1806 }
1807
1808 /**
1809 This function attempts to set the attributes for a memory range.
1810
1811 @param[in] BaseAddress The physical address that is the start
1812 address of a memory region.
1813 @param[in] Length The size in bytes of the memory region.
1814 @param[in] Attributes The bit mask of attributes to set for the
1815 memory region.
1816
1817 @retval RETURN_SUCCESS The attributes were set for the memory
1818 region.
1819 @retval RETURN_INVALID_PARAMETER Length is zero.
1820 @retval RETURN_UNSUPPORTED The processor does not support one or
1821 more bytes of the memory resource range
1822 specified by BaseAddress and Length.
1823 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support
1824 for the memory resource range specified
1825 by BaseAddress and Length.
1826 @retval RETURN_ACCESS_DENIED The attributes for the memory resource
1827 range specified by BaseAddress and Length
1828 cannot be modified.
1829 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to
1830 modify the attributes of the memory
1831 resource range.
1832
1833 **/
1834 RETURN_STATUS
1835 EFIAPI
1836 MtrrSetMemoryAttribute (
1837 IN PHYSICAL_ADDRESS BaseAddress,
1838 IN UINT64 Length,
1839 IN MTRR_MEMORY_CACHE_TYPE Attribute
1840 )
1841 {
1842 DEBUG((DEBUG_CACHE, "MtrrSetMemoryAttribute() %a:%016lx-%016lx\n", mMtrrMemoryCacheTypeShortName[Attribute], BaseAddress, Length));
1843 return MtrrSetMemoryAttributeWorker (
1844 NULL,
1845 BaseAddress,
1846 Length,
1847 Attribute
1848 );
1849 }
1850
1851 /**
1852 This function attempts to set the attributes into MTRR setting buffer for a memory range.
1853
1854 @param[in, out] MtrrSetting MTRR setting buffer to be set.
1855 @param[in] BaseAddress The physical address that is the start address
1856 of a memory region.
1857 @param[in] Length The size in bytes of the memory region.
1858 @param[in] Attribute The bit mask of attributes to set for the
1859 memory region.
1860
1861 @retval RETURN_SUCCESS The attributes were set for the memory region.
1862 @retval RETURN_INVALID_PARAMETER Length is zero.
1863 @retval RETURN_UNSUPPORTED The processor does not support one or more bytes of the
1864 memory resource range specified by BaseAddress and Length.
1865 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support for the memory resource
1866 range specified by BaseAddress and Length.
1867 @retval RETURN_ACCESS_DENIED The attributes for the memory resource range specified by
1868 BaseAddress and Length cannot be modified.
1869 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
1870 the memory resource range.
1871
1872 **/
1873 RETURN_STATUS
1874 EFIAPI
1875 MtrrSetMemoryAttributeInMtrrSettings (
1876 IN OUT MTRR_SETTINGS *MtrrSetting,
1877 IN PHYSICAL_ADDRESS BaseAddress,
1878 IN UINT64 Length,
1879 IN MTRR_MEMORY_CACHE_TYPE Attribute
1880 )
1881 {
1882 DEBUG((DEBUG_CACHE, "MtrrSetMemoryAttributeMtrrSettings(%p) %a:%016lx-%016lx\n", MtrrSetting, mMtrrMemoryCacheTypeShortName[Attribute], BaseAddress, Length));
1883 return MtrrSetMemoryAttributeWorker (
1884 MtrrSetting,
1885 BaseAddress,
1886 Length,
1887 Attribute
1888 );
1889 }
1890
1891 /**
1892 Worker function setting variable MTRRs
1893
1894 @param[in] VariableSettings A buffer to hold variable MTRRs content.
1895
1896 **/
1897 VOID
1898 MtrrSetVariableMtrrWorker (
1899 IN MTRR_VARIABLE_SETTINGS *VariableSettings
1900 )
1901 {
1902 UINT32 Index;
1903 UINT32 VariableMtrrCount;
1904
1905 VariableMtrrCount = GetVariableMtrrCountWorker ();
1906 ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);
1907
1908 for (Index = 0; Index < VariableMtrrCount; Index++) {
1909 AsmWriteMsr64 (
1910 MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1),
1911 VariableSettings->Mtrr[Index].Base
1912 );
1913 AsmWriteMsr64 (
1914 MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1) + 1,
1915 VariableSettings->Mtrr[Index].Mask
1916 );
1917 }
1918 }
1919
1920
1921 /**
1922 This function sets variable MTRRs
1923
1924 @param[in] VariableSettings A buffer to hold variable MTRRs content.
1925
1926 @return The pointer of VariableSettings
1927
1928 **/
1929 MTRR_VARIABLE_SETTINGS*
1930 EFIAPI
1931 MtrrSetVariableMtrr (
1932 IN MTRR_VARIABLE_SETTINGS *VariableSettings
1933 )
1934 {
1935 MTRR_CONTEXT MtrrContext;
1936
1937 if (!IsMtrrSupported ()) {
1938 return VariableSettings;
1939 }
1940
1941 PreMtrrChange (&MtrrContext);
1942 MtrrSetVariableMtrrWorker (VariableSettings);
1943 PostMtrrChange (&MtrrContext);
1944 MtrrDebugPrintAllMtrrs ();
1945
1946 return VariableSettings;
1947 }
1948
1949 /**
1950 Worker function setting fixed MTRRs
1951
1952 @param[in] FixedSettings A buffer to hold fixed MTRRs content.
1953
1954 **/
1955 VOID
1956 MtrrSetFixedMtrrWorker (
1957 IN MTRR_FIXED_SETTINGS *FixedSettings
1958 )
1959 {
1960 UINT32 Index;
1961
1962 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
1963 AsmWriteMsr64 (
1964 mMtrrLibFixedMtrrTable[Index].Msr,
1965 FixedSettings->Mtrr[Index]
1966 );
1967 }
1968 }
1969
1970
1971 /**
1972 This function sets fixed MTRRs
1973
1974 @param[in] FixedSettings A buffer to hold fixed MTRRs content.
1975
1976 @retval The pointer of FixedSettings
1977
1978 **/
1979 MTRR_FIXED_SETTINGS*
1980 EFIAPI
1981 MtrrSetFixedMtrr (
1982 IN MTRR_FIXED_SETTINGS *FixedSettings
1983 )
1984 {
1985 MTRR_CONTEXT MtrrContext;
1986
1987 if (!IsMtrrSupported ()) {
1988 return FixedSettings;
1989 }
1990
1991 PreMtrrChange (&MtrrContext);
1992 MtrrSetFixedMtrrWorker (FixedSettings);
1993 PostMtrrChange (&MtrrContext);
1994 MtrrDebugPrintAllMtrrs ();
1995
1996 return FixedSettings;
1997 }
1998
1999
2000 /**
2001 This function gets the content in all MTRRs (variable and fixed)
2002
2003 @param[out] MtrrSetting A buffer to hold all MTRRs content.
2004
2005 @retval the pointer of MtrrSetting
2006
2007 **/
2008 MTRR_SETTINGS *
2009 EFIAPI
2010 MtrrGetAllMtrrs (
2011 OUT MTRR_SETTINGS *MtrrSetting
2012 )
2013 {
2014 if (!IsMtrrSupported ()) {
2015 return MtrrSetting;
2016 }
2017
2018 //
2019 // Get fixed MTRRs
2020 //
2021 MtrrGetFixedMtrrWorker (&MtrrSetting->Fixed);
2022
2023 //
2024 // Get variable MTRRs
2025 //
2026 MtrrGetVariableMtrrWorker (
2027 NULL,
2028 GetVariableMtrrCountWorker (),
2029 &MtrrSetting->Variables
2030 );
2031
2032 //
2033 // Get MTRR_DEF_TYPE value
2034 //
2035 MtrrSetting->MtrrDefType = AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE);
2036
2037 return MtrrSetting;
2038 }
2039
2040
2041 /**
2042 This function sets all MTRRs (variable and fixed)
2043
2044 @param[in] MtrrSetting A buffer holding all MTRRs content.
2045
2046 @retval The pointer of MtrrSetting
2047
2048 **/
2049 MTRR_SETTINGS *
2050 EFIAPI
2051 MtrrSetAllMtrrs (
2052 IN MTRR_SETTINGS *MtrrSetting
2053 )
2054 {
2055 MTRR_CONTEXT MtrrContext;
2056
2057 if (!IsMtrrSupported ()) {
2058 return MtrrSetting;
2059 }
2060
2061 PreMtrrChange (&MtrrContext);
2062
2063 //
2064 // Set fixed MTRRs
2065 //
2066 MtrrSetFixedMtrrWorker (&MtrrSetting->Fixed);
2067
2068 //
2069 // Set variable MTRRs
2070 //
2071 MtrrSetVariableMtrrWorker (&MtrrSetting->Variables);
2072
2073 //
2074 // Set MTRR_DEF_TYPE value
2075 //
2076 AsmWriteMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE, MtrrSetting->MtrrDefType);
2077
2078 PostMtrrChangeEnableCache (&MtrrContext);
2079
2080 MtrrDebugPrintAllMtrrs ();
2081
2082 return MtrrSetting;
2083 }
2084
2085
2086 /**
2087 Checks if MTRR is supported.
2088
2089 @retval TRUE MTRR is supported.
2090 @retval FALSE MTRR is not supported.
2091
2092 **/
2093 BOOLEAN
2094 EFIAPI
2095 IsMtrrSupported (
2096 VOID
2097 )
2098 {
2099 UINT32 RegEdx;
2100 UINT64 MtrrCap;
2101
2102 //
2103 // Check CPUID(1).EDX[12] for MTRR capability
2104 //
2105 AsmCpuid (1, NULL, NULL, NULL, &RegEdx);
2106 if (BitFieldRead32 (RegEdx, 12, 12) == 0) {
2107 return FALSE;
2108 }
2109
2110 //
2111 // Check IA32_MTRRCAP.[0..7] for number of variable MTRRs and IA32_MTRRCAP[8] for
2112 // fixed MTRRs existence. If number of variable MTRRs is zero, or fixed MTRRs do not
2113 // exist, return false.
2114 //
2115 MtrrCap = AsmReadMsr64 (MTRR_LIB_IA32_MTRR_CAP);
2116 if ((BitFieldRead64 (MtrrCap, 0, 7) == 0) || (BitFieldRead64 (MtrrCap, 8, 8) == 0)) {
2117 return FALSE;
2118 }
2119
2120 return TRUE;
2121 }