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