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