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