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