]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/Library/MtrrLib/MtrrLib.c
UefiCpuPkg/MtrrLib: Add PCD PcdCpuNumberOfReservedVariableMtrrs
[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
89 },\r
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
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
209 // Disable Mtrrs\r
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
58b23d90 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
242 \r
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
275 @param MemoryCacheType The memory type to set.\r
276 @param Base The base address of memory range.\r
277 @param Length The length of memory range.\r
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
359 Get the attribute of variable MTRRs.\r
360\r
3ba736f3
JY
361 This function shadows the content of variable MTRRs into an\r
362 internal array: VariableMtrr.\r
e50466da 363\r
3ba736f3
JY
364 @param MtrrValidBitsMask The mask for the valid bit of the MTRR\r
365 @param MtrrValidAddressMask The valid address mask for MTRR\r
366 @param 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
426 @param Start The start address of memory range.\r
427 @param End The end address of memory range.\r
428 @param VariableMtrr The array to shadow variable MTRRs content\r
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
464 @param Index The index of the array VariableMtrr to be invalidated\r
465 @param VariableMtrr The array to shadow variable MTRRs content\r
466 @param UsedMtrr The number of MTRRs which has already been used\r
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
482 Combine memory attributes.\r
483\r
484 If overlap exists between given memory range and MTRRs, try to combine them.\r
485\r
486 @param Attributes The memory type to set.\r
487 @param Base The base address of memory range.\r
488 @param Length The length of memory range.\r
489 @param VariableMtrr The array to shadow variable MTRRs content\r
490 @param UsedMtrr The number of MTRRs which has already been used\r
491 @param OverwriteExistingMtrr Returns whether an existing MTRR was used\r
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
1e60a0ec 539 // if the Mtrr range contain the request range, set a flag, then continue to \r
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
600 Calculate the maximum value which is a power of 2, but less the MemoryLength.\r
601\r
602 @param MemoryLength The number to pass in.\r
603 @return The maximum value which is align to power of 2 and less the MemoryLength\r
604\r
605**/\r
606UINT64\r
607Power2MaxMemory (\r
608 IN UINT64 MemoryLength\r
609 )\r
610{\r
611 UINT64 Result;\r
612\r
430fbbe0 613 if (RShiftU64 (MemoryLength, 32) != 0) {\r
e50466da 614 Result = LShiftU64 (\r
615 (UINT64) GetPowerOfTwo32 (\r
616 (UINT32) RShiftU64 (MemoryLength, 32)\r
617 ),\r
618 32\r
619 );\r
620 } else {\r
621 Result = (UINT64) GetPowerOfTwo32 ((UINT32) MemoryLength);\r
622 }\r
623\r
624 return Result;\r
625}\r
626\r
627\r
628/**\r
1a2ad6fc 629 Determine the MTRR numbers used to program a memory range.\r
e50466da 630\r
1a2ad6fc 631 This function first checks the alignment of the base address. If the alignment of the base address <= Length,\r
632 cover the memory range (BaseAddress, alignment) by a MTRR, then BaseAddress += alignment and Length -= alignment.\r
633 Repeat the step until alignment > Length.\r
e50466da 634\r
1a2ad6fc 635 Then this function determines which direction of programming the variable MTRRs for the remaining length\r
636 will use fewer MTRRs.\r
637\r
638 @param BaseAddress Length of Memory to program MTRR\r
639 @param Length Length of Memory to program MTRR\r
e50466da 640 @param MtrrNumber Pointer to the number of necessary MTRRs\r
641\r
642 @retval TRUE Positive direction is better.\r
643 FALSE Negtive direction is better.\r
644\r
645**/\r
646BOOLEAN\r
1a2ad6fc 647GetMtrrNumberAndDirection (\r
648 IN UINT64 BaseAddress,\r
649 IN UINT64 Length,\r
e50466da 650 IN UINTN *MtrrNumber\r
651 )\r
652{\r
653 UINT64 TempQword;\r
1a2ad6fc 654 UINT64 Alignment;\r
e50466da 655 UINT32 Positive;\r
656 UINT32 Subtractive;\r
657\r
1a2ad6fc 658 *MtrrNumber = 0;\r
659\r
660 if (BaseAddress != 0) {\r
661 do {\r
662 //\r
663 // Calculate the alignment of the base address.\r
664 //\r
665 Alignment = LShiftU64 (1, (UINTN)LowBitSet64 (BaseAddress));\r
666\r
667 if (Alignment > Length) {\r
668 break;\r
669 }\r
670\r
671 (*MtrrNumber)++;\r
672 BaseAddress += Alignment;\r
673 Length -= Alignment;\r
674 } while (TRUE);\r
675\r
676 if (Length == 0) {\r
677 return TRUE;\r
678 }\r
679 }\r
680\r
681 TempQword = Length;\r
e50466da 682 Positive = 0;\r
683 Subtractive = 0;\r
684\r
685 do {\r
686 TempQword -= Power2MaxMemory (TempQword);\r
687 Positive++;\r
688 } while (TempQword != 0);\r
689\r
1a2ad6fc 690 TempQword = Power2MaxMemory (LShiftU64 (Length, 1)) - Length;\r
e50466da 691 Subtractive++;\r
692 do {\r
693 TempQword -= Power2MaxMemory (TempQword);\r
694 Subtractive++;\r
695 } while (TempQword != 0);\r
696\r
697 if (Positive <= Subtractive) {\r
1a2ad6fc 698 *MtrrNumber += Positive;\r
e50466da 699 return TRUE;\r
700 } else {\r
1a2ad6fc 701 *MtrrNumber += Subtractive;\r
e50466da 702 return FALSE;\r
703 }\r
704}\r
705\r
706/**\r
707 Invalid variable MTRRs according to the value in the shadow array.\r
708\r
709 This function programs MTRRs according to the values specified\r
710 in the shadow array.\r
711\r
712 @param VariableMtrr The array to shadow variable MTRRs content\r
713\r
714**/\r
e50466da 715VOID\r
716InvalidateMtrr (\r
717 IN VARIABLE_MTRR *VariableMtrr\r
718 )\r
719{\r
c878cee4 720 UINTN Index;\r
721 UINTN VariableMtrrCount;\r
722 MTRR_CONTEXT MtrrContext;\r
e50466da 723\r
c878cee4 724 PreMtrrChange (&MtrrContext);\r
e50466da 725 Index = 0;\r
3b9be416
JY
726 VariableMtrrCount = GetVariableMtrrCount ();\r
727 while (Index < VariableMtrrCount) {\r
430fbbe0 728 if (!VariableMtrr[Index].Valid && VariableMtrr[Index].Used) {\r
e50466da 729 AsmWriteMsr64 (VariableMtrr[Index].Msr, 0);\r
730 AsmWriteMsr64 (VariableMtrr[Index].Msr + 1, 0);\r
731 VariableMtrr[Index].Used = FALSE;\r
732 }\r
733 Index ++;\r
734 }\r
c878cee4 735 PostMtrrChange (&MtrrContext);\r
e50466da 736}\r
737\r
738\r
739/**\r
740 Programs variable MTRRs\r
741\r
742 This function programs variable MTRRs\r
743\r
744 @param MtrrNumber Index of MTRR to program.\r
745 @param BaseAddress Base address of memory region.\r
746 @param Length Length of memory region.\r
747 @param MemoryCacheType Memory type to set.\r
748 @param MtrrValidAddressMask The valid address mask for MTRR\r
749\r
750**/\r
e50466da 751VOID\r
752ProgramVariableMtrr (\r
753 IN UINTN MtrrNumber,\r
754 IN PHYSICAL_ADDRESS BaseAddress,\r
755 IN UINT64 Length,\r
756 IN UINT64 MemoryCacheType,\r
757 IN UINT64 MtrrValidAddressMask\r
758 )\r
759{\r
c878cee4 760 UINT64 TempQword;\r
761 MTRR_CONTEXT MtrrContext;\r
e50466da 762\r
c878cee4 763 PreMtrrChange (&MtrrContext);\r
e50466da 764\r
765 //\r
766 // MTRR Physical Base\r
767 //\r
768 TempQword = (BaseAddress & MtrrValidAddressMask) | MemoryCacheType;\r
769 AsmWriteMsr64 ((UINT32) MtrrNumber, TempQword);\r
770\r
771 //\r
772 // MTRR Physical Mask\r
773 //\r
774 TempQword = ~(Length - 1);\r
775 AsmWriteMsr64 (\r
776 (UINT32) (MtrrNumber + 1),\r
777 (TempQword & MtrrValidAddressMask) | MTRR_LIB_CACHE_MTRR_ENABLED\r
778 );\r
779\r
c878cee4 780 PostMtrrChange (&MtrrContext);\r
e50466da 781}\r
782\r
783\r
784/**\r
785 Convert the Memory attibute value to MTRR_MEMORY_CACHE_TYPE.\r
786\r
787 @param MtrrType MTRR memory type\r
788\r
789 @return The enum item in MTRR_MEMORY_CACHE_TYPE\r
790\r
791**/\r
e50466da 792MTRR_MEMORY_CACHE_TYPE\r
793GetMemoryCacheTypeFromMtrrType (\r
794 IN UINT64 MtrrType\r
795 )\r
796{\r
797 switch (MtrrType) {\r
798 case MTRR_CACHE_UNCACHEABLE:\r
799 return CacheUncacheable;\r
800 case MTRR_CACHE_WRITE_COMBINING:\r
801 return CacheWriteCombining;\r
802 case MTRR_CACHE_WRITE_THROUGH:\r
803 return CacheWriteThrough;\r
804 case MTRR_CACHE_WRITE_PROTECTED:\r
805 return CacheWriteProtected;\r
806 case MTRR_CACHE_WRITE_BACK:\r
807 return CacheWriteBack;\r
808 default:\r
809 //\r
810 // MtrrType is MTRR_CACHE_INVALID_TYPE, that means\r
811 // no mtrr covers the range\r
812 //\r
44c8400a 813 return MtrrGetDefaultMemoryType ();\r
e50466da 814 }\r
815}\r
816\r
817/**\r
818 Initializes the valid bits mask and valid address mask for MTRRs.\r
819\r
820 This function initializes the valid bits mask and valid address mask for MTRRs.\r
821\r
822 @param MtrrValidBitsMask The mask for the valid bit of the MTRR\r
823 @param MtrrValidAddressMask The valid address mask for the MTRR\r
824\r
825**/\r
e50466da 826VOID\r
827MtrrLibInitializeMtrrMask (\r
828 OUT UINT64 *MtrrValidBitsMask,\r
829 OUT UINT64 *MtrrValidAddressMask\r
830 )\r
831{\r
f877f300 832 UINT32 RegEax;\r
833 UINT8 PhysicalAddressBits;\r
e50466da 834\r
835 AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);\r
836\r
837 if (RegEax >= 0x80000008) {\r
838 AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);\r
839\r
840 PhysicalAddressBits = (UINT8) RegEax;\r
841\r
842 *MtrrValidBitsMask = LShiftU64 (1, PhysicalAddressBits) - 1;\r
843 *MtrrValidAddressMask = *MtrrValidBitsMask & 0xfffffffffffff000ULL;\r
844 } else {\r
0a4f7aa0
JF
845 *MtrrValidBitsMask = MTRR_LIB_MSR_VALID_MASK;\r
846 *MtrrValidAddressMask = MTRR_LIB_CACHE_VALID_ADDRESS;\r
e50466da 847 }\r
848}\r
849\r
850\r
851/**\r
852 Determing the real attribute of a memory range.\r
853\r
854 This function is to arbitrate the real attribute of the memory when\r
855 there are 2 MTRR covers the same memory range. For further details,\r
856 please refer the IA32 Software Developer's Manual, Volume 3,\r
857 Section 10.11.4.1.\r
858\r
859 @param MtrrType1 the first kind of Memory type\r
860 @param MtrrType2 the second kind of memory type\r
861\r
862**/\r
863UINT64\r
864MtrrPrecedence (\r
865 UINT64 MtrrType1,\r
866 UINT64 MtrrType2\r
867 )\r
868{\r
869 UINT64 MtrrType;\r
870\r
871 MtrrType = MTRR_CACHE_INVALID_TYPE;\r
872 switch (MtrrType1) {\r
873 case MTRR_CACHE_UNCACHEABLE:\r
874 MtrrType = MTRR_CACHE_UNCACHEABLE;\r
875 break;\r
876 case MTRR_CACHE_WRITE_COMBINING:\r
877 if (\r
878 MtrrType2==MTRR_CACHE_WRITE_COMBINING ||\r
879 MtrrType2==MTRR_CACHE_UNCACHEABLE\r
880 ) {\r
881 MtrrType = MtrrType2;\r
882 }\r
883 break;\r
884 case MTRR_CACHE_WRITE_THROUGH:\r
885 if (\r
886 MtrrType2==MTRR_CACHE_WRITE_THROUGH ||\r
887 MtrrType2==MTRR_CACHE_WRITE_BACK\r
888 ) {\r
889 MtrrType = MTRR_CACHE_WRITE_THROUGH;\r
890 } else if(MtrrType2==MTRR_CACHE_UNCACHEABLE) {\r
891 MtrrType = MTRR_CACHE_UNCACHEABLE;\r
892 }\r
893 break;\r
894 case MTRR_CACHE_WRITE_PROTECTED:\r
895 if (MtrrType2 == MTRR_CACHE_WRITE_PROTECTED ||\r
896 MtrrType2 == MTRR_CACHE_UNCACHEABLE) {\r
897 MtrrType = MtrrType2;\r
898 }\r
899 break;\r
900 case MTRR_CACHE_WRITE_BACK:\r
901 if (\r
902 MtrrType2== MTRR_CACHE_UNCACHEABLE ||\r
903 MtrrType2==MTRR_CACHE_WRITE_THROUGH ||\r
904 MtrrType2== MTRR_CACHE_WRITE_BACK\r
905 ) {\r
906 MtrrType = MtrrType2;\r
907 }\r
908 break;\r
909 case MTRR_CACHE_INVALID_TYPE:\r
910 MtrrType = MtrrType2;\r
911 break;\r
912 default:\r
913 break;\r
914 }\r
915\r
916 if (MtrrType2 == MTRR_CACHE_INVALID_TYPE) {\r
917 MtrrType = MtrrType1;\r
918 }\r
919 return MtrrType;\r
920}\r
921\r
922\r
923/**\r
924 This function attempts to set the attributes for a memory range.\r
925\r
926 @param BaseAddress The physical address that is the start\r
927 address of a memory region.\r
928 @param Length The size in bytes of the memory region.\r
929 @param Attributes The bit mask of attributes to set for the\r
930 memory region.\r
931\r
932 @retval RETURN_SUCCESS The attributes were set for the memory\r
933 region.\r
934 @retval RETURN_INVALID_PARAMETER Length is zero.\r
935 @retval RETURN_UNSUPPORTED The processor does not support one or\r
936 more bytes of the memory resource range\r
937 specified by BaseAddress and Length.\r
938 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support\r
939 for the memory resource range specified\r
940 by BaseAddress and Length.\r
941 @retval RETURN_ACCESS_DENIED The attributes for the memory resource\r
942 range specified by BaseAddress and Length\r
943 cannot be modified.\r
944 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to\r
945 modify the attributes of the memory\r
946 resource range.\r
947\r
948**/\r
949RETURN_STATUS\r
950EFIAPI\r
951MtrrSetMemoryAttribute (\r
952 IN PHYSICAL_ADDRESS BaseAddress,\r
953 IN UINT64 Length,\r
954 IN MTRR_MEMORY_CACHE_TYPE Attribute\r
955 )\r
956{\r
957 UINT64 TempQword;\r
958 RETURN_STATUS Status;\r
959 UINT64 MemoryType;\r
1a2ad6fc 960 UINT64 Alignment;\r
e50466da 961 BOOLEAN OverLap;\r
962 BOOLEAN Positive;\r
963 UINT32 MsrNum;\r
964 UINTN MtrrNumber;\r
3ba736f3 965 VARIABLE_MTRR VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];\r
e50466da 966 UINT32 UsedMtrr;\r
967 UINT64 MtrrValidBitsMask;\r
968 UINT64 MtrrValidAddressMask;\r
e50466da 969 BOOLEAN OverwriteExistingMtrr;\r
3b9be416
JY
970 UINT32 FirmwareVariableMtrrCount;\r
971 UINT32 VariableMtrrEnd;\r
c878cee4 972 MTRR_CONTEXT MtrrContext;\r
3b9be416 973\r
f877f300 974 DEBUG((DEBUG_CACHE, "MtrrSetMemoryAttribute() %a:%016lx-%016lx\n", mMtrrMemoryCacheTypeShortName[Attribute], BaseAddress, Length));\r
975\r
947a573a 976 if (!IsMtrrSupported ()) {\r
f877f300 977 Status = RETURN_UNSUPPORTED;\r
978 goto Done;\r
947a573a 979 }\r
980\r
3b9be416
JY
981 FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCount ();\r
982 VariableMtrrEnd = MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (2 * GetVariableMtrrCount ()) - 1;\r
e50466da 983\r
984 MtrrLibInitializeMtrrMask(&MtrrValidBitsMask, &MtrrValidAddressMask);\r
985\r
986 TempQword = 0;\r
987 MemoryType = (UINT64)Attribute;\r
988 OverwriteExistingMtrr = FALSE;\r
989\r
990 //\r
991 // Check for an invalid parameter\r
992 //\r
993 if (Length == 0) {\r
f877f300 994 Status = RETURN_INVALID_PARAMETER;\r
995 goto Done;\r
e50466da 996 }\r
997\r
998 if (\r
f877f300 999 (BaseAddress & ~MtrrValidAddressMask) != 0 ||\r
1000 (Length & ~MtrrValidAddressMask) != 0\r
e50466da 1001 ) {\r
f877f300 1002 Status = RETURN_UNSUPPORTED;\r
1003 goto Done;\r
e50466da 1004 }\r
1005\r
1006 //\r
1007 // Check if Fixed MTRR\r
1008 //\r
1009 Status = RETURN_SUCCESS;\r
1010 while ((BaseAddress < BASE_1MB) && (Length > 0) && Status == RETURN_SUCCESS) {\r
c878cee4 1011 PreMtrrChange (&MtrrContext);\r
e50466da 1012 Status = ProgramFixedMtrr (MemoryType, &BaseAddress, &Length);\r
c878cee4 1013 PostMtrrChange (&MtrrContext);\r
e50466da 1014 if (RETURN_ERROR (Status)) {\r
f877f300 1015 goto Done;\r
e50466da 1016 }\r
1017 }\r
1018\r
1019 if (Length == 0) {\r
1020 //\r
1021 // A Length of 0 can only make sense for fixed MTTR ranges.\r
1022 // Since we just handled the fixed MTRRs, we can skip the\r
1023 // variable MTRR section.\r
1024 //\r
1025 goto Done;\r
1026 }\r
1027\r
1028 //\r
1029 // Since memory ranges below 1MB will be overridden by the fixed MTRRs,\r
f877f300 1030 // we can set the base to 0 to save variable MTRRs.\r
e50466da 1031 //\r
1032 if (BaseAddress == BASE_1MB) {\r
1033 BaseAddress = 0;\r
1034 Length += SIZE_1MB;\r
1035 }\r
1036\r
e50466da 1037 //\r
1038 // Check for overlap\r
1039 //\r
3ba736f3 1040 UsedMtrr = MtrrGetMemoryAttributeInVariableMtrr (MtrrValidBitsMask, MtrrValidAddressMask, VariableMtrr);\r
e50466da 1041 OverLap = CheckMemoryAttributeOverlap (BaseAddress, BaseAddress + Length - 1, VariableMtrr);\r
1042 if (OverLap) {\r
1043 Status = CombineMemoryAttribute (MemoryType, &BaseAddress, &Length, VariableMtrr, &UsedMtrr, &OverwriteExistingMtrr);\r
1044 if (RETURN_ERROR (Status)) {\r
1045 goto Done;\r
1046 }\r
1047\r
1048 if (Length == 0) {\r
1049 //\r
1e60a0ec 1050 // Combined successfully, invalidate the now-unused MTRRs\r
e50466da 1051 //\r
1e60a0ec 1052 InvalidateMtrr(VariableMtrr);\r
e50466da 1053 Status = RETURN_SUCCESS;\r
1054 goto Done;\r
1055 }\r
1056 }\r
e50466da 1057\r
1058 //\r
1059 // The memory type is the same with the type specified by\r
1060 // MTRR_LIB_IA32_MTRR_DEF_TYPE.\r
1061 //\r
91ec7824 1062 if ((!OverwriteExistingMtrr) && (Attribute == MtrrGetDefaultMemoryType ())) {\r
e50466da 1063 //\r
1064 // Invalidate the now-unused MTRRs\r
1065 //\r
1066 InvalidateMtrr(VariableMtrr);\r
1067 goto Done;\r
1068 }\r
1069\r
1a2ad6fc 1070 Positive = GetMtrrNumberAndDirection (BaseAddress, Length, &MtrrNumber);\r
e50466da 1071\r
1a2ad6fc 1072 if ((UsedMtrr + MtrrNumber) > FirmwareVariableMtrrCount) {\r
1073 Status = RETURN_OUT_OF_RESOURCES;\r
1074 goto Done;\r
1075 }\r
e50466da 1076\r
1a2ad6fc 1077 //\r
1078 // Invalidate the now-unused MTRRs\r
1079 //\r
1080 InvalidateMtrr(VariableMtrr);\r
1081\r
1082 //\r
1083 // Find first unused MTRR\r
1084 //\r
1085 for (MsrNum = MTRR_LIB_IA32_VARIABLE_MTRR_BASE;\r
1086 MsrNum < VariableMtrrEnd;\r
1087 MsrNum += 2\r
1088 ) {\r
1089 if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
1090 break;\r
1091 }\r
1092 }\r
1093\r
1094 if (BaseAddress != 0) {\r
1095 do {\r
1096 //\r
1097 // Calculate the alignment of the base address.\r
1098 //\r
1099 Alignment = LShiftU64 (1, (UINTN)LowBitSet64 (BaseAddress));\r
1100\r
1101 if (Alignment > Length) {\r
1102 break;\r
1103 }\r
1104\r
1105 //\r
1106 // Find unused MTRR\r
1107 //\r
1108 for (; MsrNum < VariableMtrrEnd; MsrNum += 2) {\r
1109 if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
1110 break;\r
1111 }\r
1112 }\r
1113\r
1114 ProgramVariableMtrr (\r
1115 MsrNum,\r
1116 BaseAddress,\r
1117 Alignment,\r
1118 MemoryType,\r
1119 MtrrValidAddressMask\r
1120 );\r
1121 BaseAddress += Alignment;\r
1122 Length -= Alignment;\r
1123 } while (TRUE);\r
1124\r
1125 if (Length == 0) {\r
1126 goto Done;\r
1127 }\r
1128 }\r
1129\r
1130 TempQword = Length;\r
1131\r
1132 if (!Positive) {\r
1133 Length = Power2MaxMemory (LShiftU64 (TempQword, 1));\r
e50466da 1134\r
1135 //\r
1a2ad6fc 1136 // Find unused MTRR\r
e50466da 1137 //\r
1a2ad6fc 1138 for (; MsrNum < VariableMtrrEnd; MsrNum += 2) {\r
e50466da 1139 if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
1140 break;\r
1141 }\r
1142 }\r
1143\r
1144 ProgramVariableMtrr (\r
1145 MsrNum,\r
1146 BaseAddress,\r
1147 Length,\r
1148 MemoryType,\r
1149 MtrrValidAddressMask\r
1150 );\r
1a2ad6fc 1151 BaseAddress += Length;\r
1152 TempQword = Length - TempQword;\r
1153 MemoryType = MTRR_CACHE_UNCACHEABLE;\r
1154 }\r
e50466da 1155\r
1a2ad6fc 1156 do {\r
e50466da 1157 //\r
1a2ad6fc 1158 // Find unused MTRR\r
e50466da 1159 //\r
1a2ad6fc 1160 for (; MsrNum < VariableMtrrEnd; MsrNum += 2) {\r
e50466da 1161 if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
1162 break;\r
1163 }\r
1164 }\r
1165\r
1a2ad6fc 1166 Length = Power2MaxMemory (TempQword);\r
e50466da 1167 if (!Positive) {\r
1a2ad6fc 1168 BaseAddress -= Length;\r
e50466da 1169 }\r
1170\r
1a2ad6fc 1171 ProgramVariableMtrr (\r
1172 MsrNum,\r
1173 BaseAddress,\r
1174 Length,\r
1175 MemoryType,\r
1176 MtrrValidAddressMask\r
1177 );\r
e50466da 1178\r
1a2ad6fc 1179 if (Positive) {\r
1180 BaseAddress += Length;\r
1181 }\r
1182 TempQword -= Length;\r
e50466da 1183\r
1a2ad6fc 1184 } while (TempQword > 0);\r
e50466da 1185\r
1186Done:\r
f877f300 1187 DEBUG((DEBUG_CACHE, " Status = %r\n", Status));\r
1188 if (!RETURN_ERROR (Status)) {\r
1189 MtrrDebugPrintAllMtrrs ();\r
1190 }\r
e50466da 1191\r
f877f300 1192 return Status;\r
e50466da 1193}\r
1194\r
1195\r
1196/**\r
1197 This function will get the memory cache type of the specific address.\r
1198\r
1199 This function is mainly for debug purpose.\r
1200\r
1201 @param Address The specific address\r
1202\r
1203 @return Memory cache type of the sepcific address\r
1204\r
1205**/\r
1206MTRR_MEMORY_CACHE_TYPE\r
1207EFIAPI\r
1208MtrrGetMemoryAttribute (\r
1209 IN PHYSICAL_ADDRESS Address\r
1210 )\r
1211{\r
1212 UINT64 TempQword;\r
1213 UINTN Index;\r
1214 UINTN SubIndex;\r
1215 UINT64 MtrrType;\r
1216 UINT64 TempMtrrType;\r
1217 MTRR_MEMORY_CACHE_TYPE CacheType;\r
3ba736f3 1218 VARIABLE_MTRR VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];\r
e50466da 1219 UINT64 MtrrValidBitsMask;\r
1220 UINT64 MtrrValidAddressMask;\r
3b9be416 1221 UINTN VariableMtrrCount;\r
e50466da 1222\r
947a573a 1223 if (!IsMtrrSupported ()) {\r
1224 return CacheUncacheable;\r
1225 }\r
1226\r
e50466da 1227 //\r
1228 // Check if MTRR is enabled, if not, return UC as attribute\r
1229 //\r
1230 TempQword = AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE);\r
1231 MtrrType = MTRR_CACHE_INVALID_TYPE;\r
1232\r
1233 if ((TempQword & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
1234 return CacheUncacheable;\r
1235 }\r
1236\r
1237 //\r
1238 // If address is less than 1M, then try to go through the fixed MTRR\r
1239 //\r
1240 if (Address < BASE_1MB) {\r
1241 if ((TempQword & MTRR_LIB_CACHE_FIXED_MTRR_ENABLED) != 0) {\r
1242 //\r
1243 // Go through the fixed MTRR\r
1244 //\r
1245 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
f877f300 1246 if (Address >= mMtrrLibFixedMtrrTable[Index].BaseAddress &&\r
e50466da 1247 Address < (\r
f877f300 1248 mMtrrLibFixedMtrrTable[Index].BaseAddress +\r
1249 (mMtrrLibFixedMtrrTable[Index].Length * 8)\r
e50466da 1250 )\r
1251 ) {\r
1252 SubIndex =\r
f877f300 1253 ((UINTN)Address - mMtrrLibFixedMtrrTable[Index].BaseAddress) /\r
1254 mMtrrLibFixedMtrrTable[Index].Length;\r
1255 TempQword = AsmReadMsr64 (mMtrrLibFixedMtrrTable[Index].Msr);\r
e50466da 1256 MtrrType = RShiftU64 (TempQword, SubIndex * 8) & 0xFF;\r
1257 return GetMemoryCacheTypeFromMtrrType (MtrrType);\r
1258 }\r
1259 }\r
1260 }\r
1261 }\r
1262 MtrrLibInitializeMtrrMask(&MtrrValidBitsMask, &MtrrValidAddressMask);\r
1263 MtrrGetMemoryAttributeInVariableMtrr(\r
1264 MtrrValidBitsMask,\r
1265 MtrrValidAddressMask,\r
1266 VariableMtrr\r
1267 );\r
1268\r
1269 //\r
1270 // Go through the variable MTRR\r
1271 //\r
3b9be416 1272 VariableMtrrCount = GetVariableMtrrCount ();\r
5bdfa4e5 1273 ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);\r
1274\r
3b9be416 1275 for (Index = 0; Index < VariableMtrrCount; Index++) {\r
e50466da 1276 if (VariableMtrr[Index].Valid) {\r
1277 if (Address >= VariableMtrr[Index].BaseAddress &&\r
1278 Address < VariableMtrr[Index].BaseAddress+VariableMtrr[Index].Length) {\r
1279 TempMtrrType = VariableMtrr[Index].Type;\r
1280 MtrrType = MtrrPrecedence (MtrrType, TempMtrrType);\r
1281 }\r
1282 }\r
1283 }\r
1284 CacheType = GetMemoryCacheTypeFromMtrrType (MtrrType);\r
1285\r
1286 return CacheType;\r
1287}\r
1288\r
1289\r
1290/**\r
1291 This function will get the raw value in variable MTRRs\r
1292\r
1293 @param VariableSettings A buffer to hold variable MTRRs content.\r
1294\r
1295 @return The VariableSettings input pointer\r
1296\r
1297**/\r
1298MTRR_VARIABLE_SETTINGS*\r
1299EFIAPI\r
1300MtrrGetVariableMtrr (\r
1301 OUT MTRR_VARIABLE_SETTINGS *VariableSettings\r
1302 )\r
1303{\r
1304 UINT32 Index;\r
3b9be416 1305 UINT32 VariableMtrrCount;\r
e50466da 1306\r
947a573a 1307 if (!IsMtrrSupported ()) {\r
1308 return VariableSettings;\r
1309 }\r
1310\r
3b9be416 1311 VariableMtrrCount = GetVariableMtrrCount ();\r
5bdfa4e5 1312 ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);\r
1313\r
3b9be416 1314 for (Index = 0; Index < VariableMtrrCount; Index++) {\r
e50466da 1315 VariableSettings->Mtrr[Index].Base =\r
1316 AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1));\r
1317 VariableSettings->Mtrr[Index].Mask =\r
1318 AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1) + 1);\r
1319 }\r
1320\r
1321 return VariableSettings;\r
1322}\r
1323\r
1324\r
1325/**\r
1326 Worker function setting variable MTRRs\r
1327\r
1328 @param VariableSettings A buffer to hold variable MTRRs content.\r
1329\r
1330**/\r
1331VOID\r
1332MtrrSetVariableMtrrWorker (\r
1333 IN MTRR_VARIABLE_SETTINGS *VariableSettings\r
1334 )\r
1335{\r
1336 UINT32 Index;\r
3b9be416 1337 UINT32 VariableMtrrCount;\r
e50466da 1338\r
3b9be416 1339 VariableMtrrCount = GetVariableMtrrCount ();\r
5bdfa4e5 1340 ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);\r
1341\r
3b9be416 1342 for (Index = 0; Index < VariableMtrrCount; Index++) {\r
e50466da 1343 AsmWriteMsr64 (\r
1344 MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1),\r
1345 VariableSettings->Mtrr[Index].Base\r
1346 );\r
1347 AsmWriteMsr64 (\r
1348 MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1) + 1,\r
1349 VariableSettings->Mtrr[Index].Mask\r
1350 );\r
1351 }\r
1352}\r
1353\r
1354\r
1355/**\r
1356 This function sets variable MTRRs\r
1357\r
1358 @param VariableSettings A buffer to hold variable MTRRs content.\r
1359\r
1360 @return The pointer of VariableSettings\r
1361\r
1362**/\r
1363MTRR_VARIABLE_SETTINGS*\r
1364EFIAPI\r
1365MtrrSetVariableMtrr (\r
1366 IN MTRR_VARIABLE_SETTINGS *VariableSettings\r
1367 )\r
1368{\r
c878cee4 1369 MTRR_CONTEXT MtrrContext;\r
e50466da 1370\r
947a573a 1371 if (!IsMtrrSupported ()) {\r
1372 return VariableSettings;\r
1373 }\r
1374\r
c878cee4 1375 PreMtrrChange (&MtrrContext);\r
e50466da 1376 MtrrSetVariableMtrrWorker (VariableSettings);\r
c878cee4 1377 PostMtrrChange (&MtrrContext);\r
e50466da 1378 return VariableSettings;\r
1379}\r
1380\r
1381\r
1382/**\r
1383 This function gets the content in fixed MTRRs\r
1384\r
1385 @param FixedSettings A buffer to hold fixed Mtrrs content.\r
1386\r
1387 @retval The pointer of FixedSettings\r
1388\r
1389**/\r
1390MTRR_FIXED_SETTINGS*\r
1391EFIAPI\r
1392MtrrGetFixedMtrr (\r
1393 OUT MTRR_FIXED_SETTINGS *FixedSettings\r
1394 )\r
1395{\r
1396 UINT32 Index;\r
1397\r
947a573a 1398 if (!IsMtrrSupported ()) {\r
1399 return FixedSettings;\r
1400 }\r
1401\r
e50466da 1402 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
1403 FixedSettings->Mtrr[Index] =\r
f877f300 1404 AsmReadMsr64 (mMtrrLibFixedMtrrTable[Index].Msr);\r
e50466da 1405 };\r
1406\r
1407 return FixedSettings;\r
1408}\r
1409\r
1410/**\r
1411 Worker function setting fixed MTRRs\r
1412\r
1413 @param FixedSettings A buffer to hold fixed Mtrrs content.\r
1414\r
1415**/\r
1416VOID\r
1417MtrrSetFixedMtrrWorker (\r
1418 IN MTRR_FIXED_SETTINGS *FixedSettings\r
1419 )\r
1420{\r
1421 UINT32 Index;\r
1422\r
1423 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
1424 AsmWriteMsr64 (\r
f877f300 1425 mMtrrLibFixedMtrrTable[Index].Msr,\r
e50466da 1426 FixedSettings->Mtrr[Index]\r
1427 );\r
1428 }\r
1429}\r
1430\r
1431\r
1432/**\r
1433 This function sets fixed MTRRs\r
1434\r
1435 @param FixedSettings A buffer to hold fixed Mtrrs content.\r
1436\r
1437 @retval The pointer of FixedSettings\r
1438\r
1439**/\r
1440MTRR_FIXED_SETTINGS*\r
1441EFIAPI\r
1442MtrrSetFixedMtrr (\r
1443 IN MTRR_FIXED_SETTINGS *FixedSettings\r
1444 )\r
1445{\r
c878cee4 1446 MTRR_CONTEXT MtrrContext;\r
e50466da 1447\r
947a573a 1448 if (!IsMtrrSupported ()) {\r
1449 return FixedSettings;\r
1450 }\r
1451\r
c878cee4 1452 PreMtrrChange (&MtrrContext);\r
e50466da 1453 MtrrSetFixedMtrrWorker (FixedSettings);\r
c878cee4 1454 PostMtrrChange (&MtrrContext);\r
e50466da 1455\r
1456 return FixedSettings;\r
1457}\r
1458\r
1459\r
1460/**\r
1461 This function gets the content in all MTRRs (variable and fixed)\r
1462\r
1463 @param MtrrSetting A buffer to hold all Mtrrs content.\r
1464\r
1465 @retval the pointer of MtrrSetting\r
1466\r
1467**/\r
1468MTRR_SETTINGS *\r
1469EFIAPI\r
1470MtrrGetAllMtrrs (\r
1471 OUT MTRR_SETTINGS *MtrrSetting\r
1472 )\r
1473{\r
947a573a 1474 if (!IsMtrrSupported ()) {\r
1475 return MtrrSetting;\r
1476 }\r
1477\r
e50466da 1478 //\r
1479 // Get fixed MTRRs\r
1480 //\r
1481 MtrrGetFixedMtrr (&MtrrSetting->Fixed);\r
1482\r
1483 //\r
1484 // Get variable MTRRs\r
1485 //\r
1486 MtrrGetVariableMtrr (&MtrrSetting->Variables);\r
1487\r
1488 //\r
1489 // Get MTRR_DEF_TYPE value\r
1490 //\r
1491 MtrrSetting->MtrrDefType = AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE);\r
1492\r
1493 return MtrrSetting;\r
1494}\r
1495\r
1496\r
1497/**\r
1498 This function sets all MTRRs (variable and fixed)\r
1499\r
1500 @param MtrrSetting A buffer holding all MTRRs content.\r
1501\r
1502 @retval The pointer of MtrrSetting\r
1503\r
1504**/\r
1505MTRR_SETTINGS *\r
1506EFIAPI\r
1507MtrrSetAllMtrrs (\r
1508 IN MTRR_SETTINGS *MtrrSetting\r
1509 )\r
1510{\r
c878cee4 1511 MTRR_CONTEXT MtrrContext;\r
e50466da 1512\r
947a573a 1513 if (!IsMtrrSupported ()) {\r
1514 return MtrrSetting;\r
1515 }\r
1516\r
c878cee4 1517 PreMtrrChange (&MtrrContext);\r
e50466da 1518\r
1519 //\r
1520 // Set fixed MTRRs\r
1521 //\r
1522 MtrrSetFixedMtrrWorker (&MtrrSetting->Fixed);\r
1523\r
1524 //\r
1525 // Set variable MTRRs\r
1526 //\r
1527 MtrrSetVariableMtrrWorker (&MtrrSetting->Variables);\r
1528\r
1529 //\r
1530 // Set MTRR_DEF_TYPE value\r
1531 //\r
1532 AsmWriteMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE, MtrrSetting->MtrrDefType);\r
1533\r
c878cee4 1534 PostMtrrChangeEnableCache (&MtrrContext);\r
e50466da 1535\r
1536 return MtrrSetting;\r
1537}\r
1538\r
e50466da 1539/**\r
1540 This function prints all MTRRs for debugging.\r
1541**/\r
1542VOID\r
430fbbe0 1543EFIAPI\r
e50466da 1544MtrrDebugPrintAllMtrrs (\r
430fbbe0 1545 VOID\r
e50466da 1546 )\r
1547{\r
1548 DEBUG_CODE (\r
76f6d954 1549 MTRR_SETTINGS MtrrSettings;\r
1550 UINTN Index;\r
1551 UINTN Index1;\r
1552 UINTN VariableMtrrCount;\r
1553 UINT64 Base;\r
1554 UINT64 Limit;\r
1555 UINT64 MtrrBase;\r
1556 UINT64 MtrrLimit;\r
1557 UINT64 RangeBase;\r
1558 UINT64 RangeLimit;\r
1559 UINT64 NoRangeBase;\r
1560 UINT64 NoRangeLimit;\r
1561 UINT32 RegEax;\r
1562 UINTN MemoryType;\r
1563 UINTN PreviousMemoryType;\r
1564 BOOLEAN Found;\r
1565\r
1566 if (!IsMtrrSupported ()) {\r
1567 return;\r
1568 }\r
f877f300 1569\r
76f6d954 1570 DEBUG((DEBUG_CACHE, "MTRR Settings\n"));\r
1571 DEBUG((DEBUG_CACHE, "=============\n"));\r
1572 \r
1573 MtrrGetAllMtrrs (&MtrrSettings);\r
1574 DEBUG((DEBUG_CACHE, "MTRR Default Type: %016lx\n", MtrrSettings.MtrrDefType));\r
1575 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
1576 DEBUG((DEBUG_CACHE, "Fixed MTRR[%02d] : %016lx\n", Index, MtrrSettings.Fixed.Mtrr[Index]));\r
1577 }\r
f877f300 1578\r
76f6d954 1579 VariableMtrrCount = GetVariableMtrrCount ();\r
1580 for (Index = 0; Index < VariableMtrrCount; Index++) {\r
1581 DEBUG((DEBUG_CACHE, "Variable MTRR[%02d]: Base=%016lx Mask=%016lx\n",\r
1582 Index,\r
1583 MtrrSettings.Variables.Mtrr[Index].Base,\r
1584 MtrrSettings.Variables.Mtrr[Index].Mask\r
1585 ));\r
1586 }\r
1587 DEBUG((DEBUG_CACHE, "\n"));\r
1588 DEBUG((DEBUG_CACHE, "MTRR Ranges\n"));\r
1589 DEBUG((DEBUG_CACHE, "====================================\n"));\r
1590\r
1591 Base = 0;\r
1592 PreviousMemoryType = MTRR_CACHE_INVALID_TYPE;\r
1593 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
1594 Base = mMtrrLibFixedMtrrTable[Index].BaseAddress;\r
1595 for (Index1 = 0; Index1 < 8; Index1++) {\r
1596 MemoryType = (UINTN)(RShiftU64 (MtrrSettings.Fixed.Mtrr[Index], Index1 * 8) & 0xff);\r
f877f300 1597 if (MemoryType > CacheWriteBack) {\r
1598 MemoryType = MTRR_CACHE_INVALID_TYPE;\r
76f6d954 1599 } \r
f877f300 1600 if (MemoryType != PreviousMemoryType) {\r
1601 if (PreviousMemoryType != MTRR_CACHE_INVALID_TYPE) {\r
1602 DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));\r
1603 }\r
1604 PreviousMemoryType = MemoryType;\r
1605 DEBUG((DEBUG_CACHE, "%a:%016lx-", mMtrrMemoryCacheTypeShortName[MemoryType], Base));\r
1606 }\r
76f6d954 1607 Base += mMtrrLibFixedMtrrTable[Index].Length;\r
1608 }\r
1609 }\r
1610 DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));\r
1611\r
1612 VariableMtrrCount = GetVariableMtrrCount ();\r
1613\r
44c8400a
JF
1614 Limit = BIT36 - 1;\r
1615 AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);\r
1616 if (RegEax >= 0x80000008) {\r
1617 AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);\r
1618 Limit = LShiftU64 (1, RegEax & 0xff) - 1;\r
1619 }\r
76f6d954 1620 Base = BASE_1MB;\r
1621 PreviousMemoryType = MTRR_CACHE_INVALID_TYPE;\r
1622 do {\r
1623 MemoryType = MtrrGetMemoryAttribute (Base);\r
1624 if (MemoryType > CacheWriteBack) {\r
1625 MemoryType = MTRR_CACHE_INVALID_TYPE;\r
1626 }\r
1627\r
1628 if (MemoryType != PreviousMemoryType) {\r
1629 if (PreviousMemoryType != MTRR_CACHE_INVALID_TYPE) {\r
1630 DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));\r
f877f300 1631 }\r
76f6d954 1632 PreviousMemoryType = MemoryType;\r
1633 DEBUG((DEBUG_CACHE, "%a:%016lx-", mMtrrMemoryCacheTypeShortName[MemoryType], Base));\r
1634 }\r
1635 \r
1636 RangeBase = BASE_1MB; \r
1637 NoRangeBase = BASE_1MB;\r
76f6d954 1638 RangeLimit = Limit;\r
1639 NoRangeLimit = Limit;\r
1640 \r
1641 for (Index = 0, Found = FALSE; Index < VariableMtrrCount; Index++) {\r
1642 if ((MtrrSettings.Variables.Mtrr[Index].Mask & BIT11) == 0) {\r
1643 //\r
1644 // If mask is not valid, then do not display range\r
1645 //\r
1646 continue;\r
1647 }\r
1648 MtrrBase = (MtrrSettings.Variables.Mtrr[Index].Base & (~(SIZE_4KB - 1)));\r
1649 MtrrLimit = MtrrBase + ((~(MtrrSettings.Variables.Mtrr[Index].Mask & (~(SIZE_4KB - 1)))) & Limit);\r
f877f300 1650\r
76f6d954 1651 if (Base >= MtrrBase && Base < MtrrLimit) {\r
1652 Found = TRUE;\r
f877f300 1653 }\r
1654 \r
76f6d954 1655 if (Base >= MtrrBase && MtrrBase > RangeBase) {\r
1656 RangeBase = MtrrBase;\r
f877f300 1657 }\r
76f6d954 1658 if (Base > MtrrLimit && MtrrLimit > RangeBase) {\r
1659 RangeBase = MtrrLimit + 1;\r
1660 }\r
1661 if (Base < MtrrBase && MtrrBase < RangeLimit) {\r
1662 RangeLimit = MtrrBase - 1;\r
1663 }\r
1664 if (Base < MtrrLimit && MtrrLimit <= RangeLimit) {\r
1665 RangeLimit = MtrrLimit;\r
1666 }\r
1667 \r
1668 if (Base > MtrrLimit && NoRangeBase < MtrrLimit) {\r
1669 NoRangeBase = MtrrLimit + 1;\r
1670 }\r
1671 if (Base < MtrrBase && NoRangeLimit > MtrrBase) {\r
1672 NoRangeLimit = MtrrBase - 1;\r
1673 }\r
1674 }\r
1675 \r
1676 if (Found) {\r
1677 Base = RangeLimit + 1;\r
1678 } else {\r
1679 Base = NoRangeLimit + 1;\r
1680 }\r
44c8400a 1681 } while (Base < Limit);\r
76f6d954 1682 DEBUG((DEBUG_CACHE, "%016lx\n\n", Base - 1));\r
e50466da 1683 );\r
1684}\r
1685\r
947a573a 1686/**\r
1687 Checks if MTRR is supported.\r
1688\r
1689 @retval TRUE MTRR is supported.\r
1690 @retval FALSE MTRR is not supported.\r
1691\r
1692**/\r
1693BOOLEAN\r
1694EFIAPI\r
1695IsMtrrSupported (\r
1696 VOID\r
1697 )\r
1698{\r
1699 UINT32 RegEdx;\r
1700 UINT64 MtrrCap;\r
1701\r
1702 //\r
1703 // Check CPUID(1).EDX[12] for MTRR capability\r
1704 //\r
1705 AsmCpuid (1, NULL, NULL, NULL, &RegEdx);\r
1706 if (BitFieldRead32 (RegEdx, 12, 12) == 0) {\r
1707 return FALSE;\r
1708 }\r
1709\r
1710 //\r
1711 // Check IA32_MTRRCAP.[0..7] for number of variable MTRRs and IA32_MTRRCAP[8] for\r
1712 // fixed MTRRs existence. If number of variable MTRRs is zero, or fixed MTRRs do not\r
1713 // exist, return false.\r
1714 //\r
1715 MtrrCap = AsmReadMsr64 (MTRR_LIB_IA32_MTRR_CAP);\r
1716 if ((BitFieldRead64 (MtrrCap, 0, 7) == 0) || (BitFieldRead64 (MtrrCap, 8, 8) == 0)) {\r
1717 return FALSE;\r
1718 }\r
1719\r
1720 return TRUE;\r
1721}\r