]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/Library/MtrrLib/MtrrLib.c
UefiCpuPkg/MtrrLib: Make use of worker functions to get MTRRs count
[mirror_edk2.git] / UefiCpuPkg / Library / MtrrLib / MtrrLib.c
1 /** @file
2 MTRR setting library
3
4 Copyright (c) 2008 - 2015, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include <Base.h>
16
17 #include <Library/MtrrLib.h>
18 #include <Library/BaseLib.h>
19 #include <Library/CpuLib.h>
20 #include <Library/BaseMemoryLib.h>
21 #include <Library/DebugLib.h>
22
23 //
24 // Context to save and restore when MTRRs are programmed
25 //
26 typedef struct {
27 UINTN Cr4;
28 BOOLEAN InterruptState;
29 } MTRR_CONTEXT;
30
31 //
32 // This table defines the offset, base and length of the fixed MTRRs
33 //
34 CONST FIXED_MTRR mMtrrLibFixedMtrrTable[] = {
35 {
36 MTRR_LIB_IA32_MTRR_FIX64K_00000,
37 0,
38 SIZE_64KB
39 },
40 {
41 MTRR_LIB_IA32_MTRR_FIX16K_80000,
42 0x80000,
43 SIZE_16KB
44 },
45 {
46 MTRR_LIB_IA32_MTRR_FIX16K_A0000,
47 0xA0000,
48 SIZE_16KB
49 },
50 {
51 MTRR_LIB_IA32_MTRR_FIX4K_C0000,
52 0xC0000,
53 SIZE_4KB
54 },
55 {
56 MTRR_LIB_IA32_MTRR_FIX4K_C8000,
57 0xC8000,
58 SIZE_4KB
59 },
60 {
61 MTRR_LIB_IA32_MTRR_FIX4K_D0000,
62 0xD0000,
63 SIZE_4KB
64 },
65 {
66 MTRR_LIB_IA32_MTRR_FIX4K_D8000,
67 0xD8000,
68 SIZE_4KB
69 },
70 {
71 MTRR_LIB_IA32_MTRR_FIX4K_E0000,
72 0xE0000,
73 SIZE_4KB
74 },
75 {
76 MTRR_LIB_IA32_MTRR_FIX4K_E8000,
77 0xE8000,
78 SIZE_4KB
79 },
80 {
81 MTRR_LIB_IA32_MTRR_FIX4K_F0000,
82 0xF0000,
83 SIZE_4KB
84 },
85 {
86 MTRR_LIB_IA32_MTRR_FIX4K_F8000,
87 0xF8000,
88 SIZE_4KB
89 }
90 };
91
92 //
93 // Lookup table used to print MTRRs
94 //
95 GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 *mMtrrMemoryCacheTypeShortName[] = {
96 "UC", // CacheUncacheable
97 "WC", // CacheWriteCombining
98 "R*", // Invalid
99 "R*", // Invalid
100 "WT", // CacheWriteThrough
101 "WP", // CacheWriteProtected
102 "WB", // CacheWriteBack
103 "R*" // Invalid
104 };
105
106 /**
107 Worker function returns the variable MTRR count for the CPU.
108
109 @return Variable MTRR count
110
111 **/
112 UINT32
113 GetVariableMtrrCountWorker (
114 VOID
115 )
116 {
117 UINT32 VariableMtrrCount;
118
119 VariableMtrrCount = (UINT32)(AsmReadMsr64 (MTRR_LIB_IA32_MTRR_CAP) & MTRR_LIB_IA32_MTRR_CAP_VCNT_MASK);
120 ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);
121 return VariableMtrrCount;
122 }
123
124 /**
125 Returns the variable MTRR count for the CPU.
126
127 @return Variable MTRR count
128
129 **/
130 UINT32
131 EFIAPI
132 GetVariableMtrrCount (
133 VOID
134 )
135 {
136 if (!IsMtrrSupported ()) {
137 return 0;
138 }
139 return GetVariableMtrrCountWorker ();
140 }
141
142 /**
143 Worker function returns the firmware usable variable MTRR count for the CPU.
144
145 @return Firmware usable variable MTRR count
146
147 **/
148 UINT32
149 GetFirmwareVariableMtrrCountWorker (
150 VOID
151 )
152 {
153 UINT32 VariableMtrrCount;
154 UINT32 ReservedMtrrNumber;
155
156 VariableMtrrCount = GetVariableMtrrCountWorker ();
157 ReservedMtrrNumber = PcdGet32 (PcdCpuNumberOfReservedVariableMtrrs);
158 if (VariableMtrrCount < ReservedMtrrNumber) {
159 return 0;
160 }
161
162 return VariableMtrrCount - ReservedMtrrNumber;
163 }
164
165 /**
166 Returns the firmware usable variable MTRR count for the CPU.
167
168 @return Firmware usable variable MTRR count
169
170 **/
171 UINT32
172 EFIAPI
173 GetFirmwareVariableMtrrCount (
174 VOID
175 )
176 {
177 if (!IsMtrrSupported ()) {
178 return 0;
179 }
180 return GetFirmwareVariableMtrrCountWorker ();
181 }
182
183 /**
184 Worker function returns the default MTRR cache type for the system.
185
186 @return The default MTRR cache type.
187
188 **/
189 MTRR_MEMORY_CACHE_TYPE
190 MtrrGetDefaultMemoryTypeWorker (
191 VOID
192 )
193 {
194 return (MTRR_MEMORY_CACHE_TYPE) (AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE) & 0x7);
195 }
196
197
198 /**
199 Returns the default MTRR cache type for the system.
200
201 @return The default MTRR cache type.
202
203 **/
204 MTRR_MEMORY_CACHE_TYPE
205 EFIAPI
206 MtrrGetDefaultMemoryType (
207 VOID
208 )
209 {
210 if (!IsMtrrSupported ()) {
211 return CacheUncacheable;
212 }
213 return MtrrGetDefaultMemoryTypeWorker ();
214 }
215
216 /**
217 Preparation before programming MTRR.
218
219 This function will do some preparation for programming MTRRs:
220 disable cache, invalid cache and disable MTRR caching functionality
221
222 @param[out] MtrrContext Pointer to context to save
223
224 **/
225 VOID
226 PreMtrrChange (
227 OUT MTRR_CONTEXT *MtrrContext
228 )
229 {
230 //
231 // Disable interrupts and save current interrupt state
232 //
233 MtrrContext->InterruptState = SaveAndDisableInterrupts();
234
235 //
236 // Enter no fill cache mode, CD=1(Bit30), NW=0 (Bit29)
237 //
238 AsmDisableCache ();
239
240 //
241 // Save original CR4 value and clear PGE flag (Bit 7)
242 //
243 MtrrContext->Cr4 = AsmReadCr4 ();
244 AsmWriteCr4 (MtrrContext->Cr4 & (~BIT7));
245
246 //
247 // Flush all TLBs
248 //
249 CpuFlushTlb ();
250
251 //
252 // Disable MTRRs
253 //
254 AsmMsrBitFieldWrite64 (MTRR_LIB_IA32_MTRR_DEF_TYPE, 10, 11, 0);
255 }
256
257 /**
258 Cleaning up after programming MTRRs.
259
260 This function will do some clean up after programming MTRRs:
261 Flush all TLBs, re-enable caching, restore CR4.
262
263 @param[in] MtrrContext Pointer to context to restore
264
265 **/
266 VOID
267 PostMtrrChangeEnableCache (
268 IN MTRR_CONTEXT *MtrrContext
269 )
270 {
271 //
272 // Flush all TLBs
273 //
274 CpuFlushTlb ();
275
276 //
277 // Enable Normal Mode caching CD=NW=0, CD(Bit30), NW(Bit29)
278 //
279 AsmEnableCache ();
280
281 //
282 // Restore original CR4 value
283 //
284 AsmWriteCr4 (MtrrContext->Cr4);
285
286 //
287 // Restore original interrupt state
288 //
289 SetInterruptState (MtrrContext->InterruptState);
290 }
291
292 /**
293 Cleaning up after programming MTRRs.
294
295 This function will do some clean up after programming MTRRs:
296 enable MTRR caching functionality, and enable cache
297
298 @param[in] MtrrContext Pointer to context to restore
299
300 **/
301 VOID
302 PostMtrrChange (
303 IN MTRR_CONTEXT *MtrrContext
304 )
305 {
306 //
307 // Enable Cache MTRR
308 //
309 AsmMsrBitFieldWrite64 (MTRR_LIB_IA32_MTRR_DEF_TYPE, 10, 11, 3);
310
311 PostMtrrChangeEnableCache (MtrrContext);
312 }
313
314 /**
315 Worker function gets the content in fixed MTRRs
316
317 @param[out] FixedSettings A buffer to hold fixed MTRRs content.
318
319 @retval The pointer of FixedSettings
320
321 **/
322 MTRR_FIXED_SETTINGS*
323 MtrrGetFixedMtrrWorker (
324 OUT MTRR_FIXED_SETTINGS *FixedSettings
325 )
326 {
327 UINT32 Index;
328
329 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
330 FixedSettings->Mtrr[Index] =
331 AsmReadMsr64 (mMtrrLibFixedMtrrTable[Index].Msr);
332 }
333
334 return FixedSettings;
335 }
336
337
338 /**
339 This function gets the content in fixed MTRRs
340
341 @param[out] FixedSettings A buffer to hold fixed MTRRs content.
342
343 @retval The pointer of FixedSettings
344
345 **/
346 MTRR_FIXED_SETTINGS*
347 EFIAPI
348 MtrrGetFixedMtrr (
349 OUT MTRR_FIXED_SETTINGS *FixedSettings
350 )
351 {
352 if (!IsMtrrSupported ()) {
353 return FixedSettings;
354 }
355
356 return MtrrGetFixedMtrrWorker (FixedSettings);
357 }
358
359
360 /**
361 Worker function will get the raw value in variable MTRRs
362
363 @param[out] VariableSettings A buffer to hold variable MTRRs content.
364
365 @return The VariableSettings input pointer
366
367 **/
368 MTRR_VARIABLE_SETTINGS*
369 MtrrGetVariableMtrrWorker (
370 IN UINT32 VariableMtrrCount,
371 OUT MTRR_VARIABLE_SETTINGS *VariableSettings
372 )
373 {
374 UINT32 Index;
375
376 ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);
377
378 for (Index = 0; Index < VariableMtrrCount; Index++) {
379 VariableSettings->Mtrr[Index].Base =
380 AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1));
381 VariableSettings->Mtrr[Index].Mask =
382 AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1) + 1);
383 }
384
385 return VariableSettings;
386 }
387
388 /**
389 This function will get the raw value in variable MTRRs
390
391 @param[out] VariableSettings A buffer to hold variable MTRRs content.
392
393 @return The VariableSettings input pointer
394
395 **/
396 MTRR_VARIABLE_SETTINGS*
397 EFIAPI
398 MtrrGetVariableMtrr (
399 OUT MTRR_VARIABLE_SETTINGS *VariableSettings
400 )
401 {
402 if (!IsMtrrSupported ()) {
403 return VariableSettings;
404 }
405
406 return MtrrGetVariableMtrrWorker (
407 GetVariableMtrrCountWorker (),
408 VariableSettings
409 );
410 }
411
412 /**
413 Programs fixed MTRRs registers.
414
415 @param[in] MemoryCacheType The memory type to set.
416 @param[in, out] Base The base address of memory range.
417 @param[in, out] Length The length of memory range.
418
419 @retval RETURN_SUCCESS The cache type was updated successfully
420 @retval RETURN_UNSUPPORTED The requested range or cache type was invalid
421 for the fixed MTRRs.
422
423 **/
424 RETURN_STATUS
425 ProgramFixedMtrr (
426 IN UINT64 MemoryCacheType,
427 IN OUT UINT64 *Base,
428 IN OUT UINT64 *Length
429 )
430 {
431 UINT32 MsrNum;
432 UINT32 ByteShift;
433 UINT64 TempQword;
434 UINT64 OrMask;
435 UINT64 ClearMask;
436
437 TempQword = 0;
438 OrMask = 0;
439 ClearMask = 0;
440
441 for (MsrNum = 0; MsrNum < MTRR_NUMBER_OF_FIXED_MTRR; MsrNum++) {
442 if ((*Base >= mMtrrLibFixedMtrrTable[MsrNum].BaseAddress) &&
443 (*Base <
444 (
445 mMtrrLibFixedMtrrTable[MsrNum].BaseAddress +
446 (8 * mMtrrLibFixedMtrrTable[MsrNum].Length)
447 )
448 )
449 ) {
450 break;
451 }
452 }
453
454 if (MsrNum == MTRR_NUMBER_OF_FIXED_MTRR) {
455 return RETURN_UNSUPPORTED;
456 }
457
458 //
459 // We found the fixed MTRR to be programmed
460 //
461 for (ByteShift = 0; ByteShift < 8; ByteShift++) {
462 if (*Base ==
463 (
464 mMtrrLibFixedMtrrTable[MsrNum].BaseAddress +
465 (ByteShift * mMtrrLibFixedMtrrTable[MsrNum].Length)
466 )
467 ) {
468 break;
469 }
470 }
471
472 if (ByteShift == 8) {
473 return RETURN_UNSUPPORTED;
474 }
475
476 for (
477 ;
478 ((ByteShift < 8) && (*Length >= mMtrrLibFixedMtrrTable[MsrNum].Length));
479 ByteShift++
480 ) {
481 OrMask |= LShiftU64 ((UINT64) MemoryCacheType, (UINT32) (ByteShift * 8));
482 ClearMask |= LShiftU64 ((UINT64) 0xFF, (UINT32) (ByteShift * 8));
483 *Length -= mMtrrLibFixedMtrrTable[MsrNum].Length;
484 *Base += mMtrrLibFixedMtrrTable[MsrNum].Length;
485 }
486
487 if (ByteShift < 8 && (*Length != 0)) {
488 return RETURN_UNSUPPORTED;
489 }
490
491 TempQword =
492 (AsmReadMsr64 (mMtrrLibFixedMtrrTable[MsrNum].Msr) & ~ClearMask) | OrMask;
493 AsmWriteMsr64 (mMtrrLibFixedMtrrTable[MsrNum].Msr, TempQword);
494 return RETURN_SUCCESS;
495 }
496
497
498 /**
499 Gets the attribute of variable MTRRs.
500
501 This function shadows the content of variable MTRRs into an
502 internal array: VariableMtrr.
503
504 @param[in] MtrrValidBitsMask The mask for the valid bit of the MTRR
505 @param[in] MtrrValidAddressMask The valid address mask for MTRR
506 @param[out] VariableMtrr The array to shadow variable MTRRs content
507
508 @return The return value of this paramter indicates the
509 number of MTRRs which has been used.
510
511 **/
512 UINT32
513 EFIAPI
514 MtrrGetMemoryAttributeInVariableMtrr (
515 IN UINT64 MtrrValidBitsMask,
516 IN UINT64 MtrrValidAddressMask,
517 OUT VARIABLE_MTRR *VariableMtrr
518 )
519 {
520 UINTN Index;
521 UINT32 MsrNum;
522 UINT32 UsedMtrr;
523 UINT32 FirmwareVariableMtrrCount;
524 UINT32 VariableMtrrEnd;
525
526 if (!IsMtrrSupported ()) {
527 return 0;
528 }
529
530 FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCountWorker ();
531 VariableMtrrEnd = MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (2 * GetVariableMtrrCount ()) - 1;
532
533 ZeroMem (VariableMtrr, sizeof (VARIABLE_MTRR) * MTRR_NUMBER_OF_VARIABLE_MTRR);
534 UsedMtrr = 0;
535
536 for (MsrNum = MTRR_LIB_IA32_VARIABLE_MTRR_BASE, Index = 0;
537 (
538 (MsrNum < VariableMtrrEnd) &&
539 (Index < FirmwareVariableMtrrCount)
540 );
541 MsrNum += 2
542 ) {
543 if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) != 0) {
544 VariableMtrr[Index].Msr = MsrNum;
545 VariableMtrr[Index].BaseAddress = (AsmReadMsr64 (MsrNum) &
546 MtrrValidAddressMask);
547 VariableMtrr[Index].Length = ((~(AsmReadMsr64 (MsrNum + 1) &
548 MtrrValidAddressMask)
549 ) &
550 MtrrValidBitsMask
551 ) + 1;
552 VariableMtrr[Index].Type = (AsmReadMsr64 (MsrNum) & 0x0ff);
553 VariableMtrr[Index].Valid = TRUE;
554 VariableMtrr[Index].Used = TRUE;
555 UsedMtrr = UsedMtrr + 1;
556 Index++;
557 }
558 }
559 return UsedMtrr;
560 }
561
562
563 /**
564 Checks overlap between given memory range and MTRRs.
565
566 @param[in] FirmwareVariableMtrrCount The number of variable MTRRs available
567 to firmware.
568 @param[in] Start The start address of memory range.
569 @param[in] End The end address of memory range.
570 @param[in] VariableMtrr The array to shadow variable MTRRs content
571
572 @retval TRUE Overlap exists.
573 @retval FALSE No overlap.
574
575 **/
576 BOOLEAN
577 CheckMemoryAttributeOverlap (
578 IN UINTN FirmwareVariableMtrrCount,
579 IN PHYSICAL_ADDRESS Start,
580 IN PHYSICAL_ADDRESS End,
581 IN VARIABLE_MTRR *VariableMtrr
582 )
583 {
584 UINT32 Index;
585
586 for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) {
587 if (
588 VariableMtrr[Index].Valid &&
589 !(
590 (Start > (VariableMtrr[Index].BaseAddress +
591 VariableMtrr[Index].Length - 1)
592 ) ||
593 (End < VariableMtrr[Index].BaseAddress)
594 )
595 ) {
596 return TRUE;
597 }
598 }
599
600 return FALSE;
601 }
602
603
604 /**
605 Marks a variable MTRR as non-valid.
606
607 @param[in] Index The index of the array VariableMtrr to be invalidated
608 @param[in] VariableMtrr The array to shadow variable MTRRs content
609 @param[out] UsedMtrr The number of MTRRs which has already been used
610
611 **/
612 VOID
613 InvalidateShadowMtrr (
614 IN UINTN Index,
615 IN VARIABLE_MTRR *VariableMtrr,
616 OUT UINT32 *UsedMtrr
617 )
618 {
619 VariableMtrr[Index].Valid = FALSE;
620 *UsedMtrr = *UsedMtrr - 1;
621 }
622
623
624 /**
625 Combines memory attributes.
626
627 If overlap exists between given memory range and MTRRs, try to combine them.
628
629 @param[in] FirmwareVariableMtrrCount The number of variable MTRRs
630 available to firmware.
631 @param[in] Attributes The memory type to set.
632 @param[in, out] Base The base address of memory range.
633 @param[in, out] Length The length of memory range.
634 @param[in] VariableMtrr The array to shadow variable MTRRs content
635 @param[in, out] UsedMtrr The number of MTRRs which has already been used
636 @param[out] OverwriteExistingMtrr Returns whether an existing MTRR was used
637
638 @retval EFI_SUCCESS Memory region successfully combined.
639 @retval EFI_ACCESS_DENIED Memory region cannot be combined.
640
641 **/
642 RETURN_STATUS
643 CombineMemoryAttribute (
644 IN UINT32 FirmwareVariableMtrrCount,
645 IN UINT64 Attributes,
646 IN OUT UINT64 *Base,
647 IN OUT UINT64 *Length,
648 IN VARIABLE_MTRR *VariableMtrr,
649 IN OUT UINT32 *UsedMtrr,
650 OUT BOOLEAN *OverwriteExistingMtrr
651 )
652 {
653 UINT32 Index;
654 UINT64 CombineStart;
655 UINT64 CombineEnd;
656 UINT64 MtrrEnd;
657 UINT64 EndAddress;
658 BOOLEAN CoveredByExistingMtrr;
659
660 *OverwriteExistingMtrr = FALSE;
661 CoveredByExistingMtrr = FALSE;
662 EndAddress = *Base +*Length - 1;
663
664 for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) {
665
666 MtrrEnd = VariableMtrr[Index].BaseAddress + VariableMtrr[Index].Length - 1;
667 if (
668 !VariableMtrr[Index].Valid ||
669 (
670 *Base > (MtrrEnd) ||
671 (EndAddress < VariableMtrr[Index].BaseAddress)
672 )
673 ) {
674 continue;
675 }
676
677 //
678 // Combine same attribute MTRR range
679 //
680 if (Attributes == VariableMtrr[Index].Type) {
681 //
682 // if the MTRR range contain the request range, set a flag, then continue to
683 // invalidate any MTRR of the same request range with higher priority cache type.
684 //
685 if (VariableMtrr[Index].BaseAddress <= *Base && MtrrEnd >= EndAddress) {
686 CoveredByExistingMtrr = TRUE;
687 continue;
688 }
689 //
690 // invalid this MTRR, and program the combine range
691 //
692 CombineStart =
693 (*Base) < VariableMtrr[Index].BaseAddress ?
694 (*Base) :
695 VariableMtrr[Index].BaseAddress;
696 CombineEnd = EndAddress > MtrrEnd ? EndAddress : MtrrEnd;
697
698 //
699 // Record the MTRR usage status in VariableMtrr array.
700 //
701 InvalidateShadowMtrr (Index, VariableMtrr, UsedMtrr);
702 *Base = CombineStart;
703 *Length = CombineEnd - CombineStart + 1;
704 EndAddress = CombineEnd;
705 *OverwriteExistingMtrr = TRUE;
706 continue;
707 } else {
708 //
709 // The cache type is different, but the range is convered by one MTRR
710 //
711 if (VariableMtrr[Index].BaseAddress == *Base && MtrrEnd == EndAddress) {
712 InvalidateShadowMtrr (Index, VariableMtrr, UsedMtrr);
713 continue;
714 }
715
716 }
717
718 if ((Attributes== MTRR_CACHE_WRITE_THROUGH &&
719 VariableMtrr[Index].Type == MTRR_CACHE_WRITE_BACK) ||
720 (Attributes == MTRR_CACHE_WRITE_BACK &&
721 VariableMtrr[Index].Type == MTRR_CACHE_WRITE_THROUGH) ||
722 (Attributes == MTRR_CACHE_UNCACHEABLE) ||
723 (VariableMtrr[Index].Type == MTRR_CACHE_UNCACHEABLE)
724 ) {
725 *OverwriteExistingMtrr = TRUE;
726 continue;
727 }
728 //
729 // Other type memory overlap is invalid
730 //
731 return RETURN_ACCESS_DENIED;
732 }
733
734 if (CoveredByExistingMtrr) {
735 *Length = 0;
736 }
737
738 return RETURN_SUCCESS;
739 }
740
741
742 /**
743 Calculates the maximum value which is a power of 2, but less the MemoryLength.
744
745 @param[in] MemoryLength The number to pass in.
746
747 @return The maximum value which is align to power of 2 and less the MemoryLength
748
749 **/
750 UINT64
751 Power2MaxMemory (
752 IN UINT64 MemoryLength
753 )
754 {
755 UINT64 Result;
756
757 if (RShiftU64 (MemoryLength, 32) != 0) {
758 Result = LShiftU64 (
759 (UINT64) GetPowerOfTwo32 (
760 (UINT32) RShiftU64 (MemoryLength, 32)
761 ),
762 32
763 );
764 } else {
765 Result = (UINT64) GetPowerOfTwo32 ((UINT32) MemoryLength);
766 }
767
768 return Result;
769 }
770
771
772 /**
773 Determines the MTRR numbers used to program a memory range.
774
775 This function first checks the alignment of the base address.
776 If the alignment of the base address <= Length, cover the memory range
777 (BaseAddress, alignment) by a MTRR, then BaseAddress += alignment and
778 Length -= alignment. Repeat the step until alignment > Length.
779
780 Then this function determines which direction of programming the variable
781 MTRRs for the remaining length will use fewer MTRRs.
782
783 @param[in] BaseAddress Length of Memory to program MTRR
784 @param[in] Length Length of Memory to program MTRR
785 @param[in] MtrrNumber Pointer to the number of necessary MTRRs
786
787 @retval TRUE Positive direction is better.
788 FALSE Negative direction is better.
789
790 **/
791 BOOLEAN
792 GetMtrrNumberAndDirection (
793 IN UINT64 BaseAddress,
794 IN UINT64 Length,
795 IN UINTN *MtrrNumber
796 )
797 {
798 UINT64 TempQword;
799 UINT64 Alignment;
800 UINT32 Positive;
801 UINT32 Subtractive;
802
803 *MtrrNumber = 0;
804
805 if (BaseAddress != 0) {
806 do {
807 //
808 // Calculate the alignment of the base address.
809 //
810 Alignment = LShiftU64 (1, (UINTN)LowBitSet64 (BaseAddress));
811
812 if (Alignment > Length) {
813 break;
814 }
815
816 (*MtrrNumber)++;
817 BaseAddress += Alignment;
818 Length -= Alignment;
819 } while (TRUE);
820
821 if (Length == 0) {
822 return TRUE;
823 }
824 }
825
826 TempQword = Length;
827 Positive = 0;
828 Subtractive = 0;
829
830 do {
831 TempQword -= Power2MaxMemory (TempQword);
832 Positive++;
833 } while (TempQword != 0);
834
835 TempQword = Power2MaxMemory (LShiftU64 (Length, 1)) - Length;
836 Subtractive++;
837 do {
838 TempQword -= Power2MaxMemory (TempQword);
839 Subtractive++;
840 } while (TempQword != 0);
841
842 if (Positive <= Subtractive) {
843 *MtrrNumber += Positive;
844 return TRUE;
845 } else {
846 *MtrrNumber += Subtractive;
847 return FALSE;
848 }
849 }
850
851 /**
852 Invalid variable MTRRs according to the value in the shadow array.
853
854 This function programs MTRRs according to the values specified
855 in the shadow array.
856
857 @param[in] VariableMtrrCount Number of variable MTRRs
858 @param[in, out] VariableMtrr Shadow of variable MTRR contents
859
860 **/
861 VOID
862 InvalidateMtrr (
863 IN UINTN VariableMtrrCount,
864 IN OUT VARIABLE_MTRR *VariableMtrr
865 )
866 {
867 UINTN Index;
868 MTRR_CONTEXT MtrrContext;
869
870 PreMtrrChange (&MtrrContext);
871 Index = 0;
872 while (Index < VariableMtrrCount) {
873 if (!VariableMtrr[Index].Valid && VariableMtrr[Index].Used) {
874 AsmWriteMsr64 (VariableMtrr[Index].Msr, 0);
875 AsmWriteMsr64 (VariableMtrr[Index].Msr + 1, 0);
876 VariableMtrr[Index].Used = FALSE;
877 }
878 Index ++;
879 }
880 PostMtrrChange (&MtrrContext);
881 }
882
883
884 /**
885 Programs variable MTRRs
886
887 This function programs variable MTRRs
888
889 @param[in] MtrrNumber Index of MTRR to program.
890 @param[in] BaseAddress Base address of memory region.
891 @param[in] Length Length of memory region.
892 @param[in] MemoryCacheType Memory type to set.
893 @param[in] MtrrValidAddressMask The valid address mask for MTRR
894
895 **/
896 VOID
897 ProgramVariableMtrr (
898 IN UINTN MtrrNumber,
899 IN PHYSICAL_ADDRESS BaseAddress,
900 IN UINT64 Length,
901 IN UINT64 MemoryCacheType,
902 IN UINT64 MtrrValidAddressMask
903 )
904 {
905 UINT64 TempQword;
906 MTRR_CONTEXT MtrrContext;
907
908 PreMtrrChange (&MtrrContext);
909
910 //
911 // MTRR Physical Base
912 //
913 TempQword = (BaseAddress & MtrrValidAddressMask) | MemoryCacheType;
914 AsmWriteMsr64 ((UINT32) MtrrNumber, TempQword);
915
916 //
917 // MTRR Physical Mask
918 //
919 TempQword = ~(Length - 1);
920 AsmWriteMsr64 (
921 (UINT32) (MtrrNumber + 1),
922 (TempQword & MtrrValidAddressMask) | MTRR_LIB_CACHE_MTRR_ENABLED
923 );
924
925 PostMtrrChange (&MtrrContext);
926 }
927
928
929 /**
930 Converts the Memory attribute value to MTRR_MEMORY_CACHE_TYPE.
931
932 @param[in] MtrrType MTRR memory type
933
934 @return The enum item in MTRR_MEMORY_CACHE_TYPE
935
936 **/
937 MTRR_MEMORY_CACHE_TYPE
938 GetMemoryCacheTypeFromMtrrType (
939 IN UINT64 MtrrType
940 )
941 {
942 switch (MtrrType) {
943 case MTRR_CACHE_UNCACHEABLE:
944 return CacheUncacheable;
945 case MTRR_CACHE_WRITE_COMBINING:
946 return CacheWriteCombining;
947 case MTRR_CACHE_WRITE_THROUGH:
948 return CacheWriteThrough;
949 case MTRR_CACHE_WRITE_PROTECTED:
950 return CacheWriteProtected;
951 case MTRR_CACHE_WRITE_BACK:
952 return CacheWriteBack;
953 default:
954 //
955 // MtrrType is MTRR_CACHE_INVALID_TYPE, that means
956 // no MTRR covers the range
957 //
958 return MtrrGetDefaultMemoryType ();
959 }
960 }
961
962 /**
963 Initializes the valid bits mask and valid address mask for MTRRs.
964
965 This function initializes the valid bits mask and valid address mask for MTRRs.
966
967 @param[out] MtrrValidBitsMask The mask for the valid bit of the MTRR
968 @param[out] MtrrValidAddressMask The valid address mask for the MTRR
969
970 **/
971 VOID
972 MtrrLibInitializeMtrrMask (
973 OUT UINT64 *MtrrValidBitsMask,
974 OUT UINT64 *MtrrValidAddressMask
975 )
976 {
977 UINT32 RegEax;
978 UINT8 PhysicalAddressBits;
979
980 AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
981
982 if (RegEax >= 0x80000008) {
983 AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);
984
985 PhysicalAddressBits = (UINT8) RegEax;
986
987 *MtrrValidBitsMask = LShiftU64 (1, PhysicalAddressBits) - 1;
988 *MtrrValidAddressMask = *MtrrValidBitsMask & 0xfffffffffffff000ULL;
989 } else {
990 *MtrrValidBitsMask = MTRR_LIB_MSR_VALID_MASK;
991 *MtrrValidAddressMask = MTRR_LIB_CACHE_VALID_ADDRESS;
992 }
993 }
994
995
996 /**
997 Determines the real attribute of a memory range.
998
999 This function is to arbitrate the real attribute of the memory when
1000 there are 2 MTRRs covers the same memory range. For further details,
1001 please refer the IA32 Software Developer's Manual, Volume 3,
1002 Section 10.11.4.1.
1003
1004 @param[in] MtrrType1 The first kind of Memory type
1005 @param[in] MtrrType2 The second kind of memory type
1006
1007 **/
1008 UINT64
1009 MtrrPrecedence (
1010 IN UINT64 MtrrType1,
1011 IN UINT64 MtrrType2
1012 )
1013 {
1014 UINT64 MtrrType;
1015
1016 MtrrType = MTRR_CACHE_INVALID_TYPE;
1017 switch (MtrrType1) {
1018 case MTRR_CACHE_UNCACHEABLE:
1019 MtrrType = MTRR_CACHE_UNCACHEABLE;
1020 break;
1021 case MTRR_CACHE_WRITE_COMBINING:
1022 if (
1023 MtrrType2==MTRR_CACHE_WRITE_COMBINING ||
1024 MtrrType2==MTRR_CACHE_UNCACHEABLE
1025 ) {
1026 MtrrType = MtrrType2;
1027 }
1028 break;
1029 case MTRR_CACHE_WRITE_THROUGH:
1030 if (
1031 MtrrType2==MTRR_CACHE_WRITE_THROUGH ||
1032 MtrrType2==MTRR_CACHE_WRITE_BACK
1033 ) {
1034 MtrrType = MTRR_CACHE_WRITE_THROUGH;
1035 } else if(MtrrType2==MTRR_CACHE_UNCACHEABLE) {
1036 MtrrType = MTRR_CACHE_UNCACHEABLE;
1037 }
1038 break;
1039 case MTRR_CACHE_WRITE_PROTECTED:
1040 if (MtrrType2 == MTRR_CACHE_WRITE_PROTECTED ||
1041 MtrrType2 == MTRR_CACHE_UNCACHEABLE) {
1042 MtrrType = MtrrType2;
1043 }
1044 break;
1045 case MTRR_CACHE_WRITE_BACK:
1046 if (
1047 MtrrType2== MTRR_CACHE_UNCACHEABLE ||
1048 MtrrType2==MTRR_CACHE_WRITE_THROUGH ||
1049 MtrrType2== MTRR_CACHE_WRITE_BACK
1050 ) {
1051 MtrrType = MtrrType2;
1052 }
1053 break;
1054 case MTRR_CACHE_INVALID_TYPE:
1055 MtrrType = MtrrType2;
1056 break;
1057 default:
1058 break;
1059 }
1060
1061 if (MtrrType2 == MTRR_CACHE_INVALID_TYPE) {
1062 MtrrType = MtrrType1;
1063 }
1064 return MtrrType;
1065 }
1066
1067
1068
1069 /**
1070 This function will get the memory cache type of the specific address.
1071
1072 This function is mainly for debug purpose.
1073
1074 @param[in] Address The specific address
1075
1076 @return Memory cache type of the specific address
1077
1078 **/
1079 MTRR_MEMORY_CACHE_TYPE
1080 EFIAPI
1081 MtrrGetMemoryAttribute (
1082 IN PHYSICAL_ADDRESS Address
1083 )
1084 {
1085 UINT64 TempQword;
1086 UINTN Index;
1087 UINTN SubIndex;
1088 UINT64 MtrrType;
1089 UINT64 TempMtrrType;
1090 MTRR_MEMORY_CACHE_TYPE CacheType;
1091 VARIABLE_MTRR VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];
1092 UINT64 MtrrValidBitsMask;
1093 UINT64 MtrrValidAddressMask;
1094 UINTN VariableMtrrCount;
1095
1096 if (!IsMtrrSupported ()) {
1097 return CacheUncacheable;
1098 }
1099
1100 //
1101 // Check if MTRR is enabled, if not, return UC as attribute
1102 //
1103 TempQword = AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE);
1104 MtrrType = MTRR_CACHE_INVALID_TYPE;
1105
1106 if ((TempQword & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {
1107 return CacheUncacheable;
1108 }
1109
1110 //
1111 // If address is less than 1M, then try to go through the fixed MTRR
1112 //
1113 if (Address < BASE_1MB) {
1114 if ((TempQword & MTRR_LIB_CACHE_FIXED_MTRR_ENABLED) != 0) {
1115 //
1116 // Go through the fixed MTRR
1117 //
1118 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
1119 if (Address >= mMtrrLibFixedMtrrTable[Index].BaseAddress &&
1120 Address < (
1121 mMtrrLibFixedMtrrTable[Index].BaseAddress +
1122 (mMtrrLibFixedMtrrTable[Index].Length * 8)
1123 )
1124 ) {
1125 SubIndex =
1126 ((UINTN)Address - mMtrrLibFixedMtrrTable[Index].BaseAddress) /
1127 mMtrrLibFixedMtrrTable[Index].Length;
1128 TempQword = AsmReadMsr64 (mMtrrLibFixedMtrrTable[Index].Msr);
1129 MtrrType = RShiftU64 (TempQword, SubIndex * 8) & 0xFF;
1130 return GetMemoryCacheTypeFromMtrrType (MtrrType);
1131 }
1132 }
1133 }
1134 }
1135 MtrrLibInitializeMtrrMask(&MtrrValidBitsMask, &MtrrValidAddressMask);
1136 MtrrGetMemoryAttributeInVariableMtrr(
1137 MtrrValidBitsMask,
1138 MtrrValidAddressMask,
1139 VariableMtrr
1140 );
1141
1142 //
1143 // Go through the variable MTRR
1144 //
1145 VariableMtrrCount = GetVariableMtrrCountWorker ();
1146 ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);
1147
1148 for (Index = 0; Index < VariableMtrrCount; Index++) {
1149 if (VariableMtrr[Index].Valid) {
1150 if (Address >= VariableMtrr[Index].BaseAddress &&
1151 Address < VariableMtrr[Index].BaseAddress+VariableMtrr[Index].Length) {
1152 TempMtrrType = VariableMtrr[Index].Type;
1153 MtrrType = MtrrPrecedence (MtrrType, TempMtrrType);
1154 }
1155 }
1156 }
1157 CacheType = GetMemoryCacheTypeFromMtrrType (MtrrType);
1158
1159 return CacheType;
1160 }
1161
1162
1163
1164 /**
1165 This function prints all MTRRs for debugging.
1166 **/
1167 VOID
1168 EFIAPI
1169 MtrrDebugPrintAllMtrrs (
1170 VOID
1171 )
1172 {
1173 DEBUG_CODE (
1174 MTRR_SETTINGS MtrrSettings;
1175 UINTN Index;
1176 UINTN Index1;
1177 UINTN VariableMtrrCount;
1178 UINT64 Base;
1179 UINT64 Limit;
1180 UINT64 MtrrBase;
1181 UINT64 MtrrLimit;
1182 UINT64 RangeBase;
1183 UINT64 RangeLimit;
1184 UINT64 NoRangeBase;
1185 UINT64 NoRangeLimit;
1186 UINT32 RegEax;
1187 UINTN MemoryType;
1188 UINTN PreviousMemoryType;
1189 BOOLEAN Found;
1190
1191 if (!IsMtrrSupported ()) {
1192 return;
1193 }
1194
1195 DEBUG((DEBUG_CACHE, "MTRR Settings\n"));
1196 DEBUG((DEBUG_CACHE, "=============\n"));
1197
1198 MtrrGetAllMtrrs (&MtrrSettings);
1199 DEBUG((DEBUG_CACHE, "MTRR Default Type: %016lx\n", MtrrSettings.MtrrDefType));
1200 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
1201 DEBUG((DEBUG_CACHE, "Fixed MTRR[%02d] : %016lx\n", Index, MtrrSettings.Fixed.Mtrr[Index]));
1202 }
1203
1204 VariableMtrrCount = GetVariableMtrrCount ();
1205 for (Index = 0; Index < VariableMtrrCount; Index++) {
1206 DEBUG((DEBUG_CACHE, "Variable MTRR[%02d]: Base=%016lx Mask=%016lx\n",
1207 Index,
1208 MtrrSettings.Variables.Mtrr[Index].Base,
1209 MtrrSettings.Variables.Mtrr[Index].Mask
1210 ));
1211 }
1212 DEBUG((DEBUG_CACHE, "\n"));
1213 DEBUG((DEBUG_CACHE, "MTRR Ranges\n"));
1214 DEBUG((DEBUG_CACHE, "====================================\n"));
1215
1216 Base = 0;
1217 PreviousMemoryType = MTRR_CACHE_INVALID_TYPE;
1218 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
1219 Base = mMtrrLibFixedMtrrTable[Index].BaseAddress;
1220 for (Index1 = 0; Index1 < 8; Index1++) {
1221 MemoryType = (UINTN)(RShiftU64 (MtrrSettings.Fixed.Mtrr[Index], Index1 * 8) & 0xff);
1222 if (MemoryType > CacheWriteBack) {
1223 MemoryType = MTRR_CACHE_INVALID_TYPE;
1224 }
1225 if (MemoryType != PreviousMemoryType) {
1226 if (PreviousMemoryType != MTRR_CACHE_INVALID_TYPE) {
1227 DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));
1228 }
1229 PreviousMemoryType = MemoryType;
1230 DEBUG((DEBUG_CACHE, "%a:%016lx-", mMtrrMemoryCacheTypeShortName[MemoryType], Base));
1231 }
1232 Base += mMtrrLibFixedMtrrTable[Index].Length;
1233 }
1234 }
1235 DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));
1236
1237 VariableMtrrCount = GetVariableMtrrCount ();
1238
1239 Limit = BIT36 - 1;
1240 AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
1241 if (RegEax >= 0x80000008) {
1242 AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);
1243 Limit = LShiftU64 (1, RegEax & 0xff) - 1;
1244 }
1245 Base = BASE_1MB;
1246 PreviousMemoryType = MTRR_CACHE_INVALID_TYPE;
1247 do {
1248 MemoryType = MtrrGetMemoryAttribute (Base);
1249 if (MemoryType > CacheWriteBack) {
1250 MemoryType = MTRR_CACHE_INVALID_TYPE;
1251 }
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
1261 RangeBase = BASE_1MB;
1262 NoRangeBase = BASE_1MB;
1263 RangeLimit = Limit;
1264 NoRangeLimit = Limit;
1265
1266 for (Index = 0, Found = FALSE; Index < VariableMtrrCount; Index++) {
1267 if ((MtrrSettings.Variables.Mtrr[Index].Mask & BIT11) == 0) {
1268 //
1269 // If mask is not valid, then do not display range
1270 //
1271 continue;
1272 }
1273 MtrrBase = (MtrrSettings.Variables.Mtrr[Index].Base & (~(SIZE_4KB - 1)));
1274 MtrrLimit = MtrrBase + ((~(MtrrSettings.Variables.Mtrr[Index].Mask & (~(SIZE_4KB - 1)))) & Limit);
1275
1276 if (Base >= MtrrBase && Base < MtrrLimit) {
1277 Found = TRUE;
1278 }
1279
1280 if (Base >= MtrrBase && MtrrBase > RangeBase) {
1281 RangeBase = MtrrBase;
1282 }
1283 if (Base > MtrrLimit && MtrrLimit > RangeBase) {
1284 RangeBase = MtrrLimit + 1;
1285 }
1286 if (Base < MtrrBase && MtrrBase < RangeLimit) {
1287 RangeLimit = MtrrBase - 1;
1288 }
1289 if (Base < MtrrLimit && MtrrLimit <= RangeLimit) {
1290 RangeLimit = MtrrLimit;
1291 }
1292
1293 if (Base > MtrrLimit && NoRangeBase < MtrrLimit) {
1294 NoRangeBase = MtrrLimit + 1;
1295 }
1296 if (Base < MtrrBase && NoRangeLimit > MtrrBase) {
1297 NoRangeLimit = MtrrBase - 1;
1298 }
1299 }
1300
1301 if (Found) {
1302 Base = RangeLimit + 1;
1303 } else {
1304 Base = NoRangeLimit + 1;
1305 }
1306 } while (Base < Limit);
1307 DEBUG((DEBUG_CACHE, "%016lx\n\n", Base - 1));
1308 );
1309 }
1310 /**
1311 This function attempts to set the attributes for a memory range.
1312
1313 @param[in] BaseAddress The physical address that is the start
1314 address of a memory region.
1315 @param[in] Length The size in bytes of the memory region.
1316 @param[in] Attribute The bit mask of attributes to set for the
1317 memory region.
1318
1319 @retval RETURN_SUCCESS The attributes were set for the memory
1320 region.
1321 @retval RETURN_INVALID_PARAMETER Length is zero.
1322 @retval RETURN_UNSUPPORTED The processor does not support one or
1323 more bytes of the memory resource range
1324 specified by BaseAddress and Length.
1325 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support
1326 for the memory resource range specified
1327 by BaseAddress and Length.
1328 @retval RETURN_ACCESS_DENIED The attributes for the memory resource
1329 range specified by BaseAddress and Length
1330 cannot be modified.
1331 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to
1332 modify the attributes of the memory
1333 resource range.
1334
1335 **/
1336 RETURN_STATUS
1337 EFIAPI
1338 MtrrSetMemoryAttribute (
1339 IN PHYSICAL_ADDRESS BaseAddress,
1340 IN UINT64 Length,
1341 IN MTRR_MEMORY_CACHE_TYPE Attribute
1342 )
1343 {
1344 UINT64 TempQword;
1345 RETURN_STATUS Status;
1346 UINT64 MemoryType;
1347 UINT64 Alignment;
1348 BOOLEAN OverLap;
1349 BOOLEAN Positive;
1350 UINT32 MsrNum;
1351 UINTN MtrrNumber;
1352 VARIABLE_MTRR VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];
1353 UINT32 UsedMtrr;
1354 UINT64 MtrrValidBitsMask;
1355 UINT64 MtrrValidAddressMask;
1356 BOOLEAN OverwriteExistingMtrr;
1357 UINT32 FirmwareVariableMtrrCount;
1358 UINT32 VariableMtrrEnd;
1359 MTRR_CONTEXT MtrrContext;
1360 UINT32 VariableMtrrCount;
1361
1362 DEBUG((DEBUG_CACHE, "MtrrSetMemoryAttribute() %a:%016lx-%016lx\n", mMtrrMemoryCacheTypeShortName[Attribute], BaseAddress, Length));
1363
1364 if (!IsMtrrSupported ()) {
1365 Status = RETURN_UNSUPPORTED;
1366 goto Done;
1367 }
1368
1369 FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCountWorker ();
1370 VariableMtrrEnd = MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (2 * GetVariableMtrrCount ()) - 1;
1371
1372 MtrrLibInitializeMtrrMask(&MtrrValidBitsMask, &MtrrValidAddressMask);
1373
1374 TempQword = 0;
1375 MemoryType = (UINT64)Attribute;
1376 OverwriteExistingMtrr = FALSE;
1377
1378 //
1379 // Check for an invalid parameter
1380 //
1381 if (Length == 0) {
1382 Status = RETURN_INVALID_PARAMETER;
1383 goto Done;
1384 }
1385
1386 if (
1387 (BaseAddress & ~MtrrValidAddressMask) != 0 ||
1388 (Length & ~MtrrValidAddressMask) != 0
1389 ) {
1390 Status = RETURN_UNSUPPORTED;
1391 goto Done;
1392 }
1393
1394 //
1395 // Check if Fixed MTRR
1396 //
1397 Status = RETURN_SUCCESS;
1398 while ((BaseAddress < BASE_1MB) && (Length > 0) && Status == RETURN_SUCCESS) {
1399 PreMtrrChange (&MtrrContext);
1400 Status = ProgramFixedMtrr (MemoryType, &BaseAddress, &Length);
1401 PostMtrrChange (&MtrrContext);
1402 if (RETURN_ERROR (Status)) {
1403 goto Done;
1404 }
1405 }
1406
1407 if (Length == 0) {
1408 //
1409 // A Length of 0 can only make sense for fixed MTTR ranges.
1410 // Since we just handled the fixed MTRRs, we can skip the
1411 // variable MTRR section.
1412 //
1413 goto Done;
1414 }
1415
1416 //
1417 // Since memory ranges below 1MB will be overridden by the fixed MTRRs,
1418 // we can set the base to 0 to save variable MTRRs.
1419 //
1420 if (BaseAddress == BASE_1MB) {
1421 BaseAddress = 0;
1422 Length += SIZE_1MB;
1423 }
1424
1425 //
1426 // Read all variable MTRRs
1427 //
1428 VariableMtrrCount = GetVariableMtrrCountWorker ();
1429
1430 //
1431 // Check for overlap
1432 //
1433 UsedMtrr = MtrrGetMemoryAttributeInVariableMtrr (MtrrValidBitsMask, MtrrValidAddressMask, VariableMtrr);
1434 OverLap = CheckMemoryAttributeOverlap (
1435 FirmwareVariableMtrrCount,
1436 BaseAddress,
1437 BaseAddress + Length - 1,
1438 VariableMtrr
1439 );
1440
1441 if (OverLap) {
1442 Status = CombineMemoryAttribute (
1443 FirmwareVariableMtrrCount,
1444 MemoryType,
1445 &BaseAddress,
1446 &Length,
1447 VariableMtrr,
1448 &UsedMtrr,
1449 &OverwriteExistingMtrr
1450 );
1451 if (RETURN_ERROR (Status)) {
1452 goto Done;
1453 }
1454
1455 if (Length == 0) {
1456 //
1457 // Combined successfully, invalidate the now-unused MTRRs
1458 //
1459 InvalidateMtrr(VariableMtrrCount, VariableMtrr);
1460 Status = RETURN_SUCCESS;
1461 goto Done;
1462 }
1463 }
1464
1465 //
1466 // The memory type is the same with the type specified by
1467 // MTRR_LIB_IA32_MTRR_DEF_TYPE.
1468 //
1469 if ((!OverwriteExistingMtrr) && (Attribute == MtrrGetDefaultMemoryType ())) {
1470 //
1471 // Invalidate the now-unused MTRRs
1472 //
1473 InvalidateMtrr(VariableMtrrCount, VariableMtrr);
1474 goto Done;
1475 }
1476
1477 Positive = GetMtrrNumberAndDirection (BaseAddress, Length, &MtrrNumber);
1478
1479 if ((UsedMtrr + MtrrNumber) > FirmwareVariableMtrrCount) {
1480 Status = RETURN_OUT_OF_RESOURCES;
1481 goto Done;
1482 }
1483
1484 //
1485 // Invalidate the now-unused MTRRs
1486 //
1487 InvalidateMtrr(VariableMtrrCount, VariableMtrr);
1488
1489 //
1490 // Find first unused MTRR
1491 //
1492 for (MsrNum = MTRR_LIB_IA32_VARIABLE_MTRR_BASE;
1493 MsrNum < VariableMtrrEnd;
1494 MsrNum += 2
1495 ) {
1496 if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {
1497 break;
1498 }
1499 }
1500
1501 if (BaseAddress != 0) {
1502 do {
1503 //
1504 // Calculate the alignment of the base address.
1505 //
1506 Alignment = LShiftU64 (1, (UINTN)LowBitSet64 (BaseAddress));
1507
1508 if (Alignment > Length) {
1509 break;
1510 }
1511
1512 //
1513 // Find unused MTRR
1514 //
1515 for (; MsrNum < VariableMtrrEnd; MsrNum += 2) {
1516 if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {
1517 break;
1518 }
1519 }
1520
1521 ProgramVariableMtrr (
1522 MsrNum,
1523 BaseAddress,
1524 Alignment,
1525 MemoryType,
1526 MtrrValidAddressMask
1527 );
1528 BaseAddress += Alignment;
1529 Length -= Alignment;
1530 } while (TRUE);
1531
1532 if (Length == 0) {
1533 goto Done;
1534 }
1535 }
1536
1537 TempQword = Length;
1538
1539 if (!Positive) {
1540 Length = Power2MaxMemory (LShiftU64 (TempQword, 1));
1541
1542 //
1543 // Find unused MTRR
1544 //
1545 for (; MsrNum < VariableMtrrEnd; MsrNum += 2) {
1546 if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {
1547 break;
1548 }
1549 }
1550
1551 ProgramVariableMtrr (
1552 MsrNum,
1553 BaseAddress,
1554 Length,
1555 MemoryType,
1556 MtrrValidAddressMask
1557 );
1558 BaseAddress += Length;
1559 TempQword = Length - TempQword;
1560 MemoryType = MTRR_CACHE_UNCACHEABLE;
1561 }
1562
1563 do {
1564 //
1565 // Find unused MTRR
1566 //
1567 for (; MsrNum < VariableMtrrEnd; MsrNum += 2) {
1568 if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {
1569 break;
1570 }
1571 }
1572
1573 Length = Power2MaxMemory (TempQword);
1574 if (!Positive) {
1575 BaseAddress -= Length;
1576 }
1577
1578 ProgramVariableMtrr (
1579 MsrNum,
1580 BaseAddress,
1581 Length,
1582 MemoryType,
1583 MtrrValidAddressMask
1584 );
1585
1586 if (Positive) {
1587 BaseAddress += Length;
1588 }
1589 TempQword -= Length;
1590
1591 } while (TempQword > 0);
1592
1593 Done:
1594 DEBUG((DEBUG_CACHE, " Status = %r\n", Status));
1595 if (!RETURN_ERROR (Status)) {
1596 MtrrDebugPrintAllMtrrs ();
1597 }
1598
1599 return Status;
1600 }
1601 /**
1602 Worker function setting variable MTRRs
1603
1604 @param[in] VariableSettings A buffer to hold variable MTRRs content.
1605
1606 **/
1607 VOID
1608 MtrrSetVariableMtrrWorker (
1609 IN MTRR_VARIABLE_SETTINGS *VariableSettings
1610 )
1611 {
1612 UINT32 Index;
1613 UINT32 VariableMtrrCount;
1614
1615 VariableMtrrCount = GetVariableMtrrCountWorker ();
1616 ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);
1617
1618 for (Index = 0; Index < VariableMtrrCount; Index++) {
1619 AsmWriteMsr64 (
1620 MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1),
1621 VariableSettings->Mtrr[Index].Base
1622 );
1623 AsmWriteMsr64 (
1624 MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1) + 1,
1625 VariableSettings->Mtrr[Index].Mask
1626 );
1627 }
1628 }
1629
1630
1631 /**
1632 This function sets variable MTRRs
1633
1634 @param[in] VariableSettings A buffer to hold variable MTRRs content.
1635
1636 @return The pointer of VariableSettings
1637
1638 **/
1639 MTRR_VARIABLE_SETTINGS*
1640 EFIAPI
1641 MtrrSetVariableMtrr (
1642 IN MTRR_VARIABLE_SETTINGS *VariableSettings
1643 )
1644 {
1645 MTRR_CONTEXT MtrrContext;
1646
1647 if (!IsMtrrSupported ()) {
1648 return VariableSettings;
1649 }
1650
1651 PreMtrrChange (&MtrrContext);
1652 MtrrSetVariableMtrrWorker (VariableSettings);
1653 PostMtrrChange (&MtrrContext);
1654 return VariableSettings;
1655 }
1656
1657 /**
1658 Worker function setting fixed MTRRs
1659
1660 @param[in] FixedSettings A buffer to hold fixed MTRRs content.
1661
1662 **/
1663 VOID
1664 MtrrSetFixedMtrrWorker (
1665 IN MTRR_FIXED_SETTINGS *FixedSettings
1666 )
1667 {
1668 UINT32 Index;
1669
1670 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
1671 AsmWriteMsr64 (
1672 mMtrrLibFixedMtrrTable[Index].Msr,
1673 FixedSettings->Mtrr[Index]
1674 );
1675 }
1676 }
1677
1678
1679 /**
1680 This function sets fixed MTRRs
1681
1682 @param[in] FixedSettings A buffer to hold fixed MTRRs content.
1683
1684 @retval The pointer of FixedSettings
1685
1686 **/
1687 MTRR_FIXED_SETTINGS*
1688 EFIAPI
1689 MtrrSetFixedMtrr (
1690 IN MTRR_FIXED_SETTINGS *FixedSettings
1691 )
1692 {
1693 MTRR_CONTEXT MtrrContext;
1694
1695 if (!IsMtrrSupported ()) {
1696 return FixedSettings;
1697 }
1698
1699 PreMtrrChange (&MtrrContext);
1700 MtrrSetFixedMtrrWorker (FixedSettings);
1701 PostMtrrChange (&MtrrContext);
1702
1703 return FixedSettings;
1704 }
1705
1706
1707 /**
1708 This function gets the content in all MTRRs (variable and fixed)
1709
1710 @param[out] MtrrSetting A buffer to hold all MTRRs content.
1711
1712 @retval the pointer of MtrrSetting
1713
1714 **/
1715 MTRR_SETTINGS *
1716 EFIAPI
1717 MtrrGetAllMtrrs (
1718 OUT MTRR_SETTINGS *MtrrSetting
1719 )
1720 {
1721 if (!IsMtrrSupported ()) {
1722 return MtrrSetting;
1723 }
1724
1725 //
1726 // Get fixed MTRRs
1727 //
1728 MtrrGetFixedMtrrWorker (&MtrrSetting->Fixed);
1729
1730 //
1731 // Get variable MTRRs
1732 //
1733 MtrrGetVariableMtrrWorker (
1734 GetVariableMtrrCountWorker (),
1735 &MtrrSetting->Variables
1736 );
1737
1738 //
1739 // Get MTRR_DEF_TYPE value
1740 //
1741 MtrrSetting->MtrrDefType = AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE);
1742
1743 return MtrrSetting;
1744 }
1745
1746
1747 /**
1748 This function sets all MTRRs (variable and fixed)
1749
1750 @param[in] MtrrSetting A buffer holding all MTRRs content.
1751
1752 @retval The pointer of MtrrSetting
1753
1754 **/
1755 MTRR_SETTINGS *
1756 EFIAPI
1757 MtrrSetAllMtrrs (
1758 IN MTRR_SETTINGS *MtrrSetting
1759 )
1760 {
1761 MTRR_CONTEXT MtrrContext;
1762
1763 if (!IsMtrrSupported ()) {
1764 return MtrrSetting;
1765 }
1766
1767 PreMtrrChange (&MtrrContext);
1768
1769 //
1770 // Set fixed MTRRs
1771 //
1772 MtrrSetFixedMtrrWorker (&MtrrSetting->Fixed);
1773
1774 //
1775 // Set variable MTRRs
1776 //
1777 MtrrSetVariableMtrrWorker (&MtrrSetting->Variables);
1778
1779 //
1780 // Set MTRR_DEF_TYPE value
1781 //
1782 AsmWriteMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE, MtrrSetting->MtrrDefType);
1783
1784 PostMtrrChangeEnableCache (&MtrrContext);
1785
1786 return MtrrSetting;
1787 }
1788
1789 /**
1790 Checks if MTRR is supported.
1791
1792 @retval TRUE MTRR is supported.
1793 @retval FALSE MTRR is not supported.
1794
1795 **/
1796 BOOLEAN
1797 EFIAPI
1798 IsMtrrSupported (
1799 VOID
1800 )
1801 {
1802 UINT32 RegEdx;
1803 UINT64 MtrrCap;
1804
1805 //
1806 // Check CPUID(1).EDX[12] for MTRR capability
1807 //
1808 AsmCpuid (1, NULL, NULL, NULL, &RegEdx);
1809 if (BitFieldRead32 (RegEdx, 12, 12) == 0) {
1810 return FALSE;
1811 }
1812
1813 //
1814 // Check IA32_MTRRCAP.[0..7] for number of variable MTRRs and IA32_MTRRCAP[8] for
1815 // fixed MTRRs existence. If number of variable MTRRs is zero, or fixed MTRRs do not
1816 // exist, return false.
1817 //
1818 MtrrCap = AsmReadMsr64 (MTRR_LIB_IA32_MTRR_CAP);
1819 if ((BitFieldRead64 (MtrrCap, 0, 7) == 0) || (BitFieldRead64 (MtrrCap, 8, 8) == 0)) {
1820 return FALSE;
1821 }
1822
1823 return TRUE;
1824 }