]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/Library/MtrrLib/MtrrLib.c
UefiCpuPkg/MtrrLib: Optimize MtrrLibLeastAlignment()
[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 biggest alignment (lowest set bit) of address.
660 The function is equivalent to: 1 << LowBitSet64 (Address).
661
662 @param Address The address to return the alignment.
663 @param Alignment0 The alignment to return when Address is 0.
664
665 @return The least alignment of the Address.
666 **/
667 UINT64
668 MtrrLibBiggestAlignment (
669 UINT64 Address,
670 UINT64 Alignment0
671 )
672 {
673 if (Address == 0) {
674 return Alignment0;
675 }
676
677 return Address & ((~Address) + 1);
678 }
679
680 /**
681 Return the number of required variable MTRRs to positively cover the
682 specified range.
683
684 @param BaseAddress Base address of the range.
685 @param Length Length of the range.
686 @param Alignment0 Alignment of 0.
687
688 @return The number of the required variable MTRRs.
689 **/
690 UINT32
691 MtrrLibGetPositiveMtrrNumber (
692 IN UINT64 BaseAddress,
693 IN UINT64 Length,
694 IN UINT64 Alignment0
695 )
696 {
697 UINT64 SubLength;
698 UINT32 MtrrNumber;
699 BOOLEAN UseLeastAlignment;
700
701 UseLeastAlignment = TRUE;
702 SubLength = 0;
703
704 //
705 // Calculate the alignment of the base address.
706 //
707 for (MtrrNumber = 0; Length != 0; MtrrNumber++) {
708 if (UseLeastAlignment) {
709 SubLength = MtrrLibBiggestAlignment (BaseAddress, Alignment0);
710
711 if (SubLength > Length) {
712 //
713 // Set a flag when remaining length is too small
714 // so that MtrrLibBiggestAlignment() is not called in following loops.
715 //
716 UseLeastAlignment = FALSE;
717 }
718 }
719
720 if (!UseLeastAlignment) {
721 SubLength = GetPowerOfTwo64 (Length);
722 }
723
724 BaseAddress += SubLength;
725 Length -= SubLength;
726 }
727
728 return MtrrNumber;
729 }
730
731 /**
732 Return whether the left MTRR type precedes the right MTRR type.
733
734 The MTRR type precedence rules are:
735 1. UC precedes any other type
736 2. WT precedes WB
737 For further details, please refer the IA32 Software Developer's Manual,
738 Volume 3, Section "MTRR Precedences".
739
740 @param Left The left MTRR type.
741 @param Right The right MTRR type.
742
743 @retval TRUE Left precedes Right.
744 @retval FALSE Left doesn't precede Right.
745 **/
746 BOOLEAN
747 MtrrLibTypeLeftPrecedeRight (
748 IN MTRR_MEMORY_CACHE_TYPE Left,
749 IN MTRR_MEMORY_CACHE_TYPE Right
750 )
751 {
752 return (BOOLEAN) (Left == CacheUncacheable || (Left == CacheWriteThrough && Right == CacheWriteBack));
753 }
754
755
756 /**
757 Return whether the type of the specified range can precede the specified type.
758
759 @param Ranges Memory range array holding memory type settings for all
760 the memory address.
761 @param RangeCount Count of memory ranges.
762 @param Type Type to check precedence.
763 @param SubBase Base address of the specified range.
764 @param SubLength Length of the specified range.
765
766 @retval TRUE The type of the specified range can precede the Type.
767 @retval FALSE The type of the specified range cannot precede the Type.
768 So the subtraction is not applicable.
769 **/
770 BOOLEAN
771 MtrrLibSubstractable (
772 IN CONST MEMORY_RANGE *Ranges,
773 IN UINT32 RangeCount,
774 IN MTRR_MEMORY_CACHE_TYPE Type,
775 IN UINT64 SubBase,
776 IN UINT64 SubLength
777 )
778 {
779 UINT32 Index;
780 UINT64 Length;
781 // WT > WB
782 // UC > *
783 for (Index = 0; Index < RangeCount; Index++) {
784 if (Ranges[Index].BaseAddress <= SubBase && SubBase < Ranges[Index].BaseAddress + Ranges[Index].Length) {
785
786 if (Ranges[Index].BaseAddress + Ranges[Index].Length >= SubBase + SubLength) {
787 return MtrrLibTypeLeftPrecedeRight (Ranges[Index].Type, Type);
788
789 } else {
790 if (!MtrrLibTypeLeftPrecedeRight (Ranges[Index].Type, Type)) {
791 return FALSE;
792 }
793
794 Length = Ranges[Index].BaseAddress + Ranges[Index].Length - SubBase;
795 SubBase += Length;
796 SubLength -= Length;
797 }
798 }
799 }
800
801 ASSERT (FALSE);
802 return FALSE;
803 }
804
805 /**
806 Return the number of required variable MTRRs to cover the specified range.
807
808 The routine considers subtraction in the both side of the range to find out
809 the most optimal solution (which uses the least MTRRs).
810
811 @param Ranges Array holding memory type settings of all memory
812 address.
813 @param RangeCount Count of memory ranges.
814 @param VariableMtrr Array holding allocated variable MTRRs.
815 @param VariableMtrrCount Count of allocated variable MTRRs.
816 @param BaseAddress Base address of the specified range.
817 @param Length Length of the specified range.
818 @param Type MTRR type of the specified range.
819 @param Alignment0 Alignment of 0.
820 @param SubLeft Return the count of left subtraction.
821 @param SubRight Return the count of right subtraction.
822
823 @return Number of required variable MTRRs.
824 **/
825 UINT32
826 MtrrLibGetMtrrNumber (
827 IN CONST MEMORY_RANGE *Ranges,
828 IN UINT32 RangeCount,
829 IN CONST VARIABLE_MTRR *VariableMtrr,
830 IN UINT32 VariableMtrrCount,
831 IN UINT64 BaseAddress,
832 IN UINT64 Length,
833 IN MTRR_MEMORY_CACHE_TYPE Type,
834 IN UINT64 Alignment0,
835 OUT UINT32 *SubLeft, // subtractive from BaseAddress to get more aligned address, to save MTRR
836 OUT UINT32 *SubRight // subtractive from BaseAddress + Length, to save MTRR
837 )
838 {
839 UINT64 Alignment;
840 UINT32 LeastLeftMtrrNumber;
841 UINT32 MiddleMtrrNumber;
842 UINT32 LeastRightMtrrNumber;
843 UINT32 CurrentMtrrNumber;
844 UINT32 SubtractiveCount;
845 UINT32 SubtractiveMtrrNumber;
846 UINT32 LeastSubtractiveMtrrNumber;
847 UINT64 SubtractiveBaseAddress;
848 UINT64 SubtractiveLength;
849 UINT64 BaseAlignment;
850 UINT32 Index;
851 UINT64 OriginalBaseAddress;
852 UINT64 OriginalLength;
853
854 *SubLeft = 0;
855 *SubRight = 0;
856 LeastSubtractiveMtrrNumber = 0;
857 BaseAlignment = 0;
858
859 //
860 // Get the optimal left subtraction solution.
861 //
862 if (BaseAddress != 0) {
863
864 OriginalBaseAddress = BaseAddress;
865 OriginalLength = Length;
866 SubtractiveBaseAddress = 0;
867 SubtractiveLength = 0;
868 //
869 // Get the MTRR number needed without left subtraction.
870 //
871 LeastLeftMtrrNumber = MtrrLibGetPositiveMtrrNumber (BaseAddress, Length, Alignment0);
872
873 //
874 // Left subtraction bit by bit, to find the optimal left subtraction solution.
875 //
876 for (SubtractiveMtrrNumber = 0, SubtractiveCount = 1; BaseAddress != 0; SubtractiveCount++) {
877 Alignment = MtrrLibBiggestAlignment (BaseAddress, Alignment0);
878
879 //
880 // Check whether the memory type of [BaseAddress - Alignment, BaseAddress) can override Type.
881 // IA32 Manual defines the following override rules:
882 // WT > WB
883 // UC > * (any)
884 //
885 if (!MtrrLibSubstractable (Ranges, RangeCount, Type, BaseAddress - Alignment, Alignment)) {
886 break;
887 }
888
889 for (Index = 0; Index < VariableMtrrCount; Index++) {
890 if ((VariableMtrr[Index].BaseAddress == BaseAddress - Alignment) &&
891 (VariableMtrr[Index].Length == Alignment)) {
892 break;
893 }
894 }
895 if (Index == VariableMtrrCount) {
896 //
897 // Increment SubtractiveMtrrNumber when [BaseAddress - Alignment, BaseAddress) is not be planed as a MTRR
898 //
899 SubtractiveMtrrNumber++;
900 }
901
902 BaseAddress -= Alignment;
903 Length += Alignment;
904
905 CurrentMtrrNumber = SubtractiveMtrrNumber + MtrrLibGetPositiveMtrrNumber (BaseAddress, Length, Alignment0);
906 if (CurrentMtrrNumber <= LeastLeftMtrrNumber) {
907 LeastLeftMtrrNumber = CurrentMtrrNumber;
908 LeastSubtractiveMtrrNumber = SubtractiveMtrrNumber;
909 *SubLeft = SubtractiveCount;
910 SubtractiveBaseAddress = BaseAddress;
911 SubtractiveLength = Length;
912 }
913 }
914
915 //
916 // If left subtraction is better, subtract BaseAddress to left, and enlarge Length
917 //
918 if (*SubLeft != 0) {
919 BaseAddress = SubtractiveBaseAddress;
920 Length = SubtractiveLength;
921 } else {
922 BaseAddress = OriginalBaseAddress;
923 Length = OriginalLength;
924 }
925 }
926
927 //
928 // Increment BaseAddress greedily until (BaseAddress + Alignment) exceeds (BaseAddress + Length)
929 //
930 MiddleMtrrNumber = 0;
931 while (Length != 0) {
932 BaseAlignment = MtrrLibBiggestAlignment (BaseAddress, Alignment0);
933 if (BaseAlignment > Length) {
934 break;
935 }
936 BaseAddress += BaseAlignment;
937 Length -= BaseAlignment;
938 MiddleMtrrNumber++;
939 }
940
941
942 if (Length == 0) {
943 return LeastSubtractiveMtrrNumber + MiddleMtrrNumber;
944 }
945
946
947 //
948 // Get the optimal right subtraction solution.
949 //
950
951 //
952 // Get the MTRR number needed without right subtraction.
953 //
954 LeastRightMtrrNumber = MtrrLibGetPositiveMtrrNumber (BaseAddress, Length, Alignment0);
955
956 for (SubtractiveCount = 1; Length < BaseAlignment; SubtractiveCount++) {
957 Alignment = MtrrLibBiggestAlignment (BaseAddress + Length, Alignment0);
958 if (!MtrrLibSubstractable (Ranges, RangeCount, Type, BaseAddress + Length, Alignment)) {
959 break;
960 }
961
962 Length += Alignment;
963
964 //
965 // SubtractiveCount = Number of MTRRs used for subtraction
966 //
967 CurrentMtrrNumber = SubtractiveCount + MtrrLibGetPositiveMtrrNumber (BaseAddress, Length, Alignment0);
968 if (CurrentMtrrNumber <= LeastRightMtrrNumber) {
969 LeastRightMtrrNumber = CurrentMtrrNumber;
970 *SubRight = SubtractiveCount;
971 SubtractiveLength = Length;
972 }
973 }
974
975 return LeastSubtractiveMtrrNumber + MiddleMtrrNumber + LeastRightMtrrNumber;
976 }
977
978 /**
979 Initializes the valid bits mask and valid address mask for MTRRs.
980
981 This function initializes the valid bits mask and valid address mask for MTRRs.
982
983 @param[out] MtrrValidBitsMask The mask for the valid bit of the MTRR
984 @param[out] MtrrValidAddressMask The valid address mask for the MTRR
985
986 **/
987 VOID
988 MtrrLibInitializeMtrrMask (
989 OUT UINT64 *MtrrValidBitsMask,
990 OUT UINT64 *MtrrValidAddressMask
991 )
992 {
993 UINT32 MaxExtendedFunction;
994 CPUID_VIR_PHY_ADDRESS_SIZE_EAX VirPhyAddressSize;
995
996
997 AsmCpuid (CPUID_EXTENDED_FUNCTION, &MaxExtendedFunction, NULL, NULL, NULL);
998
999 if (MaxExtendedFunction >= CPUID_VIR_PHY_ADDRESS_SIZE) {
1000 AsmCpuid (CPUID_VIR_PHY_ADDRESS_SIZE, &VirPhyAddressSize.Uint32, NULL, NULL, NULL);
1001 } else {
1002 VirPhyAddressSize.Bits.PhysicalAddressBits = 36;
1003 }
1004
1005 *MtrrValidBitsMask = LShiftU64 (1, VirPhyAddressSize.Bits.PhysicalAddressBits) - 1;
1006 *MtrrValidAddressMask = *MtrrValidBitsMask & 0xfffffffffffff000ULL;
1007 }
1008
1009
1010 /**
1011 Determines the real attribute of a memory range.
1012
1013 This function is to arbitrate the real attribute of the memory when
1014 there are 2 MTRRs covers the same memory range. For further details,
1015 please refer the IA32 Software Developer's Manual, Volume 3,
1016 Section "MTRR Precedences".
1017
1018 @param[in] MtrrType1 The first kind of Memory type
1019 @param[in] MtrrType2 The second kind of memory type
1020
1021 **/
1022 MTRR_MEMORY_CACHE_TYPE
1023 MtrrLibPrecedence (
1024 IN MTRR_MEMORY_CACHE_TYPE MtrrType1,
1025 IN MTRR_MEMORY_CACHE_TYPE MtrrType2
1026 )
1027 {
1028 if (MtrrType1 == MtrrType2) {
1029 return MtrrType1;
1030 }
1031
1032 ASSERT (
1033 MtrrLibTypeLeftPrecedeRight (MtrrType1, MtrrType2) ||
1034 MtrrLibTypeLeftPrecedeRight (MtrrType2, MtrrType1)
1035 );
1036
1037 if (MtrrLibTypeLeftPrecedeRight (MtrrType1, MtrrType2)) {
1038 return MtrrType1;
1039 } else {
1040 return MtrrType2;
1041 }
1042 }
1043
1044 /**
1045 Worker function will get the memory cache type of the specific address.
1046
1047 If MtrrSetting is not NULL, gets the memory cache type from input
1048 MTRR settings buffer.
1049 If MtrrSetting is NULL, gets the memory cache type from MTRRs.
1050
1051 @param[in] MtrrSetting A buffer holding all MTRRs content.
1052 @param[in] Address The specific address
1053
1054 @return Memory cache type of the specific address
1055
1056 **/
1057 MTRR_MEMORY_CACHE_TYPE
1058 MtrrGetMemoryAttributeByAddressWorker (
1059 IN MTRR_SETTINGS *MtrrSetting,
1060 IN PHYSICAL_ADDRESS Address
1061 )
1062 {
1063 MSR_IA32_MTRR_DEF_TYPE_REGISTER DefType;
1064 UINT64 FixedMtrr;
1065 UINTN Index;
1066 UINTN SubIndex;
1067 MTRR_MEMORY_CACHE_TYPE MtrrType;
1068 VARIABLE_MTRR VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];
1069 UINT64 MtrrValidBitsMask;
1070 UINT64 MtrrValidAddressMask;
1071 UINT32 VariableMtrrCount;
1072 MTRR_VARIABLE_SETTINGS VariableSettings;
1073
1074 //
1075 // Check if MTRR is enabled, if not, return UC as attribute
1076 //
1077 if (MtrrSetting == NULL) {
1078 DefType.Uint64 = AsmReadMsr64 (MSR_IA32_MTRR_DEF_TYPE);
1079 } else {
1080 DefType.Uint64 = MtrrSetting->MtrrDefType;
1081 }
1082
1083 if (DefType.Bits.E == 0) {
1084 return CacheUncacheable;
1085 }
1086
1087 //
1088 // If address is less than 1M, then try to go through the fixed MTRR
1089 //
1090 if (Address < BASE_1MB) {
1091 if (DefType.Bits.FE != 0) {
1092 //
1093 // Go through the fixed MTRR
1094 //
1095 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
1096 if (Address >= mMtrrLibFixedMtrrTable[Index].BaseAddress &&
1097 Address < mMtrrLibFixedMtrrTable[Index].BaseAddress +
1098 (mMtrrLibFixedMtrrTable[Index].Length * 8)) {
1099 SubIndex =
1100 ((UINTN) Address - mMtrrLibFixedMtrrTable[Index].BaseAddress) /
1101 mMtrrLibFixedMtrrTable[Index].Length;
1102 if (MtrrSetting == NULL) {
1103 FixedMtrr = AsmReadMsr64 (mMtrrLibFixedMtrrTable[Index].Msr);
1104 } else {
1105 FixedMtrr = MtrrSetting->Fixed.Mtrr[Index];
1106 }
1107 return (MTRR_MEMORY_CACHE_TYPE) (RShiftU64 (FixedMtrr, SubIndex * 8) & 0xFF);
1108 }
1109 }
1110 }
1111 }
1112
1113 VariableMtrrCount = GetVariableMtrrCountWorker ();
1114 ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);
1115 MtrrGetVariableMtrrWorker (MtrrSetting, VariableMtrrCount, &VariableSettings);
1116
1117 MtrrLibInitializeMtrrMask (&MtrrValidBitsMask, &MtrrValidAddressMask);
1118 MtrrGetMemoryAttributeInVariableMtrrWorker (
1119 &VariableSettings,
1120 VariableMtrrCount,
1121 MtrrValidBitsMask,
1122 MtrrValidAddressMask,
1123 VariableMtrr
1124 );
1125
1126 //
1127 // Go through the variable MTRR
1128 //
1129 MtrrType = CacheInvalid;
1130 for (Index = 0; Index < VariableMtrrCount; Index++) {
1131 if (VariableMtrr[Index].Valid) {
1132 if (Address >= VariableMtrr[Index].BaseAddress &&
1133 Address < VariableMtrr[Index].BaseAddress + VariableMtrr[Index].Length) {
1134 if (MtrrType == CacheInvalid) {
1135 MtrrType = (MTRR_MEMORY_CACHE_TYPE) VariableMtrr[Index].Type;
1136 } else {
1137 MtrrType = MtrrLibPrecedence (MtrrType, (MTRR_MEMORY_CACHE_TYPE) VariableMtrr[Index].Type);
1138 }
1139 }
1140 }
1141 }
1142
1143 //
1144 // If there is no MTRR which covers the Address, use the default MTRR type.
1145 //
1146 if (MtrrType == CacheInvalid) {
1147 MtrrType = (MTRR_MEMORY_CACHE_TYPE) DefType.Bits.Type;
1148 }
1149
1150 return MtrrType;
1151 }
1152
1153
1154 /**
1155 This function will get the memory cache type of the specific address.
1156
1157 This function is mainly for debug purpose.
1158
1159 @param[in] Address The specific address
1160
1161 @return Memory cache type of the specific address
1162
1163 **/
1164 MTRR_MEMORY_CACHE_TYPE
1165 EFIAPI
1166 MtrrGetMemoryAttribute (
1167 IN PHYSICAL_ADDRESS Address
1168 )
1169 {
1170 if (!IsMtrrSupported ()) {
1171 return CacheUncacheable;
1172 }
1173
1174 return MtrrGetMemoryAttributeByAddressWorker (NULL, Address);
1175 }
1176
1177 /**
1178 Worker function prints all MTRRs for debugging.
1179
1180 If MtrrSetting is not NULL, print MTRR settings from input MTRR
1181 settings buffer.
1182 If MtrrSetting is NULL, print MTRR settings from MTRRs.
1183
1184 @param MtrrSetting A buffer holding all MTRRs content.
1185 **/
1186 VOID
1187 MtrrDebugPrintAllMtrrsWorker (
1188 IN MTRR_SETTINGS *MtrrSetting
1189 )
1190 {
1191 DEBUG_CODE (
1192 MTRR_SETTINGS LocalMtrrs;
1193 MTRR_SETTINGS *Mtrrs;
1194 UINTN Index;
1195 UINTN Index1;
1196 UINTN VariableMtrrCount;
1197 UINT64 Base;
1198 UINT64 Limit;
1199 UINT64 MtrrBase;
1200 UINT64 MtrrLimit;
1201 UINT64 RangeBase;
1202 UINT64 RangeLimit;
1203 UINT64 NoRangeBase;
1204 UINT64 NoRangeLimit;
1205 UINT32 RegEax;
1206 UINTN MemoryType;
1207 UINTN PreviousMemoryType;
1208 BOOLEAN Found;
1209
1210 if (!IsMtrrSupported ()) {
1211 return;
1212 }
1213
1214 DEBUG((DEBUG_CACHE, "MTRR Settings\n"));
1215 DEBUG((DEBUG_CACHE, "=============\n"));
1216
1217 if (MtrrSetting != NULL) {
1218 Mtrrs = MtrrSetting;
1219 } else {
1220 MtrrGetAllMtrrs (&LocalMtrrs);
1221 Mtrrs = &LocalMtrrs;
1222 }
1223
1224 DEBUG((DEBUG_CACHE, "MTRR Default Type: %016lx\n", Mtrrs->MtrrDefType));
1225 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
1226 DEBUG((DEBUG_CACHE, "Fixed MTRR[%02d] : %016lx\n", Index, Mtrrs->Fixed.Mtrr[Index]));
1227 }
1228
1229 VariableMtrrCount = GetVariableMtrrCount ();
1230 for (Index = 0; Index < VariableMtrrCount; Index++) {
1231 DEBUG((DEBUG_CACHE, "Variable MTRR[%02d]: Base=%016lx Mask=%016lx\n",
1232 Index,
1233 Mtrrs->Variables.Mtrr[Index].Base,
1234 Mtrrs->Variables.Mtrr[Index].Mask
1235 ));
1236 }
1237 DEBUG((DEBUG_CACHE, "\n"));
1238 DEBUG((DEBUG_CACHE, "MTRR Ranges\n"));
1239 DEBUG((DEBUG_CACHE, "====================================\n"));
1240
1241 Base = 0;
1242 PreviousMemoryType = MTRR_CACHE_INVALID_TYPE;
1243 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
1244 Base = mMtrrLibFixedMtrrTable[Index].BaseAddress;
1245 for (Index1 = 0; Index1 < 8; Index1++) {
1246 MemoryType = (UINTN)(RShiftU64 (Mtrrs->Fixed.Mtrr[Index], Index1 * 8) & 0xff);
1247 if (MemoryType > CacheWriteBack) {
1248 MemoryType = MTRR_CACHE_INVALID_TYPE;
1249 }
1250 if (MemoryType != PreviousMemoryType) {
1251 if (PreviousMemoryType != MTRR_CACHE_INVALID_TYPE) {
1252 DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));
1253 }
1254 PreviousMemoryType = MemoryType;
1255 DEBUG((DEBUG_CACHE, "%a:%016lx-", mMtrrMemoryCacheTypeShortName[MemoryType], Base));
1256 }
1257 Base += mMtrrLibFixedMtrrTable[Index].Length;
1258 }
1259 }
1260 DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));
1261
1262 VariableMtrrCount = GetVariableMtrrCount ();
1263
1264 Limit = BIT36 - 1;
1265 AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
1266 if (RegEax >= 0x80000008) {
1267 AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);
1268 Limit = LShiftU64 (1, RegEax & 0xff) - 1;
1269 }
1270 Base = BASE_1MB;
1271 PreviousMemoryType = MTRR_CACHE_INVALID_TYPE;
1272 do {
1273 MemoryType = MtrrGetMemoryAttributeByAddressWorker (Mtrrs, Base);
1274 if (MemoryType > CacheWriteBack) {
1275 MemoryType = MTRR_CACHE_INVALID_TYPE;
1276 }
1277
1278 if (MemoryType != PreviousMemoryType) {
1279 if (PreviousMemoryType != MTRR_CACHE_INVALID_TYPE) {
1280 DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));
1281 }
1282 PreviousMemoryType = MemoryType;
1283 DEBUG((DEBUG_CACHE, "%a:%016lx-", mMtrrMemoryCacheTypeShortName[MemoryType], Base));
1284 }
1285
1286 RangeBase = BASE_1MB;
1287 NoRangeBase = BASE_1MB;
1288 RangeLimit = Limit;
1289 NoRangeLimit = Limit;
1290
1291 for (Index = 0, Found = FALSE; Index < VariableMtrrCount; Index++) {
1292 if ((Mtrrs->Variables.Mtrr[Index].Mask & BIT11) == 0) {
1293 //
1294 // If mask is not valid, then do not display range
1295 //
1296 continue;
1297 }
1298 MtrrBase = (Mtrrs->Variables.Mtrr[Index].Base & (~(SIZE_4KB - 1)));
1299 MtrrLimit = MtrrBase + ((~(Mtrrs->Variables.Mtrr[Index].Mask & (~(SIZE_4KB - 1)))) & Limit);
1300
1301 if (Base >= MtrrBase && Base < MtrrLimit) {
1302 Found = TRUE;
1303 }
1304
1305 if (Base >= MtrrBase && MtrrBase > RangeBase) {
1306 RangeBase = MtrrBase;
1307 }
1308 if (Base > MtrrLimit && MtrrLimit > RangeBase) {
1309 RangeBase = MtrrLimit + 1;
1310 }
1311 if (Base < MtrrBase && MtrrBase < RangeLimit) {
1312 RangeLimit = MtrrBase - 1;
1313 }
1314 if (Base < MtrrLimit && MtrrLimit <= RangeLimit) {
1315 RangeLimit = MtrrLimit;
1316 }
1317
1318 if (Base > MtrrLimit && NoRangeBase < MtrrLimit) {
1319 NoRangeBase = MtrrLimit + 1;
1320 }
1321 if (Base < MtrrBase && NoRangeLimit > MtrrBase) {
1322 NoRangeLimit = MtrrBase - 1;
1323 }
1324 }
1325
1326 if (Found) {
1327 Base = RangeLimit + 1;
1328 } else {
1329 Base = NoRangeLimit + 1;
1330 }
1331 } while (Base < Limit);
1332 DEBUG((DEBUG_CACHE, "%016lx\n\n", Base - 1));
1333 );
1334 }
1335
1336
1337 /**
1338 This function prints all MTRRs for debugging.
1339 **/
1340 VOID
1341 EFIAPI
1342 MtrrDebugPrintAllMtrrs (
1343 VOID
1344 )
1345 {
1346 MtrrDebugPrintAllMtrrsWorker (NULL);
1347 }
1348
1349 /**
1350 Update the Ranges array to change the specified range identified by
1351 BaseAddress and Length to Type.
1352
1353 @param Ranges Array holding memory type settings for all memory regions.
1354 @param Capacity The maximum count of memory ranges the array can hold.
1355 @param Count Return the new memory range count in the array.
1356 @param BaseAddress The base address of the memory range to change type.
1357 @param Length The length of the memory range to change type.
1358 @param Type The new type of the specified memory range.
1359
1360 @retval RETURN_SUCCESS The type of the specified memory range is
1361 changed successfully.
1362 @retval RETURN_OUT_OF_RESOURCES The new type set causes the count of memory
1363 range exceeds capacity.
1364 **/
1365 RETURN_STATUS
1366 MtrrLibSetMemoryType (
1367 IN MEMORY_RANGE *Ranges,
1368 IN UINT32 Capacity,
1369 IN OUT UINT32 *Count,
1370 IN UINT64 BaseAddress,
1371 IN UINT64 Length,
1372 IN MTRR_MEMORY_CACHE_TYPE Type
1373 )
1374 {
1375 UINT32 Index;
1376 UINT64 Limit;
1377 UINT64 LengthLeft;
1378 UINT64 LengthRight;
1379 UINT32 StartIndex;
1380 UINT32 EndIndex;
1381 UINT32 DeltaCount;
1382
1383 LengthRight = 0;
1384 LengthLeft = 0;
1385 Limit = BaseAddress + Length;
1386 StartIndex = *Count;
1387 EndIndex = *Count;
1388 for (Index = 0; Index < *Count; Index++) {
1389 if ((StartIndex == *Count) &&
1390 (Ranges[Index].BaseAddress <= BaseAddress) &&
1391 (BaseAddress < Ranges[Index].BaseAddress + Ranges[Index].Length)) {
1392 StartIndex = Index;
1393 LengthLeft = BaseAddress - Ranges[Index].BaseAddress;
1394 }
1395
1396 if ((EndIndex == *Count) &&
1397 (Ranges[Index].BaseAddress < Limit) &&
1398 (Limit <= Ranges[Index].BaseAddress + Ranges[Index].Length)) {
1399 EndIndex = Index;
1400 LengthRight = Ranges[Index].BaseAddress + Ranges[Index].Length - Limit;
1401 break;
1402 }
1403 }
1404
1405 ASSERT (StartIndex != *Count && EndIndex != *Count);
1406 if (StartIndex == EndIndex && Ranges[StartIndex].Type == Type) {
1407 return RETURN_SUCCESS;
1408 }
1409
1410 //
1411 // The type change may cause merging with previous range or next range.
1412 // Update the StartIndex, EndIndex, BaseAddress, Length so that following
1413 // logic doesn't need to consider merging.
1414 //
1415 if (StartIndex != 0) {
1416 if (LengthLeft == 0 && Ranges[StartIndex - 1].Type == Type) {
1417 StartIndex--;
1418 Length += Ranges[StartIndex].Length;
1419 BaseAddress -= Ranges[StartIndex].Length;
1420 }
1421 }
1422 if (EndIndex != (*Count) - 1) {
1423 if (LengthRight == 0 && Ranges[EndIndex + 1].Type == Type) {
1424 EndIndex++;
1425 Length += Ranges[EndIndex].Length;
1426 }
1427 }
1428
1429 //
1430 // |- 0 -|- 1 -|- 2 -|- 3 -| StartIndex EndIndex DeltaCount Count (Count = 4)
1431 // |++++++++++++++++++| 0 3 1=3-0-2 3
1432 // |+++++++| 0 1 -1=1-0-2 5
1433 // |+| 0 0 -2=0-0-2 6
1434 // |+++| 0 0 -1=0-0-2+1 5
1435 //
1436 //
1437 DeltaCount = EndIndex - StartIndex - 2;
1438 if (LengthLeft == 0) {
1439 DeltaCount++;
1440 }
1441 if (LengthRight == 0) {
1442 DeltaCount++;
1443 }
1444 if (*Count - DeltaCount > Capacity) {
1445 return RETURN_OUT_OF_RESOURCES;
1446 }
1447
1448 //
1449 // Reserve (-DeltaCount) space
1450 //
1451 CopyMem (&Ranges[EndIndex + 1 - DeltaCount], &Ranges[EndIndex + 1], (*Count - EndIndex - 1) * sizeof (Ranges[0]));
1452 *Count -= DeltaCount;
1453
1454 if (LengthLeft != 0) {
1455 Ranges[StartIndex].Length = LengthLeft;
1456 StartIndex++;
1457 }
1458 if (LengthRight != 0) {
1459 Ranges[EndIndex - DeltaCount].BaseAddress = BaseAddress + Length;
1460 Ranges[EndIndex - DeltaCount].Length = LengthRight;
1461 Ranges[EndIndex - DeltaCount].Type = Ranges[EndIndex].Type;
1462 }
1463 Ranges[StartIndex].BaseAddress = BaseAddress;
1464 Ranges[StartIndex].Length = Length;
1465 Ranges[StartIndex].Type = Type;
1466 return RETURN_SUCCESS;
1467 }
1468
1469 /**
1470 Allocate one or more variable MTRR to cover the range identified by
1471 BaseAddress and Length.
1472
1473 @param Ranges Memory range array holding the memory type
1474 settings for all memory address.
1475 @param RangeCount Count of memory ranges.
1476 @param VariableMtrr Variable MTRR array.
1477 @param VariableMtrrCapacity Capacity of variable MTRR array.
1478 @param VariableMtrrCount Count of variable MTRR.
1479 @param BaseAddress Base address of the memory range.
1480 @param Length Length of the memory range.
1481 @param Type MTRR type of the memory range.
1482 @param Alignment0 Alignment of 0.
1483
1484 @retval RETURN_SUCCESS Variable MTRRs are allocated successfully.
1485 @retval RETURN_OUT_OF_RESOURCES Count of variable MTRRs exceeds capacity.
1486 **/
1487 RETURN_STATUS
1488 MtrrLibSetMemoryAttributeInVariableMtrr (
1489 IN CONST MEMORY_RANGE *Ranges,
1490 IN UINT32 RangeCount,
1491 IN OUT VARIABLE_MTRR *VariableMtrr,
1492 IN UINT32 VariableMtrrCapacity,
1493 IN OUT UINT32 *VariableMtrrCount,
1494 IN UINT64 BaseAddress,
1495 IN UINT64 Length,
1496 IN MTRR_MEMORY_CACHE_TYPE Type,
1497 IN UINT64 Alignment0
1498 );
1499
1500 /**
1501 Allocate one or more variable MTRR to cover the range identified by
1502 BaseAddress and Length.
1503
1504 The routine recursively calls MtrrLibSetMemoryAttributeInVariableMtrr()
1505 to allocate variable MTRRs when the range contains several sub-ranges
1506 with different attributes.
1507
1508 @param Ranges Memory range array holding the memory type
1509 settings for all memory address.
1510 @param RangeCount Count of memory ranges.
1511 @param VariableMtrr Variable MTRR array.
1512 @param VariableMtrrCapacity Capacity of variable MTRR array.
1513 @param VariableMtrrCount Count of variable MTRR.
1514 @param BaseAddress Base address of the memory range.
1515 @param Length Length of the memory range.
1516 @param Type MTRR type of the range.
1517 If it's CacheInvalid, the memory range may
1518 contains several sub-ranges with different
1519 attributes.
1520 @param Alignment0 Alignment of 0.
1521
1522 @retval RETURN_SUCCESS Variable MTRRs are allocated successfully.
1523 @retval RETURN_OUT_OF_RESOURCES Count of variable MTRRs exceeds capacity.
1524 **/
1525 RETURN_STATUS
1526 MtrrLibAddVariableMtrr (
1527 IN CONST MEMORY_RANGE *Ranges,
1528 IN UINT32 RangeCount,
1529 IN OUT VARIABLE_MTRR *VariableMtrr,
1530 IN UINT32 VariableMtrrCapacity,
1531 IN OUT UINT32 *VariableMtrrCount,
1532 IN PHYSICAL_ADDRESS BaseAddress,
1533 IN UINT64 Length,
1534 IN MTRR_MEMORY_CACHE_TYPE Type,
1535 IN UINT64 Alignment0
1536 )
1537 {
1538 RETURN_STATUS Status;
1539 UINT32 Index;
1540 UINT64 SubLength;
1541
1542 MTRR_LIB_ASSERT_ALIGNED (BaseAddress, Length);
1543 if (Type == CacheInvalid) {
1544 ASSERT (Ranges != NULL);
1545 for (Index = 0; Index < RangeCount; Index++) {
1546 if (Ranges[Index].BaseAddress <= BaseAddress && BaseAddress < Ranges[Index].BaseAddress + Ranges[Index].Length) {
1547
1548 //
1549 // Because the Length may not be aligned to BaseAddress, below code calls
1550 // MtrrLibSetMemoryAttributeInVariableMtrr() instead of itself.
1551 // MtrrLibSetMemoryAttributeInVariableMtrr() splits the range to several
1552 // aligned ranges.
1553 //
1554 if (Ranges[Index].BaseAddress + Ranges[Index].Length >= BaseAddress + Length) {
1555 return MtrrLibSetMemoryAttributeInVariableMtrr (
1556 Ranges, RangeCount, VariableMtrr, VariableMtrrCapacity, VariableMtrrCount,
1557 BaseAddress, Length, Ranges[Index].Type, Alignment0
1558 );
1559 } else {
1560 SubLength = Ranges[Index].BaseAddress + Ranges[Index].Length - BaseAddress;
1561 Status = MtrrLibSetMemoryAttributeInVariableMtrr (
1562 Ranges, RangeCount, VariableMtrr, VariableMtrrCapacity, VariableMtrrCount,
1563 BaseAddress, SubLength, Ranges[Index].Type, Alignment0
1564 );
1565 if (RETURN_ERROR (Status)) {
1566 return Status;
1567 }
1568 BaseAddress += SubLength;
1569 Length -= SubLength;
1570 }
1571 }
1572 }
1573
1574 //
1575 // Because memory ranges cover all the memory addresses, it's impossible to be here.
1576 //
1577 ASSERT (FALSE);
1578 return RETURN_DEVICE_ERROR;
1579 } else {
1580 for (Index = 0; Index < *VariableMtrrCount; Index++) {
1581 if (VariableMtrr[Index].BaseAddress == BaseAddress && VariableMtrr[Index].Length == Length) {
1582 ASSERT (VariableMtrr[Index].Type == Type);
1583 break;
1584 }
1585 }
1586 if (Index == *VariableMtrrCount) {
1587 if (*VariableMtrrCount == VariableMtrrCapacity) {
1588 return RETURN_OUT_OF_RESOURCES;
1589 }
1590 VariableMtrr[Index].BaseAddress = BaseAddress;
1591 VariableMtrr[Index].Length = Length;
1592 VariableMtrr[Index].Type = Type;
1593 VariableMtrr[Index].Valid = TRUE;
1594 VariableMtrr[Index].Used = TRUE;
1595 (*VariableMtrrCount)++;
1596 }
1597 return RETURN_SUCCESS;
1598 }
1599 }
1600
1601 /**
1602 Allocate one or more variable MTRR to cover the range identified by
1603 BaseAddress and Length.
1604
1605 @param Ranges Memory range array holding the memory type
1606 settings for all memory address.
1607 @param RangeCount Count of memory ranges.
1608 @param VariableMtrr Variable MTRR array.
1609 @param VariableMtrrCapacity Capacity of variable MTRR array.
1610 @param VariableMtrrCount Count of variable MTRR.
1611 @param BaseAddress Base address of the memory range.
1612 @param Length Length of the memory range.
1613 @param Type MTRR type of the memory range.
1614 @param Alignment0 Alignment of 0.
1615
1616 @retval RETURN_SUCCESS Variable MTRRs are allocated successfully.
1617 @retval RETURN_OUT_OF_RESOURCES Count of variable MTRRs exceeds capacity.
1618 **/
1619 RETURN_STATUS
1620 MtrrLibSetMemoryAttributeInVariableMtrr (
1621 IN CONST MEMORY_RANGE *Ranges,
1622 IN UINT32 RangeCount,
1623 IN OUT VARIABLE_MTRR *VariableMtrr,
1624 IN UINT32 VariableMtrrCapacity,
1625 IN OUT UINT32 *VariableMtrrCount,
1626 IN UINT64 BaseAddress,
1627 IN UINT64 Length,
1628 IN MTRR_MEMORY_CACHE_TYPE Type,
1629 IN UINT64 Alignment0
1630 )
1631 {
1632 UINT64 Alignment;
1633 UINT32 MtrrNumber;
1634 UINT32 SubtractiveLeft;
1635 UINT32 SubtractiveRight;
1636 BOOLEAN UseLeastAlignment;
1637
1638 Alignment = 0;
1639
1640 MtrrNumber = MtrrLibGetMtrrNumber (Ranges, RangeCount, VariableMtrr, *VariableMtrrCount,
1641 BaseAddress, Length, Type, Alignment0, &SubtractiveLeft, &SubtractiveRight);
1642
1643 if (MtrrNumber + *VariableMtrrCount > VariableMtrrCapacity) {
1644 return RETURN_OUT_OF_RESOURCES;
1645 }
1646
1647 while (SubtractiveLeft-- != 0) {
1648 Alignment = MtrrLibBiggestAlignment (BaseAddress, Alignment0);
1649 ASSERT (Alignment <= Length);
1650
1651 MtrrLibAddVariableMtrr (Ranges, RangeCount, VariableMtrr, VariableMtrrCapacity, VariableMtrrCount,
1652 BaseAddress - Alignment, Alignment, CacheInvalid, Alignment0);
1653 BaseAddress -= Alignment;
1654 Length += Alignment;
1655 }
1656
1657 while (Length != 0) {
1658 Alignment = MtrrLibBiggestAlignment (BaseAddress, Alignment0);
1659 if (Alignment > Length) {
1660 break;
1661 }
1662 MtrrLibAddVariableMtrr (NULL, 0, VariableMtrr, VariableMtrrCapacity, VariableMtrrCount,
1663 BaseAddress, Alignment, Type, Alignment0);
1664 BaseAddress += Alignment;
1665 Length -= Alignment;
1666 }
1667
1668 while (SubtractiveRight-- != 0) {
1669 Alignment = MtrrLibBiggestAlignment (BaseAddress + Length, Alignment0);
1670 MtrrLibAddVariableMtrr (Ranges, RangeCount, VariableMtrr, VariableMtrrCapacity, VariableMtrrCount,
1671 BaseAddress + Length, Alignment, CacheInvalid, Alignment0);
1672 Length += Alignment;
1673 }
1674
1675 UseLeastAlignment = TRUE;
1676 while (Length != 0) {
1677 if (UseLeastAlignment) {
1678 Alignment = MtrrLibBiggestAlignment (BaseAddress, Alignment0);
1679 if (Alignment > Length) {
1680 UseLeastAlignment = FALSE;
1681 }
1682 }
1683
1684 if (!UseLeastAlignment) {
1685 Alignment = GetPowerOfTwo64 (Length);
1686 }
1687
1688 MtrrLibAddVariableMtrr (NULL, 0, VariableMtrr, VariableMtrrCapacity, VariableMtrrCount,
1689 BaseAddress, Alignment, Type, Alignment0);
1690 BaseAddress += Alignment;
1691 Length -= Alignment;
1692 }
1693 return RETURN_SUCCESS;
1694 }
1695
1696 /**
1697 Return an array of memory ranges holding memory type settings for all memory
1698 address.
1699
1700 @param DefaultType The default memory type.
1701 @param TotalLength The total length of the memory.
1702 @param VariableMtrr The variable MTRR array.
1703 @param VariableMtrrCount The count of variable MTRRs.
1704 @param Ranges Return the memory range array holding memory type
1705 settings for all memory address.
1706 @param RangeCapacity The capacity of memory range array.
1707 @param RangeCount Return the count of memory range.
1708
1709 @retval RETURN_SUCCESS The memory range array is returned successfully.
1710 @retval RETURN_OUT_OF_RESOURCES The count of memory ranges exceeds capacity.
1711 **/
1712 RETURN_STATUS
1713 MtrrLibGetMemoryTypes (
1714 IN MTRR_MEMORY_CACHE_TYPE DefaultType,
1715 IN UINT64 TotalLength,
1716 IN CONST VARIABLE_MTRR *VariableMtrr,
1717 IN UINT32 VariableMtrrCount,
1718 OUT MEMORY_RANGE *Ranges,
1719 IN UINT32 RangeCapacity,
1720 OUT UINT32 *RangeCount
1721 )
1722 {
1723 RETURN_STATUS Status;
1724 UINTN Index;
1725
1726 //
1727 // WT > WB
1728 // UC > *
1729 // UC > * (except WB, UC) > WB
1730 //
1731
1732 //
1733 // 0. Set whole range as DefaultType
1734 //
1735 *RangeCount = 1;
1736 Ranges[0].BaseAddress = 0;
1737 Ranges[0].Length = TotalLength;
1738 Ranges[0].Type = DefaultType;
1739
1740 //
1741 // 1. Set WB
1742 //
1743 for (Index = 0; Index < VariableMtrrCount; Index++) {
1744 if (VariableMtrr[Index].Valid && VariableMtrr[Index].Type == CacheWriteBack) {
1745 Status = MtrrLibSetMemoryType (
1746 Ranges, RangeCapacity, RangeCount,
1747 VariableMtrr[Index].BaseAddress, VariableMtrr[Index].Length, (MTRR_MEMORY_CACHE_TYPE) VariableMtrr[Index].Type
1748 );
1749 if (RETURN_ERROR (Status)) {
1750 return Status;
1751 }
1752 }
1753 }
1754
1755 //
1756 // 2. Set other types than WB or UC
1757 //
1758 for (Index = 0; Index < VariableMtrrCount; Index++) {
1759 if (VariableMtrr[Index].Valid && VariableMtrr[Index].Type != CacheWriteBack && VariableMtrr[Index].Type != CacheUncacheable) {
1760 Status = MtrrLibSetMemoryType (
1761 Ranges, RangeCapacity, RangeCount,
1762 VariableMtrr[Index].BaseAddress, VariableMtrr[Index].Length, (MTRR_MEMORY_CACHE_TYPE) VariableMtrr[Index].Type
1763 );
1764 if (RETURN_ERROR (Status)) {
1765 return Status;
1766 }
1767 }
1768 }
1769
1770 //
1771 // 3. Set UC
1772 //
1773 for (Index = 0; Index < VariableMtrrCount; Index++) {
1774 if (VariableMtrr[Index].Valid && VariableMtrr[Index].Type == CacheUncacheable) {
1775 Status = MtrrLibSetMemoryType (
1776 Ranges, RangeCapacity, RangeCount,
1777 VariableMtrr[Index].BaseAddress, VariableMtrr[Index].Length, (MTRR_MEMORY_CACHE_TYPE) VariableMtrr[Index].Type
1778 );
1779 if (RETURN_ERROR (Status)) {
1780 return Status;
1781 }
1782 }
1783 }
1784 return RETURN_SUCCESS;
1785 }
1786
1787 /**
1788 Worker function attempts to set the attributes for a memory range.
1789
1790 If MtrrSetting is not NULL, set the attributes into the input MTRR
1791 settings buffer.
1792 If MtrrSetting is NULL, set the attributes into MTRRs registers.
1793
1794 @param[in, out] MtrrSetting A buffer holding all MTRRs content.
1795 @param[in] BaseAddress The physical address that is the start
1796 address of a memory range.
1797 @param[in] Length The size in bytes of the memory range.
1798 @param[in] Type The MTRR type to set for the memory range.
1799
1800 @retval RETURN_SUCCESS The attributes were set for the memory
1801 range.
1802 @retval RETURN_INVALID_PARAMETER Length is zero.
1803 @retval RETURN_UNSUPPORTED The processor does not support one or
1804 more bytes of the memory resource range
1805 specified by BaseAddress and Length.
1806 @retval RETURN_UNSUPPORTED The MTRR type is not support for the
1807 memory resource range specified
1808 by BaseAddress and Length.
1809 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to
1810 modify the attributes of the memory
1811 resource range.
1812
1813 **/
1814 RETURN_STATUS
1815 MtrrSetMemoryAttributeWorker (
1816 IN OUT MTRR_SETTINGS *MtrrSetting,
1817 IN PHYSICAL_ADDRESS BaseAddress,
1818 IN UINT64 Length,
1819 IN MTRR_MEMORY_CACHE_TYPE Type
1820 )
1821 {
1822 RETURN_STATUS Status;
1823 UINT32 Index;
1824 UINT32 WorkingIndex;
1825 //
1826 // N variable MTRRs can maximumly separate (2N + 1) Ranges, plus 1 range for [0, 1M).
1827 //
1828 MEMORY_RANGE Ranges[MTRR_NUMBER_OF_VARIABLE_MTRR * 2 + 2];
1829 UINT32 RangeCount;
1830 UINT64 MtrrValidBitsMask;
1831 UINT64 MtrrValidAddressMask;
1832 UINT64 Alignment0;
1833 MTRR_CONTEXT MtrrContext;
1834 BOOLEAN MtrrContextValid;
1835
1836 MTRR_MEMORY_CACHE_TYPE DefaultType;
1837
1838 UINT32 MsrIndex;
1839 UINT64 ClearMask;
1840 UINT64 OrMask;
1841 UINT64 NewValue;
1842 BOOLEAN FixedSettingsValid[MTRR_NUMBER_OF_FIXED_MTRR];
1843 BOOLEAN FixedSettingsModified[MTRR_NUMBER_OF_FIXED_MTRR];
1844 MTRR_FIXED_SETTINGS WorkingFixedSettings;
1845
1846 UINT32 FirmwareVariableMtrrCount;
1847 MTRR_VARIABLE_SETTINGS *VariableSettings;
1848 MTRR_VARIABLE_SETTINGS OriginalVariableSettings;
1849 UINT32 OriginalVariableMtrrCount;
1850 VARIABLE_MTRR OriginalVariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];
1851 UINT32 WorkingVariableMtrrCount;
1852 VARIABLE_MTRR WorkingVariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];
1853 BOOLEAN VariableSettingModified[MTRR_NUMBER_OF_VARIABLE_MTRR];
1854 UINTN FreeVariableMtrrCount;
1855
1856 if (Length == 0) {
1857 return RETURN_INVALID_PARAMETER;
1858 }
1859
1860 MtrrLibInitializeMtrrMask (&MtrrValidBitsMask, &MtrrValidAddressMask);
1861 if (((BaseAddress & ~MtrrValidAddressMask) != 0) || (Length & ~MtrrValidAddressMask) != 0) {
1862 return RETURN_UNSUPPORTED;
1863 }
1864 OriginalVariableMtrrCount = 0;
1865 VariableSettings = NULL;
1866
1867 ZeroMem (&WorkingFixedSettings, sizeof (WorkingFixedSettings));
1868 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
1869 FixedSettingsValid[Index] = FALSE;
1870 FixedSettingsModified[Index] = FALSE;
1871 }
1872
1873 //
1874 // Check if Fixed MTRR
1875 //
1876 if (BaseAddress < BASE_1MB) {
1877 MsrIndex = (UINT32)-1;
1878 while ((BaseAddress < BASE_1MB) && (Length != 0)) {
1879 Status = MtrrLibProgramFixedMtrr (Type, &BaseAddress, &Length, &MsrIndex, &ClearMask, &OrMask);
1880 if (RETURN_ERROR (Status)) {
1881 return Status;
1882 }
1883 if (MtrrSetting != NULL) {
1884 MtrrSetting->Fixed.Mtrr[MsrIndex] = (MtrrSetting->Fixed.Mtrr[MsrIndex] & ~ClearMask) | OrMask;
1885 ((MSR_IA32_MTRR_DEF_TYPE_REGISTER *) &MtrrSetting->MtrrDefType)->Bits.FE = 1;
1886 } else {
1887 if (!FixedSettingsValid[MsrIndex]) {
1888 WorkingFixedSettings.Mtrr[MsrIndex] = AsmReadMsr64 (mMtrrLibFixedMtrrTable[MsrIndex].Msr);
1889 FixedSettingsValid[MsrIndex] = TRUE;
1890 }
1891 NewValue = (WorkingFixedSettings.Mtrr[MsrIndex] & ~ClearMask) | OrMask;
1892 if (WorkingFixedSettings.Mtrr[MsrIndex] != NewValue) {
1893 WorkingFixedSettings.Mtrr[MsrIndex] = NewValue;
1894 FixedSettingsModified[MsrIndex] = TRUE;
1895 }
1896 }
1897 }
1898
1899 if (Length == 0) {
1900 //
1901 // A Length of 0 can only make sense for fixed MTTR ranges.
1902 // Since we just handled the fixed MTRRs, we can skip the
1903 // variable MTRR section.
1904 //
1905 goto Done;
1906 }
1907 }
1908
1909 //
1910 // Read the default MTRR type
1911 //
1912 DefaultType = MtrrGetDefaultMemoryTypeWorker (MtrrSetting);
1913
1914 //
1915 // Read all variable MTRRs and convert to Ranges.
1916 //
1917 OriginalVariableMtrrCount = GetVariableMtrrCountWorker ();
1918 if (MtrrSetting == NULL) {
1919 ZeroMem (&OriginalVariableSettings, sizeof (OriginalVariableSettings));
1920 MtrrGetVariableMtrrWorker (NULL, OriginalVariableMtrrCount, &OriginalVariableSettings);
1921 VariableSettings = &OriginalVariableSettings;
1922 } else {
1923 VariableSettings = &MtrrSetting->Variables;
1924 }
1925 MtrrGetMemoryAttributeInVariableMtrrWorker (VariableSettings, OriginalVariableMtrrCount, MtrrValidBitsMask, MtrrValidAddressMask, OriginalVariableMtrr);
1926
1927 Status = MtrrLibGetMemoryTypes (
1928 DefaultType, MtrrValidBitsMask + 1, OriginalVariableMtrr, OriginalVariableMtrrCount,
1929 Ranges, 2 * OriginalVariableMtrrCount + 1, &RangeCount
1930 );
1931 ASSERT (Status == RETURN_SUCCESS);
1932
1933 FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCountWorker ();
1934 ASSERT (RangeCount <= 2 * FirmwareVariableMtrrCount + 1);
1935
1936 //
1937 // Force [0, 1M) to UC, so that it doesn't impact left subtraction algorithm.
1938 //
1939 Status = MtrrLibSetMemoryType (Ranges, 2 * FirmwareVariableMtrrCount + 2, &RangeCount, 0, SIZE_1MB, CacheUncacheable);
1940 ASSERT (Status == RETURN_SUCCESS);
1941 //
1942 // Apply Type to [BaseAddress, BaseAddress + Length)
1943 //
1944 Status = MtrrLibSetMemoryType (Ranges, 2 * FirmwareVariableMtrrCount + 2, &RangeCount, BaseAddress, Length, Type);
1945 if (RETURN_ERROR (Status)) {
1946 return Status;
1947 }
1948
1949 Alignment0 = LShiftU64 (1, (UINTN) HighBitSet64 (MtrrValidBitsMask));
1950 WorkingVariableMtrrCount = 0;
1951 ZeroMem (&WorkingVariableMtrr, sizeof (WorkingVariableMtrr));
1952 for (Index = 0; Index < RangeCount; Index++) {
1953 if (Ranges[Index].Type != DefaultType) {
1954 //
1955 // Maximum allowed MTRR count is (FirmwareVariableMtrrCount + 1)
1956 // Because potentially the range [0, 1MB) is not merged, but can be ignored because fixed MTRR covers that
1957 //
1958 Status = MtrrLibSetMemoryAttributeInVariableMtrr (
1959 Ranges, RangeCount,
1960 WorkingVariableMtrr, FirmwareVariableMtrrCount + 1, &WorkingVariableMtrrCount,
1961 Ranges[Index].BaseAddress, Ranges[Index].Length,
1962 Ranges[Index].Type, Alignment0
1963 );
1964 if (RETURN_ERROR (Status)) {
1965 return Status;
1966 }
1967 }
1968 }
1969
1970 //
1971 // Remove the [0, 1MB) MTRR if it still exists (not merged with other range)
1972 //
1973 if (WorkingVariableMtrr[0].BaseAddress == 0 && WorkingVariableMtrr[0].Length == SIZE_1MB) {
1974 ASSERT (WorkingVariableMtrr[0].Type == CacheUncacheable);
1975 WorkingVariableMtrrCount--;
1976 CopyMem (&WorkingVariableMtrr[0], &WorkingVariableMtrr[1], WorkingVariableMtrrCount * sizeof (VARIABLE_MTRR));
1977 }
1978
1979 if (WorkingVariableMtrrCount > FirmwareVariableMtrrCount) {
1980 return RETURN_OUT_OF_RESOURCES;
1981 }
1982
1983 for (Index = 0; Index < OriginalVariableMtrrCount; Index++) {
1984 VariableSettingModified[Index] = FALSE;
1985
1986 if (!OriginalVariableMtrr[Index].Valid) {
1987 continue;
1988 }
1989 for (WorkingIndex = 0; WorkingIndex < WorkingVariableMtrrCount; WorkingIndex++) {
1990 if (OriginalVariableMtrr[Index].BaseAddress == WorkingVariableMtrr[WorkingIndex].BaseAddress &&
1991 OriginalVariableMtrr[Index].Length == WorkingVariableMtrr[WorkingIndex].Length &&
1992 OriginalVariableMtrr[Index].Type == WorkingVariableMtrr[WorkingIndex].Type) {
1993 break;
1994 }
1995 }
1996
1997 if (WorkingIndex == WorkingVariableMtrrCount) {
1998 //
1999 // Remove the one from OriginalVariableMtrr which is not in WorkingVariableMtrr
2000 //
2001 OriginalVariableMtrr[Index].Valid = FALSE;
2002 VariableSettingModified[Index] = TRUE;
2003 } else {
2004 //
2005 // Remove the one from WorkingVariableMtrr which is also in OriginalVariableMtrr
2006 //
2007 WorkingVariableMtrr[WorkingIndex].Valid = FALSE;
2008 }
2009 //
2010 // The above two operations cause that valid MTRR only exists in either OriginalVariableMtrr or WorkingVariableMtrr.
2011 //
2012 }
2013
2014 //
2015 // Merge remaining MTRRs from WorkingVariableMtrr to OriginalVariableMtrr
2016 //
2017 for (FreeVariableMtrrCount = 0, WorkingIndex = 0, Index = 0; Index < OriginalVariableMtrrCount; Index++) {
2018 if (!OriginalVariableMtrr[Index].Valid) {
2019 for (; WorkingIndex < WorkingVariableMtrrCount; WorkingIndex++) {
2020 if (WorkingVariableMtrr[WorkingIndex].Valid) {
2021 break;
2022 }
2023 }
2024 if (WorkingIndex == WorkingVariableMtrrCount) {
2025 FreeVariableMtrrCount++;
2026 } else {
2027 CopyMem (&OriginalVariableMtrr[Index], &WorkingVariableMtrr[WorkingIndex], sizeof (VARIABLE_MTRR));
2028 VariableSettingModified[Index] = TRUE;
2029 WorkingIndex++;
2030 }
2031 }
2032 }
2033 ASSERT (OriginalVariableMtrrCount - FreeVariableMtrrCount <= FirmwareVariableMtrrCount);
2034
2035 //
2036 // Move MTRRs after the FirmwareVariableMtrrCount position to beginning
2037 //
2038 if (FirmwareVariableMtrrCount < OriginalVariableMtrrCount) {
2039 WorkingIndex = FirmwareVariableMtrrCount;
2040 for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) {
2041 if (!OriginalVariableMtrr[Index].Valid) {
2042 //
2043 // Found an empty MTRR in WorkingIndex position
2044 //
2045 for (; WorkingIndex < OriginalVariableMtrrCount; WorkingIndex++) {
2046 if (OriginalVariableMtrr[WorkingIndex].Valid) {
2047 break;
2048 }
2049 }
2050
2051 if (WorkingIndex != OriginalVariableMtrrCount) {
2052 CopyMem (&OriginalVariableMtrr[Index], &OriginalVariableMtrr[WorkingIndex], sizeof (VARIABLE_MTRR));
2053 VariableSettingModified[Index] = TRUE;
2054 VariableSettingModified[WorkingIndex] = TRUE;
2055 OriginalVariableMtrr[WorkingIndex].Valid = FALSE;
2056 }
2057 }
2058 }
2059 }
2060
2061 //
2062 // Convert OriginalVariableMtrr to VariableSettings
2063 // NOTE: MTRR from FirmwareVariableMtrr to OriginalVariableMtrr need to update as well.
2064 //
2065 for (Index = 0; Index < OriginalVariableMtrrCount; Index++) {
2066 if (VariableSettingModified[Index]) {
2067 if (OriginalVariableMtrr[Index].Valid) {
2068 VariableSettings->Mtrr[Index].Base = (OriginalVariableMtrr[Index].BaseAddress & MtrrValidAddressMask) | (UINT8) OriginalVariableMtrr[Index].Type;
2069 VariableSettings->Mtrr[Index].Mask = ((~(OriginalVariableMtrr[Index].Length - 1)) & MtrrValidAddressMask) | BIT11;
2070 } else {
2071 VariableSettings->Mtrr[Index].Base = 0;
2072 VariableSettings->Mtrr[Index].Mask = 0;
2073 }
2074 }
2075 }
2076
2077 Done:
2078 if (MtrrSetting != NULL) {
2079 ((MSR_IA32_MTRR_DEF_TYPE_REGISTER *) &MtrrSetting->MtrrDefType)->Bits.E = 1;
2080 return RETURN_SUCCESS;
2081 }
2082
2083 MtrrContextValid = FALSE;
2084 //
2085 // Write fixed MTRRs that have been modified
2086 //
2087 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
2088 if (FixedSettingsModified[Index]) {
2089 if (!MtrrContextValid) {
2090 MtrrLibPreMtrrChange (&MtrrContext);
2091 MtrrContextValid = TRUE;
2092 }
2093 AsmWriteMsr64 (
2094 mMtrrLibFixedMtrrTable[Index].Msr,
2095 WorkingFixedSettings.Mtrr[Index]
2096 );
2097 }
2098 }
2099
2100 //
2101 // Write variable MTRRs
2102 // When only fixed MTRRs were changed, below loop doesn't run
2103 // because OriginalVariableMtrrCount equals to 0.
2104 //
2105 for (Index = 0; Index < OriginalVariableMtrrCount; Index++) {
2106 if (VariableSettingModified[Index]) {
2107 if (!MtrrContextValid) {
2108 MtrrLibPreMtrrChange (&MtrrContext);
2109 MtrrContextValid = TRUE;
2110 }
2111 AsmWriteMsr64 (
2112 MSR_IA32_MTRR_PHYSBASE0 + (Index << 1),
2113 VariableSettings->Mtrr[Index].Base
2114 );
2115 AsmWriteMsr64 (
2116 MSR_IA32_MTRR_PHYSMASK0 + (Index << 1),
2117 VariableSettings->Mtrr[Index].Mask
2118 );
2119 }
2120 }
2121 if (MtrrContextValid) {
2122 MtrrLibPostMtrrChange (&MtrrContext);
2123 }
2124
2125 return RETURN_SUCCESS;
2126 }
2127
2128 /**
2129 This function attempts to set the attributes for a memory range.
2130
2131 @param[in] BaseAddress The physical address that is the start
2132 address of a memory range.
2133 @param[in] Length The size in bytes of the memory range.
2134 @param[in] Attributes The bit mask of attributes to set for the
2135 memory range.
2136
2137 @retval RETURN_SUCCESS The attributes were set for the memory
2138 range.
2139 @retval RETURN_INVALID_PARAMETER Length is zero.
2140 @retval RETURN_UNSUPPORTED The processor does not support one or
2141 more bytes of the memory resource range
2142 specified by BaseAddress and Length.
2143 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support
2144 for the memory resource range specified
2145 by BaseAddress and Length.
2146 @retval RETURN_ACCESS_DENIED The attributes for the memory resource
2147 range specified by BaseAddress and Length
2148 cannot be modified.
2149 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to
2150 modify the attributes of the memory
2151 resource range.
2152
2153 **/
2154 RETURN_STATUS
2155 EFIAPI
2156 MtrrSetMemoryAttribute (
2157 IN PHYSICAL_ADDRESS BaseAddress,
2158 IN UINT64 Length,
2159 IN MTRR_MEMORY_CACHE_TYPE Attribute
2160 )
2161 {
2162 RETURN_STATUS Status;
2163
2164 if (!IsMtrrSupported ()) {
2165 return RETURN_UNSUPPORTED;
2166 }
2167
2168 Status = MtrrSetMemoryAttributeWorker (NULL, BaseAddress, Length, Attribute);
2169 DEBUG ((DEBUG_CACHE, "MtrrSetMemoryAttribute() %a: [%016lx, %016lx) - %r\n",
2170 mMtrrMemoryCacheTypeShortName[Attribute], BaseAddress, BaseAddress + Length, Status));
2171
2172 if (!RETURN_ERROR (Status)) {
2173 MtrrDebugPrintAllMtrrsWorker (NULL);
2174 }
2175 return Status;
2176 }
2177
2178 /**
2179 This function attempts to set the attributes into MTRR setting buffer for a memory range.
2180
2181 @param[in, out] MtrrSetting MTRR setting buffer to be set.
2182 @param[in] BaseAddress The physical address that is the start address
2183 of a memory range.
2184 @param[in] Length The size in bytes of the memory range.
2185 @param[in] Attribute The bit mask of attributes to set for the
2186 memory range.
2187
2188 @retval RETURN_SUCCESS The attributes were set for the memory range.
2189 @retval RETURN_INVALID_PARAMETER Length is zero.
2190 @retval RETURN_UNSUPPORTED The processor does not support one or more bytes of the
2191 memory resource range specified by BaseAddress and Length.
2192 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support for the memory resource
2193 range specified by BaseAddress and Length.
2194 @retval RETURN_ACCESS_DENIED The attributes for the memory resource range specified by
2195 BaseAddress and Length cannot be modified.
2196 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
2197 the memory resource range.
2198
2199 **/
2200 RETURN_STATUS
2201 EFIAPI
2202 MtrrSetMemoryAttributeInMtrrSettings (
2203 IN OUT MTRR_SETTINGS *MtrrSetting,
2204 IN PHYSICAL_ADDRESS BaseAddress,
2205 IN UINT64 Length,
2206 IN MTRR_MEMORY_CACHE_TYPE Attribute
2207 )
2208 {
2209 RETURN_STATUS Status;
2210 Status = MtrrSetMemoryAttributeWorker (MtrrSetting, BaseAddress, Length, Attribute);
2211 DEBUG((DEBUG_CACHE, "MtrrSetMemoryAttributeMtrrSettings(%p) %a: [%016lx, %016lx) - %r\n",
2212 MtrrSetting, mMtrrMemoryCacheTypeShortName[Attribute], BaseAddress, BaseAddress + Length, Status));
2213
2214 if (!RETURN_ERROR (Status)) {
2215 MtrrDebugPrintAllMtrrsWorker (MtrrSetting);
2216 }
2217
2218 return Status;
2219 }
2220
2221 /**
2222 Worker function setting variable MTRRs
2223
2224 @param[in] VariableSettings A buffer to hold variable MTRRs content.
2225
2226 **/
2227 VOID
2228 MtrrSetVariableMtrrWorker (
2229 IN MTRR_VARIABLE_SETTINGS *VariableSettings
2230 )
2231 {
2232 UINT32 Index;
2233 UINT32 VariableMtrrCount;
2234
2235 VariableMtrrCount = GetVariableMtrrCountWorker ();
2236 ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);
2237
2238 for (Index = 0; Index < VariableMtrrCount; Index++) {
2239 AsmWriteMsr64 (
2240 MSR_IA32_MTRR_PHYSBASE0 + (Index << 1),
2241 VariableSettings->Mtrr[Index].Base
2242 );
2243 AsmWriteMsr64 (
2244 MSR_IA32_MTRR_PHYSMASK0 + (Index << 1),
2245 VariableSettings->Mtrr[Index].Mask
2246 );
2247 }
2248 }
2249
2250
2251 /**
2252 This function sets variable MTRRs
2253
2254 @param[in] VariableSettings A buffer to hold variable MTRRs content.
2255
2256 @return The pointer of VariableSettings
2257
2258 **/
2259 MTRR_VARIABLE_SETTINGS*
2260 EFIAPI
2261 MtrrSetVariableMtrr (
2262 IN MTRR_VARIABLE_SETTINGS *VariableSettings
2263 )
2264 {
2265 MTRR_CONTEXT MtrrContext;
2266
2267 if (!IsMtrrSupported ()) {
2268 return VariableSettings;
2269 }
2270
2271 MtrrLibPreMtrrChange (&MtrrContext);
2272 MtrrSetVariableMtrrWorker (VariableSettings);
2273 MtrrLibPostMtrrChange (&MtrrContext);
2274 MtrrDebugPrintAllMtrrs ();
2275
2276 return VariableSettings;
2277 }
2278
2279 /**
2280 Worker function setting fixed MTRRs
2281
2282 @param[in] FixedSettings A buffer to hold fixed MTRRs content.
2283
2284 **/
2285 VOID
2286 MtrrSetFixedMtrrWorker (
2287 IN MTRR_FIXED_SETTINGS *FixedSettings
2288 )
2289 {
2290 UINT32 Index;
2291
2292 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
2293 AsmWriteMsr64 (
2294 mMtrrLibFixedMtrrTable[Index].Msr,
2295 FixedSettings->Mtrr[Index]
2296 );
2297 }
2298 }
2299
2300
2301 /**
2302 This function sets fixed MTRRs
2303
2304 @param[in] FixedSettings A buffer to hold fixed MTRRs content.
2305
2306 @retval The pointer of FixedSettings
2307
2308 **/
2309 MTRR_FIXED_SETTINGS*
2310 EFIAPI
2311 MtrrSetFixedMtrr (
2312 IN MTRR_FIXED_SETTINGS *FixedSettings
2313 )
2314 {
2315 MTRR_CONTEXT MtrrContext;
2316
2317 if (!IsMtrrSupported ()) {
2318 return FixedSettings;
2319 }
2320
2321 MtrrLibPreMtrrChange (&MtrrContext);
2322 MtrrSetFixedMtrrWorker (FixedSettings);
2323 MtrrLibPostMtrrChange (&MtrrContext);
2324 MtrrDebugPrintAllMtrrs ();
2325
2326 return FixedSettings;
2327 }
2328
2329
2330 /**
2331 This function gets the content in all MTRRs (variable and fixed)
2332
2333 @param[out] MtrrSetting A buffer to hold all MTRRs content.
2334
2335 @retval the pointer of MtrrSetting
2336
2337 **/
2338 MTRR_SETTINGS *
2339 EFIAPI
2340 MtrrGetAllMtrrs (
2341 OUT MTRR_SETTINGS *MtrrSetting
2342 )
2343 {
2344 if (!IsMtrrSupported ()) {
2345 return MtrrSetting;
2346 }
2347
2348 //
2349 // Get fixed MTRRs
2350 //
2351 MtrrGetFixedMtrrWorker (&MtrrSetting->Fixed);
2352
2353 //
2354 // Get variable MTRRs
2355 //
2356 MtrrGetVariableMtrrWorker (
2357 NULL,
2358 GetVariableMtrrCountWorker (),
2359 &MtrrSetting->Variables
2360 );
2361
2362 //
2363 // Get MTRR_DEF_TYPE value
2364 //
2365 MtrrSetting->MtrrDefType = AsmReadMsr64 (MSR_IA32_MTRR_DEF_TYPE);
2366
2367 return MtrrSetting;
2368 }
2369
2370
2371 /**
2372 This function sets all MTRRs (variable and fixed)
2373
2374 @param[in] MtrrSetting A buffer holding all MTRRs content.
2375
2376 @retval The pointer of MtrrSetting
2377
2378 **/
2379 MTRR_SETTINGS *
2380 EFIAPI
2381 MtrrSetAllMtrrs (
2382 IN MTRR_SETTINGS *MtrrSetting
2383 )
2384 {
2385 MTRR_CONTEXT MtrrContext;
2386
2387 if (!IsMtrrSupported ()) {
2388 return MtrrSetting;
2389 }
2390
2391 MtrrLibPreMtrrChange (&MtrrContext);
2392
2393 //
2394 // Set fixed MTRRs
2395 //
2396 MtrrSetFixedMtrrWorker (&MtrrSetting->Fixed);
2397
2398 //
2399 // Set variable MTRRs
2400 //
2401 MtrrSetVariableMtrrWorker (&MtrrSetting->Variables);
2402
2403 //
2404 // Set MTRR_DEF_TYPE value
2405 //
2406 AsmWriteMsr64 (MSR_IA32_MTRR_DEF_TYPE, MtrrSetting->MtrrDefType);
2407
2408 MtrrLibPostMtrrChangeEnableCache (&MtrrContext);
2409
2410 return MtrrSetting;
2411 }
2412
2413
2414 /**
2415 Checks if MTRR is supported.
2416
2417 @retval TRUE MTRR is supported.
2418 @retval FALSE MTRR is not supported.
2419
2420 **/
2421 BOOLEAN
2422 EFIAPI
2423 IsMtrrSupported (
2424 VOID
2425 )
2426 {
2427 CPUID_VERSION_INFO_EDX Edx;
2428 MSR_IA32_MTRRCAP_REGISTER MtrrCap;
2429
2430 //
2431 // Check CPUID(1).EDX[12] for MTRR capability
2432 //
2433 AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &Edx.Uint32);
2434 if (Edx.Bits.MTRR == 0) {
2435 return FALSE;
2436 }
2437
2438 //
2439 // Check number of variable MTRRs and fixed MTRRs existence.
2440 // If number of variable MTRRs is zero, or fixed MTRRs do not
2441 // exist, return false.
2442 //
2443 MtrrCap.Uint64 = AsmReadMsr64 (MSR_IA32_MTRRCAP);
2444 if ((MtrrCap.Bits.VCNT == 0) || (MtrrCap.Bits.FIX == 0)) {
2445 return FALSE;
2446 }
2447 return TRUE;
2448 }
2449