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