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