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