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