]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/Library/MtrrLib/MtrrLib.c
UefiCpuPkg/MtrrLib: Reduce hardware init when program fixed 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
acf431e6 886 @param[in] VariableMtrrCount Number of variable MTRRs\r
76b4cae3 887 @param[in, out] VariableMtrr Shadow of variable MTRR contents\r
e50466da 888\r
889**/\r
e50466da 890VOID\r
891InvalidateMtrr (\r
acf431e6 892 IN UINTN VariableMtrrCount,\r
76b4cae3
MK
893 IN OUT VARIABLE_MTRR *VariableMtrr\r
894 )\r
e50466da 895{\r
c878cee4 896 UINTN Index;\r
c878cee4 897 MTRR_CONTEXT MtrrContext;\r
e50466da 898\r
c878cee4 899 PreMtrrChange (&MtrrContext);\r
e50466da 900 Index = 0;\r
3b9be416 901 while (Index < VariableMtrrCount) {\r
430fbbe0 902 if (!VariableMtrr[Index].Valid && VariableMtrr[Index].Used) {\r
e50466da 903 AsmWriteMsr64 (VariableMtrr[Index].Msr, 0);\r
904 AsmWriteMsr64 (VariableMtrr[Index].Msr + 1, 0);\r
905 VariableMtrr[Index].Used = FALSE;\r
906 }\r
907 Index ++;\r
908 }\r
c878cee4 909 PostMtrrChange (&MtrrContext);\r
e50466da 910}\r
911\r
912\r
913/**\r
914 Programs variable MTRRs\r
915\r
916 This function programs variable MTRRs\r
917\r
76b4cae3
MK
918 @param[in] MtrrNumber Index of MTRR to program.\r
919 @param[in] BaseAddress Base address of memory region.\r
920 @param[in] Length Length of memory region.\r
921 @param[in] MemoryCacheType Memory type to set.\r
922 @param[in] MtrrValidAddressMask The valid address mask for MTRR\r
e50466da 923\r
924**/\r
e50466da 925VOID\r
926ProgramVariableMtrr (\r
927 IN UINTN MtrrNumber,\r
928 IN PHYSICAL_ADDRESS BaseAddress,\r
929 IN UINT64 Length,\r
930 IN UINT64 MemoryCacheType,\r
931 IN UINT64 MtrrValidAddressMask\r
932 )\r
933{\r
c878cee4 934 UINT64 TempQword;\r
935 MTRR_CONTEXT MtrrContext;\r
e50466da 936\r
c878cee4 937 PreMtrrChange (&MtrrContext);\r
e50466da 938\r
939 //\r
940 // MTRR Physical Base\r
941 //\r
942 TempQword = (BaseAddress & MtrrValidAddressMask) | MemoryCacheType;\r
943 AsmWriteMsr64 ((UINT32) MtrrNumber, TempQword);\r
944\r
945 //\r
946 // MTRR Physical Mask\r
947 //\r
948 TempQword = ~(Length - 1);\r
949 AsmWriteMsr64 (\r
950 (UINT32) (MtrrNumber + 1),\r
951 (TempQword & MtrrValidAddressMask) | MTRR_LIB_CACHE_MTRR_ENABLED\r
952 );\r
953\r
c878cee4 954 PostMtrrChange (&MtrrContext);\r
e50466da 955}\r
956\r
957\r
958/**\r
76b4cae3 959 Converts the Memory attribute value to MTRR_MEMORY_CACHE_TYPE.\r
e50466da 960\r
76b4cae3 961 @param[in] MtrrType MTRR memory type\r
e50466da 962\r
963 @return The enum item in MTRR_MEMORY_CACHE_TYPE\r
964\r
965**/\r
e50466da 966MTRR_MEMORY_CACHE_TYPE\r
967GetMemoryCacheTypeFromMtrrType (\r
968 IN UINT64 MtrrType\r
969 )\r
970{\r
971 switch (MtrrType) {\r
972 case MTRR_CACHE_UNCACHEABLE:\r
973 return CacheUncacheable;\r
974 case MTRR_CACHE_WRITE_COMBINING:\r
975 return CacheWriteCombining;\r
976 case MTRR_CACHE_WRITE_THROUGH:\r
977 return CacheWriteThrough;\r
978 case MTRR_CACHE_WRITE_PROTECTED:\r
979 return CacheWriteProtected;\r
980 case MTRR_CACHE_WRITE_BACK:\r
981 return CacheWriteBack;\r
982 default:\r
983 //\r
984 // MtrrType is MTRR_CACHE_INVALID_TYPE, that means\r
76b4cae3 985 // no MTRR covers the range\r
e50466da 986 //\r
44c8400a 987 return MtrrGetDefaultMemoryType ();\r
e50466da 988 }\r
989}\r
990\r
991/**\r
992 Initializes the valid bits mask and valid address mask for MTRRs.\r
993\r
994 This function initializes the valid bits mask and valid address mask for MTRRs.\r
995\r
76b4cae3
MK
996 @param[out] MtrrValidBitsMask The mask for the valid bit of the MTRR\r
997 @param[out] MtrrValidAddressMask The valid address mask for the MTRR\r
e50466da 998\r
999**/\r
e50466da 1000VOID\r
1001MtrrLibInitializeMtrrMask (\r
1002 OUT UINT64 *MtrrValidBitsMask,\r
1003 OUT UINT64 *MtrrValidAddressMask\r
1004 )\r
1005{\r
f877f300 1006 UINT32 RegEax;\r
1007 UINT8 PhysicalAddressBits;\r
e50466da 1008\r
1009 AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);\r
1010\r
1011 if (RegEax >= 0x80000008) {\r
1012 AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);\r
1013\r
1014 PhysicalAddressBits = (UINT8) RegEax;\r
1015\r
1016 *MtrrValidBitsMask = LShiftU64 (1, PhysicalAddressBits) - 1;\r
1017 *MtrrValidAddressMask = *MtrrValidBitsMask & 0xfffffffffffff000ULL;\r
1018 } else {\r
0a4f7aa0
JF
1019 *MtrrValidBitsMask = MTRR_LIB_MSR_VALID_MASK;\r
1020 *MtrrValidAddressMask = MTRR_LIB_CACHE_VALID_ADDRESS;\r
e50466da 1021 }\r
1022}\r
1023\r
1024\r
1025/**\r
76b4cae3 1026 Determines the real attribute of a memory range.\r
e50466da 1027\r
1028 This function is to arbitrate the real attribute of the memory when\r
76b4cae3 1029 there are 2 MTRRs covers the same memory range. For further details,\r
e50466da 1030 please refer the IA32 Software Developer's Manual, Volume 3,\r
1031 Section 10.11.4.1.\r
1032\r
76b4cae3
MK
1033 @param[in] MtrrType1 The first kind of Memory type\r
1034 @param[in] MtrrType2 The second kind of memory type\r
e50466da 1035\r
1036**/\r
1037UINT64\r
1038MtrrPrecedence (\r
76b4cae3
MK
1039 IN UINT64 MtrrType1,\r
1040 IN UINT64 MtrrType2\r
e50466da 1041 )\r
1042{\r
1043 UINT64 MtrrType;\r
1044\r
1045 MtrrType = MTRR_CACHE_INVALID_TYPE;\r
1046 switch (MtrrType1) {\r
1047 case MTRR_CACHE_UNCACHEABLE:\r
1048 MtrrType = MTRR_CACHE_UNCACHEABLE;\r
1049 break;\r
1050 case MTRR_CACHE_WRITE_COMBINING:\r
1051 if (\r
1052 MtrrType2==MTRR_CACHE_WRITE_COMBINING ||\r
1053 MtrrType2==MTRR_CACHE_UNCACHEABLE\r
1054 ) {\r
1055 MtrrType = MtrrType2;\r
1056 }\r
1057 break;\r
1058 case MTRR_CACHE_WRITE_THROUGH:\r
1059 if (\r
1060 MtrrType2==MTRR_CACHE_WRITE_THROUGH ||\r
1061 MtrrType2==MTRR_CACHE_WRITE_BACK\r
1062 ) {\r
1063 MtrrType = MTRR_CACHE_WRITE_THROUGH;\r
1064 } else if(MtrrType2==MTRR_CACHE_UNCACHEABLE) {\r
1065 MtrrType = MTRR_CACHE_UNCACHEABLE;\r
1066 }\r
1067 break;\r
1068 case MTRR_CACHE_WRITE_PROTECTED:\r
1069 if (MtrrType2 == MTRR_CACHE_WRITE_PROTECTED ||\r
1070 MtrrType2 == MTRR_CACHE_UNCACHEABLE) {\r
1071 MtrrType = MtrrType2;\r
1072 }\r
1073 break;\r
1074 case MTRR_CACHE_WRITE_BACK:\r
1075 if (\r
1076 MtrrType2== MTRR_CACHE_UNCACHEABLE ||\r
1077 MtrrType2==MTRR_CACHE_WRITE_THROUGH ||\r
1078 MtrrType2== MTRR_CACHE_WRITE_BACK\r
1079 ) {\r
1080 MtrrType = MtrrType2;\r
1081 }\r
1082 break;\r
1083 case MTRR_CACHE_INVALID_TYPE:\r
1084 MtrrType = MtrrType2;\r
1085 break;\r
1086 default:\r
1087 break;\r
1088 }\r
1089\r
1090 if (MtrrType2 == MTRR_CACHE_INVALID_TYPE) {\r
1091 MtrrType = MtrrType1;\r
1092 }\r
1093 return MtrrType;\r
1094}\r
1095\r
1096\r
85b7f65b 1097\r
e50466da 1098/**\r
85b7f65b 1099 This function will get the memory cache type of the specific address.\r
e50466da 1100\r
85b7f65b 1101 This function is mainly for debug purpose.\r
e50466da 1102\r
85b7f65b
MK
1103 @param[in] Address The specific address\r
1104\r
1105 @return Memory cache type of the specific address\r
e50466da 1106\r
1107**/\r
85b7f65b 1108MTRR_MEMORY_CACHE_TYPE\r
e50466da 1109EFIAPI\r
85b7f65b
MK
1110MtrrGetMemoryAttribute (\r
1111 IN PHYSICAL_ADDRESS Address\r
e50466da 1112 )\r
1113{\r
85b7f65b
MK
1114 UINT64 TempQword;\r
1115 UINTN Index;\r
1116 UINTN SubIndex;\r
1117 UINT64 MtrrType;\r
1118 UINT64 TempMtrrType;\r
1119 MTRR_MEMORY_CACHE_TYPE CacheType;\r
1120 VARIABLE_MTRR VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];\r
1121 UINT64 MtrrValidBitsMask;\r
1122 UINT64 MtrrValidAddressMask;\r
1123 UINTN VariableMtrrCount;\r
d0baed7d 1124 MTRR_VARIABLE_SETTINGS VariableSettings;\r
f877f300 1125\r
947a573a 1126 if (!IsMtrrSupported ()) {\r
85b7f65b 1127 return CacheUncacheable;\r
947a573a 1128 }\r
1129\r
e50466da 1130 //\r
85b7f65b 1131 // Check if MTRR is enabled, if not, return UC as attribute\r
e50466da 1132 //\r
85b7f65b
MK
1133 TempQword = AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE);\r
1134 MtrrType = MTRR_CACHE_INVALID_TYPE;\r
e50466da 1135\r
85b7f65b
MK
1136 if ((TempQword & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
1137 return CacheUncacheable;\r
e50466da 1138 }\r
1139\r
1140 //\r
85b7f65b 1141 // If address is less than 1M, then try to go through the fixed MTRR\r
e50466da 1142 //\r
85b7f65b
MK
1143 if (Address < BASE_1MB) {\r
1144 if ((TempQword & MTRR_LIB_CACHE_FIXED_MTRR_ENABLED) != 0) {\r
1145 //\r
1146 // Go through the fixed MTRR\r
1147 //\r
1148 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
1149 if (Address >= mMtrrLibFixedMtrrTable[Index].BaseAddress &&\r
1150 Address < (\r
1151 mMtrrLibFixedMtrrTable[Index].BaseAddress +\r
1152 (mMtrrLibFixedMtrrTable[Index].Length * 8)\r
1153 )\r
1154 ) {\r
1155 SubIndex =\r
1156 ((UINTN)Address - mMtrrLibFixedMtrrTable[Index].BaseAddress) /\r
1157 mMtrrLibFixedMtrrTable[Index].Length;\r
1158 TempQword = AsmReadMsr64 (mMtrrLibFixedMtrrTable[Index].Msr);\r
1159 MtrrType = RShiftU64 (TempQword, SubIndex * 8) & 0xFF;\r
1160 return GetMemoryCacheTypeFromMtrrType (MtrrType);\r
1161 }\r
1162 }\r
e50466da 1163 }\r
1164 }\r
85b7f65b 1165 MtrrLibInitializeMtrrMask(&MtrrValidBitsMask, &MtrrValidAddressMask);\r
d0baed7d
MK
1166\r
1167 MtrrGetVariableMtrrWorker (\r
1168 GetVariableMtrrCountWorker (),\r
1169 &VariableSettings\r
85b7f65b 1170 );\r
e50466da 1171\r
d0baed7d
MK
1172 MtrrGetMemoryAttributeInVariableMtrrWorker (\r
1173 &VariableSettings,\r
1174 GetFirmwareVariableMtrrCountWorker (),\r
1175 MtrrValidBitsMask,\r
1176 MtrrValidAddressMask,\r
1177 VariableMtrr\r
1178 );\r
1179\r
e50466da 1180 //\r
85b7f65b 1181 // Go through the variable MTRR\r
e50466da 1182 //\r
acf431e6 1183 VariableMtrrCount = GetVariableMtrrCountWorker ();\r
85b7f65b
MK
1184 ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);\r
1185\r
1186 for (Index = 0; Index < VariableMtrrCount; Index++) {\r
1187 if (VariableMtrr[Index].Valid) {\r
1188 if (Address >= VariableMtrr[Index].BaseAddress &&\r
1189 Address < VariableMtrr[Index].BaseAddress+VariableMtrr[Index].Length) {\r
1190 TempMtrrType = VariableMtrr[Index].Type;\r
1191 MtrrType = MtrrPrecedence (MtrrType, TempMtrrType);\r
1192 }\r
1193 }\r
e50466da 1194 }\r
85b7f65b 1195 CacheType = GetMemoryCacheTypeFromMtrrType (MtrrType);\r
e50466da 1196\r
85b7f65b
MK
1197 return CacheType;\r
1198}\r
1199\r
1200\r
1201\r
1202/**\r
1203 This function prints all MTRRs for debugging.\r
1204**/\r
1205VOID\r
1206EFIAPI\r
1207MtrrDebugPrintAllMtrrs (\r
1208 VOID\r
1209 )\r
1210{\r
1211 DEBUG_CODE (\r
1212 MTRR_SETTINGS MtrrSettings;\r
1213 UINTN Index;\r
1214 UINTN Index1;\r
1215 UINTN VariableMtrrCount;\r
1216 UINT64 Base;\r
1217 UINT64 Limit;\r
1218 UINT64 MtrrBase;\r
1219 UINT64 MtrrLimit;\r
1220 UINT64 RangeBase;\r
1221 UINT64 RangeLimit;\r
1222 UINT64 NoRangeBase;\r
1223 UINT64 NoRangeLimit;\r
1224 UINT32 RegEax;\r
1225 UINTN MemoryType;\r
1226 UINTN PreviousMemoryType;\r
1227 BOOLEAN Found;\r
1228\r
1229 if (!IsMtrrSupported ()) {\r
1230 return;\r
1231 }\r
1232\r
1233 DEBUG((DEBUG_CACHE, "MTRR Settings\n"));\r
1234 DEBUG((DEBUG_CACHE, "=============\n"));\r
1235\r
1236 MtrrGetAllMtrrs (&MtrrSettings);\r
1237 DEBUG((DEBUG_CACHE, "MTRR Default Type: %016lx\n", MtrrSettings.MtrrDefType));\r
1238 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
1239 DEBUG((DEBUG_CACHE, "Fixed MTRR[%02d] : %016lx\n", Index, MtrrSettings.Fixed.Mtrr[Index]));\r
1240 }\r
1241\r
1242 VariableMtrrCount = GetVariableMtrrCount ();\r
1243 for (Index = 0; Index < VariableMtrrCount; Index++) {\r
1244 DEBUG((DEBUG_CACHE, "Variable MTRR[%02d]: Base=%016lx Mask=%016lx\n",\r
1245 Index,\r
1246 MtrrSettings.Variables.Mtrr[Index].Base,\r
1247 MtrrSettings.Variables.Mtrr[Index].Mask\r
1248 ));\r
1249 }\r
1250 DEBUG((DEBUG_CACHE, "\n"));\r
1251 DEBUG((DEBUG_CACHE, "MTRR Ranges\n"));\r
1252 DEBUG((DEBUG_CACHE, "====================================\n"));\r
1253\r
1254 Base = 0;\r
1255 PreviousMemoryType = MTRR_CACHE_INVALID_TYPE;\r
1256 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
1257 Base = mMtrrLibFixedMtrrTable[Index].BaseAddress;\r
1258 for (Index1 = 0; Index1 < 8; Index1++) {\r
1259 MemoryType = (UINTN)(RShiftU64 (MtrrSettings.Fixed.Mtrr[Index], Index1 * 8) & 0xff);\r
1260 if (MemoryType > CacheWriteBack) {\r
1261 MemoryType = MTRR_CACHE_INVALID_TYPE;\r
1262 }\r
1263 if (MemoryType != PreviousMemoryType) {\r
1264 if (PreviousMemoryType != MTRR_CACHE_INVALID_TYPE) {\r
1265 DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));\r
1266 }\r
1267 PreviousMemoryType = MemoryType;\r
1268 DEBUG((DEBUG_CACHE, "%a:%016lx-", mMtrrMemoryCacheTypeShortName[MemoryType], Base));\r
1269 }\r
1270 Base += mMtrrLibFixedMtrrTable[Index].Length;\r
1271 }\r
1272 }\r
1273 DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));\r
1274\r
1275 VariableMtrrCount = GetVariableMtrrCount ();\r
1276\r
1277 Limit = BIT36 - 1;\r
1278 AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);\r
1279 if (RegEax >= 0x80000008) {\r
1280 AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);\r
1281 Limit = LShiftU64 (1, RegEax & 0xff) - 1;\r
1282 }\r
1283 Base = BASE_1MB;\r
1284 PreviousMemoryType = MTRR_CACHE_INVALID_TYPE;\r
1285 do {\r
1286 MemoryType = MtrrGetMemoryAttribute (Base);\r
1287 if (MemoryType > CacheWriteBack) {\r
1288 MemoryType = MTRR_CACHE_INVALID_TYPE;\r
1289 }\r
1290\r
1291 if (MemoryType != PreviousMemoryType) {\r
1292 if (PreviousMemoryType != MTRR_CACHE_INVALID_TYPE) {\r
1293 DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));\r
1294 }\r
1295 PreviousMemoryType = MemoryType;\r
1296 DEBUG((DEBUG_CACHE, "%a:%016lx-", mMtrrMemoryCacheTypeShortName[MemoryType], Base));\r
1297 }\r
1298\r
1299 RangeBase = BASE_1MB;\r
1300 NoRangeBase = BASE_1MB;\r
1301 RangeLimit = Limit;\r
1302 NoRangeLimit = Limit;\r
1303\r
1304 for (Index = 0, Found = FALSE; Index < VariableMtrrCount; Index++) {\r
1305 if ((MtrrSettings.Variables.Mtrr[Index].Mask & BIT11) == 0) {\r
1306 //\r
1307 // If mask is not valid, then do not display range\r
1308 //\r
1309 continue;\r
1310 }\r
1311 MtrrBase = (MtrrSettings.Variables.Mtrr[Index].Base & (~(SIZE_4KB - 1)));\r
1312 MtrrLimit = MtrrBase + ((~(MtrrSettings.Variables.Mtrr[Index].Mask & (~(SIZE_4KB - 1)))) & Limit);\r
1313\r
1314 if (Base >= MtrrBase && Base < MtrrLimit) {\r
1315 Found = TRUE;\r
1316 }\r
1317\r
1318 if (Base >= MtrrBase && MtrrBase > RangeBase) {\r
1319 RangeBase = MtrrBase;\r
1320 }\r
1321 if (Base > MtrrLimit && MtrrLimit > RangeBase) {\r
1322 RangeBase = MtrrLimit + 1;\r
1323 }\r
1324 if (Base < MtrrBase && MtrrBase < RangeLimit) {\r
1325 RangeLimit = MtrrBase - 1;\r
1326 }\r
1327 if (Base < MtrrLimit && MtrrLimit <= RangeLimit) {\r
1328 RangeLimit = MtrrLimit;\r
1329 }\r
1330\r
1331 if (Base > MtrrLimit && NoRangeBase < MtrrLimit) {\r
1332 NoRangeBase = MtrrLimit + 1;\r
1333 }\r
1334 if (Base < MtrrBase && NoRangeLimit > MtrrBase) {\r
1335 NoRangeLimit = MtrrBase - 1;\r
1336 }\r
1337 }\r
1338\r
1339 if (Found) {\r
1340 Base = RangeLimit + 1;\r
1341 } else {\r
1342 Base = NoRangeLimit + 1;\r
1343 }\r
1344 } while (Base < Limit);\r
1345 DEBUG((DEBUG_CACHE, "%016lx\n\n", Base - 1));\r
1346 );\r
1347}\r
1348/**\r
1349 This function attempts to set the attributes for a memory range.\r
1350\r
1351 @param[in] BaseAddress The physical address that is the start\r
1352 address of a memory region.\r
1353 @param[in] Length The size in bytes of the memory region.\r
1354 @param[in] Attribute The bit mask of attributes to set for the\r
1355 memory region.\r
1356\r
1357 @retval RETURN_SUCCESS The attributes were set for the memory\r
1358 region.\r
1359 @retval RETURN_INVALID_PARAMETER Length is zero.\r
1360 @retval RETURN_UNSUPPORTED The processor does not support one or\r
1361 more bytes of the memory resource range\r
1362 specified by BaseAddress and Length.\r
1363 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support\r
1364 for the memory resource range specified\r
1365 by BaseAddress and Length.\r
1366 @retval RETURN_ACCESS_DENIED The attributes for the memory resource\r
1367 range specified by BaseAddress and Length\r
1368 cannot be modified.\r
1369 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to\r
1370 modify the attributes of the memory\r
1371 resource range.\r
1372\r
1373**/\r
1374RETURN_STATUS\r
1375EFIAPI\r
1376MtrrSetMemoryAttribute (\r
1377 IN PHYSICAL_ADDRESS BaseAddress,\r
1378 IN UINT64 Length,\r
1379 IN MTRR_MEMORY_CACHE_TYPE Attribute\r
1380 )\r
1381{\r
1382 UINT64 TempQword;\r
1383 RETURN_STATUS Status;\r
1384 UINT64 MemoryType;\r
1385 UINT64 Alignment;\r
1386 BOOLEAN OverLap;\r
1387 BOOLEAN Positive;\r
1388 UINT32 MsrNum;\r
1389 UINTN MtrrNumber;\r
1390 VARIABLE_MTRR VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];\r
1391 UINT32 UsedMtrr;\r
1392 UINT64 MtrrValidBitsMask;\r
1393 UINT64 MtrrValidAddressMask;\r
1394 BOOLEAN OverwriteExistingMtrr;\r
1395 UINT32 FirmwareVariableMtrrCount;\r
1396 UINT32 VariableMtrrEnd;\r
1397 MTRR_CONTEXT MtrrContext;\r
fa25cf38
MK
1398 BOOLEAN MtrrContextValid;\r
1399 BOOLEAN FixedSettingsValid[MTRR_NUMBER_OF_FIXED_MTRR];\r
1400 BOOLEAN FixedSettingsModified[MTRR_NUMBER_OF_FIXED_MTRR];\r
1401 MTRR_FIXED_SETTINGS WorkingFixedSettings;\r
acf431e6 1402 UINT32 VariableMtrrCount;\r
d0baed7d
MK
1403 MTRR_VARIABLE_SETTINGS OriginalVariableSettings;\r
1404 MTRR_VARIABLE_SETTINGS WorkingVariableSettings;\r
fa25cf38
MK
1405 UINT32 Index;\r
1406 UINT64 ClearMask;\r
1407 UINT64 OrMask;\r
1408 UINT64 NewValue;\r
d0baed7d 1409 MTRR_VARIABLE_SETTINGS *VariableSettings;\r
85b7f65b
MK
1410\r
1411 DEBUG((DEBUG_CACHE, "MtrrSetMemoryAttribute() %a:%016lx-%016lx\n", mMtrrMemoryCacheTypeShortName[Attribute], BaseAddress, Length));\r
fa25cf38
MK
1412 MtrrContextValid = FALSE;\r
1413 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
1414 FixedSettingsValid[Index] = FALSE;\r
1415 FixedSettingsModified[Index] = FALSE;\r
1416 }\r
85b7f65b
MK
1417\r
1418 if (!IsMtrrSupported ()) {\r
1419 Status = RETURN_UNSUPPORTED;\r
1420 goto Done;\r
1421 }\r
1422\r
acf431e6 1423 FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCountWorker ();\r
85b7f65b
MK
1424 VariableMtrrEnd = MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (2 * GetVariableMtrrCount ()) - 1;\r
1425\r
1426 MtrrLibInitializeMtrrMask(&MtrrValidBitsMask, &MtrrValidAddressMask);\r
1427\r
1428 TempQword = 0;\r
1429 MemoryType = (UINT64)Attribute;\r
1430 OverwriteExistingMtrr = FALSE;\r
1431\r
1432 //\r
1433 // Check for an invalid parameter\r
1434 //\r
1435 if (Length == 0) {\r
1436 Status = RETURN_INVALID_PARAMETER;\r
1437 goto Done;\r
1438 }\r
1439\r
1440 if (\r
1441 (BaseAddress & ~MtrrValidAddressMask) != 0 ||\r
1442 (Length & ~MtrrValidAddressMask) != 0\r
1443 ) {\r
1444 Status = RETURN_UNSUPPORTED;\r
1445 goto Done;\r
1446 }\r
1447\r
1448 //\r
1449 // Check if Fixed MTRR\r
1450 //\r
1451 Status = RETURN_SUCCESS;\r
fa25cf38
MK
1452 if (BaseAddress < BASE_1MB) {\r
1453 while ((BaseAddress < BASE_1MB) && (Length > 0) && Status == RETURN_SUCCESS) {\r
1454 Status = ProgramFixedMtrr (MemoryType, &BaseAddress, &Length, &MsrNum, &ClearMask, &OrMask);\r
1455 if (RETURN_ERROR (Status)) {\r
1456 goto Done;\r
1457 }\r
1458 if (!FixedSettingsValid[MsrNum]) {\r
1459 WorkingFixedSettings.Mtrr[MsrNum] = AsmReadMsr64 (mMtrrLibFixedMtrrTable[MsrNum].Msr);\r
1460 FixedSettingsValid[MsrNum] = TRUE;\r
1461 }\r
1462 NewValue = (WorkingFixedSettings.Mtrr[MsrNum] & ~ClearMask) | OrMask;\r
1463 if (WorkingFixedSettings.Mtrr[MsrNum] != NewValue) {\r
1464 WorkingFixedSettings.Mtrr[MsrNum] = NewValue;\r
1465 FixedSettingsModified[MsrNum] = TRUE;\r
1466 }\r
85b7f65b 1467 }\r
85b7f65b 1468\r
fa25cf38
MK
1469 if (Length == 0) {\r
1470 //\r
1471 // A Length of 0 can only make sense for fixed MTTR ranges.\r
1472 // Since we just handled the fixed MTRRs, we can skip the\r
1473 // variable MTRR section.\r
1474 //\r
1475 goto Done;\r
1476 }\r
85b7f65b
MK
1477 }\r
1478\r
1479 //\r
1480 // Since memory ranges below 1MB will be overridden by the fixed MTRRs,\r
1481 // we can set the base to 0 to save variable MTRRs.\r
1482 //\r
1483 if (BaseAddress == BASE_1MB) {\r
1484 BaseAddress = 0;\r
1485 Length += SIZE_1MB;\r
1486 }\r
1487\r
acf431e6
MK
1488 //\r
1489 // Read all variable MTRRs\r
1490 //\r
1491 VariableMtrrCount = GetVariableMtrrCountWorker ();\r
d0baed7d
MK
1492 MtrrGetVariableMtrrWorker (VariableMtrrCount, &OriginalVariableSettings);\r
1493 CopyMem (&WorkingVariableSettings, &OriginalVariableSettings, sizeof (WorkingVariableSettings));\r
1494 VariableSettings = &WorkingVariableSettings;\r
acf431e6 1495\r
85b7f65b
MK
1496 //\r
1497 // Check for overlap\r
1498 //\r
d0baed7d
MK
1499 UsedMtrr = MtrrGetMemoryAttributeInVariableMtrrWorker (\r
1500 VariableSettings,\r
1501 FirmwareVariableMtrrCount,\r
1502 MtrrValidBitsMask,\r
1503 MtrrValidAddressMask,\r
1504 VariableMtrr\r
1505 );\r
acf431e6
MK
1506 OverLap = CheckMemoryAttributeOverlap (\r
1507 FirmwareVariableMtrrCount,\r
1508 BaseAddress,\r
1509 BaseAddress + Length - 1,\r
1510 VariableMtrr\r
1511 );\r
1512\r
85b7f65b 1513 if (OverLap) {\r
acf431e6
MK
1514 Status = CombineMemoryAttribute (\r
1515 FirmwareVariableMtrrCount,\r
1516 MemoryType,\r
1517 &BaseAddress,\r
1518 &Length,\r
1519 VariableMtrr,\r
1520 &UsedMtrr,\r
1521 &OverwriteExistingMtrr\r
1522 );\r
e50466da 1523 if (RETURN_ERROR (Status)) {\r
1524 goto Done;\r
1525 }\r
1526\r
1527 if (Length == 0) {\r
1528 //\r
1e60a0ec 1529 // Combined successfully, invalidate the now-unused MTRRs\r
e50466da 1530 //\r
acf431e6 1531 InvalidateMtrr(VariableMtrrCount, VariableMtrr);\r
e50466da 1532 Status = RETURN_SUCCESS;\r
1533 goto Done;\r
1534 }\r
1535 }\r
e50466da 1536\r
1537 //\r
1538 // The memory type is the same with the type specified by\r
1539 // MTRR_LIB_IA32_MTRR_DEF_TYPE.\r
1540 //\r
91ec7824 1541 if ((!OverwriteExistingMtrr) && (Attribute == MtrrGetDefaultMemoryType ())) {\r
e50466da 1542 //\r
1543 // Invalidate the now-unused MTRRs\r
1544 //\r
acf431e6 1545 InvalidateMtrr(VariableMtrrCount, VariableMtrr);\r
e50466da 1546 goto Done;\r
1547 }\r
1548\r
1a2ad6fc 1549 Positive = GetMtrrNumberAndDirection (BaseAddress, Length, &MtrrNumber);\r
e50466da 1550\r
1a2ad6fc 1551 if ((UsedMtrr + MtrrNumber) > FirmwareVariableMtrrCount) {\r
1552 Status = RETURN_OUT_OF_RESOURCES;\r
1553 goto Done;\r
1554 }\r
e50466da 1555\r
1a2ad6fc 1556 //\r
1557 // Invalidate the now-unused MTRRs\r
1558 //\r
acf431e6 1559 InvalidateMtrr(VariableMtrrCount, VariableMtrr);\r
1a2ad6fc 1560\r
1561 //\r
1562 // Find first unused MTRR\r
1563 //\r
1564 for (MsrNum = MTRR_LIB_IA32_VARIABLE_MTRR_BASE;\r
1565 MsrNum < VariableMtrrEnd;\r
1566 MsrNum += 2\r
1567 ) {\r
1568 if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
1569 break;\r
1570 }\r
1571 }\r
1572\r
1573 if (BaseAddress != 0) {\r
1574 do {\r
1575 //\r
1576 // Calculate the alignment of the base address.\r
1577 //\r
1578 Alignment = LShiftU64 (1, (UINTN)LowBitSet64 (BaseAddress));\r
1579\r
1580 if (Alignment > Length) {\r
1581 break;\r
1582 }\r
1583\r
1584 //\r
1585 // Find unused MTRR\r
1586 //\r
1587 for (; MsrNum < VariableMtrrEnd; MsrNum += 2) {\r
1588 if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
1589 break;\r
1590 }\r
1591 }\r
1592\r
1593 ProgramVariableMtrr (\r
1594 MsrNum,\r
1595 BaseAddress,\r
1596 Alignment,\r
1597 MemoryType,\r
1598 MtrrValidAddressMask\r
1599 );\r
1600 BaseAddress += Alignment;\r
1601 Length -= Alignment;\r
1602 } while (TRUE);\r
1603\r
1604 if (Length == 0) {\r
1605 goto Done;\r
1606 }\r
1607 }\r
1608\r
1609 TempQword = Length;\r
1610\r
1611 if (!Positive) {\r
1612 Length = Power2MaxMemory (LShiftU64 (TempQword, 1));\r
e50466da 1613\r
1614 //\r
1a2ad6fc 1615 // Find unused MTRR\r
e50466da 1616 //\r
1a2ad6fc 1617 for (; MsrNum < VariableMtrrEnd; MsrNum += 2) {\r
e50466da 1618 if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
1619 break;\r
85b7f65b
MK
1620 }\r
1621 }\r
1622\r
1623 ProgramVariableMtrr (\r
1624 MsrNum,\r
1625 BaseAddress,\r
1626 Length,\r
1627 MemoryType,\r
1628 MtrrValidAddressMask\r
1629 );\r
1630 BaseAddress += Length;\r
1631 TempQword = Length - TempQword;\r
1632 MemoryType = MTRR_CACHE_UNCACHEABLE;\r
e50466da 1633 }\r
1634\r
85b7f65b
MK
1635 do {\r
1636 //\r
1637 // Find unused MTRR\r
1638 //\r
1639 for (; MsrNum < VariableMtrrEnd; MsrNum += 2) {\r
1640 if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
1641 break;\r
1642 }\r
1643 }\r
e50466da 1644\r
85b7f65b
MK
1645 Length = Power2MaxMemory (TempQword);\r
1646 if (!Positive) {\r
1647 BaseAddress -= Length;\r
1648 }\r
31b3597e 1649\r
85b7f65b
MK
1650 ProgramVariableMtrr (\r
1651 MsrNum,\r
1652 BaseAddress,\r
1653 Length,\r
1654 MemoryType,\r
1655 MtrrValidAddressMask\r
1656 );\r
31b3597e 1657\r
85b7f65b
MK
1658 if (Positive) {\r
1659 BaseAddress += Length;\r
1660 }\r
1661 TempQword -= Length;\r
31b3597e 1662\r
85b7f65b
MK
1663 } while (TempQword > 0);\r
1664\r
1665Done:\r
fa25cf38
MK
1666\r
1667 //\r
1668 // Write fixed MTRRs that have been modified\r
1669 //\r
1670 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
1671 if (FixedSettingsModified[Index]) {\r
1672 if (!MtrrContextValid) {\r
1673 PreMtrrChange (&MtrrContext);\r
1674 MtrrContextValid = TRUE;\r
1675 }\r
1676 AsmWriteMsr64 (\r
1677 mMtrrLibFixedMtrrTable[Index].Msr,\r
1678 WorkingFixedSettings.Mtrr[Index]\r
1679 );\r
1680 }\r
1681 }\r
1682\r
1683 if (MtrrContextValid) {\r
1684 PostMtrrChange (&MtrrContext);\r
1685 }\r
1686\r
85b7f65b
MK
1687 DEBUG((DEBUG_CACHE, " Status = %r\n", Status));\r
1688 if (!RETURN_ERROR (Status)) {\r
1689 MtrrDebugPrintAllMtrrs ();\r
31b3597e
MK
1690 }\r
1691\r
85b7f65b 1692 return Status;\r
31b3597e 1693}\r
e50466da 1694/**\r
1695 Worker function setting variable MTRRs\r
1696\r
76b4cae3 1697 @param[in] VariableSettings A buffer to hold variable MTRRs content.\r
e50466da 1698\r
1699**/\r
1700VOID\r
1701MtrrSetVariableMtrrWorker (\r
1702 IN MTRR_VARIABLE_SETTINGS *VariableSettings\r
1703 )\r
1704{\r
1705 UINT32 Index;\r
3b9be416 1706 UINT32 VariableMtrrCount;\r
e50466da 1707\r
acf431e6 1708 VariableMtrrCount = GetVariableMtrrCountWorker ();\r
5bdfa4e5 1709 ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);\r
1710\r
3b9be416 1711 for (Index = 0; Index < VariableMtrrCount; Index++) {\r
e50466da 1712 AsmWriteMsr64 (\r
1713 MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1),\r
1714 VariableSettings->Mtrr[Index].Base\r
1715 );\r
1716 AsmWriteMsr64 (\r
1717 MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1) + 1,\r
1718 VariableSettings->Mtrr[Index].Mask\r
1719 );\r
1720 }\r
1721}\r
1722\r
1723\r
1724/**\r
1725 This function sets variable MTRRs\r
1726\r
76b4cae3 1727 @param[in] VariableSettings A buffer to hold variable MTRRs content.\r
e50466da 1728\r
1729 @return The pointer of VariableSettings\r
1730\r
1731**/\r
1732MTRR_VARIABLE_SETTINGS*\r
1733EFIAPI\r
1734MtrrSetVariableMtrr (\r
1735 IN MTRR_VARIABLE_SETTINGS *VariableSettings\r
1736 )\r
1737{\r
c878cee4 1738 MTRR_CONTEXT MtrrContext;\r
e50466da 1739\r
947a573a 1740 if (!IsMtrrSupported ()) {\r
1741 return VariableSettings;\r
1742 }\r
1743\r
c878cee4 1744 PreMtrrChange (&MtrrContext);\r
e50466da 1745 MtrrSetVariableMtrrWorker (VariableSettings);\r
c878cee4 1746 PostMtrrChange (&MtrrContext);\r
e50466da 1747 return VariableSettings;\r
1748}\r
1749\r
e50466da 1750/**\r
1751 Worker function setting fixed MTRRs\r
1752\r
acf431e6 1753 @param[in] FixedSettings A buffer to hold fixed MTRRs content.\r
e50466da 1754\r
1755**/\r
1756VOID\r
1757MtrrSetFixedMtrrWorker (\r
1758 IN MTRR_FIXED_SETTINGS *FixedSettings\r
1759 )\r
1760{\r
1761 UINT32 Index;\r
1762\r
1763 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
1764 AsmWriteMsr64 (\r
f877f300 1765 mMtrrLibFixedMtrrTable[Index].Msr,\r
e50466da 1766 FixedSettings->Mtrr[Index]\r
1767 );\r
1768 }\r
1769}\r
1770\r
1771\r
1772/**\r
1773 This function sets fixed MTRRs\r
1774\r
acf431e6 1775 @param[in] FixedSettings A buffer to hold fixed MTRRs content.\r
e50466da 1776\r
1777 @retval The pointer of FixedSettings\r
1778\r
1779**/\r
1780MTRR_FIXED_SETTINGS*\r
1781EFIAPI\r
1782MtrrSetFixedMtrr (\r
1783 IN MTRR_FIXED_SETTINGS *FixedSettings\r
1784 )\r
1785{\r
c878cee4 1786 MTRR_CONTEXT MtrrContext;\r
e50466da 1787\r
947a573a 1788 if (!IsMtrrSupported ()) {\r
1789 return FixedSettings;\r
1790 }\r
1791\r
c878cee4 1792 PreMtrrChange (&MtrrContext);\r
e50466da 1793 MtrrSetFixedMtrrWorker (FixedSettings);\r
c878cee4 1794 PostMtrrChange (&MtrrContext);\r
e50466da 1795\r
1796 return FixedSettings;\r
1797}\r
1798\r
1799\r
1800/**\r
1801 This function gets the content in all MTRRs (variable and fixed)\r
1802\r
acf431e6 1803 @param[out] MtrrSetting A buffer to hold all MTRRs content.\r
e50466da 1804\r
1805 @retval the pointer of MtrrSetting\r
1806\r
1807**/\r
1808MTRR_SETTINGS *\r
1809EFIAPI\r
1810MtrrGetAllMtrrs (\r
1811 OUT MTRR_SETTINGS *MtrrSetting\r
1812 )\r
1813{\r
947a573a 1814 if (!IsMtrrSupported ()) {\r
1815 return MtrrSetting;\r
1816 }\r
1817\r
e50466da 1818 //\r
1819 // Get fixed MTRRs\r
1820 //\r
acf431e6 1821 MtrrGetFixedMtrrWorker (&MtrrSetting->Fixed);\r
e50466da 1822\r
1823 //\r
1824 // Get variable MTRRs\r
1825 //\r
acf431e6
MK
1826 MtrrGetVariableMtrrWorker (\r
1827 GetVariableMtrrCountWorker (),\r
1828 &MtrrSetting->Variables\r
1829 );\r
e50466da 1830\r
1831 //\r
1832 // Get MTRR_DEF_TYPE value\r
1833 //\r
1834 MtrrSetting->MtrrDefType = AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE);\r
1835\r
1836 return MtrrSetting;\r
1837}\r
1838\r
1839\r
1840/**\r
1841 This function sets all MTRRs (variable and fixed)\r
1842\r
76b4cae3 1843 @param[in] MtrrSetting A buffer holding all MTRRs content.\r
e50466da 1844\r
1845 @retval The pointer of MtrrSetting\r
1846\r
1847**/\r
1848MTRR_SETTINGS *\r
1849EFIAPI\r
1850MtrrSetAllMtrrs (\r
1851 IN MTRR_SETTINGS *MtrrSetting\r
1852 )\r
1853{\r
c878cee4 1854 MTRR_CONTEXT MtrrContext;\r
e50466da 1855\r
947a573a 1856 if (!IsMtrrSupported ()) {\r
1857 return MtrrSetting;\r
1858 }\r
1859\r
c878cee4 1860 PreMtrrChange (&MtrrContext);\r
e50466da 1861\r
1862 //\r
1863 // Set fixed MTRRs\r
1864 //\r
1865 MtrrSetFixedMtrrWorker (&MtrrSetting->Fixed);\r
1866\r
1867 //\r
1868 // Set variable MTRRs\r
1869 //\r
1870 MtrrSetVariableMtrrWorker (&MtrrSetting->Variables);\r
1871\r
1872 //\r
1873 // Set MTRR_DEF_TYPE value\r
1874 //\r
1875 AsmWriteMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE, MtrrSetting->MtrrDefType);\r
1876\r
c878cee4 1877 PostMtrrChangeEnableCache (&MtrrContext);\r
e50466da 1878\r
1879 return MtrrSetting;\r
1880}\r
1881\r
947a573a 1882/**\r
1883 Checks if MTRR is supported.\r
1884\r
1885 @retval TRUE MTRR is supported.\r
1886 @retval FALSE MTRR is not supported.\r
1887\r
1888**/\r
1889BOOLEAN\r
1890EFIAPI\r
1891IsMtrrSupported (\r
1892 VOID\r
1893 )\r
1894{\r
1895 UINT32 RegEdx;\r
1896 UINT64 MtrrCap;\r
1897\r
1898 //\r
1899 // Check CPUID(1).EDX[12] for MTRR capability\r
1900 //\r
1901 AsmCpuid (1, NULL, NULL, NULL, &RegEdx);\r
1902 if (BitFieldRead32 (RegEdx, 12, 12) == 0) {\r
1903 return FALSE;\r
1904 }\r
1905\r
1906 //\r
1907 // Check IA32_MTRRCAP.[0..7] for number of variable MTRRs and IA32_MTRRCAP[8] for\r
1908 // fixed MTRRs existence. If number of variable MTRRs is zero, or fixed MTRRs do not\r
1909 // exist, return false.\r
1910 //\r
1911 MtrrCap = AsmReadMsr64 (MTRR_LIB_IA32_MTRR_CAP);\r
1912 if ((BitFieldRead64 (MtrrCap, 0, 7) == 0) || (BitFieldRead64 (MtrrCap, 8, 8) == 0)) {\r
1913 return FALSE;\r
1914 }\r
1915\r
1916 return TRUE;\r
1917}\r