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