]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - IntelFspPkg/Library/BaseCacheLib/CacheLib.c
Replace SetPower2 by EDKII baselib - GetPowerOfTwo64.
[mirror_edk2.git] / IntelFspPkg / Library / BaseCacheLib / CacheLib.c
... / ...
CommitLineData
1/** @file\r
2\r
3 Copyright (c) 2014 - 2015, Intel Corporation. All rights reserved.<BR>\r
4 This program and the accompanying materials\r
5 are licensed and made available under the terms and conditions of the BSD License\r
6 which accompanies this distribution. The full text of the license may be found at\r
7 http://opensource.org/licenses/bsd-license.php.\r
8\r
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
11\r
12**/\r
13\r
14#include <Uefi.h>\r
15#include <Library/BaseLib.h>\r
16#include <Library/CacheLib.h>\r
17#include <Library/CacheAsRamLib.h>\r
18#include "CacheLibInternal.h"\r
19\r
20/**\r
21 Search the memory cache type for specific memory from MTRR.\r
22\r
23 @param[in] MemoryAddress the address of target memory\r
24 @param[in] MemoryLength the length of target memory\r
25 @param[in] ValidMtrrAddressMask the MTRR address mask\r
26 @param[out] UsedMsrNum the used MSR number\r
27 @param[out] UsedMemoryCacheType the cache type for the target memory\r
28\r
29 @retval EFI_SUCCESS The memory is found in MTRR and cache type is returned\r
30 @retval EFI_NOT_FOUND The memory is not found in MTRR\r
31\r
32**/\r
33EFI_STATUS\r
34SearchForExactMtrr (\r
35 IN EFI_PHYSICAL_ADDRESS MemoryAddress,\r
36 IN UINT64 MemoryLength,\r
37 IN UINT64 ValidMtrrAddressMask,\r
38 OUT UINT32 *UsedMsrNum,\r
39 OUT EFI_MEMORY_CACHE_TYPE *MemoryCacheType\r
40 );\r
41\r
42/**\r
43 Check if CacheType match current default setting.\r
44\r
45 @param[in] MemoryCacheType input cache type to be checked.\r
46\r
47 @retval TRUE MemoryCacheType is default MTRR setting.\r
48 @retval TRUE MemoryCacheType is NOT default MTRR setting.\r
49**/\r
50BOOLEAN\r
51IsDefaultType (\r
52 IN EFI_MEMORY_CACHE_TYPE MemoryCacheType\r
53 );\r
54\r
55/**\r
56 Return MTRR alignment requirement for base address and size.\r
57\r
58 @param[in] BaseAddress Base address.\r
59 @param[in] Size Size.\r
60\r
61 @retval Zero Alligned.\r
62 @retval Non-Zero Not alligned.\r
63\r
64**/\r
65UINT32\r
66CheckMtrrAlignment (\r
67 IN UINT64 BaseAddress,\r
68 IN UINT64 Size\r
69 );\r
70\r
71typedef struct {\r
72 UINT32 Msr;\r
73 UINT32 BaseAddress;\r
74 UINT32 Length;\r
75} EFI_FIXED_MTRR;\r
76\r
77EFI_FIXED_MTRR mFixedMtrrTable[] = {\r
78 { EFI_MSR_IA32_MTRR_FIX64K_00000, 0, 0x10000},\r
79 { EFI_MSR_IA32_MTRR_FIX16K_80000, 0x80000, 0x4000},\r
80 { EFI_MSR_IA32_MTRR_FIX16K_A0000, 0xA0000, 0x4000},\r
81 { EFI_MSR_IA32_MTRR_FIX4K_C0000, 0xC0000, 0x1000},\r
82 { EFI_MSR_IA32_MTRR_FIX4K_C8000, 0xC8000, 0x1000},\r
83 { EFI_MSR_IA32_MTRR_FIX4K_D0000, 0xD0000, 0x1000},\r
84 { EFI_MSR_IA32_MTRR_FIX4K_D8000, 0xD8000, 0x1000},\r
85 { EFI_MSR_IA32_MTRR_FIX4K_E0000, 0xE0000, 0x1000},\r
86 { EFI_MSR_IA32_MTRR_FIX4K_E8000, 0xE8000, 0x1000},\r
87 { EFI_MSR_IA32_MTRR_FIX4K_F0000, 0xF0000, 0x1000},\r
88 { EFI_MSR_IA32_MTRR_FIX4K_F8000, 0xF8000, 0x1000}\r
89};\r
90\r
91/**\r
92 Given the input, check if the number of MTRR is lesser.\r
93 if positive or subtractive.\r
94\r
95 @param[in] Input Length of Memory to program MTRR.\r
96\r
97 @retval Zero do positive.\r
98 @retval Non-Zero do subtractive.\r
99\r
100**/\r
101INT8\r
102CheckDirection (\r
103 IN UINT64 Input\r
104 )\r
105{\r
106 return 0;\r
107}\r
108\r
109/**\r
110 Disable cache and its mtrr.\r
111\r
112 @param[out] OldMtrr To return the Old MTRR value\r
113\r
114**/\r
115VOID\r
116EfiDisableCacheMtrr (\r
117 OUT UINT64 *OldMtrr\r
118 )\r
119{\r
120 UINT64 TempQword;\r
121\r
122 //\r
123 // Disable Cache MTRR\r
124 //\r
125 *OldMtrr = AsmReadMsr64(EFI_MSR_CACHE_IA32_MTRR_DEF_TYPE);\r
126 TempQword = (*OldMtrr) & ~B_EFI_MSR_GLOBAL_MTRR_ENABLE & ~B_EFI_MSR_FIXED_MTRR_ENABLE;\r
127 AsmWriteMsr64(EFI_MSR_CACHE_IA32_MTRR_DEF_TYPE, TempQword);\r
128 AsmDisableCache ();\r
129}\r
130\r
131/**\r
132 Recover cache MTRR.\r
133\r
134 @param[in] EnableMtrr Whether to enable the MTRR\r
135 @param[in] OldMtrr The saved old MTRR value to restore when not to enable the MTRR\r
136\r
137**/\r
138VOID\r
139EfiRecoverCacheMtrr (\r
140 IN BOOLEAN EnableMtrr,\r
141 IN UINT64 OldMtrr\r
142 )\r
143{\r
144 UINT64 TempQword;\r
145\r
146 //\r
147 // Enable Cache MTRR\r
148 //\r
149 if (EnableMtrr) {\r
150 TempQword = AsmReadMsr64(EFI_MSR_CACHE_IA32_MTRR_DEF_TYPE);\r
151 TempQword |= (UINT64)(B_EFI_MSR_GLOBAL_MTRR_ENABLE | B_EFI_MSR_FIXED_MTRR_ENABLE);\r
152 } else {\r
153 TempQword = OldMtrr;\r
154 }\r
155\r
156 AsmWriteMsr64 (EFI_MSR_CACHE_IA32_MTRR_DEF_TYPE, TempQword);\r
157\r
158 AsmEnableCache ();\r
159}\r
160\r
161/**\r
162 Programming MTRR according to Memory address, length, and type.\r
163\r
164 @param[in] MtrrNumber the variable MTRR index number\r
165 @param[in] MemoryAddress the address of target memory\r
166 @param[in] MemoryLength the length of target memory\r
167 @param[in] MemoryCacheType the cache type of target memory\r
168 @param[in] ValidMtrrAddressMask the MTRR address mask\r
169\r
170**/\r
171VOID\r
172EfiProgramMtrr (\r
173 IN UINTN MtrrNumber,\r
174 IN EFI_PHYSICAL_ADDRESS MemoryAddress,\r
175 IN UINT64 MemoryLength,\r
176 IN EFI_MEMORY_CACHE_TYPE MemoryCacheType,\r
177 IN UINT64 ValidMtrrAddressMask\r
178 )\r
179{\r
180 UINT64 TempQword;\r
181 UINT64 OldMtrr;\r
182\r
183 if (MemoryLength == 0) {\r
184 return;\r
185 }\r
186\r
187 EfiDisableCacheMtrr (&OldMtrr);\r
188\r
189 //\r
190 // MTRR Physical Base\r
191 //\r
192 TempQword = (MemoryAddress & ValidMtrrAddressMask) | MemoryCacheType;\r
193 AsmWriteMsr64 (MtrrNumber, TempQword);\r
194\r
195 //\r
196 // MTRR Physical Mask\r
197 //\r
198 TempQword = ~(MemoryLength - 1);\r
199 AsmWriteMsr64 (MtrrNumber + 1, (TempQword & ValidMtrrAddressMask) | B_EFI_MSR_CACHE_MTRR_VALID);\r
200\r
201 EfiRecoverCacheMtrr (TRUE, OldMtrr);\r
202}\r
203\r
204/**\r
205 Calculate the maximum value which is a power of 2, but less the MemoryLength.\r
206\r
207 @param[in] MemoryAddress Memory address.\r
208 @param[in] MemoryLength The number to pass in.\r
209\r
210 @return The maximum value which is align to power of 2 and less the MemoryLength\r
211\r
212**/\r
213UINT64\r
214Power2MaxMemory (\r
215 IN UINT64 MemoryAddress,\r
216 IN UINT64 MemoryLength\r
217 )\r
218{\r
219 UINT64 Result;\r
220\r
221 if (MemoryLength == 0) {\r
222 return EFI_INVALID_PARAMETER;\r
223 }\r
224\r
225 //\r
226 // Compute inital power of 2 size to return\r
227 //\r
228 Result = GetPowerOfTwo64(MemoryLength);\r
229\r
230 //\r
231 // Special case base of 0 as all ranges are valid\r
232 //\r
233 if (MemoryAddress == 0) {\r
234 return Result;\r
235 }\r
236\r
237 //\r
238 // Loop till a value that can be mapped to this base address is found\r
239 //\r
240 while (CheckMtrrAlignment (MemoryAddress, Result) != 0) {\r
241 //\r
242 // Need to try the next smaller power of 2\r
243 //\r
244 Result = RShiftU64 (Result, 1);\r
245 }\r
246\r
247 return Result;\r
248}\r
249\r
250/**\r
251 Return MTRR alignment requirement for base address and size.\r
252\r
253 @param[in] BaseAddress Base address.\r
254 @param[in] Size Size.\r
255\r
256 @retval Zero Alligned.\r
257 @retval Non-Zero Not alligned.\r
258\r
259**/\r
260UINT32\r
261CheckMtrrAlignment (\r
262 IN UINT64 BaseAddress,\r
263 IN UINT64 Size\r
264 )\r
265{\r
266 UINT32 ShiftedBase;\r
267 UINT32 ShiftedSize;\r
268\r
269 //\r
270 // Shift base and size right 12 bits to allow for larger memory sizes. The\r
271 // MTRRs do not use the first 12 bits so this is safe for now. Only supports\r
272 // up to 52 bits of physical address space.\r
273 //\r
274 ShiftedBase = (UINT32) RShiftU64 (BaseAddress, 12);\r
275 ShiftedSize = (UINT32) RShiftU64 (Size, 12);\r
276\r
277 //\r
278 // Return the results to the caller of the MOD\r
279 //\r
280 return ShiftedBase % ShiftedSize;\r
281}\r
282\r
283/**\r
284 Programs fixed MTRRs registers.\r
285\r
286 @param[in] MemoryCacheType The memory type to set.\r
287 @param[in] Base The base address of memory range.\r
288 @param[in] Length The length of memory range.\r
289\r
290 @retval RETURN_SUCCESS The cache type was updated successfully\r
291 @retval RETURN_UNSUPPORTED The requested range or cache type was invalid\r
292 for the fixed MTRRs.\r
293\r
294**/\r
295EFI_STATUS\r
296ProgramFixedMtrr (\r
297 IN EFI_MEMORY_CACHE_TYPE MemoryCacheType,\r
298 IN UINT64 *Base,\r
299 IN UINT64 *Len\r
300 )\r
301{\r
302 UINT32 MsrNum;\r
303 UINT32 ByteShift;\r
304 UINT64 TempQword;\r
305 UINT64 OrMask;\r
306 UINT64 ClearMask;\r
307\r
308 TempQword = 0;\r
309 OrMask = 0;\r
310 ClearMask = 0;\r
311\r
312 for (MsrNum = 0; MsrNum < V_EFI_FIXED_MTRR_NUMBER; MsrNum++) {\r
313 if ((*Base >= mFixedMtrrTable[MsrNum].BaseAddress) &&\r
314 (*Base < (mFixedMtrrTable[MsrNum].BaseAddress + 8 * mFixedMtrrTable[MsrNum].Length))) {\r
315 break;\r
316 }\r
317 }\r
318 if (MsrNum == V_EFI_FIXED_MTRR_NUMBER ) {\r
319 return EFI_DEVICE_ERROR;\r
320 }\r
321 //\r
322 // We found the fixed MTRR to be programmed\r
323 //\r
324 for (ByteShift=0; ByteShift < 8; ByteShift++) {\r
325 if ( *Base == (mFixedMtrrTable[MsrNum].BaseAddress + ByteShift * mFixedMtrrTable[MsrNum].Length)) {\r
326 break;\r
327 }\r
328 }\r
329 if (ByteShift == 8 ) {\r
330 return EFI_DEVICE_ERROR;\r
331 }\r
332 for (; ((ByteShift<8) && (*Len >= mFixedMtrrTable[MsrNum].Length));ByteShift++) {\r
333 OrMask |= LShiftU64((UINT64) MemoryCacheType, (UINT32) (ByteShift* 8));\r
334 ClearMask |= LShiftU64((UINT64) 0xFF, (UINT32) (ByteShift * 8));\r
335 *Len -= mFixedMtrrTable[MsrNum].Length;\r
336 *Base += mFixedMtrrTable[MsrNum].Length;\r
337 }\r
338 TempQword = (AsmReadMsr64 (mFixedMtrrTable[MsrNum].Msr) & (~ClearMask)) | OrMask;\r
339 AsmWriteMsr64 (mFixedMtrrTable[MsrNum].Msr, TempQword);\r
340\r
341 return EFI_SUCCESS;\r
342}\r
343\r
344/**\r
345 Check if there is a valid variable MTRR that overlaps the given range.\r
346\r
347 @param[in] Start Base Address of the range to check.\r
348 @param[in] End End address of the range to check.\r
349\r
350 @retval TRUE Mtrr overlap.\r
351 @retval FALSE Mtrr not overlap.\r
352**/\r
353BOOLEAN\r
354CheckMtrrOverlap (\r
355 IN EFI_PHYSICAL_ADDRESS Start,\r
356 IN EFI_PHYSICAL_ADDRESS End\r
357 )\r
358{\r
359 return FALSE;\r
360}\r
361\r
362/**\r
363 Given the memory range and cache type, programs the MTRRs.\r
364\r
365 @param[in] MemoryAddress Base Address of Memory to program MTRR.\r
366 @param[in] MemoryLength Length of Memory to program MTRR.\r
367 @param[in] MemoryCacheType Cache Type.\r
368\r
369 @retval EFI_SUCCESS Mtrr are set successfully.\r
370 @retval EFI_LOAD_ERROR No empty MTRRs to use.\r
371 @retval EFI_INVALID_PARAMETER The input parameter is not valid.\r
372 @retval others An error occurs when setting MTTR.\r
373\r
374**/\r
375EFI_STATUS\r
376EFIAPI\r
377SetCacheAttributes (\r
378 IN EFI_PHYSICAL_ADDRESS MemoryAddress,\r
379 IN UINT64 MemoryLength,\r
380 IN EFI_MEMORY_CACHE_TYPE MemoryCacheType\r
381 )\r
382{\r
383 EFI_STATUS Status;\r
384 UINT32 MsrNum, MsrNumEnd;\r
385 UINT64 TempQword;\r
386 UINT32 LastVariableMtrrForBios;\r
387 UINT64 OldMtrr;\r
388 UINT32 UsedMsrNum;\r
389 EFI_MEMORY_CACHE_TYPE UsedMemoryCacheType;\r
390 UINT64 ValidMtrrAddressMask;\r
391 UINT32 Cpuid_RegEax;\r
392\r
393 AsmCpuid (CPUID_EXTENDED_FUNCTION, &Cpuid_RegEax, NULL, NULL, NULL);\r
394 if (Cpuid_RegEax >= CPUID_VIR_PHY_ADDRESS_SIZE) {\r
395 AsmCpuid (CPUID_VIR_PHY_ADDRESS_SIZE, &Cpuid_RegEax, NULL, NULL, NULL);\r
396 ValidMtrrAddressMask = (LShiftU64((UINT64) 1, (Cpuid_RegEax & 0xFF)) - 1) & (~(UINT64)0x0FFF);\r
397 } else {\r
398 ValidMtrrAddressMask = (LShiftU64((UINT64) 1, 36) - 1) & (~(UINT64)0x0FFF);\r
399 }\r
400\r
401 //\r
402 // Check for invalid parameter\r
403 //\r
404 if ((MemoryAddress & ~ValidMtrrAddressMask) != 0 || (MemoryLength & ~ValidMtrrAddressMask) != 0) {\r
405 return EFI_INVALID_PARAMETER;\r
406 }\r
407\r
408 if (MemoryLength == 0) {\r
409 return EFI_INVALID_PARAMETER;\r
410 }\r
411\r
412 switch (MemoryCacheType) {\r
413 case EFI_CACHE_UNCACHEABLE:\r
414 case EFI_CACHE_WRITECOMBINING:\r
415 case EFI_CACHE_WRITETHROUGH:\r
416 case EFI_CACHE_WRITEPROTECTED:\r
417 case EFI_CACHE_WRITEBACK:\r
418 break;\r
419\r
420 default:\r
421 return EFI_INVALID_PARAMETER;\r
422 }\r
423\r
424 //\r
425 // Check if Fixed MTRR\r
426 //\r
427 if ((MemoryAddress + MemoryLength) <= (1 << 20)) {\r
428 Status = EFI_SUCCESS;\r
429 EfiDisableCacheMtrr (&OldMtrr);\r
430 while ((MemoryLength > 0) && (Status == EFI_SUCCESS)) {\r
431 Status = ProgramFixedMtrr (MemoryCacheType, &MemoryAddress, &MemoryLength);\r
432 }\r
433 EfiRecoverCacheMtrr (TRUE, OldMtrr);\r
434 return Status;\r
435 }\r
436\r
437 //\r
438 // Search if the range attribute has been set before\r
439 //\r
440 Status = SearchForExactMtrr(\r
441 MemoryAddress,\r
442 MemoryLength,\r
443 ValidMtrrAddressMask,\r
444 &UsedMsrNum,\r
445 &UsedMemoryCacheType\r
446 );\r
447\r
448 if (!EFI_ERROR(Status)) {\r
449 //\r
450 // Compare if it has the same type as current setting\r
451 //\r
452 if (UsedMemoryCacheType == MemoryCacheType) {\r
453 return EFI_SUCCESS;\r
454 } else {\r
455 //\r
456 // Different type\r
457 //\r
458\r
459 //\r
460 // Check if the set type is the same as Default Type\r
461 //\r
462 if (IsDefaultType(MemoryCacheType)) {\r
463 //\r
464 // Clear the MTRR\r
465 //\r
466 AsmWriteMsr64(UsedMsrNum, 0);\r
467 AsmWriteMsr64(UsedMsrNum + 1, 0);\r
468\r
469 return EFI_SUCCESS;\r
470 } else {\r
471 //\r
472 // Modify the MTRR type\r
473 //\r
474 EfiProgramMtrr(UsedMsrNum,\r
475 MemoryAddress,\r
476 MemoryLength,\r
477 MemoryCacheType,\r
478 ValidMtrrAddressMask\r
479 );\r
480 return EFI_SUCCESS;\r
481 }\r
482 }\r
483 }\r
484\r
485#if 0\r
486 //\r
487 // @bug - Need to create memory map so that when checking for overlap we\r
488 // can determine if an overlap exists based on all caching requests.\r
489 //\r
490 // Don't waste a variable MTRR if the caching attrib is same as default in MTRR_DEF_TYPE\r
491 //\r
492 if (MemoryCacheType == (AsmReadMsr64(EFI_MSR_CACHE_IA32_MTRR_DEF_TYPE) & B_EFI_MSR_CACHE_MEMORY_TYPE)) {\r
493 if (!CheckMtrrOverlap (MemoryAddress, MemoryAddress+MemoryLength-1)) {\r
494 return EFI_SUCCESS;\r
495 }\r
496 }\r
497#endif\r
498\r
499 //\r
500 // Find first unused MTRR\r
501 //\r
502 MsrNumEnd = EFI_MSR_CACHE_VARIABLE_MTRR_BASE + (2 * (UINT32)(AsmReadMsr64(EFI_MSR_IA32_MTRR_CAP) & B_EFI_MSR_IA32_MTRR_CAP_VARIABLE_SUPPORT));\r
503 for (MsrNum = EFI_MSR_CACHE_VARIABLE_MTRR_BASE; MsrNum < MsrNumEnd; MsrNum +=2) {\r
504 if ((AsmReadMsr64(MsrNum+1) & B_EFI_MSR_CACHE_MTRR_VALID) == 0 ) {\r
505 break;\r
506 }\r
507 }\r
508\r
509 //\r
510 // Reserve 1 MTRR pair for OS.\r
511 //\r
512 LastVariableMtrrForBios = MsrNumEnd - 1 - (EFI_CACHE_NUM_VAR_MTRR_PAIRS_FOR_OS * 2);\r
513 if (MsrNum > LastVariableMtrrForBios) {\r
514 return EFI_LOAD_ERROR;\r
515 }\r
516\r
517 //\r
518 // Special case for 1 MB base address\r
519 //\r
520 if (MemoryAddress == BASE_1MB) {\r
521 MemoryAddress = 0;\r
522 }\r
523\r
524 //\r
525 // Program MTRRs\r
526 //\r
527 TempQword = MemoryLength;\r
528\r
529 if (TempQword == Power2MaxMemory(MemoryAddress, TempQword)) {\r
530 EfiProgramMtrr(MsrNum,\r
531 MemoryAddress,\r
532 MemoryLength,\r
533 MemoryCacheType,\r
534 ValidMtrrAddressMask\r
535 );\r
536\r
537 } else {\r
538 //\r
539 // Fill in MTRRs with values. Direction can not be checked for this method\r
540 // as we are using WB as the default cache type and only setting areas to UC.\r
541 //\r
542 do {\r
543 //\r
544 // Do boundary check so we don't go past last MTRR register\r
545 // for BIOS use. Leave one MTRR pair for OS use.\r
546 //\r
547 if (MsrNum > LastVariableMtrrForBios) {\r
548 return EFI_LOAD_ERROR;\r
549 }\r
550\r
551 //\r
552 // Set next power of 2 region\r
553 //\r
554 MemoryLength = Power2MaxMemory(MemoryAddress, TempQword);\r
555 EfiProgramMtrr(MsrNum,\r
556 MemoryAddress,\r
557 MemoryLength,\r
558 MemoryCacheType,\r
559 ValidMtrrAddressMask\r
560 );\r
561 MemoryAddress += MemoryLength;\r
562 TempQword -= MemoryLength;\r
563 MsrNum += 2;\r
564 } while (TempQword != 0);\r
565 }\r
566\r
567 return EFI_SUCCESS;\r
568}\r
569\r
570/**\r
571 Reset all the MTRRs to a known state.\r
572\r
573 @retval EFI_SUCCESS All MTRRs have been reset successfully.\r
574\r
575**/\r
576EFI_STATUS\r
577EFIAPI\r
578ResetCacheAttributes (\r
579 VOID\r
580 )\r
581{\r
582 UINT32 MsrNum, MsrNumEnd;\r
583 UINT16 Index;\r
584 UINT64 OldMtrr;\r
585 UINT64 CacheType;\r
586 BOOLEAN DisableCar;\r
587 Index = 0;\r
588 DisableCar = TRUE;\r
589\r
590 //\r
591 // Determine default cache type\r
592 //\r
593 CacheType = EFI_CACHE_UNCACHEABLE;\r
594\r
595 //\r
596 // Set default cache type\r
597 //\r
598 AsmWriteMsr64(EFI_MSR_CACHE_IA32_MTRR_DEF_TYPE, CacheType);\r
599\r
600 //\r
601 // Disable CAR\r
602 //\r
603 DisableCacheAsRam (DisableCar);\r
604\r
605 EfiDisableCacheMtrr (&OldMtrr);\r
606\r
607 //\r
608 // Reset Fixed MTRRs\r
609 //\r
610 for (Index = 0; Index < V_EFI_FIXED_MTRR_NUMBER; Index++) {\r
611 AsmWriteMsr64 (mFixedMtrrTable[Index].Msr, 0);\r
612 }\r
613\r
614 //\r
615 // Reset Variable MTRRs\r
616 //\r
617 MsrNumEnd = EFI_MSR_CACHE_VARIABLE_MTRR_BASE + (2 * (UINT32)(AsmReadMsr64(EFI_MSR_IA32_MTRR_CAP) & B_EFI_MSR_IA32_MTRR_CAP_VARIABLE_SUPPORT));\r
618 for (MsrNum = EFI_MSR_CACHE_VARIABLE_MTRR_BASE; MsrNum < MsrNumEnd; MsrNum++) {\r
619 AsmWriteMsr64 (MsrNum, 0);\r
620 }\r
621\r
622 //\r
623 // Enable Fixed and Variable MTRRs\r
624 //\r
625 EfiRecoverCacheMtrr (TRUE, OldMtrr);\r
626\r
627 return EFI_SUCCESS;\r
628}\r
629\r
630/**\r
631 Search the memory cache type for specific memory from MTRR.\r
632\r
633 @param[in] MemoryAddress the address of target memory\r
634 @param[in] MemoryLength the length of target memory\r
635 @param[in] ValidMtrrAddressMask the MTRR address mask\r
636 @param[out] UsedMsrNum the used MSR number\r
637 @param[out] UsedMemoryCacheType the cache type for the target memory\r
638\r
639 @retval EFI_SUCCESS The memory is found in MTRR and cache type is returned\r
640 @retval EFI_NOT_FOUND The memory is not found in MTRR\r
641\r
642**/\r
643EFI_STATUS\r
644SearchForExactMtrr (\r
645 IN EFI_PHYSICAL_ADDRESS MemoryAddress,\r
646 IN UINT64 MemoryLength,\r
647 IN UINT64 ValidMtrrAddressMask,\r
648 OUT UINT32 *UsedMsrNum,\r
649 OUT EFI_MEMORY_CACHE_TYPE *UsedMemoryCacheType\r
650 )\r
651{\r
652 UINT32 MsrNum, MsrNumEnd;\r
653 UINT64 TempQword;\r
654\r
655 if (MemoryLength == 0) {\r
656 return EFI_INVALID_PARAMETER;\r
657 }\r
658\r
659 MsrNumEnd = EFI_MSR_CACHE_VARIABLE_MTRR_BASE + (2 * (UINT32)(AsmReadMsr64(EFI_MSR_IA32_MTRR_CAP) & B_EFI_MSR_IA32_MTRR_CAP_VARIABLE_SUPPORT));\r
660 for (MsrNum = EFI_MSR_CACHE_VARIABLE_MTRR_BASE; MsrNum < MsrNumEnd; MsrNum +=2) {\r
661 TempQword = AsmReadMsr64(MsrNum+1);\r
662 if ((TempQword & B_EFI_MSR_CACHE_MTRR_VALID) == 0) {\r
663 continue;\r
664 }\r
665\r
666 if ((TempQword & ValidMtrrAddressMask) != ((~(MemoryLength - 1)) & ValidMtrrAddressMask)) {\r
667 continue;\r
668 }\r
669\r
670 TempQword = AsmReadMsr64 (MsrNum);\r
671 if ((TempQword & ValidMtrrAddressMask) != (MemoryAddress & ValidMtrrAddressMask)) {\r
672 continue;\r
673 }\r
674\r
675 *UsedMemoryCacheType = (EFI_MEMORY_CACHE_TYPE)(TempQword & B_EFI_MSR_CACHE_MEMORY_TYPE);\r
676 *UsedMsrNum = MsrNum;\r
677\r
678 return EFI_SUCCESS;\r
679 }\r
680\r
681 return EFI_NOT_FOUND;\r
682}\r
683\r
684/**\r
685 Check if CacheType match current default setting.\r
686\r
687 @param[in] MemoryCacheType input cache type to be checked.\r
688\r
689 @retval TRUE MemoryCacheType is default MTRR setting.\r
690 @retval TRUE MemoryCacheType is NOT default MTRR setting.\r
691**/\r
692BOOLEAN\r
693IsDefaultType (\r
694 IN EFI_MEMORY_CACHE_TYPE MemoryCacheType\r
695 )\r
696{\r
697 if ((AsmReadMsr64(EFI_MSR_CACHE_IA32_MTRR_DEF_TYPE) & B_EFI_MSR_CACHE_MEMORY_TYPE) != MemoryCacheType) {\r
698 return FALSE;\r
699 }\r
700\r
701 return TRUE;\r
702}\r
703\r