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