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