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