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