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