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