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