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