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