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