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