TianoCore EDK2 master
Loading...
Searching...
No Matches
CacheLib.c
Go to the documentation of this file.
1
8#include <Uefi.h>
9#include <Library/BaseLib.h>
10#include <Library/CacheLib.h>
12#include "CacheLibInternal.h"
13
29 IN EFI_PHYSICAL_ADDRESS MemoryAddress,
30 IN UINT64 MemoryLength,
31 IN UINT64 ValidMtrrAddressMask,
32 OUT UINT32 *UsedMsrNum,
33 OUT EFI_MEMORY_CACHE_TYPE *MemoryCacheType
34 );
35
44BOOLEAN
46 IN EFI_MEMORY_CACHE_TYPE MemoryCacheType
47 );
48
59UINT32
61 IN UINT64 BaseAddress,
62 IN UINT64 Size
63 );
64
65typedef struct {
66 UINT32 Msr;
67 UINT32 BaseAddress;
68 UINT32 Length;
70
71EFI_FIXED_MTRR mFixedMtrrTable[] = {
72 { EFI_MSR_IA32_MTRR_FIX64K_00000, 0, 0x10000 },
73 { EFI_MSR_IA32_MTRR_FIX16K_80000, 0x80000, 0x4000 },
74 { EFI_MSR_IA32_MTRR_FIX16K_A0000, 0xA0000, 0x4000 },
75 { EFI_MSR_IA32_MTRR_FIX4K_C0000, 0xC0000, 0x1000 },
76 { EFI_MSR_IA32_MTRR_FIX4K_C8000, 0xC8000, 0x1000 },
77 { EFI_MSR_IA32_MTRR_FIX4K_D0000, 0xD0000, 0x1000 },
78 { EFI_MSR_IA32_MTRR_FIX4K_D8000, 0xD8000, 0x1000 },
79 { EFI_MSR_IA32_MTRR_FIX4K_E0000, 0xE0000, 0x1000 },
80 { EFI_MSR_IA32_MTRR_FIX4K_E8000, 0xE8000, 0x1000 },
81 { EFI_MSR_IA32_MTRR_FIX4K_F0000, 0xF0000, 0x1000 },
82 { EFI_MSR_IA32_MTRR_FIX4K_F8000, 0xF8000, 0x1000 }
83};
84
95INT8
97 IN UINT64 Input
98 )
99{
100 return 0;
101}
102
109VOID
111 OUT UINT64 *OldMtrr
112 )
113{
114 UINT64 TempQword;
115
116 //
117 // Disable Cache MTRR
118 //
119 *OldMtrr = AsmReadMsr64 (EFI_MSR_CACHE_IA32_MTRR_DEF_TYPE);
120 TempQword = (*OldMtrr) & ~B_EFI_MSR_GLOBAL_MTRR_ENABLE & ~B_EFI_MSR_FIXED_MTRR_ENABLE;
121 AsmWriteMsr64 (EFI_MSR_CACHE_IA32_MTRR_DEF_TYPE, TempQword);
123}
124
132VOID
134 IN BOOLEAN EnableMtrr,
135 IN UINT64 OldMtrr
136 )
137{
138 UINT64 TempQword;
139
140 //
141 // Enable Cache MTRR
142 //
143 if (EnableMtrr) {
144 TempQword = AsmReadMsr64 (EFI_MSR_CACHE_IA32_MTRR_DEF_TYPE);
145 TempQword |= (UINT64)(B_EFI_MSR_GLOBAL_MTRR_ENABLE | B_EFI_MSR_FIXED_MTRR_ENABLE);
146 } else {
147 TempQword = OldMtrr;
148 }
149
150 AsmWriteMsr64 (EFI_MSR_CACHE_IA32_MTRR_DEF_TYPE, TempQword);
151
153}
154
165VOID
167 IN UINT32 MtrrNumber,
168 IN EFI_PHYSICAL_ADDRESS MemoryAddress,
169 IN UINT64 MemoryLength,
170 IN EFI_MEMORY_CACHE_TYPE MemoryCacheType,
171 IN UINT64 ValidMtrrAddressMask
172 )
173{
174 UINT64 TempQword;
175 UINT64 OldMtrr;
176
177 if (MemoryLength == 0) {
178 return;
179 }
180
181 EfiDisableCacheMtrr (&OldMtrr);
182
183 //
184 // MTRR Physical Base
185 //
186 TempQword = (MemoryAddress & ValidMtrrAddressMask) | MemoryCacheType;
187 AsmWriteMsr64 (MtrrNumber, TempQword);
188
189 //
190 // MTRR Physical Mask
191 //
192 TempQword = ~(MemoryLength - 1);
193 AsmWriteMsr64 (MtrrNumber + 1, (TempQword & ValidMtrrAddressMask) | B_EFI_MSR_CACHE_MTRR_VALID);
194
195 EfiRecoverCacheMtrr (TRUE, OldMtrr);
196}
197
207UINT64
209 IN UINT64 MemoryAddress,
210 IN UINT64 MemoryLength
211 )
212{
213 UINT64 Result;
214
215 if (MemoryLength == 0) {
216 return EFI_INVALID_PARAMETER;
217 }
218
219 //
220 // Compute initial power of 2 size to return
221 //
222 Result = GetPowerOfTwo64 (MemoryLength);
223
224 //
225 // Special case base of 0 as all ranges are valid
226 //
227 if (MemoryAddress == 0) {
228 return Result;
229 }
230
231 //
232 // Loop till a value that can be mapped to this base address is found
233 //
234 while (CheckMtrrAlignment (MemoryAddress, Result) != 0) {
235 //
236 // Need to try the next smaller power of 2
237 //
238 Result = RShiftU64 (Result, 1);
239 }
240
241 return Result;
242}
243
254UINT32
256 IN UINT64 BaseAddress,
257 IN UINT64 Size
258 )
259{
260 UINT32 ShiftedBase;
261 UINT32 ShiftedSize;
262
263 //
264 // Shift base and size right 12 bits to allow for larger memory sizes. The
265 // MTRRs do not use the first 12 bits so this is safe for now. Only supports
266 // up to 52 bits of physical address space.
267 //
268 ShiftedBase = (UINT32)RShiftU64 (BaseAddress, 12);
269 ShiftedSize = (UINT32)RShiftU64 (Size, 12);
270
271 //
272 // Return the results to the caller of the MOD
273 //
274 return ShiftedBase % ShiftedSize;
275}
276
291 IN EFI_MEMORY_CACHE_TYPE MemoryCacheType,
292 IN UINT64 *Base,
293 IN UINT64 *Len
294 )
295{
296 UINT32 MsrNum;
297 UINT32 ByteShift;
298 UINT64 TempQword;
299 UINT64 OrMask;
300 UINT64 ClearMask;
301
302 TempQword = 0;
303 OrMask = 0;
304 ClearMask = 0;
305
306 for (MsrNum = 0; MsrNum < V_EFI_FIXED_MTRR_NUMBER; MsrNum++) {
307 if ((*Base >= mFixedMtrrTable[MsrNum].BaseAddress) &&
308 (*Base < (mFixedMtrrTable[MsrNum].BaseAddress + 8 * mFixedMtrrTable[MsrNum].Length)))
309 {
310 break;
311 }
312 }
313
314 if (MsrNum == V_EFI_FIXED_MTRR_NUMBER ) {
315 return EFI_DEVICE_ERROR;
316 }
317
318 //
319 // We found the fixed MTRR to be programmed
320 //
321 for (ByteShift = 0; ByteShift < 8; ByteShift++) {
322 if ( *Base == (mFixedMtrrTable[MsrNum].BaseAddress + ByteShift * mFixedMtrrTable[MsrNum].Length)) {
323 break;
324 }
325 }
326
327 if (ByteShift == 8 ) {
328 return EFI_DEVICE_ERROR;
329 }
330
331 for ( ; ((ByteShift < 8) && (*Len >= mFixedMtrrTable[MsrNum].Length)); ByteShift++) {
332 OrMask |= LShiftU64 ((UINT64)MemoryCacheType, (UINT32)(ByteShift* 8));
333 ClearMask |= LShiftU64 ((UINT64)0xFF, (UINT32)(ByteShift * 8));
334 *Len -= mFixedMtrrTable[MsrNum].Length;
335 *Base += mFixedMtrrTable[MsrNum].Length;
336 }
337
338 TempQword = (AsmReadMsr64 (mFixedMtrrTable[MsrNum].Msr) & (~ClearMask)) | OrMask;
339 AsmWriteMsr64 (mFixedMtrrTable[MsrNum].Msr, TempQword);
340
341 return EFI_SUCCESS;
342}
343
353BOOLEAN
357 )
358{
359 return FALSE;
360}
361
376EFIAPI
378 IN EFI_PHYSICAL_ADDRESS MemoryAddress,
379 IN UINT64 MemoryLength,
380 IN EFI_MEMORY_CACHE_TYPE MemoryCacheType
381 )
382{
383 EFI_STATUS Status;
384 UINT32 MsrNum, MsrNumEnd;
385 UINT64 TempQword;
386 UINT32 LastVariableMtrrForBios;
387 UINT64 OldMtrr;
388 UINT32 UsedMsrNum;
389 EFI_MEMORY_CACHE_TYPE UsedMemoryCacheType;
390 UINT64 ValidMtrrAddressMask;
391 UINT32 Cpuid_RegEax;
392
393 AsmCpuid (CPUID_EXTENDED_FUNCTION, &Cpuid_RegEax, NULL, NULL, NULL);
394 if (Cpuid_RegEax >= CPUID_VIR_PHY_ADDRESS_SIZE) {
395 AsmCpuid (CPUID_VIR_PHY_ADDRESS_SIZE, &Cpuid_RegEax, NULL, NULL, NULL);
396 ValidMtrrAddressMask = (LShiftU64 ((UINT64)1, (Cpuid_RegEax & 0xFF)) - 1) & (~(UINT64)0x0FFF);
397 } else {
398 ValidMtrrAddressMask = (LShiftU64 ((UINT64)1, 36) - 1) & (~(UINT64)0x0FFF);
399 }
400
401 //
402 // Check for invalid parameter
403 //
404 if (((MemoryAddress & ~ValidMtrrAddressMask) != 0) || ((MemoryLength & ~ValidMtrrAddressMask) != 0)) {
405 return EFI_INVALID_PARAMETER;
406 }
407
408 if (MemoryLength == 0) {
409 return EFI_INVALID_PARAMETER;
410 }
411
412 switch (MemoryCacheType) {
413 case EFI_CACHE_UNCACHEABLE:
414 case EFI_CACHE_WRITECOMBINING:
415 case EFI_CACHE_WRITETHROUGH:
416 case EFI_CACHE_WRITEPROTECTED:
417 case EFI_CACHE_WRITEBACK:
418 break;
419
420 default:
421 return EFI_INVALID_PARAMETER;
422 }
423
424 //
425 // Check if Fixed MTRR
426 //
427 if ((MemoryAddress + MemoryLength) <= (1 << 20)) {
428 Status = EFI_SUCCESS;
429 EfiDisableCacheMtrr (&OldMtrr);
430 while ((MemoryLength > 0) && (Status == EFI_SUCCESS)) {
431 Status = ProgramFixedMtrr (MemoryCacheType, &MemoryAddress, &MemoryLength);
432 }
433
434 EfiRecoverCacheMtrr (TRUE, OldMtrr);
435 return Status;
436 }
437
438 //
439 // Search if the range attribute has been set before
440 //
441 Status = SearchForExactMtrr (
442 MemoryAddress,
443 MemoryLength,
444 ValidMtrrAddressMask,
445 &UsedMsrNum,
446 &UsedMemoryCacheType
447 );
448
449 if (!EFI_ERROR (Status)) {
450 //
451 // Compare if it has the same type as current setting
452 //
453 if (UsedMemoryCacheType == MemoryCacheType) {
454 return EFI_SUCCESS;
455 } else {
456 //
457 // Different type
458 //
459
460 //
461 // Check if the set type is the same as Default Type
462 //
463 if (IsDefaultType (MemoryCacheType)) {
464 //
465 // Clear the MTRR
466 //
467 AsmWriteMsr64 (UsedMsrNum, 0);
468 AsmWriteMsr64 (UsedMsrNum + 1, 0);
469
470 return EFI_SUCCESS;
471 } else {
472 //
473 // Modify the MTRR type
474 //
476 UsedMsrNum,
477 MemoryAddress,
478 MemoryLength,
479 MemoryCacheType,
480 ValidMtrrAddressMask
481 );
482 return EFI_SUCCESS;
483 }
484 }
485 }
486
487 #if 0
488 //
489 // @bug - Need to create memory map so that when checking for overlap we
490 // can determine if an overlap exists based on all caching requests.
491 //
492 // Don't waste a variable MTRR if the caching attrib is same as default in MTRR_DEF_TYPE
493 //
494 if (MemoryCacheType == (AsmReadMsr64 (EFI_MSR_CACHE_IA32_MTRR_DEF_TYPE) & B_EFI_MSR_CACHE_MEMORY_TYPE)) {
495 if (!CheckMtrrOverlap (MemoryAddress, MemoryAddress+MemoryLength-1)) {
496 return EFI_SUCCESS;
497 }
498 }
499
500 #endif
501
502 //
503 // Find first unused MTRR
504 //
505 MsrNumEnd = EFI_MSR_CACHE_VARIABLE_MTRR_BASE + (2 * (UINT32)(AsmReadMsr64 (EFI_MSR_IA32_MTRR_CAP) & B_EFI_MSR_IA32_MTRR_CAP_VARIABLE_SUPPORT));
506 for (MsrNum = EFI_MSR_CACHE_VARIABLE_MTRR_BASE; MsrNum < MsrNumEnd; MsrNum += 2) {
507 if ((AsmReadMsr64 (MsrNum+1) & B_EFI_MSR_CACHE_MTRR_VALID) == 0 ) {
508 break;
509 }
510 }
511
512 //
513 // Reserve 1 MTRR pair for OS.
514 //
515 LastVariableMtrrForBios = MsrNumEnd - 1 - (EFI_CACHE_NUM_VAR_MTRR_PAIRS_FOR_OS * 2);
516 if (MsrNum > LastVariableMtrrForBios) {
517 return EFI_LOAD_ERROR;
518 }
519
520 //
521 // Special case for 1 MB base address
522 //
523 if (MemoryAddress == BASE_1MB) {
524 MemoryAddress = 0;
525 }
526
527 //
528 // Program MTRRs
529 //
530 TempQword = MemoryLength;
531
532 if (TempQword == Power2MaxMemory (MemoryAddress, TempQword)) {
534 MsrNum,
535 MemoryAddress,
536 MemoryLength,
537 MemoryCacheType,
538 ValidMtrrAddressMask
539 );
540 } else {
541 //
542 // Fill in MTRRs with values. Direction can not be checked for this method
543 // as we are using WB as the default cache type and only setting areas to UC.
544 //
545 do {
546 //
547 // Do boundary check so we don't go past last MTRR register
548 // for BIOS use. Leave one MTRR pair for OS use.
549 //
550 if (MsrNum > LastVariableMtrrForBios) {
551 return EFI_LOAD_ERROR;
552 }
553
554 //
555 // Set next power of 2 region
556 //
557 MemoryLength = Power2MaxMemory (MemoryAddress, TempQword);
559 MsrNum,
560 MemoryAddress,
561 MemoryLength,
562 MemoryCacheType,
563 ValidMtrrAddressMask
564 );
565 MemoryAddress += MemoryLength;
566 TempQword -= MemoryLength;
567 MsrNum += 2;
568 } while (TempQword != 0);
569 }
570
571 return EFI_SUCCESS;
572}
573
581EFIAPI
583 VOID
584 )
585{
586 UINT32 MsrNum, MsrNumEnd;
587 UINT16 Index;
588 UINT64 OldMtrr;
589 UINT64 CacheType;
590 BOOLEAN DisableCar;
591
592 Index = 0;
593 DisableCar = TRUE;
594
595 //
596 // Determine default cache type
597 //
598 CacheType = EFI_CACHE_UNCACHEABLE;
599
600 //
601 // Set default cache type
602 //
603 AsmWriteMsr64 (EFI_MSR_CACHE_IA32_MTRR_DEF_TYPE, CacheType);
604
605 //
606 // Disable CAR
607 //
608 DisableCacheAsRam (DisableCar);
609
610 EfiDisableCacheMtrr (&OldMtrr);
611
612 //
613 // Reset Fixed MTRRs
614 //
615 for (Index = 0; Index < V_EFI_FIXED_MTRR_NUMBER; Index++) {
616 AsmWriteMsr64 (mFixedMtrrTable[Index].Msr, 0);
617 }
618
619 //
620 // Reset Variable MTRRs
621 //
622 MsrNumEnd = EFI_MSR_CACHE_VARIABLE_MTRR_BASE + (2 * (UINT32)(AsmReadMsr64 (EFI_MSR_IA32_MTRR_CAP) & B_EFI_MSR_IA32_MTRR_CAP_VARIABLE_SUPPORT));
623 for (MsrNum = EFI_MSR_CACHE_VARIABLE_MTRR_BASE; MsrNum < MsrNumEnd; MsrNum++) {
624 AsmWriteMsr64 (MsrNum, 0);
625 }
626
627 //
628 // Enable Fixed and Variable MTRRs
629 //
630 EfiRecoverCacheMtrr (TRUE, OldMtrr);
631
632 return EFI_SUCCESS;
633}
634
650 IN EFI_PHYSICAL_ADDRESS MemoryAddress,
651 IN UINT64 MemoryLength,
652 IN UINT64 ValidMtrrAddressMask,
653 OUT UINT32 *UsedMsrNum,
654 OUT EFI_MEMORY_CACHE_TYPE *UsedMemoryCacheType
655 )
656{
657 UINT32 MsrNum, MsrNumEnd;
658 UINT64 TempQword;
659
660 if (MemoryLength == 0) {
661 return EFI_INVALID_PARAMETER;
662 }
663
664 MsrNumEnd = EFI_MSR_CACHE_VARIABLE_MTRR_BASE + (2 * (UINT32)(AsmReadMsr64 (EFI_MSR_IA32_MTRR_CAP) & B_EFI_MSR_IA32_MTRR_CAP_VARIABLE_SUPPORT));
665 for (MsrNum = EFI_MSR_CACHE_VARIABLE_MTRR_BASE; MsrNum < MsrNumEnd; MsrNum += 2) {
666 TempQword = AsmReadMsr64 (MsrNum+1);
667 if ((TempQword & B_EFI_MSR_CACHE_MTRR_VALID) == 0) {
668 continue;
669 }
670
671 if ((TempQword & ValidMtrrAddressMask) != ((~(MemoryLength - 1)) & ValidMtrrAddressMask)) {
672 continue;
673 }
674
675 TempQword = AsmReadMsr64 (MsrNum);
676 if ((TempQword & ValidMtrrAddressMask) != (MemoryAddress & ValidMtrrAddressMask)) {
677 continue;
678 }
679
680 *UsedMemoryCacheType = (EFI_MEMORY_CACHE_TYPE)(TempQword & B_EFI_MSR_CACHE_MEMORY_TYPE);
681 *UsedMsrNum = MsrNum;
682
683 return EFI_SUCCESS;
684 }
685
686 return EFI_NOT_FOUND;
687}
688
697BOOLEAN
699 IN EFI_MEMORY_CACHE_TYPE MemoryCacheType
700 )
701{
702 if ((AsmReadMsr64 (EFI_MSR_CACHE_IA32_MTRR_DEF_TYPE) & B_EFI_MSR_CACHE_MEMORY_TYPE) != MemoryCacheType) {
703 return FALSE;
704 }
705
706 return TRUE;
707}
UINT64 EFIAPI RShiftU64(IN UINT64 Operand, IN UINTN Count)
Definition: RShiftU64.c:28
UINT64 EFIAPI GetPowerOfTwo64(IN UINT64 Operand)
UINT64 EFIAPI LShiftU64(IN UINT64 Operand, IN UINTN Count)
Definition: LShiftU64.c:28
VOID EFIAPI DisableCacheAsRam(IN BOOLEAN DisableCar)
EFI_STATUS EFIAPI SetCacheAttributes(IN EFI_PHYSICAL_ADDRESS MemoryAddress, IN UINT64 MemoryLength, IN EFI_MEMORY_CACHE_TYPE MemoryCacheType)
Definition: CacheLib.c:377
VOID EfiDisableCacheMtrr(OUT UINT64 *OldMtrr)
Definition: CacheLib.c:110
EFI_STATUS EFIAPI ResetCacheAttributes(VOID)
Definition: CacheLib.c:582
VOID EfiProgramMtrr(IN UINT32 MtrrNumber, IN EFI_PHYSICAL_ADDRESS MemoryAddress, IN UINT64 MemoryLength, IN EFI_MEMORY_CACHE_TYPE MemoryCacheType, IN UINT64 ValidMtrrAddressMask)
Definition: CacheLib.c:166
UINT32 CheckMtrrAlignment(IN UINT64 BaseAddress, IN UINT64 Size)
Definition: CacheLib.c:255
EFI_STATUS SearchForExactMtrr(IN EFI_PHYSICAL_ADDRESS MemoryAddress, IN UINT64 MemoryLength, IN UINT64 ValidMtrrAddressMask, OUT UINT32 *UsedMsrNum, OUT EFI_MEMORY_CACHE_TYPE *MemoryCacheType)
Definition: CacheLib.c:649
BOOLEAN CheckMtrrOverlap(IN EFI_PHYSICAL_ADDRESS Start, IN EFI_PHYSICAL_ADDRESS End)
Definition: CacheLib.c:354
INT8 CheckDirection(IN UINT64 Input)
Definition: CacheLib.c:96
BOOLEAN IsDefaultType(IN EFI_MEMORY_CACHE_TYPE MemoryCacheType)
Definition: CacheLib.c:698
EFI_STATUS ProgramFixedMtrr(IN EFI_MEMORY_CACHE_TYPE MemoryCacheType, IN UINT64 *Base, IN UINT64 *Len)
Definition: CacheLib.c:290
VOID EfiRecoverCacheMtrr(IN BOOLEAN EnableMtrr, IN UINT64 OldMtrr)
Definition: CacheLib.c:133
UINT64 Power2MaxMemory(IN UINT64 MemoryAddress, IN UINT64 MemoryLength)
Definition: CacheLib.c:208
VOID EFIAPI AsmDisableCache(VOID)
Definition: DisableCache.c:18
VOID EFIAPI Input(IN CHAR16 *Prompt OPTIONAL, OUT CHAR16 *InStr, IN UINTN StrLen)
Definition: EdbSupportUI.c:187
VOID EFIAPI AsmEnableCache(VOID)
Definition: EnableCache.c:18
UINT64 EFIAPI AsmReadMsr64(IN UINT32 Index)
Definition: GccInlinePriv.c:60
UINT64 EFIAPI AsmWriteMsr64(IN UINT32 Index, IN UINT64 Value)
#define NULL
Definition: Base.h:319
#define TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
#define IN
Definition: Base.h:279
#define OUT
Definition: Base.h:284
UINT32 EFIAPI AsmCpuid(IN UINT32 Index, OUT UINT32 *RegisterEax OPTIONAL, OUT UINT32 *RegisterEbx OPTIONAL, OUT UINT32 *RegisterEcx OPTIONAL, OUT UINT32 *RegisterEdx OPTIONAL)
Definition: CpuId.c:36
UINT64 EFI_PHYSICAL_ADDRESS
Definition: UefiBaseType.h:50
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
#define EFI_SUCCESS
Definition: UefiBaseType.h:112