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