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