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