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