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