]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/Library/MtrrLib/MtrrLib.c
UefiCpuPkg/MtrrLib: GetVariableMtrrCountWorker uses definitions in Msr.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
e50466da 246PreMtrrChange (\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
0779e5bf 287PostMtrrChangeEnableCache (\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
322PostMtrrChange (\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
c878cee4 331 PostMtrrChangeEnableCache (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
76b4cae3
MK
448 @param[in] MemoryCacheType The memory type to set.\r
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
462ProgramFixedMtrr (\r
fa25cf38
MK
463 IN UINT64 MemoryCacheType,\r
464 IN OUT UINT64 *Base,\r
465 IN OUT UINT64 *Length,\r
0f354122 466 IN OUT UINT32 *LastMsrNum,\r
fa25cf38
MK
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
0f354122 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
JF
528 ClearMask = CLEAR_SEED;\r
529 OrMask = MultU64x32 (OR_SEED, (UINT32)MemoryCacheType);\r
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
f877f300 1057 UINT32 RegEax;\r
1058 UINT8 PhysicalAddressBits;\r
e50466da 1059\r
1060 AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);\r
1061\r
1062 if (RegEax >= 0x80000008) {\r
1063 AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);\r
1064\r
1065 PhysicalAddressBits = (UINT8) RegEax;\r
1066\r
1067 *MtrrValidBitsMask = LShiftU64 (1, PhysicalAddressBits) - 1;\r
1068 *MtrrValidAddressMask = *MtrrValidBitsMask & 0xfffffffffffff000ULL;\r
1069 } else {\r
0a4f7aa0
JF
1070 *MtrrValidBitsMask = MTRR_LIB_MSR_VALID_MASK;\r
1071 *MtrrValidAddressMask = MTRR_LIB_CACHE_VALID_ADDRESS;\r
e50466da 1072 }\r
1073}\r
1074\r
1075\r
1076/**\r
76b4cae3 1077 Determines the real attribute of a memory range.\r
e50466da 1078\r
1079 This function is to arbitrate the real attribute of the memory when\r
76b4cae3 1080 there are 2 MTRRs covers the same memory range. For further details,\r
e50466da 1081 please refer the IA32 Software Developer's Manual, Volume 3,\r
1082 Section 10.11.4.1.\r
1083\r
76b4cae3
MK
1084 @param[in] MtrrType1 The first kind of Memory type\r
1085 @param[in] MtrrType2 The second kind of memory type\r
e50466da 1086\r
1087**/\r
1088UINT64\r
1089MtrrPrecedence (\r
76b4cae3
MK
1090 IN UINT64 MtrrType1,\r
1091 IN UINT64 MtrrType2\r
e50466da 1092 )\r
1093{\r
1094 UINT64 MtrrType;\r
1095\r
1096 MtrrType = MTRR_CACHE_INVALID_TYPE;\r
1097 switch (MtrrType1) {\r
1098 case MTRR_CACHE_UNCACHEABLE:\r
1099 MtrrType = MTRR_CACHE_UNCACHEABLE;\r
1100 break;\r
1101 case MTRR_CACHE_WRITE_COMBINING:\r
1102 if (\r
1103 MtrrType2==MTRR_CACHE_WRITE_COMBINING ||\r
1104 MtrrType2==MTRR_CACHE_UNCACHEABLE\r
1105 ) {\r
1106 MtrrType = MtrrType2;\r
1107 }\r
1108 break;\r
1109 case MTRR_CACHE_WRITE_THROUGH:\r
1110 if (\r
1111 MtrrType2==MTRR_CACHE_WRITE_THROUGH ||\r
1112 MtrrType2==MTRR_CACHE_WRITE_BACK\r
1113 ) {\r
1114 MtrrType = MTRR_CACHE_WRITE_THROUGH;\r
1115 } else if(MtrrType2==MTRR_CACHE_UNCACHEABLE) {\r
1116 MtrrType = MTRR_CACHE_UNCACHEABLE;\r
1117 }\r
1118 break;\r
1119 case MTRR_CACHE_WRITE_PROTECTED:\r
1120 if (MtrrType2 == MTRR_CACHE_WRITE_PROTECTED ||\r
1121 MtrrType2 == MTRR_CACHE_UNCACHEABLE) {\r
1122 MtrrType = MtrrType2;\r
1123 }\r
1124 break;\r
1125 case MTRR_CACHE_WRITE_BACK:\r
1126 if (\r
1127 MtrrType2== MTRR_CACHE_UNCACHEABLE ||\r
1128 MtrrType2==MTRR_CACHE_WRITE_THROUGH ||\r
1129 MtrrType2== MTRR_CACHE_WRITE_BACK\r
1130 ) {\r
1131 MtrrType = MtrrType2;\r
1132 }\r
1133 break;\r
1134 case MTRR_CACHE_INVALID_TYPE:\r
1135 MtrrType = MtrrType2;\r
1136 break;\r
1137 default:\r
1138 break;\r
1139 }\r
1140\r
1141 if (MtrrType2 == MTRR_CACHE_INVALID_TYPE) {\r
1142 MtrrType = MtrrType1;\r
1143 }\r
1144 return MtrrType;\r
1145}\r
1146\r
e50466da 1147/**\r
5abd5ed4 1148 Worker function will get the memory cache type of the specific address.\r
e50466da 1149\r
5abd5ed4
MK
1150 If MtrrSetting is not NULL, gets the memory cache type from input\r
1151 MTRR settings buffer.\r
1152 If MtrrSetting is NULL, gets the memory cache type from MTRRs.\r
e50466da 1153\r
5abd5ed4 1154 @param[in] MtrrSetting A buffer holding all MTRRs content.\r
85b7f65b
MK
1155 @param[in] Address The specific address\r
1156\r
1157 @return Memory cache type of the specific address\r
e50466da 1158\r
1159**/\r
85b7f65b 1160MTRR_MEMORY_CACHE_TYPE\r
5abd5ed4
MK
1161MtrrGetMemoryAttributeByAddressWorker (\r
1162 IN MTRR_SETTINGS *MtrrSetting,\r
85b7f65b 1163 IN PHYSICAL_ADDRESS Address\r
e50466da 1164 )\r
1165{\r
85b7f65b
MK
1166 UINT64 TempQword;\r
1167 UINTN Index;\r
1168 UINTN SubIndex;\r
1169 UINT64 MtrrType;\r
1170 UINT64 TempMtrrType;\r
1171 MTRR_MEMORY_CACHE_TYPE CacheType;\r
1172 VARIABLE_MTRR VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];\r
1173 UINT64 MtrrValidBitsMask;\r
1174 UINT64 MtrrValidAddressMask;\r
1175 UINTN VariableMtrrCount;\r
d0baed7d 1176 MTRR_VARIABLE_SETTINGS VariableSettings;\r
f877f300 1177\r
e50466da 1178 //\r
85b7f65b 1179 // Check if MTRR is enabled, if not, return UC as attribute\r
e50466da 1180 //\r
5abd5ed4
MK
1181 if (MtrrSetting == NULL) {\r
1182 TempQword = AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE);\r
1183 } else {\r
1184 TempQword = MtrrSetting->MtrrDefType;\r
1185 }\r
85b7f65b 1186 MtrrType = MTRR_CACHE_INVALID_TYPE;\r
e50466da 1187\r
85b7f65b
MK
1188 if ((TempQword & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
1189 return CacheUncacheable;\r
e50466da 1190 }\r
1191\r
1192 //\r
85b7f65b 1193 // If address is less than 1M, then try to go through the fixed MTRR\r
e50466da 1194 //\r
85b7f65b
MK
1195 if (Address < BASE_1MB) {\r
1196 if ((TempQword & MTRR_LIB_CACHE_FIXED_MTRR_ENABLED) != 0) {\r
1197 //\r
1198 // Go through the fixed MTRR\r
1199 //\r
1200 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
1201 if (Address >= mMtrrLibFixedMtrrTable[Index].BaseAddress &&\r
1202 Address < (\r
1203 mMtrrLibFixedMtrrTable[Index].BaseAddress +\r
1204 (mMtrrLibFixedMtrrTable[Index].Length * 8)\r
1205 )\r
1206 ) {\r
1207 SubIndex =\r
1208 ((UINTN)Address - mMtrrLibFixedMtrrTable[Index].BaseAddress) /\r
1209 mMtrrLibFixedMtrrTable[Index].Length;\r
5abd5ed4
MK
1210 if (MtrrSetting == NULL) {\r
1211 TempQword = AsmReadMsr64 (mMtrrLibFixedMtrrTable[Index].Msr);\r
1212 } else {\r
1213 TempQword = MtrrSetting->Fixed.Mtrr[Index];\r
1214 }\r
85b7f65b 1215 MtrrType = RShiftU64 (TempQword, SubIndex * 8) & 0xFF;\r
5abd5ed4 1216 return GetMemoryCacheTypeFromMtrrType (MtrrSetting, MtrrType);\r
85b7f65b
MK
1217 }\r
1218 }\r
e50466da 1219 }\r
1220 }\r
85b7f65b 1221 MtrrLibInitializeMtrrMask(&MtrrValidBitsMask, &MtrrValidAddressMask);\r
d0baed7d
MK
1222\r
1223 MtrrGetVariableMtrrWorker (\r
5abd5ed4 1224 MtrrSetting,\r
d0baed7d
MK
1225 GetVariableMtrrCountWorker (),\r
1226 &VariableSettings\r
85b7f65b 1227 );\r
e50466da 1228\r
d0baed7d
MK
1229 MtrrGetMemoryAttributeInVariableMtrrWorker (\r
1230 &VariableSettings,\r
1231 GetFirmwareVariableMtrrCountWorker (),\r
1232 MtrrValidBitsMask,\r
1233 MtrrValidAddressMask,\r
1234 VariableMtrr\r
1235 );\r
1236\r
e50466da 1237 //\r
85b7f65b 1238 // Go through the variable MTRR\r
e50466da 1239 //\r
acf431e6 1240 VariableMtrrCount = GetVariableMtrrCountWorker ();\r
85b7f65b
MK
1241 ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);\r
1242\r
1243 for (Index = 0; Index < VariableMtrrCount; Index++) {\r
1244 if (VariableMtrr[Index].Valid) {\r
1245 if (Address >= VariableMtrr[Index].BaseAddress &&\r
1246 Address < VariableMtrr[Index].BaseAddress+VariableMtrr[Index].Length) {\r
1247 TempMtrrType = VariableMtrr[Index].Type;\r
1248 MtrrType = MtrrPrecedence (MtrrType, TempMtrrType);\r
1249 }\r
1250 }\r
e50466da 1251 }\r
5abd5ed4 1252 CacheType = GetMemoryCacheTypeFromMtrrType (MtrrSetting, MtrrType);\r
e50466da 1253\r
85b7f65b
MK
1254 return CacheType;\r
1255}\r
1256\r
1257\r
5abd5ed4
MK
1258/**\r
1259 This function will get the memory cache type of the specific address.\r
1260\r
1261 This function is mainly for debug purpose.\r
1262\r
1263 @param[in] Address The specific address\r
1264\r
1265 @return Memory cache type of the specific address\r
1266\r
1267**/\r
1268MTRR_MEMORY_CACHE_TYPE\r
1269EFIAPI\r
1270MtrrGetMemoryAttribute (\r
1271 IN PHYSICAL_ADDRESS Address\r
1272 )\r
1273{\r
1274 if (!IsMtrrSupported ()) {\r
1275 return CacheUncacheable;\r
1276 }\r
1277\r
1278 return MtrrGetMemoryAttributeByAddressWorker (NULL, Address);\r
1279}\r
1280\r
85b7f65b 1281/**\r
16c2d37e
MK
1282 Worker function prints all MTRRs for debugging.\r
1283\r
341fea64 1284 If MtrrSetting is not NULL, print MTRR settings from input MTRR\r
16c2d37e
MK
1285 settings buffer.\r
1286 If MtrrSetting is NULL, print MTRR settings from MTRRs.\r
1287\r
1288 @param MtrrSetting A buffer holding all MTRRs content.\r
85b7f65b
MK
1289**/\r
1290VOID\r
16c2d37e
MK
1291MtrrDebugPrintAllMtrrsWorker (\r
1292 IN MTRR_SETTINGS *MtrrSetting\r
85b7f65b
MK
1293 )\r
1294{\r
1295 DEBUG_CODE (\r
16c2d37e
MK
1296 MTRR_SETTINGS LocalMtrrs;\r
1297 MTRR_SETTINGS *Mtrrs;\r
85b7f65b
MK
1298 UINTN Index;\r
1299 UINTN Index1;\r
1300 UINTN VariableMtrrCount;\r
1301 UINT64 Base;\r
1302 UINT64 Limit;\r
1303 UINT64 MtrrBase;\r
1304 UINT64 MtrrLimit;\r
1305 UINT64 RangeBase;\r
1306 UINT64 RangeLimit;\r
1307 UINT64 NoRangeBase;\r
1308 UINT64 NoRangeLimit;\r
1309 UINT32 RegEax;\r
1310 UINTN MemoryType;\r
1311 UINTN PreviousMemoryType;\r
1312 BOOLEAN Found;\r
1313\r
1314 if (!IsMtrrSupported ()) {\r
1315 return;\r
1316 }\r
1317\r
1318 DEBUG((DEBUG_CACHE, "MTRR Settings\n"));\r
1319 DEBUG((DEBUG_CACHE, "=============\n"));\r
1320\r
16c2d37e
MK
1321 if (MtrrSetting != NULL) {\r
1322 Mtrrs = MtrrSetting;\r
1323 } else {\r
1324 MtrrGetAllMtrrs (&LocalMtrrs);\r
1325 Mtrrs = &LocalMtrrs;\r
1326 }\r
1327\r
1328 DEBUG((DEBUG_CACHE, "MTRR Default Type: %016lx\n", Mtrrs->MtrrDefType));\r
85b7f65b 1329 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
16c2d37e 1330 DEBUG((DEBUG_CACHE, "Fixed MTRR[%02d] : %016lx\n", Index, Mtrrs->Fixed.Mtrr[Index]));\r
85b7f65b
MK
1331 }\r
1332\r
1333 VariableMtrrCount = GetVariableMtrrCount ();\r
1334 for (Index = 0; Index < VariableMtrrCount; Index++) {\r
1335 DEBUG((DEBUG_CACHE, "Variable MTRR[%02d]: Base=%016lx Mask=%016lx\n",\r
1336 Index,\r
16c2d37e
MK
1337 Mtrrs->Variables.Mtrr[Index].Base,\r
1338 Mtrrs->Variables.Mtrr[Index].Mask\r
85b7f65b
MK
1339 ));\r
1340 }\r
1341 DEBUG((DEBUG_CACHE, "\n"));\r
1342 DEBUG((DEBUG_CACHE, "MTRR Ranges\n"));\r
1343 DEBUG((DEBUG_CACHE, "====================================\n"));\r
1344\r
1345 Base = 0;\r
1346 PreviousMemoryType = MTRR_CACHE_INVALID_TYPE;\r
1347 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
1348 Base = mMtrrLibFixedMtrrTable[Index].BaseAddress;\r
1349 for (Index1 = 0; Index1 < 8; Index1++) {\r
16c2d37e 1350 MemoryType = (UINTN)(RShiftU64 (Mtrrs->Fixed.Mtrr[Index], Index1 * 8) & 0xff);\r
85b7f65b
MK
1351 if (MemoryType > CacheWriteBack) {\r
1352 MemoryType = MTRR_CACHE_INVALID_TYPE;\r
1353 }\r
1354 if (MemoryType != PreviousMemoryType) {\r
1355 if (PreviousMemoryType != MTRR_CACHE_INVALID_TYPE) {\r
1356 DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));\r
1357 }\r
1358 PreviousMemoryType = MemoryType;\r
1359 DEBUG((DEBUG_CACHE, "%a:%016lx-", mMtrrMemoryCacheTypeShortName[MemoryType], Base));\r
1360 }\r
1361 Base += mMtrrLibFixedMtrrTable[Index].Length;\r
1362 }\r
1363 }\r
1364 DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));\r
1365\r
1366 VariableMtrrCount = GetVariableMtrrCount ();\r
1367\r
1368 Limit = BIT36 - 1;\r
1369 AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);\r
1370 if (RegEax >= 0x80000008) {\r
1371 AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);\r
1372 Limit = LShiftU64 (1, RegEax & 0xff) - 1;\r
1373 }\r
1374 Base = BASE_1MB;\r
1375 PreviousMemoryType = MTRR_CACHE_INVALID_TYPE;\r
1376 do {\r
16c2d37e 1377 MemoryType = MtrrGetMemoryAttributeByAddressWorker (Mtrrs, Base);\r
85b7f65b
MK
1378 if (MemoryType > CacheWriteBack) {\r
1379 MemoryType = MTRR_CACHE_INVALID_TYPE;\r
1380 }\r
1381\r
1382 if (MemoryType != PreviousMemoryType) {\r
1383 if (PreviousMemoryType != MTRR_CACHE_INVALID_TYPE) {\r
1384 DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));\r
1385 }\r
1386 PreviousMemoryType = MemoryType;\r
1387 DEBUG((DEBUG_CACHE, "%a:%016lx-", mMtrrMemoryCacheTypeShortName[MemoryType], Base));\r
1388 }\r
1389\r
1390 RangeBase = BASE_1MB;\r
1391 NoRangeBase = BASE_1MB;\r
1392 RangeLimit = Limit;\r
1393 NoRangeLimit = Limit;\r
1394\r
1395 for (Index = 0, Found = FALSE; Index < VariableMtrrCount; Index++) {\r
16c2d37e 1396 if ((Mtrrs->Variables.Mtrr[Index].Mask & BIT11) == 0) {\r
85b7f65b
MK
1397 //\r
1398 // If mask is not valid, then do not display range\r
1399 //\r
1400 continue;\r
1401 }\r
16c2d37e
MK
1402 MtrrBase = (Mtrrs->Variables.Mtrr[Index].Base & (~(SIZE_4KB - 1)));\r
1403 MtrrLimit = MtrrBase + ((~(Mtrrs->Variables.Mtrr[Index].Mask & (~(SIZE_4KB - 1)))) & Limit);\r
85b7f65b
MK
1404\r
1405 if (Base >= MtrrBase && Base < MtrrLimit) {\r
1406 Found = TRUE;\r
1407 }\r
1408\r
1409 if (Base >= MtrrBase && MtrrBase > RangeBase) {\r
1410 RangeBase = MtrrBase;\r
1411 }\r
1412 if (Base > MtrrLimit && MtrrLimit > RangeBase) {\r
1413 RangeBase = MtrrLimit + 1;\r
1414 }\r
1415 if (Base < MtrrBase && MtrrBase < RangeLimit) {\r
1416 RangeLimit = MtrrBase - 1;\r
1417 }\r
1418 if (Base < MtrrLimit && MtrrLimit <= RangeLimit) {\r
1419 RangeLimit = MtrrLimit;\r
1420 }\r
1421\r
1422 if (Base > MtrrLimit && NoRangeBase < MtrrLimit) {\r
1423 NoRangeBase = MtrrLimit + 1;\r
1424 }\r
1425 if (Base < MtrrBase && NoRangeLimit > MtrrBase) {\r
1426 NoRangeLimit = MtrrBase - 1;\r
1427 }\r
1428 }\r
1429\r
1430 if (Found) {\r
1431 Base = RangeLimit + 1;\r
1432 } else {\r
1433 Base = NoRangeLimit + 1;\r
1434 }\r
1435 } while (Base < Limit);\r
1436 DEBUG((DEBUG_CACHE, "%016lx\n\n", Base - 1));\r
1437 );\r
1438}\r
16c2d37e
MK
1439\r
1440\r
1441/**\r
1442 This function prints all MTRRs for debugging.\r
1443**/\r
1444VOID\r
1445EFIAPI\r
1446MtrrDebugPrintAllMtrrs (\r
1447 VOID\r
1448 )\r
1449{\r
1450 MtrrDebugPrintAllMtrrsWorker (NULL);\r
1451}\r
1452\r
1453\r
85b7f65b 1454/**\r
16c2d37e 1455 Worker function attempts to set the attributes for a memory range.\r
85b7f65b 1456\r
b970ed68
MK
1457 If MtrrSettings is not NULL, set the attributes into the input MTRR\r
1458 settings buffer.\r
1459 If MtrrSettings is NULL, set the attributes into MTRRs registers.\r
1460\r
1461 @param[in, out] MtrrSetting A buffer holding all MTRRs content.\r
85b7f65b
MK
1462 @param[in] BaseAddress The physical address that is the start\r
1463 address of a memory region.\r
1464 @param[in] Length The size in bytes of the memory region.\r
1465 @param[in] Attribute The bit mask of attributes to set for the\r
1466 memory region.\r
1467\r
1468 @retval RETURN_SUCCESS The attributes were set for the memory\r
1469 region.\r
1470 @retval RETURN_INVALID_PARAMETER Length is zero.\r
1471 @retval RETURN_UNSUPPORTED The processor does not support one or\r
1472 more bytes of the memory resource range\r
1473 specified by BaseAddress and Length.\r
1474 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support\r
1475 for the memory resource range specified\r
1476 by BaseAddress and Length.\r
1477 @retval RETURN_ACCESS_DENIED The attributes for the memory resource\r
1478 range specified by BaseAddress and Length\r
1479 cannot be modified.\r
1480 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to\r
1481 modify the attributes of the memory\r
1482 resource range.\r
1483\r
1484**/\r
1485RETURN_STATUS\r
b970ed68
MK
1486MtrrSetMemoryAttributeWorker (\r
1487 IN OUT MTRR_SETTINGS *MtrrSetting,\r
1488 IN PHYSICAL_ADDRESS BaseAddress,\r
1489 IN UINT64 Length,\r
1490 IN MTRR_MEMORY_CACHE_TYPE Attribute\r
85b7f65b
MK
1491 )\r
1492{\r
1493 UINT64 TempQword;\r
1494 RETURN_STATUS Status;\r
1495 UINT64 MemoryType;\r
1496 UINT64 Alignment;\r
1497 BOOLEAN OverLap;\r
1498 BOOLEAN Positive;\r
1499 UINT32 MsrNum;\r
1500 UINTN MtrrNumber;\r
1501 VARIABLE_MTRR VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];\r
1502 UINT32 UsedMtrr;\r
1503 UINT64 MtrrValidBitsMask;\r
1504 UINT64 MtrrValidAddressMask;\r
1505 BOOLEAN OverwriteExistingMtrr;\r
1506 UINT32 FirmwareVariableMtrrCount;\r
85b7f65b 1507 MTRR_CONTEXT MtrrContext;\r
fa25cf38
MK
1508 BOOLEAN MtrrContextValid;\r
1509 BOOLEAN FixedSettingsValid[MTRR_NUMBER_OF_FIXED_MTRR];\r
1510 BOOLEAN FixedSettingsModified[MTRR_NUMBER_OF_FIXED_MTRR];\r
1511 MTRR_FIXED_SETTINGS WorkingFixedSettings;\r
acf431e6 1512 UINT32 VariableMtrrCount;\r
d0baed7d 1513 MTRR_VARIABLE_SETTINGS OriginalVariableSettings;\r
b0fa5d29 1514 BOOLEAN ProgramVariableSettings;\r
d0baed7d 1515 MTRR_VARIABLE_SETTINGS WorkingVariableSettings;\r
fa25cf38
MK
1516 UINT32 Index;\r
1517 UINT64 ClearMask;\r
1518 UINT64 OrMask;\r
1519 UINT64 NewValue;\r
d0baed7d 1520 MTRR_VARIABLE_SETTINGS *VariableSettings;\r
85b7f65b 1521\r
2d675c1c
JF
1522 MtrrContextValid = FALSE;\r
1523 VariableMtrrCount = 0;\r
1524 ZeroMem (&WorkingFixedSettings, sizeof (WorkingFixedSettings));\r
fa25cf38
MK
1525 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
1526 FixedSettingsValid[Index] = FALSE;\r
1527 FixedSettingsModified[Index] = FALSE;\r
1528 }\r
b0fa5d29 1529 ProgramVariableSettings = FALSE;\r
85b7f65b
MK
1530\r
1531 if (!IsMtrrSupported ()) {\r
1532 Status = RETURN_UNSUPPORTED;\r
1533 goto Done;\r
1534 }\r
1535\r
b0fa5d29 1536 MtrrLibInitializeMtrrMask (&MtrrValidBitsMask, &MtrrValidAddressMask);\r
85b7f65b
MK
1537\r
1538 TempQword = 0;\r
1539 MemoryType = (UINT64)Attribute;\r
1540 OverwriteExistingMtrr = FALSE;\r
1541\r
1542 //\r
1543 // Check for an invalid parameter\r
1544 //\r
1545 if (Length == 0) {\r
1546 Status = RETURN_INVALID_PARAMETER;\r
1547 goto Done;\r
1548 }\r
1549\r
1550 if (\r
1551 (BaseAddress & ~MtrrValidAddressMask) != 0 ||\r
1552 (Length & ~MtrrValidAddressMask) != 0\r
1553 ) {\r
1554 Status = RETURN_UNSUPPORTED;\r
1555 goto Done;\r
1556 }\r
1557\r
1558 //\r
1559 // Check if Fixed MTRR\r
1560 //\r
1561 Status = RETURN_SUCCESS;\r
fa25cf38 1562 if (BaseAddress < BASE_1MB) {\r
0f354122 1563 MsrNum = (UINT32)-1;\r
fa25cf38
MK
1564 while ((BaseAddress < BASE_1MB) && (Length > 0) && Status == RETURN_SUCCESS) {\r
1565 Status = ProgramFixedMtrr (MemoryType, &BaseAddress, &Length, &MsrNum, &ClearMask, &OrMask);\r
1566 if (RETURN_ERROR (Status)) {\r
1567 goto Done;\r
1568 }\r
b970ed68
MK
1569 if (MtrrSetting != NULL) {\r
1570 MtrrSetting->Fixed.Mtrr[MsrNum] = (MtrrSetting->Fixed.Mtrr[MsrNum] & ~ClearMask) | OrMask;\r
1571 MtrrSetting->MtrrDefType |= MTRR_LIB_CACHE_FIXED_MTRR_ENABLED;\r
1572 } else {\r
1573 if (!FixedSettingsValid[MsrNum]) {\r
1574 WorkingFixedSettings.Mtrr[MsrNum] = AsmReadMsr64 (mMtrrLibFixedMtrrTable[MsrNum].Msr);\r
1575 FixedSettingsValid[MsrNum] = TRUE;\r
1576 }\r
1577 NewValue = (WorkingFixedSettings.Mtrr[MsrNum] & ~ClearMask) | OrMask;\r
1578 if (WorkingFixedSettings.Mtrr[MsrNum] != NewValue) {\r
1579 WorkingFixedSettings.Mtrr[MsrNum] = NewValue;\r
1580 FixedSettingsModified[MsrNum] = TRUE;\r
1581 }\r
fa25cf38 1582 }\r
85b7f65b 1583 }\r
85b7f65b 1584\r
fa25cf38
MK
1585 if (Length == 0) {\r
1586 //\r
1587 // A Length of 0 can only make sense for fixed MTTR ranges.\r
1588 // Since we just handled the fixed MTRRs, we can skip the\r
1589 // variable MTRR section.\r
1590 //\r
1591 goto Done;\r
1592 }\r
85b7f65b
MK
1593 }\r
1594\r
1595 //\r
1596 // Since memory ranges below 1MB will be overridden by the fixed MTRRs,\r
1597 // we can set the base to 0 to save variable MTRRs.\r
1598 //\r
1599 if (BaseAddress == BASE_1MB) {\r
1600 BaseAddress = 0;\r
1601 Length += SIZE_1MB;\r
1602 }\r
1603\r
acf431e6
MK
1604 //\r
1605 // Read all variable MTRRs\r
1606 //\r
1607 VariableMtrrCount = GetVariableMtrrCountWorker ();\r
b0fa5d29 1608 FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCountWorker ();\r
b970ed68
MK
1609 if (MtrrSetting != NULL) {\r
1610 VariableSettings = &MtrrSetting->Variables;\r
1611 } else {\r
1612 MtrrGetVariableMtrrWorker (NULL, VariableMtrrCount, &OriginalVariableSettings);\r
1613 CopyMem (&WorkingVariableSettings, &OriginalVariableSettings, sizeof (WorkingVariableSettings));\r
1614 ProgramVariableSettings = TRUE;\r
1615 VariableSettings = &WorkingVariableSettings;\r
1616 }\r
acf431e6 1617\r
85b7f65b
MK
1618 //\r
1619 // Check for overlap\r
1620 //\r
d0baed7d
MK
1621 UsedMtrr = MtrrGetMemoryAttributeInVariableMtrrWorker (\r
1622 VariableSettings,\r
1623 FirmwareVariableMtrrCount,\r
1624 MtrrValidBitsMask,\r
1625 MtrrValidAddressMask,\r
1626 VariableMtrr\r
1627 );\r
acf431e6
MK
1628 OverLap = CheckMemoryAttributeOverlap (\r
1629 FirmwareVariableMtrrCount,\r
1630 BaseAddress,\r
1631 BaseAddress + Length - 1,\r
1632 VariableMtrr\r
1633 );\r
85b7f65b 1634 if (OverLap) {\r
acf431e6
MK
1635 Status = CombineMemoryAttribute (\r
1636 FirmwareVariableMtrrCount,\r
1637 MemoryType,\r
1638 &BaseAddress,\r
1639 &Length,\r
1640 VariableMtrr,\r
1641 &UsedMtrr,\r
1642 &OverwriteExistingMtrr\r
1643 );\r
e50466da 1644 if (RETURN_ERROR (Status)) {\r
1645 goto Done;\r
1646 }\r
1647\r
1648 if (Length == 0) {\r
1649 //\r
1e60a0ec 1650 // Combined successfully, invalidate the now-unused MTRRs\r
e50466da 1651 //\r
b0fa5d29 1652 InvalidateMtrr (VariableSettings, VariableMtrrCount, VariableMtrr);\r
e50466da 1653 Status = RETURN_SUCCESS;\r
1654 goto Done;\r
1655 }\r
1656 }\r
e50466da 1657\r
1658 //\r
1659 // The memory type is the same with the type specified by\r
1660 // MTRR_LIB_IA32_MTRR_DEF_TYPE.\r
1661 //\r
b970ed68 1662 if ((!OverwriteExistingMtrr) && (Attribute == MtrrGetDefaultMemoryTypeWorker (MtrrSetting))) {\r
e50466da 1663 //\r
1664 // Invalidate the now-unused MTRRs\r
1665 //\r
b0fa5d29 1666 InvalidateMtrr (VariableSettings, VariableMtrrCount, VariableMtrr);\r
e50466da 1667 goto Done;\r
1668 }\r
1669\r
1a2ad6fc 1670 Positive = GetMtrrNumberAndDirection (BaseAddress, Length, &MtrrNumber);\r
e50466da 1671\r
1a2ad6fc 1672 if ((UsedMtrr + MtrrNumber) > FirmwareVariableMtrrCount) {\r
1673 Status = RETURN_OUT_OF_RESOURCES;\r
1674 goto Done;\r
1675 }\r
e50466da 1676\r
1a2ad6fc 1677 //\r
1678 // Invalidate the now-unused MTRRs\r
1679 //\r
b0fa5d29 1680 InvalidateMtrr (VariableSettings, VariableMtrrCount, VariableMtrr);\r
1a2ad6fc 1681\r
1682 //\r
1683 // Find first unused MTRR\r
1684 //\r
b0fa5d29
MK
1685 for (MsrNum = 0; MsrNum < VariableMtrrCount; MsrNum++) {\r
1686 if ((VariableSettings->Mtrr[MsrNum].Mask & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
1a2ad6fc 1687 break;\r
1688 }\r
1689 }\r
1690\r
1691 if (BaseAddress != 0) {\r
1692 do {\r
1693 //\r
1694 // Calculate the alignment of the base address.\r
1695 //\r
1696 Alignment = LShiftU64 (1, (UINTN)LowBitSet64 (BaseAddress));\r
1697\r
1698 if (Alignment > Length) {\r
1699 break;\r
1700 }\r
1701\r
1702 //\r
1703 // Find unused MTRR\r
1704 //\r
b0fa5d29
MK
1705 for (; MsrNum < VariableMtrrCount; MsrNum++) {\r
1706 if ((VariableSettings->Mtrr[MsrNum].Mask & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
1a2ad6fc 1707 break;\r
1708 }\r
1709 }\r
1710\r
1711 ProgramVariableMtrr (\r
b0fa5d29 1712 VariableSettings,\r
1a2ad6fc 1713 MsrNum,\r
1714 BaseAddress,\r
1715 Alignment,\r
1716 MemoryType,\r
1717 MtrrValidAddressMask\r
1718 );\r
1719 BaseAddress += Alignment;\r
1720 Length -= Alignment;\r
1721 } while (TRUE);\r
1722\r
1723 if (Length == 0) {\r
1724 goto Done;\r
1725 }\r
1726 }\r
1727\r
1728 TempQword = Length;\r
1729\r
1730 if (!Positive) {\r
1731 Length = Power2MaxMemory (LShiftU64 (TempQword, 1));\r
e50466da 1732\r
1733 //\r
1a2ad6fc 1734 // Find unused MTRR\r
e50466da 1735 //\r
b0fa5d29
MK
1736 for (; MsrNum < VariableMtrrCount; MsrNum++) {\r
1737 if ((VariableSettings->Mtrr[MsrNum].Mask & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
e50466da 1738 break;\r
85b7f65b
MK
1739 }\r
1740 }\r
1741\r
1742 ProgramVariableMtrr (\r
b0fa5d29 1743 VariableSettings,\r
85b7f65b
MK
1744 MsrNum,\r
1745 BaseAddress,\r
1746 Length,\r
1747 MemoryType,\r
1748 MtrrValidAddressMask\r
1749 );\r
1750 BaseAddress += Length;\r
1751 TempQword = Length - TempQword;\r
1752 MemoryType = MTRR_CACHE_UNCACHEABLE;\r
e50466da 1753 }\r
1754\r
85b7f65b
MK
1755 do {\r
1756 //\r
1757 // Find unused MTRR\r
1758 //\r
b0fa5d29
MK
1759 for (; MsrNum < VariableMtrrCount; MsrNum++) {\r
1760 if ((VariableSettings->Mtrr[MsrNum].Mask & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
85b7f65b
MK
1761 break;\r
1762 }\r
1763 }\r
e50466da 1764\r
85b7f65b
MK
1765 Length = Power2MaxMemory (TempQword);\r
1766 if (!Positive) {\r
1767 BaseAddress -= Length;\r
1768 }\r
31b3597e 1769\r
85b7f65b 1770 ProgramVariableMtrr (\r
b0fa5d29 1771 VariableSettings,\r
85b7f65b
MK
1772 MsrNum,\r
1773 BaseAddress,\r
1774 Length,\r
1775 MemoryType,\r
1776 MtrrValidAddressMask\r
1777 );\r
31b3597e 1778\r
85b7f65b
MK
1779 if (Positive) {\r
1780 BaseAddress += Length;\r
1781 }\r
1782 TempQword -= Length;\r
31b3597e 1783\r
85b7f65b
MK
1784 } while (TempQword > 0);\r
1785\r
1786Done:\r
fa25cf38
MK
1787\r
1788 //\r
1789 // Write fixed MTRRs that have been modified\r
1790 //\r
1791 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
1792 if (FixedSettingsModified[Index]) {\r
1793 if (!MtrrContextValid) {\r
1794 PreMtrrChange (&MtrrContext);\r
1795 MtrrContextValid = TRUE;\r
1796 }\r
1797 AsmWriteMsr64 (\r
1798 mMtrrLibFixedMtrrTable[Index].Msr,\r
1799 WorkingFixedSettings.Mtrr[Index]\r
1800 );\r
1801 }\r
1802 }\r
1803\r
b0fa5d29
MK
1804 //\r
1805 // Write variable MTRRs\r
1806 //\r
1807 if (ProgramVariableSettings) {\r
1808 for (Index = 0; Index < VariableMtrrCount; Index++) {\r
1809 if (WorkingVariableSettings.Mtrr[Index].Base != OriginalVariableSettings.Mtrr[Index].Base ||\r
1810 WorkingVariableSettings.Mtrr[Index].Mask != OriginalVariableSettings.Mtrr[Index].Mask ) {\r
1811 if (!MtrrContextValid) {\r
1812 PreMtrrChange (&MtrrContext);\r
1813 MtrrContextValid = TRUE;\r
1814 }\r
1815 AsmWriteMsr64 (\r
1816 MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1),\r
1817 WorkingVariableSettings.Mtrr[Index].Base\r
1818 );\r
1819 AsmWriteMsr64 (\r
1820 MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1) + 1,\r
1821 WorkingVariableSettings.Mtrr[Index].Mask\r
1822 );\r
1823 }\r
1824 }\r
1825 }\r
fa25cf38
MK
1826 if (MtrrContextValid) {\r
1827 PostMtrrChange (&MtrrContext);\r
1828 }\r
1829\r
85b7f65b
MK
1830 DEBUG((DEBUG_CACHE, " Status = %r\n", Status));\r
1831 if (!RETURN_ERROR (Status)) {\r
b970ed68
MK
1832 if (MtrrSetting != NULL) {\r
1833 MtrrSetting->MtrrDefType |= MTRR_LIB_CACHE_MTRR_ENABLED;\r
1834 }\r
1835 MtrrDebugPrintAllMtrrsWorker (MtrrSetting);\r
31b3597e
MK
1836 }\r
1837\r
85b7f65b 1838 return Status;\r
31b3597e 1839}\r
b970ed68
MK
1840\r
1841/**\r
1842 This function attempts to set the attributes for a memory range.\r
1843\r
1844 @param[in] BaseAddress The physical address that is the start\r
1845 address of a memory region.\r
1846 @param[in] Length The size in bytes of the memory region.\r
1847 @param[in] Attributes The bit mask of attributes to set for the\r
1848 memory region.\r
1849\r
1850 @retval RETURN_SUCCESS The attributes were set for the memory\r
1851 region.\r
1852 @retval RETURN_INVALID_PARAMETER Length is zero.\r
1853 @retval RETURN_UNSUPPORTED The processor does not support one or\r
1854 more bytes of the memory resource range\r
1855 specified by BaseAddress and Length.\r
1856 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support\r
1857 for the memory resource range specified\r
1858 by BaseAddress and Length.\r
1859 @retval RETURN_ACCESS_DENIED The attributes for the memory resource\r
1860 range specified by BaseAddress and Length\r
1861 cannot be modified.\r
1862 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to\r
1863 modify the attributes of the memory\r
1864 resource range.\r
1865\r
1866**/\r
1867RETURN_STATUS\r
1868EFIAPI\r
1869MtrrSetMemoryAttribute (\r
1870 IN PHYSICAL_ADDRESS BaseAddress,\r
1871 IN UINT64 Length,\r
1872 IN MTRR_MEMORY_CACHE_TYPE Attribute\r
1873 )\r
1874{\r
1875 DEBUG((DEBUG_CACHE, "MtrrSetMemoryAttribute() %a:%016lx-%016lx\n", mMtrrMemoryCacheTypeShortName[Attribute], BaseAddress, Length));\r
1876 return MtrrSetMemoryAttributeWorker (\r
1877 NULL,\r
1878 BaseAddress,\r
1879 Length,\r
1880 Attribute\r
1881 );\r
1882}\r
1883\r
1884/**\r
1885 This function attempts to set the attributes into MTRR setting buffer for a memory range.\r
1886\r
1887 @param[in, out] MtrrSetting MTRR setting buffer to be set.\r
1888 @param[in] BaseAddress The physical address that is the start address\r
1889 of a memory region.\r
1890 @param[in] Length The size in bytes of the memory region.\r
1891 @param[in] Attribute The bit mask of attributes to set for the\r
1892 memory region.\r
1893\r
1894 @retval RETURN_SUCCESS The attributes were set for the memory region.\r
1895 @retval RETURN_INVALID_PARAMETER Length is zero.\r
1896 @retval RETURN_UNSUPPORTED The processor does not support one or more bytes of the\r
1897 memory resource range specified by BaseAddress and Length.\r
1898 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support for the memory resource\r
1899 range specified by BaseAddress and Length.\r
1900 @retval RETURN_ACCESS_DENIED The attributes for the memory resource range specified by\r
1901 BaseAddress and Length cannot be modified.\r
1902 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of\r
1903 the memory resource range.\r
1904\r
1905**/\r
1906RETURN_STATUS\r
1907EFIAPI\r
1908MtrrSetMemoryAttributeInMtrrSettings (\r
1909 IN OUT MTRR_SETTINGS *MtrrSetting,\r
1910 IN PHYSICAL_ADDRESS BaseAddress,\r
1911 IN UINT64 Length,\r
1912 IN MTRR_MEMORY_CACHE_TYPE Attribute\r
1913 )\r
1914{\r
1915 DEBUG((DEBUG_CACHE, "MtrrSetMemoryAttributeMtrrSettings(%p) %a:%016lx-%016lx\n", MtrrSetting, mMtrrMemoryCacheTypeShortName[Attribute], BaseAddress, Length));\r
1916 return MtrrSetMemoryAttributeWorker (\r
1917 MtrrSetting,\r
1918 BaseAddress,\r
1919 Length,\r
1920 Attribute\r
1921 );\r
1922}\r
1923\r
e50466da 1924/**\r
1925 Worker function setting variable MTRRs\r
1926\r
76b4cae3 1927 @param[in] VariableSettings A buffer to hold variable MTRRs content.\r
e50466da 1928\r
1929**/\r
1930VOID\r
1931MtrrSetVariableMtrrWorker (\r
1932 IN MTRR_VARIABLE_SETTINGS *VariableSettings\r
1933 )\r
1934{\r
1935 UINT32 Index;\r
3b9be416 1936 UINT32 VariableMtrrCount;\r
e50466da 1937\r
acf431e6 1938 VariableMtrrCount = GetVariableMtrrCountWorker ();\r
5bdfa4e5 1939 ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);\r
1940\r
3b9be416 1941 for (Index = 0; Index < VariableMtrrCount; Index++) {\r
e50466da 1942 AsmWriteMsr64 (\r
1943 MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1),\r
1944 VariableSettings->Mtrr[Index].Base\r
1945 );\r
1946 AsmWriteMsr64 (\r
1947 MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1) + 1,\r
1948 VariableSettings->Mtrr[Index].Mask\r
1949 );\r
1950 }\r
1951}\r
1952\r
1953\r
1954/**\r
1955 This function sets variable MTRRs\r
1956\r
76b4cae3 1957 @param[in] VariableSettings A buffer to hold variable MTRRs content.\r
e50466da 1958\r
1959 @return The pointer of VariableSettings\r
1960\r
1961**/\r
1962MTRR_VARIABLE_SETTINGS*\r
1963EFIAPI\r
1964MtrrSetVariableMtrr (\r
1965 IN MTRR_VARIABLE_SETTINGS *VariableSettings\r
1966 )\r
1967{\r
c878cee4 1968 MTRR_CONTEXT MtrrContext;\r
e50466da 1969\r
947a573a 1970 if (!IsMtrrSupported ()) {\r
1971 return VariableSettings;\r
1972 }\r
1973\r
c878cee4 1974 PreMtrrChange (&MtrrContext);\r
e50466da 1975 MtrrSetVariableMtrrWorker (VariableSettings);\r
c878cee4 1976 PostMtrrChange (&MtrrContext);\r
e518b80d
MK
1977 MtrrDebugPrintAllMtrrs ();\r
1978\r
e50466da 1979 return VariableSettings;\r
1980}\r
1981\r
e50466da 1982/**\r
1983 Worker function setting fixed MTRRs\r
1984\r
acf431e6 1985 @param[in] FixedSettings A buffer to hold fixed MTRRs content.\r
e50466da 1986\r
1987**/\r
1988VOID\r
1989MtrrSetFixedMtrrWorker (\r
1990 IN MTRR_FIXED_SETTINGS *FixedSettings\r
1991 )\r
1992{\r
1993 UINT32 Index;\r
1994\r
1995 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
1996 AsmWriteMsr64 (\r
f877f300 1997 mMtrrLibFixedMtrrTable[Index].Msr,\r
e50466da 1998 FixedSettings->Mtrr[Index]\r
1999 );\r
2000 }\r
2001}\r
2002\r
2003\r
2004/**\r
2005 This function sets fixed MTRRs\r
2006\r
acf431e6 2007 @param[in] FixedSettings A buffer to hold fixed MTRRs content.\r
e50466da 2008\r
2009 @retval The pointer of FixedSettings\r
2010\r
2011**/\r
2012MTRR_FIXED_SETTINGS*\r
2013EFIAPI\r
2014MtrrSetFixedMtrr (\r
2015 IN MTRR_FIXED_SETTINGS *FixedSettings\r
2016 )\r
2017{\r
c878cee4 2018 MTRR_CONTEXT MtrrContext;\r
e50466da 2019\r
947a573a 2020 if (!IsMtrrSupported ()) {\r
2021 return FixedSettings;\r
2022 }\r
2023\r
c878cee4 2024 PreMtrrChange (&MtrrContext);\r
e50466da 2025 MtrrSetFixedMtrrWorker (FixedSettings);\r
c878cee4 2026 PostMtrrChange (&MtrrContext);\r
e518b80d 2027 MtrrDebugPrintAllMtrrs ();\r
e50466da 2028\r
2029 return FixedSettings;\r
2030}\r
2031\r
2032\r
2033/**\r
2034 This function gets the content in all MTRRs (variable and fixed)\r
2035\r
acf431e6 2036 @param[out] MtrrSetting A buffer to hold all MTRRs content.\r
e50466da 2037\r
2038 @retval the pointer of MtrrSetting\r
2039\r
2040**/\r
2041MTRR_SETTINGS *\r
2042EFIAPI\r
2043MtrrGetAllMtrrs (\r
2044 OUT MTRR_SETTINGS *MtrrSetting\r
2045 )\r
2046{\r
947a573a 2047 if (!IsMtrrSupported ()) {\r
2048 return MtrrSetting;\r
2049 }\r
2050\r
e50466da 2051 //\r
2052 // Get fixed MTRRs\r
2053 //\r
acf431e6 2054 MtrrGetFixedMtrrWorker (&MtrrSetting->Fixed);\r
e50466da 2055\r
2056 //\r
2057 // Get variable MTRRs\r
2058 //\r
acf431e6 2059 MtrrGetVariableMtrrWorker (\r
5abd5ed4 2060 NULL,\r
acf431e6
MK
2061 GetVariableMtrrCountWorker (),\r
2062 &MtrrSetting->Variables\r
2063 );\r
e50466da 2064\r
2065 //\r
2066 // Get MTRR_DEF_TYPE value\r
2067 //\r
2068 MtrrSetting->MtrrDefType = AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE);\r
2069\r
2070 return MtrrSetting;\r
2071}\r
2072\r
2073\r
2074/**\r
2075 This function sets all MTRRs (variable and fixed)\r
2076\r
76b4cae3 2077 @param[in] MtrrSetting A buffer holding all MTRRs content.\r
e50466da 2078\r
2079 @retval The pointer of MtrrSetting\r
2080\r
2081**/\r
2082MTRR_SETTINGS *\r
2083EFIAPI\r
2084MtrrSetAllMtrrs (\r
2085 IN MTRR_SETTINGS *MtrrSetting\r
2086 )\r
2087{\r
c878cee4 2088 MTRR_CONTEXT MtrrContext;\r
e50466da 2089\r
947a573a 2090 if (!IsMtrrSupported ()) {\r
2091 return MtrrSetting;\r
2092 }\r
2093\r
c878cee4 2094 PreMtrrChange (&MtrrContext);\r
e50466da 2095\r
2096 //\r
2097 // Set fixed MTRRs\r
2098 //\r
2099 MtrrSetFixedMtrrWorker (&MtrrSetting->Fixed);\r
2100\r
2101 //\r
2102 // Set variable MTRRs\r
2103 //\r
2104 MtrrSetVariableMtrrWorker (&MtrrSetting->Variables);\r
2105\r
2106 //\r
2107 // Set MTRR_DEF_TYPE value\r
2108 //\r
2109 AsmWriteMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE, MtrrSetting->MtrrDefType);\r
2110\r
c878cee4 2111 PostMtrrChangeEnableCache (&MtrrContext);\r
e50466da 2112\r
2113 return MtrrSetting;\r
2114}\r
2115\r
e518b80d 2116\r
947a573a 2117/**\r
2118 Checks if MTRR is supported.\r
2119\r
2120 @retval TRUE MTRR is supported.\r
2121 @retval FALSE MTRR is not supported.\r
2122\r
2123**/\r
2124BOOLEAN\r
2125EFIAPI\r
2126IsMtrrSupported (\r
2127 VOID\r
2128 )\r
2129{\r
3bb13d35
RN
2130 CPUID_VERSION_INFO_EDX Edx;\r
2131 MSR_IA32_MTRRCAP_REGISTER MtrrCap;\r
947a573a 2132\r
2133 //\r
2134 // Check CPUID(1).EDX[12] for MTRR capability\r
2135 //\r
3bb13d35
RN
2136 AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &Edx.Uint32);\r
2137 if (Edx.Bits.MTRR == 0) {\r
947a573a 2138 return FALSE;\r
2139 }\r
2140\r
2141 //\r
3bb13d35
RN
2142 // Check number of variable MTRRs and fixed MTRRs existence.\r
2143 // If number of variable MTRRs is zero, or fixed MTRRs do not\r
947a573a 2144 // exist, return false.\r
2145 //\r
3bb13d35
RN
2146 MtrrCap.Uint64 = AsmReadMsr64 (MSR_IA32_MTRRCAP);\r
2147 if ((MtrrCap.Bits.VCNT == 0) || (MtrrCap.Bits.FIX == 0)) {\r
947a573a 2148 return FALSE;\r
2149 }\r
947a573a 2150 return TRUE;\r
2151}\r