]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/Library/MtrrLib/MtrrLib.c
UefiCpuPkg/MtrrLib: Fix some typo and clean up code format
[mirror_edk2.git] / UefiCpuPkg / Library / MtrrLib / MtrrLib.c
CommitLineData
e50466da 1/** @file\r
2 MTRR setting library\r
3\r
0a4f7aa0 4 Copyright (c) 2008 - 2015, Intel Corporation. All rights reserved.<BR>\r
01a1c0fc 5 This program and the accompanying materials\r
e50466da 6 are licensed and made available under the terms and conditions of the BSD License\r
7 which accompanies this distribution. The full text of the license may be found at\r
8 http://opensource.org/licenses/bsd-license.php\r
9\r
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13**/\r
14\r
15#include <Base.h>\r
16\r
17#include <Library/MtrrLib.h>\r
18#include <Library/BaseLib.h>\r
19#include <Library/CpuLib.h>\r
20#include <Library/BaseMemoryLib.h>\r
21#include <Library/DebugLib.h>\r
22\r
c878cee4 23//\r
24// Context to save and restore when MTRRs are programmed\r
25//\r
26typedef struct {\r
27 UINTN Cr4;\r
28 BOOLEAN InterruptState;\r
29} MTRR_CONTEXT;\r
30\r
e50466da 31//\r
32// This table defines the offset, base and length of the fixed MTRRs\r
33//\r
f877f300 34CONST FIXED_MTRR mMtrrLibFixedMtrrTable[] = {\r
e50466da 35 {\r
36 MTRR_LIB_IA32_MTRR_FIX64K_00000,\r
37 0,\r
38 SIZE_64KB\r
39 },\r
40 {\r
41 MTRR_LIB_IA32_MTRR_FIX16K_80000,\r
42 0x80000,\r
43 SIZE_16KB\r
44 },\r
45 {\r
46 MTRR_LIB_IA32_MTRR_FIX16K_A0000,\r
47 0xA0000,\r
48 SIZE_16KB\r
49 },\r
50 {\r
51 MTRR_LIB_IA32_MTRR_FIX4K_C0000,\r
52 0xC0000,\r
53 SIZE_4KB\r
54 },\r
55 {\r
56 MTRR_LIB_IA32_MTRR_FIX4K_C8000,\r
57 0xC8000,\r
58 SIZE_4KB\r
59 },\r
60 {\r
61 MTRR_LIB_IA32_MTRR_FIX4K_D0000,\r
62 0xD0000,\r
63 SIZE_4KB\r
64 },\r
65 {\r
66 MTRR_LIB_IA32_MTRR_FIX4K_D8000,\r
67 0xD8000,\r
68 SIZE_4KB\r
69 },\r
70 {\r
71 MTRR_LIB_IA32_MTRR_FIX4K_E0000,\r
72 0xE0000,\r
73 SIZE_4KB\r
74 },\r
75 {\r
76 MTRR_LIB_IA32_MTRR_FIX4K_E8000,\r
77 0xE8000,\r
78 SIZE_4KB\r
79 },\r
80 {\r
81 MTRR_LIB_IA32_MTRR_FIX4K_F0000,\r
82 0xF0000,\r
83 SIZE_4KB\r
84 },\r
85 {\r
86 MTRR_LIB_IA32_MTRR_FIX4K_F8000,\r
87 0xF8000,\r
88 SIZE_4KB\r
76b4cae3 89 }\r
e50466da 90};\r
91\r
f877f300 92//\r
93// Lookup table used to print MTRRs\r
94//\r
95GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 *mMtrrMemoryCacheTypeShortName[] = {\r
96 "UC", // CacheUncacheable\r
97 "WC", // CacheWriteCombining\r
98 "R*", // Invalid\r
99 "R*", // Invalid\r
100 "WT", // CacheWriteThrough\r
101 "WP", // CacheWriteProtected\r
102 "WB", // CacheWriteBack\r
103 "R*" // Invalid\r
104};\r
105\r
3b9be416
JY
106/**\r
107 Returns the variable MTRR count for the CPU.\r
108\r
109 @return Variable MTRR count\r
110\r
111**/\r
112UINT32\r
ed8dfd7b 113EFIAPI\r
3b9be416
JY
114GetVariableMtrrCount (\r
115 VOID\r
116 )\r
117{\r
a48caeeb 118 UINT32 VariableMtrrCount;\r
119\r
947a573a 120 if (!IsMtrrSupported ()) {\r
121 return 0;\r
122 }\r
123\r
a48caeeb 124 VariableMtrrCount = (UINT32)(AsmReadMsr64 (MTRR_LIB_IA32_MTRR_CAP) & MTRR_LIB_IA32_MTRR_CAP_VCNT_MASK);\r
125 ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);\r
126\r
127 return VariableMtrrCount;\r
3b9be416
JY
128}\r
129\r
130/**\r
131 Returns the firmware usable variable MTRR count for the CPU.\r
132\r
133 @return Firmware usable variable MTRR count\r
134\r
135**/\r
136UINT32\r
ed8dfd7b 137EFIAPI\r
3b9be416
JY
138GetFirmwareVariableMtrrCount (\r
139 VOID\r
140 )\r
141{\r
947a573a 142 UINT32 VariableMtrrCount;\r
46309b11 143 UINT32 ReservedMtrrNumber;\r
947a573a 144\r
145 VariableMtrrCount = GetVariableMtrrCount ();\r
46309b11
JF
146 ReservedMtrrNumber = PcdGet32 (PcdCpuNumberOfReservedVariableMtrrs);\r
147 if (VariableMtrrCount < ReservedMtrrNumber) {\r
947a573a 148 return 0;\r
149 }\r
150\r
46309b11 151 return VariableMtrrCount - ReservedMtrrNumber;\r
3b9be416 152}\r
e50466da 153\r
154/**\r
155 Returns the default MTRR cache type for the system.\r
156\r
91ec7824 157 @return The default MTRR cache type.\r
e50466da 158\r
159**/\r
91ec7824 160MTRR_MEMORY_CACHE_TYPE\r
161EFIAPI\r
162MtrrGetDefaultMemoryType (\r
e50466da 163 VOID\r
91ec7824 164 )\r
e50466da 165{\r
91ec7824 166 if (!IsMtrrSupported ()) {\r
167 return CacheUncacheable;\r
168 }\r
e50466da 169\r
91ec7824 170 return (MTRR_MEMORY_CACHE_TYPE) (AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE) & 0x7);\r
171}\r
e50466da 172\r
173/**\r
174 Preparation before programming MTRR.\r
175\r
176 This function will do some preparation for programming MTRRs:\r
177 disable cache, invalid cache and disable MTRR caching functionality\r
178\r
a5953380 179 @param[out] MtrrContext Pointer to context to save\r
e50466da 180\r
181**/\r
c878cee4 182VOID\r
e50466da 183PreMtrrChange (\r
c878cee4 184 OUT MTRR_CONTEXT *MtrrContext\r
e50466da 185 )\r
186{\r
c878cee4 187 //\r
188 // Disable interrupts and save current interrupt state\r
189 //\r
190 MtrrContext->InterruptState = SaveAndDisableInterrupts();\r
76b4cae3 191\r
e50466da 192 //\r
193 // Enter no fill cache mode, CD=1(Bit30), NW=0 (Bit29)\r
194 //\r
58b23d90 195 AsmDisableCache ();\r
196\r
e50466da 197 //\r
58b23d90 198 // Save original CR4 value and clear PGE flag (Bit 7)\r
e50466da 199 //\r
c878cee4 200 MtrrContext->Cr4 = AsmReadCr4 ();\r
201 AsmWriteCr4 (MtrrContext->Cr4 & (~BIT7));\r
58b23d90 202\r
e50466da 203 //\r
204 // Flush all TLBs\r
205 //\r
206 CpuFlushTlb ();\r
58b23d90 207\r
e50466da 208 //\r
76b4cae3 209 // Disable MTRRs\r
e50466da 210 //\r
211 AsmMsrBitFieldWrite64 (MTRR_LIB_IA32_MTRR_DEF_TYPE, 10, 11, 0);\r
e50466da 212}\r
213\r
e50466da 214/**\r
215 Cleaning up after programming MTRRs.\r
216\r
217 This function will do some clean up after programming MTRRs:\r
0779e5bf 218 Flush all TLBs, re-enable caching, restore CR4.\r
e50466da 219\r
a5953380 220 @param[in] MtrrContext Pointer to context to restore\r
e50466da 221\r
222**/\r
223VOID\r
0779e5bf 224PostMtrrChangeEnableCache (\r
c878cee4 225 IN MTRR_CONTEXT *MtrrContext\r
e50466da 226 )\r
227{\r
e50466da 228 //\r
76b4cae3 229 // Flush all TLBs\r
e50466da 230 //\r
e50466da 231 CpuFlushTlb ();\r
232\r
233 //\r
234 // Enable Normal Mode caching CD=NW=0, CD(Bit30), NW(Bit29)\r
235 //\r
58b23d90 236 AsmEnableCache ();\r
e50466da 237\r
58b23d90 238 //\r
239 // Restore original CR4 value\r
240 //\r
c878cee4 241 AsmWriteCr4 (MtrrContext->Cr4);\r
76b4cae3 242\r
c878cee4 243 //\r
244 // Restore original interrupt state\r
245 //\r
246 SetInterruptState (MtrrContext->InterruptState);\r
e50466da 247}\r
248\r
0779e5bf 249/**\r
250 Cleaning up after programming MTRRs.\r
251\r
252 This function will do some clean up after programming MTRRs:\r
253 enable MTRR caching functionality, and enable cache\r
254\r
a5953380 255 @param[in] MtrrContext Pointer to context to restore\r
0779e5bf 256\r
257**/\r
258VOID\r
259PostMtrrChange (\r
c878cee4 260 IN MTRR_CONTEXT *MtrrContext\r
0779e5bf 261 )\r
262{\r
263 //\r
264 // Enable Cache MTRR\r
265 //\r
266 AsmMsrBitFieldWrite64 (MTRR_LIB_IA32_MTRR_DEF_TYPE, 10, 11, 3);\r
267\r
c878cee4 268 PostMtrrChangeEnableCache (MtrrContext);\r
0779e5bf 269}\r
270\r
e50466da 271\r
272/**\r
273 Programs fixed MTRRs registers.\r
274\r
76b4cae3
MK
275 @param[in] MemoryCacheType The memory type to set.\r
276 @param[in, out] Base The base address of memory range.\r
277 @param[in, out] Length The length of memory range.\r
e50466da 278\r
279 @retval RETURN_SUCCESS The cache type was updated successfully\r
280 @retval RETURN_UNSUPPORTED The requested range or cache type was invalid\r
281 for the fixed MTRRs.\r
282\r
283**/\r
284RETURN_STATUS\r
285ProgramFixedMtrr (\r
286 IN UINT64 MemoryCacheType,\r
287 IN OUT UINT64 *Base,\r
288 IN OUT UINT64 *Length\r
289 )\r
290{\r
291 UINT32 MsrNum;\r
292 UINT32 ByteShift;\r
293 UINT64 TempQword;\r
294 UINT64 OrMask;\r
295 UINT64 ClearMask;\r
296\r
297 TempQword = 0;\r
298 OrMask = 0;\r
299 ClearMask = 0;\r
300\r
301 for (MsrNum = 0; MsrNum < MTRR_NUMBER_OF_FIXED_MTRR; MsrNum++) {\r
f877f300 302 if ((*Base >= mMtrrLibFixedMtrrTable[MsrNum].BaseAddress) &&\r
e50466da 303 (*Base <\r
304 (\r
f877f300 305 mMtrrLibFixedMtrrTable[MsrNum].BaseAddress +\r
306 (8 * mMtrrLibFixedMtrrTable[MsrNum].Length)\r
e50466da 307 )\r
308 )\r
309 ) {\r
310 break;\r
311 }\r
312 }\r
313\r
314 if (MsrNum == MTRR_NUMBER_OF_FIXED_MTRR) {\r
315 return RETURN_UNSUPPORTED;\r
316 }\r
317\r
318 //\r
319 // We found the fixed MTRR to be programmed\r
320 //\r
321 for (ByteShift = 0; ByteShift < 8; ByteShift++) {\r
322 if (*Base ==\r
323 (\r
f877f300 324 mMtrrLibFixedMtrrTable[MsrNum].BaseAddress +\r
325 (ByteShift * mMtrrLibFixedMtrrTable[MsrNum].Length)\r
e50466da 326 )\r
327 ) {\r
328 break;\r
329 }\r
330 }\r
331\r
332 if (ByteShift == 8) {\r
333 return RETURN_UNSUPPORTED;\r
334 }\r
335\r
336 for (\r
337 ;\r
f877f300 338 ((ByteShift < 8) && (*Length >= mMtrrLibFixedMtrrTable[MsrNum].Length));\r
e50466da 339 ByteShift++\r
340 ) {\r
341 OrMask |= LShiftU64 ((UINT64) MemoryCacheType, (UINT32) (ByteShift * 8));\r
342 ClearMask |= LShiftU64 ((UINT64) 0xFF, (UINT32) (ByteShift * 8));\r
f877f300 343 *Length -= mMtrrLibFixedMtrrTable[MsrNum].Length;\r
344 *Base += mMtrrLibFixedMtrrTable[MsrNum].Length;\r
e50466da 345 }\r
346\r
347 if (ByteShift < 8 && (*Length != 0)) {\r
348 return RETURN_UNSUPPORTED;\r
349 }\r
350\r
351 TempQword =\r
f877f300 352 (AsmReadMsr64 (mMtrrLibFixedMtrrTable[MsrNum].Msr) & ~ClearMask) | OrMask;\r
353 AsmWriteMsr64 (mMtrrLibFixedMtrrTable[MsrNum].Msr, TempQword);\r
e50466da 354 return RETURN_SUCCESS;\r
355}\r
356\r
357\r
358/**\r
76b4cae3 359 Gets the attribute of variable MTRRs.\r
e50466da 360\r
3ba736f3
JY
361 This function shadows the content of variable MTRRs into an\r
362 internal array: VariableMtrr.\r
e50466da 363\r
76b4cae3
MK
364 @param[in] MtrrValidBitsMask The mask for the valid bit of the MTRR\r
365 @param[in] MtrrValidAddressMask The valid address mask for MTRR\r
366 @param[out] VariableMtrr The array to shadow variable MTRRs content\r
e50466da 367\r
3ba736f3
JY
368 @return The return value of this paramter indicates the\r
369 number of MTRRs which has been used.\r
e50466da 370\r
371**/\r
3ba736f3 372UINT32\r
e50466da 373EFIAPI\r
374MtrrGetMemoryAttributeInVariableMtrr (\r
375 IN UINT64 MtrrValidBitsMask,\r
376 IN UINT64 MtrrValidAddressMask,\r
377 OUT VARIABLE_MTRR *VariableMtrr\r
378 )\r
379{\r
380 UINTN Index;\r
381 UINT32 MsrNum;\r
382 UINT32 UsedMtrr;\r
3ba736f3 383 UINT32 FirmwareVariableMtrrCount;\r
3b9be416
JY
384 UINT32 VariableMtrrEnd;\r
385\r
947a573a 386 if (!IsMtrrSupported ()) {\r
387 return 0;\r
388 }\r
389\r
3b9be416 390 FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCount ();\r
3b9be416 391 VariableMtrrEnd = MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (2 * GetVariableMtrrCount ()) - 1;\r
e50466da 392\r
3ba736f3 393 ZeroMem (VariableMtrr, sizeof (VARIABLE_MTRR) * MTRR_NUMBER_OF_VARIABLE_MTRR);\r
e50466da 394 UsedMtrr = 0;\r
395\r
396 for (MsrNum = MTRR_LIB_IA32_VARIABLE_MTRR_BASE, Index = 0;\r
397 (\r
3b9be416
JY
398 (MsrNum < VariableMtrrEnd) &&\r
399 (Index < FirmwareVariableMtrrCount)\r
e50466da 400 );\r
401 MsrNum += 2\r
402 ) {\r
403 if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) != 0) {\r
404 VariableMtrr[Index].Msr = MsrNum;\r
405 VariableMtrr[Index].BaseAddress = (AsmReadMsr64 (MsrNum) &\r
406 MtrrValidAddressMask);\r
407 VariableMtrr[Index].Length = ((~(AsmReadMsr64 (MsrNum + 1) &\r
408 MtrrValidAddressMask)\r
409 ) &\r
410 MtrrValidBitsMask\r
411 ) + 1;\r
412 VariableMtrr[Index].Type = (AsmReadMsr64 (MsrNum) & 0x0ff);\r
413 VariableMtrr[Index].Valid = TRUE;\r
414 VariableMtrr[Index].Used = TRUE;\r
415 UsedMtrr = UsedMtrr + 1;\r
416 Index++;\r
417 }\r
418 }\r
3ba736f3 419 return UsedMtrr;\r
e50466da 420}\r
421\r
422\r
423/**\r
424 Checks overlap between given memory range and MTRRs.\r
425\r
76b4cae3
MK
426 @param[in] Start The start address of memory range.\r
427 @param[in] End The end address of memory range.\r
428 @param[in] VariableMtrr The array to shadow variable MTRRs content\r
e50466da 429\r
430 @retval TRUE Overlap exists.\r
431 @retval FALSE No overlap.\r
432\r
433**/\r
434BOOLEAN\r
435CheckMemoryAttributeOverlap (\r
436 IN PHYSICAL_ADDRESS Start,\r
437 IN PHYSICAL_ADDRESS End,\r
438 IN VARIABLE_MTRR *VariableMtrr\r
439 )\r
440{\r
441 UINT32 Index;\r
442\r
443 for (Index = 0; Index < 6; Index++) {\r
444 if (\r
445 VariableMtrr[Index].Valid &&\r
446 !(\r
447 (Start > (VariableMtrr[Index].BaseAddress +\r
448 VariableMtrr[Index].Length - 1)\r
449 ) ||\r
450 (End < VariableMtrr[Index].BaseAddress)\r
451 )\r
452 ) {\r
453 return TRUE;\r
454 }\r
455 }\r
456\r
457 return FALSE;\r
458}\r
459\r
460\r
461/**\r
462 Marks a variable MTRR as non-valid.\r
463\r
76b4cae3
MK
464 @param[in] Index The index of the array VariableMtrr to be invalidated\r
465 @param[in] VariableMtrr The array to shadow variable MTRRs content\r
466 @param[out] UsedMtrr The number of MTRRs which has already been used\r
e50466da 467\r
468**/\r
469VOID\r
470InvalidateShadowMtrr (\r
471 IN UINTN Index,\r
472 IN VARIABLE_MTRR *VariableMtrr,\r
473 OUT UINT32 *UsedMtrr\r
474 )\r
475{\r
476 VariableMtrr[Index].Valid = FALSE;\r
477 *UsedMtrr = *UsedMtrr - 1;\r
478}\r
479\r
480\r
481/**\r
76b4cae3 482 Combines memory attributes.\r
e50466da 483\r
484 If overlap exists between given memory range and MTRRs, try to combine them.\r
485\r
76b4cae3
MK
486 @param[in] Attributes The memory type to set.\r
487 @param[in, out] Base The base address of memory range.\r
488 @param[in, out] Length The length of memory range.\r
489 @param[in] VariableMtrr The array to shadow variable MTRRs content\r
490 @param[in, out] UsedMtrr The number of MTRRs which has already been used\r
491 @param[out] OverwriteExistingMtrr Returns whether an existing MTRR was used\r
e50466da 492\r
493 @retval EFI_SUCCESS Memory region successfully combined.\r
494 @retval EFI_ACCESS_DENIED Memory region cannot be combined.\r
495\r
496**/\r
497RETURN_STATUS\r
498CombineMemoryAttribute (\r
499 IN UINT64 Attributes,\r
500 IN OUT UINT64 *Base,\r
501 IN OUT UINT64 *Length,\r
502 IN VARIABLE_MTRR *VariableMtrr,\r
503 IN OUT UINT32 *UsedMtrr,\r
504 OUT BOOLEAN *OverwriteExistingMtrr\r
505 )\r
506{\r
507 UINT32 Index;\r
508 UINT64 CombineStart;\r
509 UINT64 CombineEnd;\r
510 UINT64 MtrrEnd;\r
511 UINT64 EndAddress;\r
3b9be416 512 UINT32 FirmwareVariableMtrrCount;\r
1e60a0ec 513 BOOLEAN CoveredByExistingMtrr;\r
3b9be416
JY
514\r
515 FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCount ();\r
e50466da 516\r
517 *OverwriteExistingMtrr = FALSE;\r
1e60a0ec 518 CoveredByExistingMtrr = FALSE;\r
e50466da 519 EndAddress = *Base +*Length - 1;\r
520\r
3b9be416 521 for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) {\r
e50466da 522\r
523 MtrrEnd = VariableMtrr[Index].BaseAddress + VariableMtrr[Index].Length - 1;\r
524 if (\r
525 !VariableMtrr[Index].Valid ||\r
526 (\r
527 *Base > (MtrrEnd) ||\r
528 (EndAddress < VariableMtrr[Index].BaseAddress)\r
529 )\r
530 ) {\r
531 continue;\r
532 }\r
533\r
534 //\r
535 // Combine same attribute MTRR range\r
536 //\r
537 if (Attributes == VariableMtrr[Index].Type) {\r
538 //\r
76b4cae3 539 // if the MTRR range contain the request range, set a flag, then continue to\r
1e60a0ec 540 // invalidate any MTRR of the same request range with higher priority cache type.\r
e50466da 541 //\r
542 if (VariableMtrr[Index].BaseAddress <= *Base && MtrrEnd >= EndAddress) {\r
1e60a0ec 543 CoveredByExistingMtrr = TRUE;\r
544 continue;\r
e50466da 545 }\r
546 //\r
547 // invalid this MTRR, and program the combine range\r
548 //\r
549 CombineStart =\r
550 (*Base) < VariableMtrr[Index].BaseAddress ?\r
551 (*Base) :\r
552 VariableMtrr[Index].BaseAddress;\r
553 CombineEnd = EndAddress > MtrrEnd ? EndAddress : MtrrEnd;\r
554\r
555 //\r
556 // Record the MTRR usage status in VariableMtrr array.\r
557 //\r
558 InvalidateShadowMtrr (Index, VariableMtrr, UsedMtrr);\r
559 *Base = CombineStart;\r
560 *Length = CombineEnd - CombineStart + 1;\r
561 EndAddress = CombineEnd;\r
562 *OverwriteExistingMtrr = TRUE;\r
563 continue;\r
564 } else {\r
565 //\r
566 // The cache type is different, but the range is convered by one MTRR\r
567 //\r
568 if (VariableMtrr[Index].BaseAddress == *Base && MtrrEnd == EndAddress) {\r
569 InvalidateShadowMtrr (Index, VariableMtrr, UsedMtrr);\r
570 continue;\r
571 }\r
572\r
573 }\r
574\r
575 if ((Attributes== MTRR_CACHE_WRITE_THROUGH &&\r
576 VariableMtrr[Index].Type == MTRR_CACHE_WRITE_BACK) ||\r
577 (Attributes == MTRR_CACHE_WRITE_BACK &&\r
578 VariableMtrr[Index].Type == MTRR_CACHE_WRITE_THROUGH) ||\r
579 (Attributes == MTRR_CACHE_UNCACHEABLE) ||\r
580 (VariableMtrr[Index].Type == MTRR_CACHE_UNCACHEABLE)\r
581 ) {\r
582 *OverwriteExistingMtrr = TRUE;\r
583 continue;\r
584 }\r
585 //\r
586 // Other type memory overlap is invalid\r
587 //\r
588 return RETURN_ACCESS_DENIED;\r
589 }\r
590\r
1e60a0ec 591 if (CoveredByExistingMtrr) {\r
592 *Length = 0;\r
593 }\r
594\r
e50466da 595 return RETURN_SUCCESS;\r
596}\r
597\r
598\r
599/**\r
76b4cae3
MK
600 Calculates the maximum value which is a power of 2, but less the MemoryLength.\r
601\r
602 @param[in] MemoryLength The number to pass in.\r
e50466da 603\r
e50466da 604 @return The maximum value which is align to power of 2 and less the MemoryLength\r
605\r
606**/\r
607UINT64\r
608Power2MaxMemory (\r
609 IN UINT64 MemoryLength\r
610 )\r
611{\r
612 UINT64 Result;\r
613\r
430fbbe0 614 if (RShiftU64 (MemoryLength, 32) != 0) {\r
e50466da 615 Result = LShiftU64 (\r
616 (UINT64) GetPowerOfTwo32 (\r
617 (UINT32) RShiftU64 (MemoryLength, 32)\r
618 ),\r
619 32\r
620 );\r
621 } else {\r
622 Result = (UINT64) GetPowerOfTwo32 ((UINT32) MemoryLength);\r
623 }\r
624\r
625 return Result;\r
626}\r
627\r
628\r
629/**\r
76b4cae3 630 Determines the MTRR numbers used to program a memory range.\r
e50466da 631\r
76b4cae3
MK
632 This function first checks the alignment of the base address.\r
633 If the alignment of the base address <= Length, cover the memory range\r
634 (BaseAddress, alignment) by a MTRR, then BaseAddress += alignment and\r
635 Length -= alignment. Repeat the step until alignment > Length.\r
e50466da 636\r
76b4cae3
MK
637 Then this function determines which direction of programming the variable\r
638 MTRRs for the remaining length will use fewer MTRRs.\r
1a2ad6fc 639\r
76b4cae3
MK
640 @param[in] BaseAddress Length of Memory to program MTRR\r
641 @param[in] Length Length of Memory to program MTRR\r
642 @param[in] MtrrNumber Pointer to the number of necessary MTRRs\r
e50466da 643\r
644 @retval TRUE Positive direction is better.\r
76b4cae3 645 FALSE Negative direction is better.\r
e50466da 646\r
647**/\r
648BOOLEAN\r
1a2ad6fc 649GetMtrrNumberAndDirection (\r
650 IN UINT64 BaseAddress,\r
651 IN UINT64 Length,\r
e50466da 652 IN UINTN *MtrrNumber\r
653 )\r
654{\r
655 UINT64 TempQword;\r
1a2ad6fc 656 UINT64 Alignment;\r
e50466da 657 UINT32 Positive;\r
658 UINT32 Subtractive;\r
659\r
1a2ad6fc 660 *MtrrNumber = 0;\r
661\r
662 if (BaseAddress != 0) {\r
663 do {\r
664 //\r
665 // Calculate the alignment of the base address.\r
666 //\r
667 Alignment = LShiftU64 (1, (UINTN)LowBitSet64 (BaseAddress));\r
668\r
669 if (Alignment > Length) {\r
670 break;\r
671 }\r
672\r
673 (*MtrrNumber)++;\r
674 BaseAddress += Alignment;\r
675 Length -= Alignment;\r
676 } while (TRUE);\r
677\r
678 if (Length == 0) {\r
679 return TRUE;\r
680 }\r
681 }\r
682\r
683 TempQword = Length;\r
e50466da 684 Positive = 0;\r
685 Subtractive = 0;\r
686\r
687 do {\r
688 TempQword -= Power2MaxMemory (TempQword);\r
689 Positive++;\r
690 } while (TempQword != 0);\r
691\r
1a2ad6fc 692 TempQword = Power2MaxMemory (LShiftU64 (Length, 1)) - Length;\r
e50466da 693 Subtractive++;\r
694 do {\r
695 TempQword -= Power2MaxMemory (TempQword);\r
696 Subtractive++;\r
697 } while (TempQword != 0);\r
698\r
699 if (Positive <= Subtractive) {\r
1a2ad6fc 700 *MtrrNumber += Positive;\r
e50466da 701 return TRUE;\r
702 } else {\r
1a2ad6fc 703 *MtrrNumber += Subtractive;\r
e50466da 704 return FALSE;\r
705 }\r
706}\r
707\r
708/**\r
709 Invalid variable MTRRs according to the value in the shadow array.\r
710\r
711 This function programs MTRRs according to the values specified\r
712 in the shadow array.\r
713\r
76b4cae3 714 @param[in, out] VariableMtrr Shadow of variable MTRR contents\r
e50466da 715\r
716**/\r
e50466da 717VOID\r
718InvalidateMtrr (\r
76b4cae3
MK
719 IN OUT VARIABLE_MTRR *VariableMtrr\r
720 )\r
e50466da 721{\r
c878cee4 722 UINTN Index;\r
723 UINTN VariableMtrrCount;\r
724 MTRR_CONTEXT MtrrContext;\r
e50466da 725\r
c878cee4 726 PreMtrrChange (&MtrrContext);\r
e50466da 727 Index = 0;\r
3b9be416
JY
728 VariableMtrrCount = GetVariableMtrrCount ();\r
729 while (Index < VariableMtrrCount) {\r
430fbbe0 730 if (!VariableMtrr[Index].Valid && VariableMtrr[Index].Used) {\r
e50466da 731 AsmWriteMsr64 (VariableMtrr[Index].Msr, 0);\r
732 AsmWriteMsr64 (VariableMtrr[Index].Msr + 1, 0);\r
733 VariableMtrr[Index].Used = FALSE;\r
734 }\r
735 Index ++;\r
736 }\r
c878cee4 737 PostMtrrChange (&MtrrContext);\r
e50466da 738}\r
739\r
740\r
741/**\r
742 Programs variable MTRRs\r
743\r
744 This function programs variable MTRRs\r
745\r
76b4cae3
MK
746 @param[in] MtrrNumber Index of MTRR to program.\r
747 @param[in] BaseAddress Base address of memory region.\r
748 @param[in] Length Length of memory region.\r
749 @param[in] MemoryCacheType Memory type to set.\r
750 @param[in] MtrrValidAddressMask The valid address mask for MTRR\r
e50466da 751\r
752**/\r
e50466da 753VOID\r
754ProgramVariableMtrr (\r
755 IN UINTN MtrrNumber,\r
756 IN PHYSICAL_ADDRESS BaseAddress,\r
757 IN UINT64 Length,\r
758 IN UINT64 MemoryCacheType,\r
759 IN UINT64 MtrrValidAddressMask\r
760 )\r
761{\r
c878cee4 762 UINT64 TempQword;\r
763 MTRR_CONTEXT MtrrContext;\r
e50466da 764\r
c878cee4 765 PreMtrrChange (&MtrrContext);\r
e50466da 766\r
767 //\r
768 // MTRR Physical Base\r
769 //\r
770 TempQword = (BaseAddress & MtrrValidAddressMask) | MemoryCacheType;\r
771 AsmWriteMsr64 ((UINT32) MtrrNumber, TempQword);\r
772\r
773 //\r
774 // MTRR Physical Mask\r
775 //\r
776 TempQword = ~(Length - 1);\r
777 AsmWriteMsr64 (\r
778 (UINT32) (MtrrNumber + 1),\r
779 (TempQword & MtrrValidAddressMask) | MTRR_LIB_CACHE_MTRR_ENABLED\r
780 );\r
781\r
c878cee4 782 PostMtrrChange (&MtrrContext);\r
e50466da 783}\r
784\r
785\r
786/**\r
76b4cae3 787 Converts the Memory attribute value to MTRR_MEMORY_CACHE_TYPE.\r
e50466da 788\r
76b4cae3 789 @param[in] MtrrType MTRR memory type\r
e50466da 790\r
791 @return The enum item in MTRR_MEMORY_CACHE_TYPE\r
792\r
793**/\r
e50466da 794MTRR_MEMORY_CACHE_TYPE\r
795GetMemoryCacheTypeFromMtrrType (\r
796 IN UINT64 MtrrType\r
797 )\r
798{\r
799 switch (MtrrType) {\r
800 case MTRR_CACHE_UNCACHEABLE:\r
801 return CacheUncacheable;\r
802 case MTRR_CACHE_WRITE_COMBINING:\r
803 return CacheWriteCombining;\r
804 case MTRR_CACHE_WRITE_THROUGH:\r
805 return CacheWriteThrough;\r
806 case MTRR_CACHE_WRITE_PROTECTED:\r
807 return CacheWriteProtected;\r
808 case MTRR_CACHE_WRITE_BACK:\r
809 return CacheWriteBack;\r
810 default:\r
811 //\r
812 // MtrrType is MTRR_CACHE_INVALID_TYPE, that means\r
76b4cae3 813 // no MTRR covers the range\r
e50466da 814 //\r
44c8400a 815 return MtrrGetDefaultMemoryType ();\r
e50466da 816 }\r
817}\r
818\r
819/**\r
820 Initializes the valid bits mask and valid address mask for MTRRs.\r
821\r
822 This function initializes the valid bits mask and valid address mask for MTRRs.\r
823\r
76b4cae3
MK
824 @param[out] MtrrValidBitsMask The mask for the valid bit of the MTRR\r
825 @param[out] MtrrValidAddressMask The valid address mask for the MTRR\r
e50466da 826\r
827**/\r
e50466da 828VOID\r
829MtrrLibInitializeMtrrMask (\r
830 OUT UINT64 *MtrrValidBitsMask,\r
831 OUT UINT64 *MtrrValidAddressMask\r
832 )\r
833{\r
f877f300 834 UINT32 RegEax;\r
835 UINT8 PhysicalAddressBits;\r
e50466da 836\r
837 AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);\r
838\r
839 if (RegEax >= 0x80000008) {\r
840 AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);\r
841\r
842 PhysicalAddressBits = (UINT8) RegEax;\r
843\r
844 *MtrrValidBitsMask = LShiftU64 (1, PhysicalAddressBits) - 1;\r
845 *MtrrValidAddressMask = *MtrrValidBitsMask & 0xfffffffffffff000ULL;\r
846 } else {\r
0a4f7aa0
JF
847 *MtrrValidBitsMask = MTRR_LIB_MSR_VALID_MASK;\r
848 *MtrrValidAddressMask = MTRR_LIB_CACHE_VALID_ADDRESS;\r
e50466da 849 }\r
850}\r
851\r
852\r
853/**\r
76b4cae3 854 Determines the real attribute of a memory range.\r
e50466da 855\r
856 This function is to arbitrate the real attribute of the memory when\r
76b4cae3 857 there are 2 MTRRs covers the same memory range. For further details,\r
e50466da 858 please refer the IA32 Software Developer's Manual, Volume 3,\r
859 Section 10.11.4.1.\r
860\r
76b4cae3
MK
861 @param[in] MtrrType1 The first kind of Memory type\r
862 @param[in] MtrrType2 The second kind of memory type\r
e50466da 863\r
864**/\r
865UINT64\r
866MtrrPrecedence (\r
76b4cae3
MK
867 IN UINT64 MtrrType1,\r
868 IN UINT64 MtrrType2\r
e50466da 869 )\r
870{\r
871 UINT64 MtrrType;\r
872\r
873 MtrrType = MTRR_CACHE_INVALID_TYPE;\r
874 switch (MtrrType1) {\r
875 case MTRR_CACHE_UNCACHEABLE:\r
876 MtrrType = MTRR_CACHE_UNCACHEABLE;\r
877 break;\r
878 case MTRR_CACHE_WRITE_COMBINING:\r
879 if (\r
880 MtrrType2==MTRR_CACHE_WRITE_COMBINING ||\r
881 MtrrType2==MTRR_CACHE_UNCACHEABLE\r
882 ) {\r
883 MtrrType = MtrrType2;\r
884 }\r
885 break;\r
886 case MTRR_CACHE_WRITE_THROUGH:\r
887 if (\r
888 MtrrType2==MTRR_CACHE_WRITE_THROUGH ||\r
889 MtrrType2==MTRR_CACHE_WRITE_BACK\r
890 ) {\r
891 MtrrType = MTRR_CACHE_WRITE_THROUGH;\r
892 } else if(MtrrType2==MTRR_CACHE_UNCACHEABLE) {\r
893 MtrrType = MTRR_CACHE_UNCACHEABLE;\r
894 }\r
895 break;\r
896 case MTRR_CACHE_WRITE_PROTECTED:\r
897 if (MtrrType2 == MTRR_CACHE_WRITE_PROTECTED ||\r
898 MtrrType2 == MTRR_CACHE_UNCACHEABLE) {\r
899 MtrrType = MtrrType2;\r
900 }\r
901 break;\r
902 case MTRR_CACHE_WRITE_BACK:\r
903 if (\r
904 MtrrType2== MTRR_CACHE_UNCACHEABLE ||\r
905 MtrrType2==MTRR_CACHE_WRITE_THROUGH ||\r
906 MtrrType2== MTRR_CACHE_WRITE_BACK\r
907 ) {\r
908 MtrrType = MtrrType2;\r
909 }\r
910 break;\r
911 case MTRR_CACHE_INVALID_TYPE:\r
912 MtrrType = MtrrType2;\r
913 break;\r
914 default:\r
915 break;\r
916 }\r
917\r
918 if (MtrrType2 == MTRR_CACHE_INVALID_TYPE) {\r
919 MtrrType = MtrrType1;\r
920 }\r
921 return MtrrType;\r
922}\r
923\r
924\r
925/**\r
926 This function attempts to set the attributes for a memory range.\r
927\r
76b4cae3
MK
928 @param[in] BaseAddress The physical address that is the start\r
929 address of a memory region.\r
930 @param[in] Length The size in bytes of the memory region.\r
931 @param[in] Attribute The bit mask of attributes to set for the\r
932 memory region.\r
e50466da 933\r
934 @retval RETURN_SUCCESS The attributes were set for the memory\r
935 region.\r
936 @retval RETURN_INVALID_PARAMETER Length is zero.\r
937 @retval RETURN_UNSUPPORTED The processor does not support one or\r
938 more bytes of the memory resource range\r
939 specified by BaseAddress and Length.\r
940 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support\r
941 for the memory resource range specified\r
942 by BaseAddress and Length.\r
943 @retval RETURN_ACCESS_DENIED The attributes for the memory resource\r
944 range specified by BaseAddress and Length\r
945 cannot be modified.\r
946 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to\r
947 modify the attributes of the memory\r
948 resource range.\r
949\r
950**/\r
951RETURN_STATUS\r
952EFIAPI\r
953MtrrSetMemoryAttribute (\r
954 IN PHYSICAL_ADDRESS BaseAddress,\r
955 IN UINT64 Length,\r
956 IN MTRR_MEMORY_CACHE_TYPE Attribute\r
957 )\r
958{\r
959 UINT64 TempQword;\r
960 RETURN_STATUS Status;\r
961 UINT64 MemoryType;\r
1a2ad6fc 962 UINT64 Alignment;\r
e50466da 963 BOOLEAN OverLap;\r
964 BOOLEAN Positive;\r
965 UINT32 MsrNum;\r
966 UINTN MtrrNumber;\r
3ba736f3 967 VARIABLE_MTRR VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];\r
e50466da 968 UINT32 UsedMtrr;\r
969 UINT64 MtrrValidBitsMask;\r
970 UINT64 MtrrValidAddressMask;\r
e50466da 971 BOOLEAN OverwriteExistingMtrr;\r
3b9be416
JY
972 UINT32 FirmwareVariableMtrrCount;\r
973 UINT32 VariableMtrrEnd;\r
c878cee4 974 MTRR_CONTEXT MtrrContext;\r
3b9be416 975\r
f877f300 976 DEBUG((DEBUG_CACHE, "MtrrSetMemoryAttribute() %a:%016lx-%016lx\n", mMtrrMemoryCacheTypeShortName[Attribute], BaseAddress, Length));\r
977\r
947a573a 978 if (!IsMtrrSupported ()) {\r
f877f300 979 Status = RETURN_UNSUPPORTED;\r
980 goto Done;\r
947a573a 981 }\r
982\r
3b9be416
JY
983 FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCount ();\r
984 VariableMtrrEnd = MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (2 * GetVariableMtrrCount ()) - 1;\r
e50466da 985\r
986 MtrrLibInitializeMtrrMask(&MtrrValidBitsMask, &MtrrValidAddressMask);\r
987\r
988 TempQword = 0;\r
989 MemoryType = (UINT64)Attribute;\r
990 OverwriteExistingMtrr = FALSE;\r
991\r
992 //\r
993 // Check for an invalid parameter\r
994 //\r
995 if (Length == 0) {\r
f877f300 996 Status = RETURN_INVALID_PARAMETER;\r
997 goto Done;\r
e50466da 998 }\r
999\r
1000 if (\r
f877f300 1001 (BaseAddress & ~MtrrValidAddressMask) != 0 ||\r
1002 (Length & ~MtrrValidAddressMask) != 0\r
e50466da 1003 ) {\r
f877f300 1004 Status = RETURN_UNSUPPORTED;\r
1005 goto Done;\r
e50466da 1006 }\r
1007\r
1008 //\r
1009 // Check if Fixed MTRR\r
1010 //\r
1011 Status = RETURN_SUCCESS;\r
1012 while ((BaseAddress < BASE_1MB) && (Length > 0) && Status == RETURN_SUCCESS) {\r
c878cee4 1013 PreMtrrChange (&MtrrContext);\r
e50466da 1014 Status = ProgramFixedMtrr (MemoryType, &BaseAddress, &Length);\r
c878cee4 1015 PostMtrrChange (&MtrrContext);\r
e50466da 1016 if (RETURN_ERROR (Status)) {\r
f877f300 1017 goto Done;\r
e50466da 1018 }\r
1019 }\r
1020\r
1021 if (Length == 0) {\r
1022 //\r
1023 // A Length of 0 can only make sense for fixed MTTR ranges.\r
1024 // Since we just handled the fixed MTRRs, we can skip the\r
1025 // variable MTRR section.\r
1026 //\r
1027 goto Done;\r
1028 }\r
1029\r
1030 //\r
1031 // Since memory ranges below 1MB will be overridden by the fixed MTRRs,\r
f877f300 1032 // we can set the base to 0 to save variable MTRRs.\r
e50466da 1033 //\r
1034 if (BaseAddress == BASE_1MB) {\r
1035 BaseAddress = 0;\r
1036 Length += SIZE_1MB;\r
1037 }\r
1038\r
e50466da 1039 //\r
1040 // Check for overlap\r
1041 //\r
3ba736f3 1042 UsedMtrr = MtrrGetMemoryAttributeInVariableMtrr (MtrrValidBitsMask, MtrrValidAddressMask, VariableMtrr);\r
e50466da 1043 OverLap = CheckMemoryAttributeOverlap (BaseAddress, BaseAddress + Length - 1, VariableMtrr);\r
1044 if (OverLap) {\r
1045 Status = CombineMemoryAttribute (MemoryType, &BaseAddress, &Length, VariableMtrr, &UsedMtrr, &OverwriteExistingMtrr);\r
1046 if (RETURN_ERROR (Status)) {\r
1047 goto Done;\r
1048 }\r
1049\r
1050 if (Length == 0) {\r
1051 //\r
1e60a0ec 1052 // Combined successfully, invalidate the now-unused MTRRs\r
e50466da 1053 //\r
1e60a0ec 1054 InvalidateMtrr(VariableMtrr);\r
e50466da 1055 Status = RETURN_SUCCESS;\r
1056 goto Done;\r
1057 }\r
1058 }\r
e50466da 1059\r
1060 //\r
1061 // The memory type is the same with the type specified by\r
1062 // MTRR_LIB_IA32_MTRR_DEF_TYPE.\r
1063 //\r
91ec7824 1064 if ((!OverwriteExistingMtrr) && (Attribute == MtrrGetDefaultMemoryType ())) {\r
e50466da 1065 //\r
1066 // Invalidate the now-unused MTRRs\r
1067 //\r
1068 InvalidateMtrr(VariableMtrr);\r
1069 goto Done;\r
1070 }\r
1071\r
1a2ad6fc 1072 Positive = GetMtrrNumberAndDirection (BaseAddress, Length, &MtrrNumber);\r
e50466da 1073\r
1a2ad6fc 1074 if ((UsedMtrr + MtrrNumber) > FirmwareVariableMtrrCount) {\r
1075 Status = RETURN_OUT_OF_RESOURCES;\r
1076 goto Done;\r
1077 }\r
e50466da 1078\r
1a2ad6fc 1079 //\r
1080 // Invalidate the now-unused MTRRs\r
1081 //\r
1082 InvalidateMtrr(VariableMtrr);\r
1083\r
1084 //\r
1085 // Find first unused MTRR\r
1086 //\r
1087 for (MsrNum = MTRR_LIB_IA32_VARIABLE_MTRR_BASE;\r
1088 MsrNum < VariableMtrrEnd;\r
1089 MsrNum += 2\r
1090 ) {\r
1091 if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
1092 break;\r
1093 }\r
1094 }\r
1095\r
1096 if (BaseAddress != 0) {\r
1097 do {\r
1098 //\r
1099 // Calculate the alignment of the base address.\r
1100 //\r
1101 Alignment = LShiftU64 (1, (UINTN)LowBitSet64 (BaseAddress));\r
1102\r
1103 if (Alignment > Length) {\r
1104 break;\r
1105 }\r
1106\r
1107 //\r
1108 // Find unused MTRR\r
1109 //\r
1110 for (; MsrNum < VariableMtrrEnd; MsrNum += 2) {\r
1111 if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
1112 break;\r
1113 }\r
1114 }\r
1115\r
1116 ProgramVariableMtrr (\r
1117 MsrNum,\r
1118 BaseAddress,\r
1119 Alignment,\r
1120 MemoryType,\r
1121 MtrrValidAddressMask\r
1122 );\r
1123 BaseAddress += Alignment;\r
1124 Length -= Alignment;\r
1125 } while (TRUE);\r
1126\r
1127 if (Length == 0) {\r
1128 goto Done;\r
1129 }\r
1130 }\r
1131\r
1132 TempQword = Length;\r
1133\r
1134 if (!Positive) {\r
1135 Length = Power2MaxMemory (LShiftU64 (TempQword, 1));\r
e50466da 1136\r
1137 //\r
1a2ad6fc 1138 // Find unused MTRR\r
e50466da 1139 //\r
1a2ad6fc 1140 for (; MsrNum < VariableMtrrEnd; MsrNum += 2) {\r
e50466da 1141 if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
1142 break;\r
1143 }\r
1144 }\r
1145\r
1146 ProgramVariableMtrr (\r
1147 MsrNum,\r
1148 BaseAddress,\r
1149 Length,\r
1150 MemoryType,\r
1151 MtrrValidAddressMask\r
1152 );\r
1a2ad6fc 1153 BaseAddress += Length;\r
1154 TempQword = Length - TempQword;\r
1155 MemoryType = MTRR_CACHE_UNCACHEABLE;\r
1156 }\r
e50466da 1157\r
1a2ad6fc 1158 do {\r
e50466da 1159 //\r
1a2ad6fc 1160 // Find unused MTRR\r
e50466da 1161 //\r
1a2ad6fc 1162 for (; MsrNum < VariableMtrrEnd; MsrNum += 2) {\r
e50466da 1163 if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
1164 break;\r
1165 }\r
1166 }\r
1167\r
1a2ad6fc 1168 Length = Power2MaxMemory (TempQword);\r
e50466da 1169 if (!Positive) {\r
1a2ad6fc 1170 BaseAddress -= Length;\r
e50466da 1171 }\r
1172\r
1a2ad6fc 1173 ProgramVariableMtrr (\r
1174 MsrNum,\r
1175 BaseAddress,\r
1176 Length,\r
1177 MemoryType,\r
1178 MtrrValidAddressMask\r
1179 );\r
e50466da 1180\r
1a2ad6fc 1181 if (Positive) {\r
1182 BaseAddress += Length;\r
1183 }\r
1184 TempQword -= Length;\r
e50466da 1185\r
1a2ad6fc 1186 } while (TempQword > 0);\r
e50466da 1187\r
1188Done:\r
f877f300 1189 DEBUG((DEBUG_CACHE, " Status = %r\n", Status));\r
1190 if (!RETURN_ERROR (Status)) {\r
1191 MtrrDebugPrintAllMtrrs ();\r
1192 }\r
e50466da 1193\r
f877f300 1194 return Status;\r
e50466da 1195}\r
1196\r
1197\r
1198/**\r
1199 This function will get the memory cache type of the specific address.\r
1200\r
1201 This function is mainly for debug purpose.\r
1202\r
76b4cae3 1203 @param[in] Address The specific address\r
e50466da 1204\r
76b4cae3 1205 @return Memory cache type of the specific address\r
e50466da 1206\r
1207**/\r
1208MTRR_MEMORY_CACHE_TYPE\r
1209EFIAPI\r
1210MtrrGetMemoryAttribute (\r
1211 IN PHYSICAL_ADDRESS Address\r
1212 )\r
1213{\r
1214 UINT64 TempQword;\r
1215 UINTN Index;\r
1216 UINTN SubIndex;\r
1217 UINT64 MtrrType;\r
1218 UINT64 TempMtrrType;\r
1219 MTRR_MEMORY_CACHE_TYPE CacheType;\r
3ba736f3 1220 VARIABLE_MTRR VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];\r
e50466da 1221 UINT64 MtrrValidBitsMask;\r
1222 UINT64 MtrrValidAddressMask;\r
3b9be416 1223 UINTN VariableMtrrCount;\r
e50466da 1224\r
947a573a 1225 if (!IsMtrrSupported ()) {\r
1226 return CacheUncacheable;\r
1227 }\r
1228\r
e50466da 1229 //\r
1230 // Check if MTRR is enabled, if not, return UC as attribute\r
1231 //\r
1232 TempQword = AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE);\r
1233 MtrrType = MTRR_CACHE_INVALID_TYPE;\r
1234\r
1235 if ((TempQword & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
1236 return CacheUncacheable;\r
1237 }\r
1238\r
1239 //\r
1240 // If address is less than 1M, then try to go through the fixed MTRR\r
1241 //\r
1242 if (Address < BASE_1MB) {\r
1243 if ((TempQword & MTRR_LIB_CACHE_FIXED_MTRR_ENABLED) != 0) {\r
1244 //\r
1245 // Go through the fixed MTRR\r
1246 //\r
1247 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
f877f300 1248 if (Address >= mMtrrLibFixedMtrrTable[Index].BaseAddress &&\r
e50466da 1249 Address < (\r
f877f300 1250 mMtrrLibFixedMtrrTable[Index].BaseAddress +\r
1251 (mMtrrLibFixedMtrrTable[Index].Length * 8)\r
e50466da 1252 )\r
1253 ) {\r
1254 SubIndex =\r
f877f300 1255 ((UINTN)Address - mMtrrLibFixedMtrrTable[Index].BaseAddress) /\r
1256 mMtrrLibFixedMtrrTable[Index].Length;\r
1257 TempQword = AsmReadMsr64 (mMtrrLibFixedMtrrTable[Index].Msr);\r
e50466da 1258 MtrrType = RShiftU64 (TempQword, SubIndex * 8) & 0xFF;\r
1259 return GetMemoryCacheTypeFromMtrrType (MtrrType);\r
1260 }\r
1261 }\r
1262 }\r
1263 }\r
1264 MtrrLibInitializeMtrrMask(&MtrrValidBitsMask, &MtrrValidAddressMask);\r
1265 MtrrGetMemoryAttributeInVariableMtrr(\r
1266 MtrrValidBitsMask,\r
1267 MtrrValidAddressMask,\r
1268 VariableMtrr\r
1269 );\r
1270\r
1271 //\r
1272 // Go through the variable MTRR\r
1273 //\r
3b9be416 1274 VariableMtrrCount = GetVariableMtrrCount ();\r
5bdfa4e5 1275 ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);\r
1276\r
3b9be416 1277 for (Index = 0; Index < VariableMtrrCount; Index++) {\r
e50466da 1278 if (VariableMtrr[Index].Valid) {\r
1279 if (Address >= VariableMtrr[Index].BaseAddress &&\r
1280 Address < VariableMtrr[Index].BaseAddress+VariableMtrr[Index].Length) {\r
1281 TempMtrrType = VariableMtrr[Index].Type;\r
1282 MtrrType = MtrrPrecedence (MtrrType, TempMtrrType);\r
1283 }\r
1284 }\r
1285 }\r
1286 CacheType = GetMemoryCacheTypeFromMtrrType (MtrrType);\r
1287\r
1288 return CacheType;\r
1289}\r
1290\r
1291\r
1292/**\r
1293 This function will get the raw value in variable MTRRs\r
1294\r
76b4cae3 1295 @param[out] FixedSettings A buffer to hold fixed MTRRs content.\r
e50466da 1296\r
1297 @return The VariableSettings input pointer\r
1298\r
1299**/\r
1300MTRR_VARIABLE_SETTINGS*\r
1301EFIAPI\r
1302MtrrGetVariableMtrr (\r
1303 OUT MTRR_VARIABLE_SETTINGS *VariableSettings\r
1304 )\r
1305{\r
1306 UINT32 Index;\r
3b9be416 1307 UINT32 VariableMtrrCount;\r
e50466da 1308\r
947a573a 1309 if (!IsMtrrSupported ()) {\r
1310 return VariableSettings;\r
1311 }\r
1312\r
3b9be416 1313 VariableMtrrCount = GetVariableMtrrCount ();\r
5bdfa4e5 1314 ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);\r
1315\r
3b9be416 1316 for (Index = 0; Index < VariableMtrrCount; Index++) {\r
e50466da 1317 VariableSettings->Mtrr[Index].Base =\r
1318 AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1));\r
1319 VariableSettings->Mtrr[Index].Mask =\r
1320 AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1) + 1);\r
1321 }\r
1322\r
1323 return VariableSettings;\r
1324}\r
1325\r
1326\r
1327/**\r
1328 Worker function setting variable MTRRs\r
1329\r
76b4cae3 1330 @param[in] VariableSettings A buffer to hold variable MTRRs content.\r
e50466da 1331\r
1332**/\r
1333VOID\r
1334MtrrSetVariableMtrrWorker (\r
1335 IN MTRR_VARIABLE_SETTINGS *VariableSettings\r
1336 )\r
1337{\r
1338 UINT32 Index;\r
3b9be416 1339 UINT32 VariableMtrrCount;\r
e50466da 1340\r
3b9be416 1341 VariableMtrrCount = GetVariableMtrrCount ();\r
5bdfa4e5 1342 ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);\r
1343\r
3b9be416 1344 for (Index = 0; Index < VariableMtrrCount; Index++) {\r
e50466da 1345 AsmWriteMsr64 (\r
1346 MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1),\r
1347 VariableSettings->Mtrr[Index].Base\r
1348 );\r
1349 AsmWriteMsr64 (\r
1350 MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1) + 1,\r
1351 VariableSettings->Mtrr[Index].Mask\r
1352 );\r
1353 }\r
1354}\r
1355\r
1356\r
1357/**\r
1358 This function sets variable MTRRs\r
1359\r
76b4cae3 1360 @param[in] VariableSettings A buffer to hold variable MTRRs content.\r
e50466da 1361\r
1362 @return The pointer of VariableSettings\r
1363\r
1364**/\r
1365MTRR_VARIABLE_SETTINGS*\r
1366EFIAPI\r
1367MtrrSetVariableMtrr (\r
1368 IN MTRR_VARIABLE_SETTINGS *VariableSettings\r
1369 )\r
1370{\r
c878cee4 1371 MTRR_CONTEXT MtrrContext;\r
e50466da 1372\r
947a573a 1373 if (!IsMtrrSupported ()) {\r
1374 return VariableSettings;\r
1375 }\r
1376\r
c878cee4 1377 PreMtrrChange (&MtrrContext);\r
e50466da 1378 MtrrSetVariableMtrrWorker (VariableSettings);\r
c878cee4 1379 PostMtrrChange (&MtrrContext);\r
e50466da 1380 return VariableSettings;\r
1381}\r
1382\r
1383\r
1384/**\r
1385 This function gets the content in fixed MTRRs\r
1386\r
76b4cae3 1387 @param[out] FixedSettings A buffer to hold fixed Mtrrs content.\r
e50466da 1388\r
1389 @retval The pointer of FixedSettings\r
1390\r
1391**/\r
1392MTRR_FIXED_SETTINGS*\r
1393EFIAPI\r
1394MtrrGetFixedMtrr (\r
1395 OUT MTRR_FIXED_SETTINGS *FixedSettings\r
1396 )\r
1397{\r
1398 UINT32 Index;\r
1399\r
947a573a 1400 if (!IsMtrrSupported ()) {\r
1401 return FixedSettings;\r
1402 }\r
1403\r
e50466da 1404 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
1405 FixedSettings->Mtrr[Index] =\r
f877f300 1406 AsmReadMsr64 (mMtrrLibFixedMtrrTable[Index].Msr);\r
e50466da 1407 };\r
1408\r
1409 return FixedSettings;\r
1410}\r
1411\r
1412/**\r
1413 Worker function setting fixed MTRRs\r
1414\r
76b4cae3 1415 @param[in] FixedSettings A buffer to hold fixed Mtrrs content.\r
e50466da 1416\r
1417**/\r
1418VOID\r
1419MtrrSetFixedMtrrWorker (\r
1420 IN MTRR_FIXED_SETTINGS *FixedSettings\r
1421 )\r
1422{\r
1423 UINT32 Index;\r
1424\r
1425 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
1426 AsmWriteMsr64 (\r
f877f300 1427 mMtrrLibFixedMtrrTable[Index].Msr,\r
e50466da 1428 FixedSettings->Mtrr[Index]\r
1429 );\r
1430 }\r
1431}\r
1432\r
1433\r
1434/**\r
1435 This function sets fixed MTRRs\r
1436\r
76b4cae3 1437 @param[in] FixedSettings A buffer to hold fixed Mtrrs content.\r
e50466da 1438\r
1439 @retval The pointer of FixedSettings\r
1440\r
1441**/\r
1442MTRR_FIXED_SETTINGS*\r
1443EFIAPI\r
1444MtrrSetFixedMtrr (\r
1445 IN MTRR_FIXED_SETTINGS *FixedSettings\r
1446 )\r
1447{\r
c878cee4 1448 MTRR_CONTEXT MtrrContext;\r
e50466da 1449\r
947a573a 1450 if (!IsMtrrSupported ()) {\r
1451 return FixedSettings;\r
1452 }\r
1453\r
c878cee4 1454 PreMtrrChange (&MtrrContext);\r
e50466da 1455 MtrrSetFixedMtrrWorker (FixedSettings);\r
c878cee4 1456 PostMtrrChange (&MtrrContext);\r
e50466da 1457\r
1458 return FixedSettings;\r
1459}\r
1460\r
1461\r
1462/**\r
1463 This function gets the content in all MTRRs (variable and fixed)\r
1464\r
76b4cae3 1465 @param[out] MtrrSetting A buffer to hold all Mtrrs content.\r
e50466da 1466\r
1467 @retval the pointer of MtrrSetting\r
1468\r
1469**/\r
1470MTRR_SETTINGS *\r
1471EFIAPI\r
1472MtrrGetAllMtrrs (\r
1473 OUT MTRR_SETTINGS *MtrrSetting\r
1474 )\r
1475{\r
947a573a 1476 if (!IsMtrrSupported ()) {\r
1477 return MtrrSetting;\r
1478 }\r
1479\r
e50466da 1480 //\r
1481 // Get fixed MTRRs\r
1482 //\r
1483 MtrrGetFixedMtrr (&MtrrSetting->Fixed);\r
1484\r
1485 //\r
1486 // Get variable MTRRs\r
1487 //\r
1488 MtrrGetVariableMtrr (&MtrrSetting->Variables);\r
1489\r
1490 //\r
1491 // Get MTRR_DEF_TYPE value\r
1492 //\r
1493 MtrrSetting->MtrrDefType = AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE);\r
1494\r
1495 return MtrrSetting;\r
1496}\r
1497\r
1498\r
1499/**\r
1500 This function sets all MTRRs (variable and fixed)\r
1501\r
76b4cae3 1502 @param[in] MtrrSetting A buffer holding all MTRRs content.\r
e50466da 1503\r
1504 @retval The pointer of MtrrSetting\r
1505\r
1506**/\r
1507MTRR_SETTINGS *\r
1508EFIAPI\r
1509MtrrSetAllMtrrs (\r
1510 IN MTRR_SETTINGS *MtrrSetting\r
1511 )\r
1512{\r
c878cee4 1513 MTRR_CONTEXT MtrrContext;\r
e50466da 1514\r
947a573a 1515 if (!IsMtrrSupported ()) {\r
1516 return MtrrSetting;\r
1517 }\r
1518\r
c878cee4 1519 PreMtrrChange (&MtrrContext);\r
e50466da 1520\r
1521 //\r
1522 // Set fixed MTRRs\r
1523 //\r
1524 MtrrSetFixedMtrrWorker (&MtrrSetting->Fixed);\r
1525\r
1526 //\r
1527 // Set variable MTRRs\r
1528 //\r
1529 MtrrSetVariableMtrrWorker (&MtrrSetting->Variables);\r
1530\r
1531 //\r
1532 // Set MTRR_DEF_TYPE value\r
1533 //\r
1534 AsmWriteMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE, MtrrSetting->MtrrDefType);\r
1535\r
c878cee4 1536 PostMtrrChangeEnableCache (&MtrrContext);\r
e50466da 1537\r
1538 return MtrrSetting;\r
1539}\r
1540\r
e50466da 1541/**\r
1542 This function prints all MTRRs for debugging.\r
1543**/\r
1544VOID\r
430fbbe0 1545EFIAPI\r
e50466da 1546MtrrDebugPrintAllMtrrs (\r
430fbbe0 1547 VOID\r
e50466da 1548 )\r
1549{\r
1550 DEBUG_CODE (\r
76f6d954 1551 MTRR_SETTINGS MtrrSettings;\r
1552 UINTN Index;\r
1553 UINTN Index1;\r
1554 UINTN VariableMtrrCount;\r
1555 UINT64 Base;\r
1556 UINT64 Limit;\r
1557 UINT64 MtrrBase;\r
1558 UINT64 MtrrLimit;\r
1559 UINT64 RangeBase;\r
1560 UINT64 RangeLimit;\r
1561 UINT64 NoRangeBase;\r
1562 UINT64 NoRangeLimit;\r
1563 UINT32 RegEax;\r
1564 UINTN MemoryType;\r
1565 UINTN PreviousMemoryType;\r
1566 BOOLEAN Found;\r
1567\r
1568 if (!IsMtrrSupported ()) {\r
1569 return;\r
1570 }\r
f877f300 1571\r
76f6d954 1572 DEBUG((DEBUG_CACHE, "MTRR Settings\n"));\r
1573 DEBUG((DEBUG_CACHE, "=============\n"));\r
76b4cae3 1574\r
76f6d954 1575 MtrrGetAllMtrrs (&MtrrSettings);\r
1576 DEBUG((DEBUG_CACHE, "MTRR Default Type: %016lx\n", MtrrSettings.MtrrDefType));\r
1577 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
1578 DEBUG((DEBUG_CACHE, "Fixed MTRR[%02d] : %016lx\n", Index, MtrrSettings.Fixed.Mtrr[Index]));\r
1579 }\r
f877f300 1580\r
76f6d954 1581 VariableMtrrCount = GetVariableMtrrCount ();\r
1582 for (Index = 0; Index < VariableMtrrCount; Index++) {\r
1583 DEBUG((DEBUG_CACHE, "Variable MTRR[%02d]: Base=%016lx Mask=%016lx\n",\r
1584 Index,\r
1585 MtrrSettings.Variables.Mtrr[Index].Base,\r
1586 MtrrSettings.Variables.Mtrr[Index].Mask\r
1587 ));\r
1588 }\r
1589 DEBUG((DEBUG_CACHE, "\n"));\r
1590 DEBUG((DEBUG_CACHE, "MTRR Ranges\n"));\r
1591 DEBUG((DEBUG_CACHE, "====================================\n"));\r
1592\r
1593 Base = 0;\r
1594 PreviousMemoryType = MTRR_CACHE_INVALID_TYPE;\r
1595 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
1596 Base = mMtrrLibFixedMtrrTable[Index].BaseAddress;\r
1597 for (Index1 = 0; Index1 < 8; Index1++) {\r
1598 MemoryType = (UINTN)(RShiftU64 (MtrrSettings.Fixed.Mtrr[Index], Index1 * 8) & 0xff);\r
f877f300 1599 if (MemoryType > CacheWriteBack) {\r
1600 MemoryType = MTRR_CACHE_INVALID_TYPE;\r
76b4cae3 1601 }\r
f877f300 1602 if (MemoryType != PreviousMemoryType) {\r
1603 if (PreviousMemoryType != MTRR_CACHE_INVALID_TYPE) {\r
1604 DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));\r
1605 }\r
1606 PreviousMemoryType = MemoryType;\r
1607 DEBUG((DEBUG_CACHE, "%a:%016lx-", mMtrrMemoryCacheTypeShortName[MemoryType], Base));\r
1608 }\r
76f6d954 1609 Base += mMtrrLibFixedMtrrTable[Index].Length;\r
1610 }\r
1611 }\r
1612 DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));\r
1613\r
1614 VariableMtrrCount = GetVariableMtrrCount ();\r
1615\r
44c8400a
JF
1616 Limit = BIT36 - 1;\r
1617 AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);\r
1618 if (RegEax >= 0x80000008) {\r
1619 AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);\r
1620 Limit = LShiftU64 (1, RegEax & 0xff) - 1;\r
1621 }\r
76f6d954 1622 Base = BASE_1MB;\r
1623 PreviousMemoryType = MTRR_CACHE_INVALID_TYPE;\r
1624 do {\r
1625 MemoryType = MtrrGetMemoryAttribute (Base);\r
1626 if (MemoryType > CacheWriteBack) {\r
1627 MemoryType = MTRR_CACHE_INVALID_TYPE;\r
1628 }\r
1629\r
1630 if (MemoryType != PreviousMemoryType) {\r
1631 if (PreviousMemoryType != MTRR_CACHE_INVALID_TYPE) {\r
1632 DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));\r
f877f300 1633 }\r
76f6d954 1634 PreviousMemoryType = MemoryType;\r
1635 DEBUG((DEBUG_CACHE, "%a:%016lx-", mMtrrMemoryCacheTypeShortName[MemoryType], Base));\r
1636 }\r
76b4cae3
MK
1637\r
1638 RangeBase = BASE_1MB;\r
76f6d954 1639 NoRangeBase = BASE_1MB;\r
76f6d954 1640 RangeLimit = Limit;\r
1641 NoRangeLimit = Limit;\r
76b4cae3 1642\r
76f6d954 1643 for (Index = 0, Found = FALSE; Index < VariableMtrrCount; Index++) {\r
1644 if ((MtrrSettings.Variables.Mtrr[Index].Mask & BIT11) == 0) {\r
1645 //\r
1646 // If mask is not valid, then do not display range\r
1647 //\r
1648 continue;\r
1649 }\r
1650 MtrrBase = (MtrrSettings.Variables.Mtrr[Index].Base & (~(SIZE_4KB - 1)));\r
1651 MtrrLimit = MtrrBase + ((~(MtrrSettings.Variables.Mtrr[Index].Mask & (~(SIZE_4KB - 1)))) & Limit);\r
f877f300 1652\r
76f6d954 1653 if (Base >= MtrrBase && Base < MtrrLimit) {\r
1654 Found = TRUE;\r
f877f300 1655 }\r
76b4cae3 1656\r
76f6d954 1657 if (Base >= MtrrBase && MtrrBase > RangeBase) {\r
1658 RangeBase = MtrrBase;\r
f877f300 1659 }\r
76f6d954 1660 if (Base > MtrrLimit && MtrrLimit > RangeBase) {\r
1661 RangeBase = MtrrLimit + 1;\r
1662 }\r
1663 if (Base < MtrrBase && MtrrBase < RangeLimit) {\r
1664 RangeLimit = MtrrBase - 1;\r
1665 }\r
1666 if (Base < MtrrLimit && MtrrLimit <= RangeLimit) {\r
1667 RangeLimit = MtrrLimit;\r
1668 }\r
76b4cae3 1669\r
76f6d954 1670 if (Base > MtrrLimit && NoRangeBase < MtrrLimit) {\r
1671 NoRangeBase = MtrrLimit + 1;\r
1672 }\r
1673 if (Base < MtrrBase && NoRangeLimit > MtrrBase) {\r
1674 NoRangeLimit = MtrrBase - 1;\r
1675 }\r
1676 }\r
76b4cae3 1677\r
76f6d954 1678 if (Found) {\r
1679 Base = RangeLimit + 1;\r
1680 } else {\r
1681 Base = NoRangeLimit + 1;\r
1682 }\r
44c8400a 1683 } while (Base < Limit);\r
76f6d954 1684 DEBUG((DEBUG_CACHE, "%016lx\n\n", Base - 1));\r
e50466da 1685 );\r
1686}\r
1687\r
947a573a 1688/**\r
1689 Checks if MTRR is supported.\r
1690\r
1691 @retval TRUE MTRR is supported.\r
1692 @retval FALSE MTRR is not supported.\r
1693\r
1694**/\r
1695BOOLEAN\r
1696EFIAPI\r
1697IsMtrrSupported (\r
1698 VOID\r
1699 )\r
1700{\r
1701 UINT32 RegEdx;\r
1702 UINT64 MtrrCap;\r
1703\r
1704 //\r
1705 // Check CPUID(1).EDX[12] for MTRR capability\r
1706 //\r
1707 AsmCpuid (1, NULL, NULL, NULL, &RegEdx);\r
1708 if (BitFieldRead32 (RegEdx, 12, 12) == 0) {\r
1709 return FALSE;\r
1710 }\r
1711\r
1712 //\r
1713 // Check IA32_MTRRCAP.[0..7] for number of variable MTRRs and IA32_MTRRCAP[8] for\r
1714 // fixed MTRRs existence. If number of variable MTRRs is zero, or fixed MTRRs do not\r
1715 // exist, return false.\r
1716 //\r
1717 MtrrCap = AsmReadMsr64 (MTRR_LIB_IA32_MTRR_CAP);\r
1718 if ((BitFieldRead64 (MtrrCap, 0, 7) == 0) || (BitFieldRead64 (MtrrCap, 8, 8) == 0)) {\r
1719 return FALSE;\r
1720 }\r
1721\r
1722 return TRUE;\r
1723}\r