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