]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/Library/MtrrLib/MtrrLib.c
UefiCpuPkg/MtrrLib: Use a better algorithm to calculate MTRR
[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
8051302a 33#define MTRR_LIB_ASSERT_ALIGNED(B, L) ASSERT ((B & ~(L - 1)) == B);\r
c878cee4 34//\r
35// Context to save and restore when MTRRs are programmed\r
36//\r
37typedef struct {\r
38 UINTN Cr4;\r
39 BOOLEAN InterruptState;\r
40} MTRR_CONTEXT;\r
41\r
8051302a
RN
42typedef struct {\r
43 UINT64 BaseAddress;\r
44 UINT64 Length;\r
45 MTRR_MEMORY_CACHE_TYPE Type;\r
46} MEMORY_RANGE;\r
47\r
e50466da 48//\r
49// This table defines the offset, base and length of the fixed MTRRs\r
50//\r
f877f300 51CONST FIXED_MTRR mMtrrLibFixedMtrrTable[] = {\r
e50466da 52 {\r
53 MTRR_LIB_IA32_MTRR_FIX64K_00000,\r
54 0,\r
55 SIZE_64KB\r
56 },\r
57 {\r
58 MTRR_LIB_IA32_MTRR_FIX16K_80000,\r
59 0x80000,\r
60 SIZE_16KB\r
61 },\r
62 {\r
63 MTRR_LIB_IA32_MTRR_FIX16K_A0000,\r
64 0xA0000,\r
65 SIZE_16KB\r
66 },\r
67 {\r
68 MTRR_LIB_IA32_MTRR_FIX4K_C0000,\r
69 0xC0000,\r
70 SIZE_4KB\r
71 },\r
72 {\r
73 MTRR_LIB_IA32_MTRR_FIX4K_C8000,\r
74 0xC8000,\r
75 SIZE_4KB\r
76 },\r
77 {\r
78 MTRR_LIB_IA32_MTRR_FIX4K_D0000,\r
79 0xD0000,\r
80 SIZE_4KB\r
81 },\r
82 {\r
83 MTRR_LIB_IA32_MTRR_FIX4K_D8000,\r
84 0xD8000,\r
85 SIZE_4KB\r
86 },\r
87 {\r
88 MTRR_LIB_IA32_MTRR_FIX4K_E0000,\r
89 0xE0000,\r
90 SIZE_4KB\r
91 },\r
92 {\r
93 MTRR_LIB_IA32_MTRR_FIX4K_E8000,\r
94 0xE8000,\r
95 SIZE_4KB\r
96 },\r
97 {\r
98 MTRR_LIB_IA32_MTRR_FIX4K_F0000,\r
99 0xF0000,\r
100 SIZE_4KB\r
101 },\r
102 {\r
103 MTRR_LIB_IA32_MTRR_FIX4K_F8000,\r
104 0xF8000,\r
105 SIZE_4KB\r
76b4cae3 106 }\r
e50466da 107};\r
108\r
f877f300 109//\r
110// Lookup table used to print MTRRs\r
111//\r
112GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 *mMtrrMemoryCacheTypeShortName[] = {\r
113 "UC", // CacheUncacheable\r
114 "WC", // CacheWriteCombining\r
115 "R*", // Invalid\r
116 "R*", // Invalid\r
117 "WT", // CacheWriteThrough\r
118 "WP", // CacheWriteProtected\r
119 "WB", // CacheWriteBack\r
120 "R*" // Invalid\r
121};\r
122\r
31b3597e
MK
123/**\r
124 Worker function returns the variable MTRR count for the CPU.\r
125\r
126 @return Variable MTRR count\r
127\r
128**/\r
129UINT32\r
130GetVariableMtrrCountWorker (\r
131 VOID\r
132 )\r
133{\r
386f5785 134 MSR_IA32_MTRRCAP_REGISTER MtrrCap;\r
31b3597e 135\r
386f5785
RN
136 MtrrCap.Uint64 = AsmReadMsr64 (MSR_IA32_MTRRCAP);\r
137 ASSERT (MtrrCap.Bits.VCNT <= MTRR_NUMBER_OF_VARIABLE_MTRR);\r
138 return MtrrCap.Bits.VCNT;\r
31b3597e
MK
139}\r
140\r
3b9be416
JY
141/**\r
142 Returns the variable MTRR count for the CPU.\r
143\r
144 @return Variable MTRR count\r
145\r
146**/\r
147UINT32\r
ed8dfd7b 148EFIAPI\r
3b9be416
JY
149GetVariableMtrrCount (\r
150 VOID\r
151 )\r
152{\r
947a573a 153 if (!IsMtrrSupported ()) {\r
154 return 0;\r
155 }\r
31b3597e 156 return GetVariableMtrrCountWorker ();\r
3b9be416
JY
157}\r
158\r
159/**\r
31b3597e 160 Worker function returns the firmware usable variable MTRR count for the CPU.\r
3b9be416
JY
161\r
162 @return Firmware usable variable MTRR count\r
163\r
164**/\r
165UINT32\r
31b3597e 166GetFirmwareVariableMtrrCountWorker (\r
3b9be416
JY
167 VOID\r
168 )\r
169{\r
947a573a 170 UINT32 VariableMtrrCount;\r
46309b11 171 UINT32 ReservedMtrrNumber;\r
947a573a 172\r
31b3597e 173 VariableMtrrCount = GetVariableMtrrCountWorker ();\r
46309b11
JF
174 ReservedMtrrNumber = PcdGet32 (PcdCpuNumberOfReservedVariableMtrrs);\r
175 if (VariableMtrrCount < ReservedMtrrNumber) {\r
947a573a 176 return 0;\r
177 }\r
178\r
46309b11 179 return VariableMtrrCount - ReservedMtrrNumber;\r
3b9be416 180}\r
e50466da 181\r
31b3597e
MK
182/**\r
183 Returns the firmware usable variable MTRR count for the CPU.\r
184\r
185 @return Firmware usable variable MTRR count\r
186\r
187**/\r
188UINT32\r
189EFIAPI\r
190GetFirmwareVariableMtrrCount (\r
191 VOID\r
192 )\r
193{\r
194 if (!IsMtrrSupported ()) {\r
195 return 0;\r
196 }\r
197 return GetFirmwareVariableMtrrCountWorker ();\r
198}\r
199\r
200/**\r
201 Worker function returns the default MTRR cache type for the system.\r
202\r
5abd5ed4
MK
203 If MtrrSetting is not NULL, returns the default MTRR cache type from input\r
204 MTRR settings buffer.\r
205 If MtrrSetting is NULL, returns the default MTRR cache type from MSR.\r
206\r
207 @param[in] MtrrSetting A buffer holding all MTRRs content.\r
208\r
31b3597e
MK
209 @return The default MTRR cache type.\r
210\r
211**/\r
212MTRR_MEMORY_CACHE_TYPE\r
213MtrrGetDefaultMemoryTypeWorker (\r
5abd5ed4 214 IN MTRR_SETTINGS *MtrrSetting\r
31b3597e
MK
215 )\r
216{\r
5abd5ed4
MK
217 if (MtrrSetting == NULL) {\r
218 return (MTRR_MEMORY_CACHE_TYPE) (AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE) & 0x7);\r
219 } else {\r
220 return (MTRR_MEMORY_CACHE_TYPE) (MtrrSetting->MtrrDefType & 0x7);\r
221 }\r
31b3597e
MK
222}\r
223\r
224\r
e50466da 225/**\r
226 Returns the default MTRR cache type for the system.\r
227\r
91ec7824 228 @return The default MTRR cache type.\r
e50466da 229\r
230**/\r
91ec7824 231MTRR_MEMORY_CACHE_TYPE\r
232EFIAPI\r
233MtrrGetDefaultMemoryType (\r
e50466da 234 VOID\r
91ec7824 235 )\r
e50466da 236{\r
91ec7824 237 if (!IsMtrrSupported ()) {\r
238 return CacheUncacheable;\r
239 }\r
5abd5ed4 240 return MtrrGetDefaultMemoryTypeWorker (NULL);\r
91ec7824 241}\r
e50466da 242\r
243/**\r
244 Preparation before programming MTRR.\r
245\r
246 This function will do some preparation for programming MTRRs:\r
247 disable cache, invalid cache and disable MTRR caching functionality\r
248\r
a5953380 249 @param[out] MtrrContext Pointer to context to save\r
e50466da 250\r
251**/\r
c878cee4 252VOID\r
b8f01599 253MtrrLibPreMtrrChange (\r
c878cee4 254 OUT MTRR_CONTEXT *MtrrContext\r
e50466da 255 )\r
256{\r
c878cee4 257 //\r
258 // Disable interrupts and save current interrupt state\r
259 //\r
260 MtrrContext->InterruptState = SaveAndDisableInterrupts();\r
76b4cae3 261\r
e50466da 262 //\r
263 // Enter no fill cache mode, CD=1(Bit30), NW=0 (Bit29)\r
264 //\r
58b23d90 265 AsmDisableCache ();\r
266\r
e50466da 267 //\r
58b23d90 268 // Save original CR4 value and clear PGE flag (Bit 7)\r
e50466da 269 //\r
c878cee4 270 MtrrContext->Cr4 = AsmReadCr4 ();\r
271 AsmWriteCr4 (MtrrContext->Cr4 & (~BIT7));\r
58b23d90 272\r
e50466da 273 //\r
274 // Flush all TLBs\r
275 //\r
276 CpuFlushTlb ();\r
58b23d90 277\r
e50466da 278 //\r
76b4cae3 279 // Disable MTRRs\r
e50466da 280 //\r
281 AsmMsrBitFieldWrite64 (MTRR_LIB_IA32_MTRR_DEF_TYPE, 10, 11, 0);\r
e50466da 282}\r
283\r
e50466da 284/**\r
285 Cleaning up after programming MTRRs.\r
286\r
287 This function will do some clean up after programming MTRRs:\r
0779e5bf 288 Flush all TLBs, re-enable caching, restore CR4.\r
e50466da 289\r
a5953380 290 @param[in] MtrrContext Pointer to context to restore\r
e50466da 291\r
292**/\r
293VOID\r
b8f01599 294MtrrLibPostMtrrChangeEnableCache (\r
c878cee4 295 IN MTRR_CONTEXT *MtrrContext\r
e50466da 296 )\r
297{\r
e50466da 298 //\r
76b4cae3 299 // Flush all TLBs\r
e50466da 300 //\r
e50466da 301 CpuFlushTlb ();\r
302\r
303 //\r
304 // Enable Normal Mode caching CD=NW=0, CD(Bit30), NW(Bit29)\r
305 //\r
58b23d90 306 AsmEnableCache ();\r
e50466da 307\r
58b23d90 308 //\r
309 // Restore original CR4 value\r
310 //\r
c878cee4 311 AsmWriteCr4 (MtrrContext->Cr4);\r
76b4cae3 312\r
c878cee4 313 //\r
314 // Restore original interrupt state\r
315 //\r
316 SetInterruptState (MtrrContext->InterruptState);\r
e50466da 317}\r
318\r
0779e5bf 319/**\r
320 Cleaning up after programming MTRRs.\r
321\r
322 This function will do some clean up after programming MTRRs:\r
323 enable MTRR caching functionality, and enable cache\r
324\r
a5953380 325 @param[in] MtrrContext Pointer to context to restore\r
0779e5bf 326\r
327**/\r
328VOID\r
b8f01599 329MtrrLibPostMtrrChange (\r
c878cee4 330 IN MTRR_CONTEXT *MtrrContext\r
0779e5bf 331 )\r
332{\r
333 //\r
334 // Enable Cache MTRR\r
335 //\r
336 AsmMsrBitFieldWrite64 (MTRR_LIB_IA32_MTRR_DEF_TYPE, 10, 11, 3);\r
337\r
b8f01599 338 MtrrLibPostMtrrChangeEnableCache (MtrrContext);\r
0779e5bf 339}\r
340\r
85b7f65b
MK
341/**\r
342 Worker function gets the content in fixed MTRRs\r
343\r
344 @param[out] FixedSettings A buffer to hold fixed MTRRs content.\r
345\r
346 @retval The pointer of FixedSettings\r
347\r
348**/\r
349MTRR_FIXED_SETTINGS*\r
350MtrrGetFixedMtrrWorker (\r
351 OUT MTRR_FIXED_SETTINGS *FixedSettings\r
352 )\r
353{\r
354 UINT32 Index;\r
355\r
356 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
357 FixedSettings->Mtrr[Index] =\r
358 AsmReadMsr64 (mMtrrLibFixedMtrrTable[Index].Msr);\r
359 }\r
360\r
361 return FixedSettings;\r
362}\r
363\r
364\r
365/**\r
366 This function gets the content in fixed MTRRs\r
367\r
368 @param[out] FixedSettings A buffer to hold fixed MTRRs content.\r
369\r
370 @retval The pointer of FixedSettings\r
371\r
372**/\r
373MTRR_FIXED_SETTINGS*\r
374EFIAPI\r
375MtrrGetFixedMtrr (\r
376 OUT MTRR_FIXED_SETTINGS *FixedSettings\r
377 )\r
378{\r
379 if (!IsMtrrSupported ()) {\r
380 return FixedSettings;\r
381 }\r
382\r
383 return MtrrGetFixedMtrrWorker (FixedSettings);\r
384}\r
385\r
386\r
387/**\r
388 Worker function will get the raw value in variable MTRRs\r
389\r
5abd5ed4
MK
390 If MtrrSetting is not NULL, gets the variable MTRRs raw value from input\r
391 MTRR settings buffer.\r
392 If MtrrSetting is NULL, gets the variable MTRRs raw value from MTRRs.\r
393\r
394 @param[in] MtrrSetting A buffer holding all MTRRs content.\r
395 @param[in] VariableMtrrCount Number of variable MTRRs.\r
85b7f65b
MK
396 @param[out] VariableSettings A buffer to hold variable MTRRs content.\r
397\r
398 @return The VariableSettings input pointer\r
399\r
400**/\r
401MTRR_VARIABLE_SETTINGS*\r
402MtrrGetVariableMtrrWorker (\r
5abd5ed4 403 IN MTRR_SETTINGS *MtrrSetting,\r
acf431e6 404 IN UINT32 VariableMtrrCount,\r
85b7f65b
MK
405 OUT MTRR_VARIABLE_SETTINGS *VariableSettings\r
406 )\r
407{\r
408 UINT32 Index;\r
85b7f65b 409\r
85b7f65b
MK
410 ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);\r
411\r
412 for (Index = 0; Index < VariableMtrrCount; Index++) {\r
5abd5ed4
MK
413 if (MtrrSetting == NULL) {\r
414 VariableSettings->Mtrr[Index].Base =\r
415 AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1));\r
416 VariableSettings->Mtrr[Index].Mask =\r
417 AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1) + 1);\r
418 } else {\r
419 VariableSettings->Mtrr[Index].Base = MtrrSetting->Variables.Mtrr[Index].Base;\r
420 VariableSettings->Mtrr[Index].Mask = MtrrSetting->Variables.Mtrr[Index].Mask;\r
421 }\r
85b7f65b
MK
422 }\r
423\r
424 return VariableSettings;\r
425}\r
426\r
427/**\r
428 This function will get the raw value in variable MTRRs\r
429\r
430 @param[out] VariableSettings A buffer to hold variable MTRRs content.\r
431\r
432 @return The VariableSettings input pointer\r
433\r
434**/\r
435MTRR_VARIABLE_SETTINGS*\r
436EFIAPI\r
437MtrrGetVariableMtrr (\r
438 OUT MTRR_VARIABLE_SETTINGS *VariableSettings\r
439 )\r
440{\r
441 if (!IsMtrrSupported ()) {\r
442 return VariableSettings;\r
443 }\r
444\r
445 return MtrrGetVariableMtrrWorker (\r
5abd5ed4 446 NULL,\r
acf431e6 447 GetVariableMtrrCountWorker (),\r
85b7f65b
MK
448 VariableSettings\r
449 );\r
450}\r
e50466da 451\r
452/**\r
453 Programs fixed MTRRs registers.\r
454\r
94240f1b 455 @param[in] Type The memory type to set.\r
76b4cae3
MK
456 @param[in, out] Base The base address of memory range.\r
457 @param[in, out] Length The length of memory range.\r
0f354122
JF
458 @param[in, out] LastMsrNum On input, the last index of the fixed MTRR MSR to program.\r
459 On return, the current index of the fixed MTRR MSR to program.\r
fa25cf38
MK
460 @param[out] ReturnClearMask The bits to clear in the fixed MTRR MSR.\r
461 @param[out] ReturnOrMask The bits to set in the fixed MTRR MSR.\r
e50466da 462\r
463 @retval RETURN_SUCCESS The cache type was updated successfully\r
464 @retval RETURN_UNSUPPORTED The requested range or cache type was invalid\r
465 for the fixed MTRRs.\r
466\r
467**/\r
468RETURN_STATUS\r
94240f1b
RN
469MtrrLibProgramFixedMtrr (\r
470 IN MTRR_MEMORY_CACHE_TYPE Type,\r
471 IN OUT UINT64 *Base,\r
472 IN OUT UINT64 *Length,\r
473 IN OUT UINT32 *LastMsrNum,\r
474 OUT UINT64 *ReturnClearMask,\r
475 OUT UINT64 *ReturnOrMask\r
e50466da 476 )\r
477{\r
478 UINT32 MsrNum;\r
eecad349
JF
479 UINT32 LeftByteShift;\r
480 UINT32 RightByteShift;\r
481 UINT64 OrMask;\r
482 UINT64 ClearMask;\r
07e88920 483 UINT64 SubLength;\r
e50466da 484\r
eecad349
JF
485 //\r
486 // Find the fixed MTRR index to be programmed\r
487 //\r
0f354122 488 for (MsrNum = *LastMsrNum + 1; MsrNum < MTRR_NUMBER_OF_FIXED_MTRR; MsrNum++) {\r
f877f300 489 if ((*Base >= mMtrrLibFixedMtrrTable[MsrNum].BaseAddress) &&\r
e50466da 490 (*Base <\r
491 (\r
f877f300 492 mMtrrLibFixedMtrrTable[MsrNum].BaseAddress +\r
493 (8 * mMtrrLibFixedMtrrTable[MsrNum].Length)\r
e50466da 494 )\r
495 )\r
496 ) {\r
497 break;\r
498 }\r
499 }\r
500\r
94240f1b 501 if (MsrNum == MTRR_NUMBER_OF_FIXED_MTRR) {\r
e50466da 502 return RETURN_UNSUPPORTED;\r
503 }\r
504\r
505 //\r
eecad349 506 // Find the begin offset in fixed MTRR and calculate byte offset of left shift\r
e50466da 507 //\r
eecad349 508 LeftByteShift = ((UINT32)*Base - mMtrrLibFixedMtrrTable[MsrNum].BaseAddress)\r
aaa1e579 509 / mMtrrLibFixedMtrrTable[MsrNum].Length;\r
e50466da 510\r
eecad349 511 if (LeftByteShift >= 8) {\r
e50466da 512 return RETURN_UNSUPPORTED;\r
513 }\r
514\r
eecad349
JF
515 //\r
516 // Find the end offset in fixed MTRR and calculate byte offset of right shift\r
517 //\r
518 SubLength = mMtrrLibFixedMtrrTable[MsrNum].Length * (8 - LeftByteShift);\r
519 if (*Length >= SubLength) {\r
520 RightByteShift = 0;\r
07e88920 521 } else {\r
eecad349
JF
522 RightByteShift = 8 - LeftByteShift -\r
523 (UINT32)(*Length) / mMtrrLibFixedMtrrTable[MsrNum].Length;\r
524 if ((LeftByteShift >= 8) ||\r
525 (((UINT32)(*Length) % mMtrrLibFixedMtrrTable[MsrNum].Length) != 0)\r
526 ) {\r
527 return RETURN_UNSUPPORTED;\r
528 }\r
529 //\r
530 // Update SubLength by actual length\r
531 //\r
532 SubLength = *Length;\r
e50466da 533 }\r
534\r
eecad349 535 ClearMask = CLEAR_SEED;\r
94240f1b 536 OrMask = MultU64x32 (OR_SEED, (UINT32) Type);\r
eecad349
JF
537\r
538 if (LeftByteShift != 0) {\r
539 //\r
540 // Clear the low bits by LeftByteShift\r
541 //\r
542 ClearMask &= LShiftU64 (ClearMask, LeftByteShift * 8);\r
543 OrMask &= LShiftU64 (OrMask, LeftByteShift * 8);\r
544 }\r
545\r
546 if (RightByteShift != 0) {\r
547 //\r
548 // Clear the high bits by RightByteShift\r
549 //\r
550 ClearMask &= RShiftU64 (ClearMask, RightByteShift * 8);\r
551 OrMask &= RShiftU64 (OrMask, RightByteShift * 8);\r
e50466da 552 }\r
553\r
07e88920
JF
554 *Length -= SubLength;\r
555 *Base += SubLength;\r
556\r
0f354122 557 *LastMsrNum = MsrNum;\r
eecad349
JF
558 *ReturnClearMask = ClearMask;\r
559 *ReturnOrMask = OrMask;\r
fa25cf38 560\r
e50466da 561 return RETURN_SUCCESS;\r
562}\r
563\r
564\r
d0baed7d
MK
565/**\r
566 Worker function gets the attribute of variable MTRRs.\r
567\r
568 This function shadows the content of variable MTRRs into an\r
569 internal array: VariableMtrr.\r
570\r
571 @param[in] VariableSettings The variable MTRR values to shadow\r
572 @param[in] FirmwareVariableMtrrCount The number of variable MTRRs available to firmware\r
573 @param[in] MtrrValidBitsMask The mask for the valid bit of the MTRR\r
574 @param[in] MtrrValidAddressMask The valid address mask for MTRR\r
575 @param[out] VariableMtrr The array to shadow variable MTRRs content\r
576\r
577 @return The return value of this parameter indicates the\r
578 number of MTRRs which has been used.\r
579\r
580**/\r
581UINT32\r
582MtrrGetMemoryAttributeInVariableMtrrWorker (\r
583 IN MTRR_VARIABLE_SETTINGS *VariableSettings,\r
584 IN UINTN FirmwareVariableMtrrCount,\r
585 IN UINT64 MtrrValidBitsMask,\r
586 IN UINT64 MtrrValidAddressMask,\r
587 OUT VARIABLE_MTRR *VariableMtrr\r
588 )\r
589{\r
590 UINTN Index;\r
591 UINT32 UsedMtrr;\r
592\r
593 ZeroMem (VariableMtrr, sizeof (VARIABLE_MTRR) * MTRR_NUMBER_OF_VARIABLE_MTRR);\r
594 for (Index = 0, UsedMtrr = 0; Index < FirmwareVariableMtrrCount; Index++) {\r
595 if ((VariableSettings->Mtrr[Index].Mask & MTRR_LIB_CACHE_MTRR_ENABLED) != 0) {\r
596 VariableMtrr[Index].Msr = (UINT32)Index;\r
597 VariableMtrr[Index].BaseAddress = (VariableSettings->Mtrr[Index].Base & MtrrValidAddressMask);\r
598 VariableMtrr[Index].Length = ((~(VariableSettings->Mtrr[Index].Mask & MtrrValidAddressMask)) & MtrrValidBitsMask) + 1;\r
599 VariableMtrr[Index].Type = (VariableSettings->Mtrr[Index].Base & 0x0ff);\r
600 VariableMtrr[Index].Valid = TRUE;\r
601 VariableMtrr[Index].Used = TRUE;\r
602 UsedMtrr++;\r
603 }\r
604 }\r
605 return UsedMtrr;\r
606}\r
607\r
608\r
e50466da 609/**\r
76b4cae3 610 Gets the attribute of variable MTRRs.\r
e50466da 611\r
3ba736f3
JY
612 This function shadows the content of variable MTRRs into an\r
613 internal array: VariableMtrr.\r
e50466da 614\r
76b4cae3
MK
615 @param[in] MtrrValidBitsMask The mask for the valid bit of the MTRR\r
616 @param[in] MtrrValidAddressMask The valid address mask for MTRR\r
617 @param[out] VariableMtrr The array to shadow variable MTRRs content\r
e50466da 618\r
438f1766 619 @return The return value of this parameter indicates the\r
3ba736f3 620 number of MTRRs which has been used.\r
e50466da 621\r
622**/\r
3ba736f3 623UINT32\r
e50466da 624EFIAPI\r
625MtrrGetMemoryAttributeInVariableMtrr (\r
626 IN UINT64 MtrrValidBitsMask,\r
627 IN UINT64 MtrrValidAddressMask,\r
628 OUT VARIABLE_MTRR *VariableMtrr\r
629 )\r
630{\r
d0baed7d 631 MTRR_VARIABLE_SETTINGS VariableSettings;\r
3b9be416 632\r
947a573a 633 if (!IsMtrrSupported ()) {\r
634 return 0;\r
635 }\r
636\r
d0baed7d 637 MtrrGetVariableMtrrWorker (\r
5abd5ed4 638 NULL,\r
d0baed7d
MK
639 GetVariableMtrrCountWorker (),\r
640 &VariableSettings\r
641 );\r
e50466da 642\r
d0baed7d
MK
643 return MtrrGetMemoryAttributeInVariableMtrrWorker (\r
644 &VariableSettings,\r
645 GetFirmwareVariableMtrrCountWorker (),\r
646 MtrrValidBitsMask,\r
647 MtrrValidAddressMask,\r
648 VariableMtrr\r
649 );\r
e50466da 650}\r
651\r
e50466da 652/**\r
8051302a 653 Return the least alignment of address.\r
e50466da 654\r
8051302a
RN
655 @param Address The address to return the alignment.\r
656 @param Alignment0 The alignment to return when Address is 0.\r
e50466da 657\r
8051302a 658 @return The least alignment of the Address.\r
e50466da 659**/\r
8051302a
RN
660UINT64\r
661MtrrLibLeastAlignment (\r
662 UINT64 Address,\r
663 UINT64 Alignment0\r
664)\r
e50466da 665{\r
8051302a
RN
666 if (Address == 0) {\r
667 return Alignment0;\r
e50466da 668 }\r
669\r
8051302a 670 return LShiftU64 (1, (UINTN) LowBitSet64 (Address));\r
e50466da 671}\r
672\r
e50466da 673/**\r
8051302a
RN
674 Return the number of required variable MTRRs to positively cover the\r
675 specified range.\r
e50466da 676\r
8051302a
RN
677 @param BaseAddress Base address of the range.\r
678 @param Length Length of the range.\r
679 @param Alignment0 Alignment of 0.\r
e50466da 680\r
8051302a 681 @return The number of the required variable MTRRs.\r
e50466da 682**/\r
8051302a
RN
683UINT32\r
684MtrrLibGetPositiveMtrrNumber (\r
685 IN UINT64 BaseAddress,\r
686 IN UINT64 Length,\r
687 IN UINT64 Alignment0\r
688)\r
e50466da 689{\r
8051302a
RN
690 UINT64 SubLength;\r
691 UINT32 MtrrNumber;\r
692 BOOLEAN UseLeastAlignment;\r
e50466da 693\r
8051302a 694 UseLeastAlignment = TRUE;\r
e50466da 695\r
8051302a
RN
696 //\r
697 // Calculate the alignment of the base address.\r
698 //\r
699 for (MtrrNumber = 0; Length != 0; MtrrNumber++) {\r
700 if (UseLeastAlignment) {\r
701 SubLength = MtrrLibLeastAlignment (BaseAddress, Alignment0);\r
e50466da 702\r
8051302a
RN
703 if (SubLength > Length) {\r
704 //\r
705 // Set a flag when remaining length is too small\r
706 // so that MtrrLibLeastAlignment() is not called in following loops.\r
707 //\r
708 UseLeastAlignment = FALSE;\r
e50466da 709 }\r
e50466da 710 }\r
711\r
8051302a
RN
712 if (!UseLeastAlignment) {\r
713 SubLength = GetPowerOfTwo64 (Length);\r
e50466da 714 }\r
e50466da 715\r
8051302a
RN
716 BaseAddress += SubLength;\r
717 Length -= SubLength;\r
1e60a0ec 718 }\r
719\r
8051302a 720 return MtrrNumber;\r
e50466da 721}\r
722\r
e50466da 723/**\r
8051302a 724 Return whether the left MTRR type precedes the right MTRR type.\r
76b4cae3 725\r
8051302a
RN
726 The MTRR type precedence rules are:\r
727 1. UC precedes any other type\r
728 2. WT precedes WB\r
e50466da 729\r
8051302a
RN
730 @param Left The left MTRR type.\r
731 @param Right The right MTRR type.\r
e50466da 732\r
8051302a
RN
733 @retval TRUE Left precedes Right.\r
734 @retval FALSE Left doesn't precede Right.\r
e50466da 735**/\r
8051302a
RN
736BOOLEAN\r
737MtrrLibTypeLeftPrecedeRight (\r
738 IN MTRR_MEMORY_CACHE_TYPE Left,\r
739 IN MTRR_MEMORY_CACHE_TYPE Right\r
740)\r
e50466da 741{\r
8051302a 742 return (BOOLEAN) (Left == CacheUncacheable || (Left == CacheWriteThrough && Right == CacheWriteBack));\r
e50466da 743}\r
744\r
745\r
746/**\r
8051302a
RN
747 Return whether the type of the specified range can precede the specified type.\r
748\r
749 @param Ranges Memory range array holding memory type settings for all\r
750 the memory address.\r
751 @param RangeCount Count of memory ranges.\r
752 @param Type Type to check precedence.\r
753 @param SubBase Base address of the specified range.\r
754 @param SubLength Length of the specified range.\r
755\r
756 @retval TRUE The type of the specified range can precede the Type.\r
757 @retval FALSE The type of the specified range cannot precede the Type.\r
758 So the subtraction is not applicable.\r
759**/\r
760BOOLEAN\r
761MtrrLibSubstractable (\r
762 IN CONST MEMORY_RANGE *Ranges,\r
763 IN UINT32 RangeCount,\r
764 IN MTRR_MEMORY_CACHE_TYPE Type,\r
765 IN UINT64 SubBase,\r
766 IN UINT64 SubLength\r
767)\r
768{\r
769 UINT32 Index;\r
770 UINT64 Length;\r
771 // WT > WB\r
772 // UC > *\r
773 for (Index = 0; Index < RangeCount; Index++) {\r
774 if (Ranges[Index].BaseAddress <= SubBase && SubBase < Ranges[Index].BaseAddress + Ranges[Index].Length) {\r
e50466da 775\r
8051302a
RN
776 if (Ranges[Index].BaseAddress + Ranges[Index].Length >= SubBase + SubLength) {\r
777 return MtrrLibTypeLeftPrecedeRight (Ranges[Index].Type, Type);\r
e50466da 778\r
8051302a
RN
779 } else {\r
780 if (!MtrrLibTypeLeftPrecedeRight (Ranges[Index].Type, Type)) {\r
781 return FALSE;\r
782 }\r
1a2ad6fc 783\r
8051302a
RN
784 Length = Ranges[Index].BaseAddress + Ranges[Index].Length - SubBase;\r
785 SubBase += Length;\r
786 SubLength -= Length;\r
787 }\r
788 }\r
789 }\r
e50466da 790\r
8051302a
RN
791 ASSERT (FALSE);\r
792 return FALSE;\r
793}\r
e50466da 794\r
8051302a
RN
795/**\r
796 Return the number of required variable MTRRs to cover the specified range.\r
797\r
798 The routine considers subtraction in the both side of the range to find out\r
799 the most optimal solution (which uses the least MTRRs).\r
800\r
801 @param Ranges Array holding memory type settings of all memory\r
802 address.\r
803 @param RangeCount Count of memory ranges.\r
804 @param VariableMtrr Array holding allocated variable MTRRs.\r
805 @param VariableMtrrCount Count of allocated variable MTRRs.\r
806 @param BaseAddress Base address of the specified range.\r
807 @param Length Length of the specified range.\r
808 @param Type MTRR type of the specified range.\r
809 @param Alignment0 Alignment of 0.\r
810 @param SubLeft Return the count of left subtraction.\r
811 @param SubRight Return the count of right subtraction.\r
812\r
813 @return Number of required variable MTRRs.\r
e50466da 814**/\r
8051302a
RN
815UINT32\r
816MtrrLibGetMtrrNumber (\r
817 IN CONST MEMORY_RANGE *Ranges,\r
818 IN UINT32 RangeCount,\r
819 IN CONST VARIABLE_MTRR *VariableMtrr,\r
820 IN UINT32 VariableMtrrCount,\r
821 IN UINT64 BaseAddress,\r
822 IN UINT64 Length,\r
823 IN MTRR_MEMORY_CACHE_TYPE Type,\r
824 IN UINT64 Alignment0,\r
825 OUT UINT32 *SubLeft, // subtractive from BaseAddress to get more aligned address, to save MTRR\r
826 OUT UINT32 *SubRight // subtractive from BaseAddress + Length, to save MTRR\r
827)\r
e50466da 828{\r
1a2ad6fc 829 UINT64 Alignment;\r
8051302a
RN
830 UINT32 LeastLeftMtrrNumber;\r
831 UINT32 MiddleMtrrNumber;\r
832 UINT32 LeastRightMtrrNumber;\r
833 UINT32 CurrentMtrrNumber;\r
834 UINT32 SubtractiveCount;\r
835 UINT32 SubtractiveMtrrNumber;\r
836 UINT32 LeastSubtractiveMtrrNumber;\r
837 UINT64 SubtractiveBaseAddress;\r
838 UINT64 SubtractiveLength;\r
839 UINT64 BaseAlignment;\r
840 UINT32 Index;\r
e50466da 841\r
8051302a
RN
842 *SubLeft = 0;\r
843 *SubRight = 0;\r
844 LeastSubtractiveMtrrNumber = 0;\r
1a2ad6fc 845\r
8051302a
RN
846 //\r
847 // Get the optimal left subtraction solution.\r
848 //\r
1a2ad6fc 849 if (BaseAddress != 0) {\r
8051302a
RN
850 //\r
851 // Get the MTRR number needed without left subtraction.\r
852 //\r
853 LeastLeftMtrrNumber = MtrrLibGetPositiveMtrrNumber (BaseAddress, Length, Alignment0);\r
854\r
855 //\r
856 // Left subtraction bit by bit, to find the optimal left subtraction solution.\r
857 //\r
858 for (SubtractiveMtrrNumber = 0, SubtractiveCount = 1; BaseAddress != 0; SubtractiveCount++) {\r
859 Alignment = MtrrLibLeastAlignment (BaseAddress, Alignment0);\r
860\r
1a2ad6fc 861 //\r
8051302a
RN
862 // Check whether the memory type of [BaseAddress - Alignment, BaseAddress) can override Type.\r
863 // IA32 Manual defines the following override rules:\r
864 // WT > WB\r
865 // UC > * (any)\r
1a2ad6fc 866 //\r
8051302a 867 if (!MtrrLibSubstractable (Ranges, RangeCount, Type, BaseAddress - Alignment, Alignment)) {\r
1a2ad6fc 868 break;\r
869 }\r
870\r
8051302a
RN
871 for (Index = 0; Index < VariableMtrrCount; Index++) {\r
872 if ((VariableMtrr[Index].BaseAddress == BaseAddress - Alignment) &&\r
873 (VariableMtrr[Index].Length == Alignment)) {\r
874 break;\r
875 }\r
876 }\r
877 if (Index == VariableMtrrCount) {\r
878 //\r
879 // Increment SubtractiveMtrrNumber when [BaseAddress - Alignment, BaseAddress) is not be planed as a MTRR\r
880 //\r
881 SubtractiveMtrrNumber++;\r
882 }\r
e50466da 883\r
8051302a
RN
884 BaseAddress -= Alignment;\r
885 Length += Alignment;\r
e50466da 886\r
8051302a
RN
887 CurrentMtrrNumber = SubtractiveMtrrNumber + MtrrLibGetPositiveMtrrNumber (BaseAddress, Length, Alignment0);\r
888 if (CurrentMtrrNumber <= LeastLeftMtrrNumber) {\r
889 LeastLeftMtrrNumber = CurrentMtrrNumber;\r
890 LeastSubtractiveMtrrNumber = SubtractiveMtrrNumber;\r
891 *SubLeft = SubtractiveCount;\r
892 SubtractiveBaseAddress = BaseAddress;\r
893 SubtractiveLength = Length;\r
894 }\r
895 }\r
e50466da 896\r
8051302a
RN
897 //\r
898 // If left subtraction is better, subtract BaseAddress to left, and enlarge Length\r
899 //\r
900 if (*SubLeft != 0) {\r
901 BaseAddress = SubtractiveBaseAddress;\r
902 Length = SubtractiveLength;\r
903 }\r
e50466da 904 }\r
e50466da 905\r
8051302a
RN
906 //\r
907 // Increment BaseAddress greedily until (BaseAddress + Alignment) exceeds (BaseAddress + Length)\r
908 //\r
909 MiddleMtrrNumber = 0;\r
910 while (Length != 0) {\r
911 BaseAlignment = MtrrLibLeastAlignment (BaseAddress, Alignment0);\r
912 if (BaseAlignment > Length) {\r
913 break;\r
e50466da 914 }\r
8051302a
RN
915 BaseAddress += BaseAlignment;\r
916 Length -= BaseAlignment;\r
917 MiddleMtrrNumber++;\r
e50466da 918 }\r
e50466da 919\r
920\r
8051302a
RN
921 if (Length == 0) {\r
922 return LeastSubtractiveMtrrNumber + MiddleMtrrNumber;\r
923 }\r
e50466da 924\r
e50466da 925\r
926 //\r
8051302a 927 // Get the optimal right subtraction solution.\r
e50466da 928 //\r
e50466da 929\r
930 //\r
8051302a 931 // Get the MTRR number needed without right subtraction.\r
e50466da 932 //\r
8051302a
RN
933 LeastRightMtrrNumber = MtrrLibGetPositiveMtrrNumber (BaseAddress, Length, Alignment0);\r
934\r
935 for (SubtractiveCount = 1; Length < BaseAlignment; SubtractiveCount++) {\r
936 Alignment = MtrrLibLeastAlignment (BaseAddress + Length, Alignment0);\r
937 if (!MtrrLibSubstractable (Ranges, RangeCount, Type, BaseAddress + Length, Alignment)) {\r
938 break;\r
939 }\r
940\r
941 Length += Alignment;\r
942\r
943 //\r
944 // SubtractiveCount = Number of MTRRs used for subtraction\r
945 //\r
946 CurrentMtrrNumber = SubtractiveCount + MtrrLibGetPositiveMtrrNumber (BaseAddress, Length, Alignment0);\r
947 if (CurrentMtrrNumber <= LeastRightMtrrNumber) {\r
948 LeastRightMtrrNumber = CurrentMtrrNumber;\r
949 *SubRight = SubtractiveCount;\r
950 SubtractiveLength = Length;\r
951 }\r
952 }\r
953\r
954 return LeastSubtractiveMtrrNumber + MiddleMtrrNumber + LeastRightMtrrNumber;\r
e50466da 955}\r
956\r
957\r
958/**\r
76b4cae3 959 Converts the Memory attribute value to MTRR_MEMORY_CACHE_TYPE.\r
e50466da 960\r
5abd5ed4
MK
961 If MtrrSetting is not NULL, gets the default memory attribute from input\r
962 MTRR settings buffer.\r
963 If MtrrSetting is NULL, gets the default memory attribute from MSR.\r
964\r
965 @param[in] MtrrSetting A buffer holding all MTRRs content.\r
76b4cae3 966 @param[in] MtrrType MTRR memory type\r
e50466da 967\r
968 @return The enum item in MTRR_MEMORY_CACHE_TYPE\r
969\r
970**/\r
e50466da 971MTRR_MEMORY_CACHE_TYPE\r
972GetMemoryCacheTypeFromMtrrType (\r
5abd5ed4 973 IN MTRR_SETTINGS *MtrrSetting,\r
e50466da 974 IN UINT64 MtrrType\r
975 )\r
976{\r
977 switch (MtrrType) {\r
978 case MTRR_CACHE_UNCACHEABLE:\r
979 return CacheUncacheable;\r
980 case MTRR_CACHE_WRITE_COMBINING:\r
981 return CacheWriteCombining;\r
982 case MTRR_CACHE_WRITE_THROUGH:\r
983 return CacheWriteThrough;\r
984 case MTRR_CACHE_WRITE_PROTECTED:\r
985 return CacheWriteProtected;\r
986 case MTRR_CACHE_WRITE_BACK:\r
987 return CacheWriteBack;\r
988 default:\r
989 //\r
990 // MtrrType is MTRR_CACHE_INVALID_TYPE, that means\r
76b4cae3 991 // no MTRR covers the range\r
e50466da 992 //\r
5abd5ed4 993 return MtrrGetDefaultMemoryTypeWorker (MtrrSetting);\r
e50466da 994 }\r
995}\r
996\r
997/**\r
998 Initializes the valid bits mask and valid address mask for MTRRs.\r
999\r
1000 This function initializes the valid bits mask and valid address mask for MTRRs.\r
1001\r
76b4cae3
MK
1002 @param[out] MtrrValidBitsMask The mask for the valid bit of the MTRR\r
1003 @param[out] MtrrValidAddressMask The valid address mask for the MTRR\r
e50466da 1004\r
1005**/\r
e50466da 1006VOID\r
1007MtrrLibInitializeMtrrMask (\r
1008 OUT UINT64 *MtrrValidBitsMask,\r
1009 OUT UINT64 *MtrrValidAddressMask\r
1010 )\r
1011{\r
012f4054
RN
1012 UINT32 MaxExtendedFunction;\r
1013 CPUID_VIR_PHY_ADDRESS_SIZE_EAX VirPhyAddressSize;\r
e50466da 1014\r
e50466da 1015\r
012f4054 1016 AsmCpuid (CPUID_EXTENDED_FUNCTION, &MaxExtendedFunction, NULL, NULL, NULL);\r
e50466da 1017\r
012f4054
RN
1018 if (MaxExtendedFunction >= CPUID_VIR_PHY_ADDRESS_SIZE) {\r
1019 AsmCpuid (CPUID_VIR_PHY_ADDRESS_SIZE, &VirPhyAddressSize.Uint32, NULL, NULL, NULL);\r
e50466da 1020 } else {\r
012f4054 1021 VirPhyAddressSize.Bits.PhysicalAddressBits = 36;\r
e50466da 1022 }\r
012f4054
RN
1023\r
1024 *MtrrValidBitsMask = LShiftU64 (1, VirPhyAddressSize.Bits.PhysicalAddressBits) - 1;\r
1025 *MtrrValidAddressMask = *MtrrValidBitsMask & 0xfffffffffffff000ULL;\r
e50466da 1026}\r
1027\r
1028\r
1029/**\r
76b4cae3 1030 Determines the real attribute of a memory range.\r
e50466da 1031\r
1032 This function is to arbitrate the real attribute of the memory when\r
76b4cae3 1033 there are 2 MTRRs covers the same memory range. For further details,\r
e50466da 1034 please refer the IA32 Software Developer's Manual, Volume 3,\r
1035 Section 10.11.4.1.\r
1036\r
76b4cae3
MK
1037 @param[in] MtrrType1 The first kind of Memory type\r
1038 @param[in] MtrrType2 The second kind of memory type\r
e50466da 1039\r
1040**/\r
1041UINT64\r
b8f01599 1042MtrrLibPrecedence (\r
76b4cae3
MK
1043 IN UINT64 MtrrType1,\r
1044 IN UINT64 MtrrType2\r
e50466da 1045 )\r
1046{\r
1047 UINT64 MtrrType;\r
1048\r
1049 MtrrType = MTRR_CACHE_INVALID_TYPE;\r
1050 switch (MtrrType1) {\r
1051 case MTRR_CACHE_UNCACHEABLE:\r
1052 MtrrType = MTRR_CACHE_UNCACHEABLE;\r
1053 break;\r
1054 case MTRR_CACHE_WRITE_COMBINING:\r
1055 if (\r
1056 MtrrType2==MTRR_CACHE_WRITE_COMBINING ||\r
1057 MtrrType2==MTRR_CACHE_UNCACHEABLE\r
1058 ) {\r
1059 MtrrType = MtrrType2;\r
1060 }\r
1061 break;\r
1062 case MTRR_CACHE_WRITE_THROUGH:\r
1063 if (\r
1064 MtrrType2==MTRR_CACHE_WRITE_THROUGH ||\r
1065 MtrrType2==MTRR_CACHE_WRITE_BACK\r
1066 ) {\r
1067 MtrrType = MTRR_CACHE_WRITE_THROUGH;\r
1068 } else if(MtrrType2==MTRR_CACHE_UNCACHEABLE) {\r
1069 MtrrType = MTRR_CACHE_UNCACHEABLE;\r
1070 }\r
1071 break;\r
1072 case MTRR_CACHE_WRITE_PROTECTED:\r
1073 if (MtrrType2 == MTRR_CACHE_WRITE_PROTECTED ||\r
1074 MtrrType2 == MTRR_CACHE_UNCACHEABLE) {\r
1075 MtrrType = MtrrType2;\r
1076 }\r
1077 break;\r
1078 case MTRR_CACHE_WRITE_BACK:\r
1079 if (\r
1080 MtrrType2== MTRR_CACHE_UNCACHEABLE ||\r
1081 MtrrType2==MTRR_CACHE_WRITE_THROUGH ||\r
1082 MtrrType2== MTRR_CACHE_WRITE_BACK\r
1083 ) {\r
1084 MtrrType = MtrrType2;\r
1085 }\r
1086 break;\r
1087 case MTRR_CACHE_INVALID_TYPE:\r
1088 MtrrType = MtrrType2;\r
1089 break;\r
1090 default:\r
1091 break;\r
1092 }\r
1093\r
1094 if (MtrrType2 == MTRR_CACHE_INVALID_TYPE) {\r
1095 MtrrType = MtrrType1;\r
1096 }\r
1097 return MtrrType;\r
1098}\r
1099\r
e50466da 1100/**\r
5abd5ed4 1101 Worker function will get the memory cache type of the specific address.\r
e50466da 1102\r
5abd5ed4
MK
1103 If MtrrSetting is not NULL, gets the memory cache type from input\r
1104 MTRR settings buffer.\r
1105 If MtrrSetting is NULL, gets the memory cache type from MTRRs.\r
e50466da 1106\r
5abd5ed4 1107 @param[in] MtrrSetting A buffer holding all MTRRs content.\r
85b7f65b
MK
1108 @param[in] Address The specific address\r
1109\r
1110 @return Memory cache type of the specific address\r
e50466da 1111\r
1112**/\r
85b7f65b 1113MTRR_MEMORY_CACHE_TYPE\r
5abd5ed4
MK
1114MtrrGetMemoryAttributeByAddressWorker (\r
1115 IN MTRR_SETTINGS *MtrrSetting,\r
85b7f65b 1116 IN PHYSICAL_ADDRESS Address\r
e50466da 1117 )\r
1118{\r
85b7f65b
MK
1119 UINT64 TempQword;\r
1120 UINTN Index;\r
1121 UINTN SubIndex;\r
1122 UINT64 MtrrType;\r
1123 UINT64 TempMtrrType;\r
1124 MTRR_MEMORY_CACHE_TYPE CacheType;\r
1125 VARIABLE_MTRR VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];\r
1126 UINT64 MtrrValidBitsMask;\r
1127 UINT64 MtrrValidAddressMask;\r
1128 UINTN VariableMtrrCount;\r
d0baed7d 1129 MTRR_VARIABLE_SETTINGS VariableSettings;\r
f877f300 1130\r
e50466da 1131 //\r
85b7f65b 1132 // Check if MTRR is enabled, if not, return UC as attribute\r
e50466da 1133 //\r
5abd5ed4
MK
1134 if (MtrrSetting == NULL) {\r
1135 TempQword = AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE);\r
1136 } else {\r
1137 TempQword = MtrrSetting->MtrrDefType;\r
1138 }\r
85b7f65b 1139 MtrrType = MTRR_CACHE_INVALID_TYPE;\r
e50466da 1140\r
85b7f65b
MK
1141 if ((TempQword & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
1142 return CacheUncacheable;\r
e50466da 1143 }\r
1144\r
1145 //\r
85b7f65b 1146 // If address is less than 1M, then try to go through the fixed MTRR\r
e50466da 1147 //\r
85b7f65b
MK
1148 if (Address < BASE_1MB) {\r
1149 if ((TempQword & MTRR_LIB_CACHE_FIXED_MTRR_ENABLED) != 0) {\r
1150 //\r
1151 // Go through the fixed MTRR\r
1152 //\r
1153 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
1154 if (Address >= mMtrrLibFixedMtrrTable[Index].BaseAddress &&\r
1155 Address < (\r
1156 mMtrrLibFixedMtrrTable[Index].BaseAddress +\r
1157 (mMtrrLibFixedMtrrTable[Index].Length * 8)\r
1158 )\r
1159 ) {\r
1160 SubIndex =\r
1161 ((UINTN)Address - mMtrrLibFixedMtrrTable[Index].BaseAddress) /\r
1162 mMtrrLibFixedMtrrTable[Index].Length;\r
5abd5ed4
MK
1163 if (MtrrSetting == NULL) {\r
1164 TempQword = AsmReadMsr64 (mMtrrLibFixedMtrrTable[Index].Msr);\r
1165 } else {\r
1166 TempQword = MtrrSetting->Fixed.Mtrr[Index];\r
1167 }\r
85b7f65b 1168 MtrrType = RShiftU64 (TempQword, SubIndex * 8) & 0xFF;\r
5abd5ed4 1169 return GetMemoryCacheTypeFromMtrrType (MtrrSetting, MtrrType);\r
85b7f65b
MK
1170 }\r
1171 }\r
e50466da 1172 }\r
1173 }\r
85b7f65b 1174 MtrrLibInitializeMtrrMask(&MtrrValidBitsMask, &MtrrValidAddressMask);\r
d0baed7d
MK
1175\r
1176 MtrrGetVariableMtrrWorker (\r
5abd5ed4 1177 MtrrSetting,\r
d0baed7d
MK
1178 GetVariableMtrrCountWorker (),\r
1179 &VariableSettings\r
85b7f65b 1180 );\r
e50466da 1181\r
d0baed7d
MK
1182 MtrrGetMemoryAttributeInVariableMtrrWorker (\r
1183 &VariableSettings,\r
1184 GetFirmwareVariableMtrrCountWorker (),\r
1185 MtrrValidBitsMask,\r
1186 MtrrValidAddressMask,\r
1187 VariableMtrr\r
1188 );\r
1189\r
e50466da 1190 //\r
85b7f65b 1191 // Go through the variable MTRR\r
e50466da 1192 //\r
acf431e6 1193 VariableMtrrCount = GetVariableMtrrCountWorker ();\r
85b7f65b
MK
1194 ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);\r
1195\r
1196 for (Index = 0; Index < VariableMtrrCount; Index++) {\r
1197 if (VariableMtrr[Index].Valid) {\r
1198 if (Address >= VariableMtrr[Index].BaseAddress &&\r
1199 Address < VariableMtrr[Index].BaseAddress+VariableMtrr[Index].Length) {\r
1200 TempMtrrType = VariableMtrr[Index].Type;\r
b8f01599 1201 MtrrType = MtrrLibPrecedence (MtrrType, TempMtrrType);\r
85b7f65b
MK
1202 }\r
1203 }\r
e50466da 1204 }\r
5abd5ed4 1205 CacheType = GetMemoryCacheTypeFromMtrrType (MtrrSetting, MtrrType);\r
e50466da 1206\r
85b7f65b
MK
1207 return CacheType;\r
1208}\r
1209\r
1210\r
5abd5ed4
MK
1211/**\r
1212 This function will get the memory cache type of the specific address.\r
1213\r
1214 This function is mainly for debug purpose.\r
1215\r
1216 @param[in] Address The specific address\r
1217\r
1218 @return Memory cache type of the specific address\r
1219\r
1220**/\r
1221MTRR_MEMORY_CACHE_TYPE\r
1222EFIAPI\r
1223MtrrGetMemoryAttribute (\r
1224 IN PHYSICAL_ADDRESS Address\r
1225 )\r
1226{\r
1227 if (!IsMtrrSupported ()) {\r
1228 return CacheUncacheable;\r
1229 }\r
1230\r
1231 return MtrrGetMemoryAttributeByAddressWorker (NULL, Address);\r
1232}\r
1233\r
85b7f65b 1234/**\r
16c2d37e
MK
1235 Worker function prints all MTRRs for debugging.\r
1236\r
341fea64 1237 If MtrrSetting is not NULL, print MTRR settings from input MTRR\r
16c2d37e
MK
1238 settings buffer.\r
1239 If MtrrSetting is NULL, print MTRR settings from MTRRs.\r
1240\r
1241 @param MtrrSetting A buffer holding all MTRRs content.\r
85b7f65b
MK
1242**/\r
1243VOID\r
16c2d37e
MK
1244MtrrDebugPrintAllMtrrsWorker (\r
1245 IN MTRR_SETTINGS *MtrrSetting\r
85b7f65b
MK
1246 )\r
1247{\r
1248 DEBUG_CODE (\r
16c2d37e
MK
1249 MTRR_SETTINGS LocalMtrrs;\r
1250 MTRR_SETTINGS *Mtrrs;\r
85b7f65b
MK
1251 UINTN Index;\r
1252 UINTN Index1;\r
1253 UINTN VariableMtrrCount;\r
1254 UINT64 Base;\r
1255 UINT64 Limit;\r
1256 UINT64 MtrrBase;\r
1257 UINT64 MtrrLimit;\r
1258 UINT64 RangeBase;\r
1259 UINT64 RangeLimit;\r
1260 UINT64 NoRangeBase;\r
1261 UINT64 NoRangeLimit;\r
1262 UINT32 RegEax;\r
1263 UINTN MemoryType;\r
1264 UINTN PreviousMemoryType;\r
1265 BOOLEAN Found;\r
1266\r
1267 if (!IsMtrrSupported ()) {\r
1268 return;\r
1269 }\r
1270\r
1271 DEBUG((DEBUG_CACHE, "MTRR Settings\n"));\r
1272 DEBUG((DEBUG_CACHE, "=============\n"));\r
1273\r
16c2d37e
MK
1274 if (MtrrSetting != NULL) {\r
1275 Mtrrs = MtrrSetting;\r
1276 } else {\r
1277 MtrrGetAllMtrrs (&LocalMtrrs);\r
1278 Mtrrs = &LocalMtrrs;\r
1279 }\r
1280\r
1281 DEBUG((DEBUG_CACHE, "MTRR Default Type: %016lx\n", Mtrrs->MtrrDefType));\r
85b7f65b 1282 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
16c2d37e 1283 DEBUG((DEBUG_CACHE, "Fixed MTRR[%02d] : %016lx\n", Index, Mtrrs->Fixed.Mtrr[Index]));\r
85b7f65b
MK
1284 }\r
1285\r
1286 VariableMtrrCount = GetVariableMtrrCount ();\r
1287 for (Index = 0; Index < VariableMtrrCount; Index++) {\r
1288 DEBUG((DEBUG_CACHE, "Variable MTRR[%02d]: Base=%016lx Mask=%016lx\n",\r
1289 Index,\r
16c2d37e
MK
1290 Mtrrs->Variables.Mtrr[Index].Base,\r
1291 Mtrrs->Variables.Mtrr[Index].Mask\r
85b7f65b
MK
1292 ));\r
1293 }\r
1294 DEBUG((DEBUG_CACHE, "\n"));\r
1295 DEBUG((DEBUG_CACHE, "MTRR Ranges\n"));\r
1296 DEBUG((DEBUG_CACHE, "====================================\n"));\r
1297\r
1298 Base = 0;\r
1299 PreviousMemoryType = MTRR_CACHE_INVALID_TYPE;\r
1300 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
1301 Base = mMtrrLibFixedMtrrTable[Index].BaseAddress;\r
1302 for (Index1 = 0; Index1 < 8; Index1++) {\r
16c2d37e 1303 MemoryType = (UINTN)(RShiftU64 (Mtrrs->Fixed.Mtrr[Index], Index1 * 8) & 0xff);\r
85b7f65b
MK
1304 if (MemoryType > CacheWriteBack) {\r
1305 MemoryType = MTRR_CACHE_INVALID_TYPE;\r
1306 }\r
1307 if (MemoryType != PreviousMemoryType) {\r
1308 if (PreviousMemoryType != MTRR_CACHE_INVALID_TYPE) {\r
1309 DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));\r
1310 }\r
1311 PreviousMemoryType = MemoryType;\r
1312 DEBUG((DEBUG_CACHE, "%a:%016lx-", mMtrrMemoryCacheTypeShortName[MemoryType], Base));\r
1313 }\r
1314 Base += mMtrrLibFixedMtrrTable[Index].Length;\r
1315 }\r
1316 }\r
1317 DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));\r
1318\r
1319 VariableMtrrCount = GetVariableMtrrCount ();\r
1320\r
1321 Limit = BIT36 - 1;\r
1322 AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);\r
1323 if (RegEax >= 0x80000008) {\r
1324 AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);\r
1325 Limit = LShiftU64 (1, RegEax & 0xff) - 1;\r
1326 }\r
1327 Base = BASE_1MB;\r
1328 PreviousMemoryType = MTRR_CACHE_INVALID_TYPE;\r
1329 do {\r
16c2d37e 1330 MemoryType = MtrrGetMemoryAttributeByAddressWorker (Mtrrs, Base);\r
85b7f65b
MK
1331 if (MemoryType > CacheWriteBack) {\r
1332 MemoryType = MTRR_CACHE_INVALID_TYPE;\r
1333 }\r
1334\r
1335 if (MemoryType != PreviousMemoryType) {\r
1336 if (PreviousMemoryType != MTRR_CACHE_INVALID_TYPE) {\r
1337 DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));\r
1338 }\r
1339 PreviousMemoryType = MemoryType;\r
1340 DEBUG((DEBUG_CACHE, "%a:%016lx-", mMtrrMemoryCacheTypeShortName[MemoryType], Base));\r
1341 }\r
1342\r
1343 RangeBase = BASE_1MB;\r
1344 NoRangeBase = BASE_1MB;\r
1345 RangeLimit = Limit;\r
1346 NoRangeLimit = Limit;\r
1347\r
1348 for (Index = 0, Found = FALSE; Index < VariableMtrrCount; Index++) {\r
16c2d37e 1349 if ((Mtrrs->Variables.Mtrr[Index].Mask & BIT11) == 0) {\r
85b7f65b
MK
1350 //\r
1351 // If mask is not valid, then do not display range\r
1352 //\r
1353 continue;\r
1354 }\r
16c2d37e
MK
1355 MtrrBase = (Mtrrs->Variables.Mtrr[Index].Base & (~(SIZE_4KB - 1)));\r
1356 MtrrLimit = MtrrBase + ((~(Mtrrs->Variables.Mtrr[Index].Mask & (~(SIZE_4KB - 1)))) & Limit);\r
85b7f65b
MK
1357\r
1358 if (Base >= MtrrBase && Base < MtrrLimit) {\r
1359 Found = TRUE;\r
1360 }\r
1361\r
1362 if (Base >= MtrrBase && MtrrBase > RangeBase) {\r
1363 RangeBase = MtrrBase;\r
1364 }\r
1365 if (Base > MtrrLimit && MtrrLimit > RangeBase) {\r
1366 RangeBase = MtrrLimit + 1;\r
1367 }\r
1368 if (Base < MtrrBase && MtrrBase < RangeLimit) {\r
1369 RangeLimit = MtrrBase - 1;\r
1370 }\r
1371 if (Base < MtrrLimit && MtrrLimit <= RangeLimit) {\r
1372 RangeLimit = MtrrLimit;\r
1373 }\r
1374\r
1375 if (Base > MtrrLimit && NoRangeBase < MtrrLimit) {\r
1376 NoRangeBase = MtrrLimit + 1;\r
1377 }\r
1378 if (Base < MtrrBase && NoRangeLimit > MtrrBase) {\r
1379 NoRangeLimit = MtrrBase - 1;\r
1380 }\r
1381 }\r
1382\r
1383 if (Found) {\r
1384 Base = RangeLimit + 1;\r
1385 } else {\r
1386 Base = NoRangeLimit + 1;\r
1387 }\r
1388 } while (Base < Limit);\r
1389 DEBUG((DEBUG_CACHE, "%016lx\n\n", Base - 1));\r
1390 );\r
1391}\r
16c2d37e
MK
1392\r
1393\r
1394/**\r
1395 This function prints all MTRRs for debugging.\r
1396**/\r
1397VOID\r
1398EFIAPI\r
1399MtrrDebugPrintAllMtrrs (\r
1400 VOID\r
1401 )\r
1402{\r
1403 MtrrDebugPrintAllMtrrsWorker (NULL);\r
1404}\r
1405\r
8051302a
RN
1406/**\r
1407 Update the Ranges array to change the specified range identified by\r
1408 BaseAddress and Length to Type.\r
1409\r
1410 @param Ranges Array holding memory type settings for all memory regions.\r
1411 @param Capacity The maximum count of memory ranges the array can hold.\r
1412 @param Count Return the new memory range count in the array.\r
1413 @param BaseAddress The base address of the memory range to change type.\r
1414 @param Length The length of the memory range to change type.\r
1415 @param Type The new type of the specified memory range.\r
1416\r
1417 @retval RETURN_SUCCESS The type of the specified memory range is\r
1418 changed successfully.\r
1419 @retval RETURN_OUT_OF_RESOURCES The new type set causes the count of memory\r
1420 range exceeds capacity.\r
1421**/\r
1422RETURN_STATUS\r
1423MtrrLibSetMemoryType (\r
1424 IN MEMORY_RANGE *Ranges,\r
1425 IN UINT32 Capacity,\r
1426 IN OUT UINT32 *Count,\r
1427 IN UINT64 BaseAddress,\r
1428 IN UINT64 Length,\r
1429 IN MTRR_MEMORY_CACHE_TYPE Type\r
1430 )\r
1431{\r
1432 UINT32 Index;\r
1433 UINT64 Limit;\r
1434 UINT64 LengthLeft;\r
1435 UINT64 LengthRight;\r
1436 UINT32 StartIndex;\r
1437 UINT32 EndIndex;\r
1438 UINT32 DeltaCount;\r
1439\r
1440 Limit = BaseAddress + Length;\r
1441 StartIndex = *Count;\r
1442 EndIndex = *Count;\r
1443 for (Index = 0; Index < *Count; Index++) {\r
1444 if ((StartIndex == *Count) &&\r
1445 (Ranges[Index].BaseAddress <= BaseAddress) &&\r
1446 (BaseAddress < Ranges[Index].BaseAddress + Ranges[Index].Length)) {\r
1447 StartIndex = Index;\r
1448 LengthLeft = BaseAddress - Ranges[Index].BaseAddress;\r
1449 }\r
1450\r
1451 if ((EndIndex == *Count) &&\r
1452 (Ranges[Index].BaseAddress < Limit) &&\r
1453 (Limit <= Ranges[Index].BaseAddress + Ranges[Index].Length)) {\r
1454 EndIndex = Index;\r
1455 LengthRight = Ranges[Index].BaseAddress + Ranges[Index].Length - Limit;\r
1456 break;\r
1457 }\r
1458 }\r
1459\r
1460 ASSERT (StartIndex != *Count && EndIndex != *Count);\r
1461 if (StartIndex == EndIndex && Ranges[StartIndex].Type == Type) {\r
1462 return RETURN_SUCCESS;\r
1463 }\r
1464\r
1465 //\r
1466 // The type change may cause merging with previous range or next range.\r
1467 // Update the StartIndex, EndIndex, BaseAddress, Length so that following\r
1468 // logic doesn't need to consider merging.\r
1469 //\r
1470 if (StartIndex != 0) {\r
1471 if (LengthLeft == 0 && Ranges[StartIndex - 1].Type == Type) {\r
1472 StartIndex--;\r
1473 Length += Ranges[StartIndex].Length;\r
1474 BaseAddress -= Ranges[StartIndex].Length;\r
1475 }\r
1476 }\r
1477 if (EndIndex != (*Count) - 1) {\r
1478 if (LengthRight == 0 && Ranges[EndIndex + 1].Type == Type) {\r
1479 EndIndex++;\r
1480 Length += Ranges[EndIndex].Length;\r
1481 }\r
1482 }\r
1483\r
1484 //\r
1485 // |- 0 -|- 1 -|- 2 -|- 3 -| StartIndex EndIndex DeltaCount Count (Count = 4)\r
1486 // |++++++++++++++++++| 0 3 1=3-0-2 3\r
1487 // |+++++++| 0 1 -1=1-0-2 5\r
1488 // |+| 0 0 -2=0-0-2 6\r
1489 // |+++| 0 0 -1=0-0-2+1 5\r
1490 //\r
1491 //\r
1492 DeltaCount = EndIndex - StartIndex - 2;\r
1493 if (LengthLeft == 0) {\r
1494 DeltaCount++;\r
1495 }\r
1496 if (LengthRight == 0) {\r
1497 DeltaCount++;\r
1498 }\r
1499 if (*Count - DeltaCount > Capacity) {\r
1500 return RETURN_OUT_OF_RESOURCES;\r
1501 }\r
1502\r
1503 //\r
1504 // Reserve (-DeltaCount) space\r
1505 //\r
1506 CopyMem (&Ranges[EndIndex + 1 - DeltaCount], &Ranges[EndIndex + 1], (*Count - EndIndex - 1) * sizeof (Ranges[0]));\r
1507 *Count -= DeltaCount;\r
1508\r
1509 if (LengthLeft != 0) {\r
1510 Ranges[StartIndex].Length = LengthLeft;\r
1511 StartIndex++;\r
1512 }\r
1513 if (LengthRight != 0) {\r
1514 Ranges[EndIndex - DeltaCount].BaseAddress = BaseAddress + Length;\r
1515 Ranges[EndIndex - DeltaCount].Length = LengthRight;\r
1516 Ranges[EndIndex - DeltaCount].Type = Ranges[EndIndex].Type;\r
1517 }\r
1518 Ranges[StartIndex].BaseAddress = BaseAddress;\r
1519 Ranges[StartIndex].Length = Length;\r
1520 Ranges[StartIndex].Type = Type;\r
1521 return RETURN_SUCCESS;\r
1522}\r
1523\r
1524/**\r
1525 Allocate one or more variable MTRR to cover the range identified by\r
1526 BaseAddress and Length.\r
1527\r
1528 @param Ranges Memory range array holding the memory type\r
1529 settings for all memory address.\r
1530 @param RangeCount Count of memory ranges.\r
1531 @param VariableMtrr Variable MTRR array.\r
1532 @param VariableMtrrCapacity Capacity of variable MTRR array.\r
1533 @param VariableMtrrCount Count of variable MTRR.\r
1534 @param BaseAddress Base address of the memory range.\r
1535 @param Length Length of the memory range.\r
1536 @param Type MTRR type of the memory range.\r
1537 @param Alignment0 Alignment of 0.\r
1538\r
1539 @retval RETURN_SUCCESS Variable MTRRs are allocated successfully.\r
1540 @retval RETURN_OUT_OF_RESOURCES Count of variable MTRRs exceeds capacity.\r
1541**/\r
1542RETURN_STATUS\r
1543MtrrLibSetMemoryAttributeInVariableMtrr (\r
1544 IN CONST MEMORY_RANGE *Ranges,\r
1545 IN UINT32 RangeCount,\r
1546 IN OUT VARIABLE_MTRR *VariableMtrr,\r
1547 IN UINT32 VariableMtrrCapacity,\r
1548 IN OUT UINT32 *VariableMtrrCount,\r
1549 IN UINT64 BaseAddress,\r
1550 IN UINT64 Length,\r
1551 IN MTRR_MEMORY_CACHE_TYPE Type,\r
1552 IN UINT64 Alignment0\r
1553 );\r
1554\r
1555/**\r
1556 Allocate one or more variable MTRR to cover the range identified by\r
1557 BaseAddress and Length.\r
1558\r
1559 The routine recursively calls MtrrLibSetMemoryAttributeInVariableMtrr()\r
1560 to allocate variable MTRRs when the range contains several sub-ranges\r
1561 with different attributes.\r
1562\r
1563 @param Ranges Memory range array holding the memory type\r
1564 settings for all memory address.\r
1565 @param RangeCount Count of memory ranges.\r
1566 @param VariableMtrr Variable MTRR array.\r
1567 @param VariableMtrrCapacity Capacity of variable MTRR array.\r
1568 @param VariableMtrrCount Count of variable MTRR.\r
1569 @param BaseAddress Base address of the memory range.\r
1570 @param Length Length of the memory range.\r
1571 @param Type MTRR type of the range.\r
1572 If it's CacheInvalid, the memory range may\r
1573 contains several sub-ranges with different\r
1574 attributes.\r
1575 @param Alignment0 Alignment of 0.\r
1576\r
1577 @retval RETURN_SUCCESS Variable MTRRs are allocated successfully.\r
1578 @retval RETURN_OUT_OF_RESOURCES Count of variable MTRRs exceeds capacity.\r
1579**/\r
1580RETURN_STATUS\r
1581MtrrLibAddVariableMtrr (\r
1582 IN CONST MEMORY_RANGE *Ranges,\r
1583 IN UINT32 RangeCount,\r
1584 IN OUT VARIABLE_MTRR *VariableMtrr,\r
1585 IN UINT32 VariableMtrrCapacity,\r
1586 IN OUT UINT32 *VariableMtrrCount,\r
1587 IN PHYSICAL_ADDRESS BaseAddress,\r
1588 IN UINT64 Length,\r
1589 IN MTRR_MEMORY_CACHE_TYPE Type,\r
1590 IN UINT64 Alignment0\r
1591)\r
1592{\r
1593 RETURN_STATUS Status;\r
1594 UINT32 Index;\r
1595 UINT64 SubLength;\r
1596\r
1597 MTRR_LIB_ASSERT_ALIGNED (BaseAddress, Length);\r
1598 if (Type == CacheInvalid) {\r
1599 for (Index = 0; Index < RangeCount; Index++) {\r
1600 if (Ranges[Index].BaseAddress <= BaseAddress && BaseAddress < Ranges[Index].BaseAddress + Ranges[Index].Length) {\r
1601\r
1602 //\r
1603 // Because the Length may not be aligned to BaseAddress, below code calls\r
1604 // MtrrLibSetMemoryAttributeInVariableMtrr() instead of itself.\r
1605 // MtrrLibSetMemoryAttributeInVariableMtrr() splits the range to several\r
1606 // aligned ranges.\r
1607 //\r
1608 if (Ranges[Index].BaseAddress + Ranges[Index].Length >= BaseAddress + Length) {\r
1609 return MtrrLibSetMemoryAttributeInVariableMtrr (\r
1610 Ranges, RangeCount, VariableMtrr, VariableMtrrCapacity, VariableMtrrCount,\r
1611 BaseAddress, Length, Ranges[Index].Type, Alignment0\r
1612 );\r
1613 } else {\r
1614 SubLength = Ranges[Index].BaseAddress + Ranges[Index].Length - BaseAddress;\r
1615 Status = MtrrLibSetMemoryAttributeInVariableMtrr (\r
1616 Ranges, RangeCount, VariableMtrr, VariableMtrrCapacity, VariableMtrrCount,\r
1617 BaseAddress, SubLength, Ranges[Index].Type, Alignment0\r
1618 );\r
1619 if (RETURN_ERROR (Status)) {\r
1620 return Status;\r
1621 }\r
1622 BaseAddress += SubLength;\r
1623 Length -= SubLength;\r
1624 }\r
1625 }\r
1626 }\r
1627\r
1628 //\r
1629 // Because memory ranges cover all the memory addresses, it's impossible to be here.\r
1630 //\r
1631 ASSERT (FALSE);\r
1632 return RETURN_DEVICE_ERROR;\r
1633 } else {\r
1634 for (Index = 0; Index < *VariableMtrrCount; Index++) {\r
1635 if (VariableMtrr[Index].BaseAddress == BaseAddress && VariableMtrr[Index].Length == Length) {\r
1636 ASSERT (VariableMtrr[Index].Type == Type);\r
1637 break;\r
1638 }\r
1639 }\r
1640 if (Index == *VariableMtrrCount) {\r
1641 if (*VariableMtrrCount == VariableMtrrCapacity) {\r
1642 return RETURN_OUT_OF_RESOURCES;\r
1643 }\r
1644 VariableMtrr[Index].BaseAddress = BaseAddress;\r
1645 VariableMtrr[Index].Length = Length;\r
1646 VariableMtrr[Index].Type = Type;\r
1647 VariableMtrr[Index].Valid = TRUE;\r
1648 VariableMtrr[Index].Used = TRUE;\r
1649 (*VariableMtrrCount)++;\r
1650 }\r
1651 return RETURN_SUCCESS;\r
1652 }\r
1653}\r
1654\r
1655/**\r
1656 Allocate one or more variable MTRR to cover the range identified by\r
1657 BaseAddress and Length.\r
1658\r
1659 @param Ranges Memory range array holding the memory type\r
1660 settings for all memory address.\r
1661 @param RangeCount Count of memory ranges.\r
1662 @param VariableMtrr Variable MTRR array.\r
1663 @param VariableMtrrCapacity Capacity of variable MTRR array.\r
1664 @param VariableMtrrCount Count of variable MTRR.\r
1665 @param BaseAddress Base address of the memory range.\r
1666 @param Length Length of the memory range.\r
1667 @param Type MTRR type of the memory range.\r
1668 @param Alignment0 Alignment of 0.\r
1669\r
1670 @retval RETURN_SUCCESS Variable MTRRs are allocated successfully.\r
1671 @retval RETURN_OUT_OF_RESOURCES Count of variable MTRRs exceeds capacity.\r
1672**/\r
1673RETURN_STATUS\r
1674MtrrLibSetMemoryAttributeInVariableMtrr (\r
1675 IN CONST MEMORY_RANGE *Ranges,\r
1676 IN UINT32 RangeCount,\r
1677 IN OUT VARIABLE_MTRR *VariableMtrr,\r
1678 IN UINT32 VariableMtrrCapacity,\r
1679 IN OUT UINT32 *VariableMtrrCount,\r
1680 IN UINT64 BaseAddress,\r
1681 IN UINT64 Length,\r
1682 IN MTRR_MEMORY_CACHE_TYPE Type,\r
1683 IN UINT64 Alignment0\r
1684)\r
1685{\r
1686 UINT64 Alignment;\r
1687 UINT32 MtrrNumber;\r
1688 UINT32 SubtractiveLeft;\r
1689 UINT32 SubtractiveRight;\r
1690 BOOLEAN UseLeastAlignment;\r
1691\r
1692 MtrrNumber = MtrrLibGetMtrrNumber (Ranges, RangeCount, VariableMtrr, *VariableMtrrCount,\r
1693 BaseAddress, Length, Type, Alignment0, &SubtractiveLeft, &SubtractiveRight);\r
1694\r
1695 if (MtrrNumber + *VariableMtrrCount > VariableMtrrCapacity) {\r
1696 return RETURN_OUT_OF_RESOURCES;\r
1697 }\r
1698\r
1699 while (SubtractiveLeft-- != 0) {\r
1700 Alignment = MtrrLibLeastAlignment (BaseAddress, Alignment0);\r
1701 ASSERT (Alignment <= Length);\r
1702\r
1703 MtrrLibAddVariableMtrr (Ranges, RangeCount, VariableMtrr, VariableMtrrCapacity, VariableMtrrCount,\r
1704 BaseAddress - Alignment, Alignment, CacheInvalid, Alignment0);\r
1705 BaseAddress -= Alignment;\r
1706 Length += Alignment;\r
1707 }\r
1708\r
1709 while (Length != 0) {\r
1710 Alignment = MtrrLibLeastAlignment (BaseAddress, Alignment0);\r
1711 if (Alignment > Length) {\r
1712 break;\r
1713 }\r
1714 MtrrLibAddVariableMtrr (NULL, 0, VariableMtrr, VariableMtrrCapacity, VariableMtrrCount,\r
1715 BaseAddress, Alignment, Type, Alignment0);\r
1716 BaseAddress += Alignment;\r
1717 Length -= Alignment;\r
1718 }\r
1719\r
1720 while (SubtractiveRight-- != 0) {\r
1721 Alignment = MtrrLibLeastAlignment (BaseAddress + Length, Alignment0);\r
1722 MtrrLibAddVariableMtrr (Ranges, RangeCount, VariableMtrr, VariableMtrrCapacity, VariableMtrrCount,\r
1723 BaseAddress + Length, Alignment, CacheInvalid, Alignment0);\r
1724 Length += Alignment;\r
1725 }\r
1726\r
1727 UseLeastAlignment = TRUE;\r
1728 while (Length != 0) {\r
1729 if (UseLeastAlignment) {\r
1730 Alignment = MtrrLibLeastAlignment (BaseAddress, Alignment0);\r
1731 if (Alignment > Length) {\r
1732 UseLeastAlignment = FALSE;\r
1733 }\r
1734 }\r
1735\r
1736 if (!UseLeastAlignment) {\r
1737 Alignment = GetPowerOfTwo64 (Length);\r
1738 }\r
1739\r
1740 MtrrLibAddVariableMtrr (NULL, 0, VariableMtrr, VariableMtrrCapacity, VariableMtrrCount,\r
1741 BaseAddress, Alignment, Type, Alignment0);\r
1742 BaseAddress += Alignment;\r
1743 Length -= Alignment;\r
1744 }\r
1745 return RETURN_SUCCESS;\r
1746}\r
1747\r
1748/**\r
1749 Return an array of memory ranges holding memory type settings for all memory\r
1750 address.\r
1751\r
1752 @param DefaultType The default memory type.\r
1753 @param TotalLength The total length of the memory.\r
1754 @param VariableMtrr The variable MTRR array.\r
1755 @param VariableMtrrCount The count of variable MTRRs.\r
1756 @param Ranges Return the memory range array holding memory type\r
1757 settings for all memory address.\r
1758 @param RangeCapacity The capacity of memory range array.\r
1759 @param RangeCount Return the count of memory range.\r
1760\r
1761 @retval RETURN_SUCCESS The memory range array is returned successfully.\r
1762 @retval RETURN_OUT_OF_RESOURCES The count of memory ranges exceeds capacity.\r
1763**/\r
1764RETURN_STATUS\r
1765MtrrLibGetMemoryTypes (\r
1766 IN MTRR_MEMORY_CACHE_TYPE DefaultType,\r
1767 IN UINT64 TotalLength,\r
1768 IN CONST VARIABLE_MTRR *VariableMtrr,\r
1769 IN UINT32 VariableMtrrCount,\r
1770 OUT MEMORY_RANGE *Ranges,\r
1771 IN UINT32 RangeCapacity,\r
1772 OUT UINT32 *RangeCount\r
1773)\r
1774{\r
1775 RETURN_STATUS Status;\r
1776 UINTN Index;\r
1777\r
1778 //\r
1779 // WT > WB\r
1780 // UC > *\r
1781 // UC > * (except WB, UC) > WB\r
1782 //\r
1783\r
1784 //\r
1785 // 0. Set whole range as DefaultType\r
1786 //\r
1787 *RangeCount = 1;\r
1788 Ranges[0].BaseAddress = 0;\r
1789 Ranges[0].Length = TotalLength;\r
1790 Ranges[0].Type = DefaultType;\r
1791\r
1792 //\r
1793 // 1. Set WB\r
1794 //\r
1795 for (Index = 0; Index < VariableMtrrCount; Index++) {\r
1796 if (VariableMtrr[Index].Valid && VariableMtrr[Index].Type == CacheWriteBack) {\r
1797 Status = MtrrLibSetMemoryType (\r
1798 Ranges, RangeCapacity, RangeCount,\r
1799 VariableMtrr[Index].BaseAddress, VariableMtrr[Index].Length, (MTRR_MEMORY_CACHE_TYPE) VariableMtrr[Index].Type\r
1800 );\r
1801 if (RETURN_ERROR (Status)) {\r
1802 return Status;\r
1803 }\r
1804 }\r
1805 }\r
1806\r
1807 //\r
1808 // 2. Set other types than WB or UC\r
1809 //\r
1810 for (Index = 0; Index < VariableMtrrCount; Index++) {\r
1811 if (VariableMtrr[Index].Valid && VariableMtrr[Index].Type != CacheWriteBack && VariableMtrr[Index].Type != CacheUncacheable) {\r
1812 Status = MtrrLibSetMemoryType (\r
1813 Ranges, RangeCapacity, RangeCount,\r
1814 VariableMtrr[Index].BaseAddress, VariableMtrr[Index].Length, (MTRR_MEMORY_CACHE_TYPE) VariableMtrr[Index].Type\r
1815 );\r
1816 if (RETURN_ERROR (Status)) {\r
1817 return Status;\r
1818 }\r
1819 }\r
1820 }\r
1821\r
1822 //\r
1823 // 3. Set UC\r
1824 //\r
1825 for (Index = 0; Index < VariableMtrrCount; Index++) {\r
1826 if (VariableMtrr[Index].Valid && VariableMtrr[Index].Type == CacheUncacheable) {\r
1827 Status = MtrrLibSetMemoryType (\r
1828 Ranges, RangeCapacity, RangeCount,\r
1829 VariableMtrr[Index].BaseAddress, VariableMtrr[Index].Length, (MTRR_MEMORY_CACHE_TYPE) VariableMtrr[Index].Type\r
1830 );\r
1831 if (RETURN_ERROR (Status)) {\r
1832 return Status;\r
1833 }\r
1834 }\r
1835 }\r
1836 return RETURN_SUCCESS;\r
1837}\r
16c2d37e 1838\r
85b7f65b 1839/**\r
16c2d37e 1840 Worker function attempts to set the attributes for a memory range.\r
85b7f65b 1841\r
8051302a 1842 If MtrrSetting is not NULL, set the attributes into the input MTRR\r
b970ed68 1843 settings buffer.\r
8051302a 1844 If MtrrSetting is NULL, set the attributes into MTRRs registers.\r
b970ed68
MK
1845\r
1846 @param[in, out] MtrrSetting A buffer holding all MTRRs content.\r
85b7f65b 1847 @param[in] BaseAddress The physical address that is the start\r
8051302a
RN
1848 address of a memory range.\r
1849 @param[in] Length The size in bytes of the memory range.\r
1850 @param[in] Type The MTRR type to set for the memory range.\r
85b7f65b
MK
1851\r
1852 @retval RETURN_SUCCESS The attributes were set for the memory\r
8051302a 1853 range.\r
85b7f65b
MK
1854 @retval RETURN_INVALID_PARAMETER Length is zero.\r
1855 @retval RETURN_UNSUPPORTED The processor does not support one or\r
1856 more bytes of the memory resource range\r
1857 specified by BaseAddress and Length.\r
8051302a
RN
1858 @retval RETURN_UNSUPPORTED The MTRR type is not support for the\r
1859 memory resource range specified\r
85b7f65b 1860 by BaseAddress and Length.\r
85b7f65b
MK
1861 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to\r
1862 modify the attributes of the memory\r
1863 resource range.\r
1864\r
1865**/\r
1866RETURN_STATUS\r
b970ed68
MK
1867MtrrSetMemoryAttributeWorker (\r
1868 IN OUT MTRR_SETTINGS *MtrrSetting,\r
1869 IN PHYSICAL_ADDRESS BaseAddress,\r
1870 IN UINT64 Length,\r
8051302a 1871 IN MTRR_MEMORY_CACHE_TYPE Type\r
85b7f65b
MK
1872 )\r
1873{\r
85b7f65b 1874 RETURN_STATUS Status;\r
8051302a
RN
1875 UINT32 Index;\r
1876 UINT32 WorkingIndex;\r
1877 //\r
1878 // N variable MTRRs can maximumly separate (2N + 1) Ranges, plus 1 range for [0, 1M).\r
1879 //\r
1880 MEMORY_RANGE Ranges[MTRR_NUMBER_OF_VARIABLE_MTRR * 2 + 2];\r
1881 UINT32 RangeCount;\r
85b7f65b
MK
1882 UINT64 MtrrValidBitsMask;\r
1883 UINT64 MtrrValidAddressMask;\r
8051302a 1884 UINT64 Alignment0;\r
85b7f65b 1885 MTRR_CONTEXT MtrrContext;\r
fa25cf38 1886 BOOLEAN MtrrContextValid;\r
8051302a
RN
1887\r
1888 MTRR_MEMORY_CACHE_TYPE DefaultType;\r
1889\r
1890 UINT32 MsrIndex;\r
fa25cf38
MK
1891 UINT64 ClearMask;\r
1892 UINT64 OrMask;\r
1893 UINT64 NewValue;\r
8051302a
RN
1894 BOOLEAN FixedSettingsValid[MTRR_NUMBER_OF_FIXED_MTRR];\r
1895 BOOLEAN FixedSettingsModified[MTRR_NUMBER_OF_FIXED_MTRR];\r
1896 MTRR_FIXED_SETTINGS WorkingFixedSettings;\r
85b7f65b 1897\r
8051302a
RN
1898 UINT32 FirmwareVariableMtrrCount;\r
1899 MTRR_VARIABLE_SETTINGS *VariableSettings;\r
1900 MTRR_VARIABLE_SETTINGS OriginalVariableSettings;\r
1901 UINT32 OriginalVariableMtrrCount;\r
1902 VARIABLE_MTRR OriginalVariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];\r
1903 UINT32 WorkingVariableMtrrCount;\r
1904 VARIABLE_MTRR WorkingVariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];\r
1905 BOOLEAN VariableSettingModified[MTRR_NUMBER_OF_VARIABLE_MTRR];\r
1906 UINTN FreeVariableMtrrCount;\r
85b7f65b 1907\r
8051302a
RN
1908 if (Length == 0) {\r
1909 return RETURN_INVALID_PARAMETER;\r
85b7f65b
MK
1910 }\r
1911\r
b0fa5d29 1912 MtrrLibInitializeMtrrMask (&MtrrValidBitsMask, &MtrrValidAddressMask);\r
8051302a
RN
1913 if (((BaseAddress & ~MtrrValidAddressMask) != 0) || (Length & ~MtrrValidAddressMask) != 0) {\r
1914 return RETURN_UNSUPPORTED;\r
85b7f65b
MK
1915 }\r
1916\r
8051302a
RN
1917 ZeroMem (&WorkingFixedSettings, sizeof (WorkingFixedSettings));\r
1918 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
1919 FixedSettingsValid[Index] = FALSE;\r
1920 FixedSettingsModified[Index] = FALSE;\r
85b7f65b
MK
1921 }\r
1922\r
1923 //\r
1924 // Check if Fixed MTRR\r
1925 //\r
fa25cf38 1926 if (BaseAddress < BASE_1MB) {\r
8051302a
RN
1927 MsrIndex = (UINT32)-1;\r
1928 while ((BaseAddress < BASE_1MB) && (Length != 0)) {\r
1929 Status = MtrrLibProgramFixedMtrr (Type, &BaseAddress, &Length, &MsrIndex, &ClearMask, &OrMask);\r
fa25cf38 1930 if (RETURN_ERROR (Status)) {\r
8051302a 1931 return Status;\r
fa25cf38 1932 }\r
b970ed68 1933 if (MtrrSetting != NULL) {\r
8051302a
RN
1934 MtrrSetting->Fixed.Mtrr[MsrIndex] = (MtrrSetting->Fixed.Mtrr[MsrIndex] & ~ClearMask) | OrMask;\r
1935 ((MSR_IA32_MTRR_DEF_TYPE_REGISTER *) &MtrrSetting->MtrrDefType)->Bits.FE = 1;\r
b970ed68 1936 } else {\r
8051302a
RN
1937 if (!FixedSettingsValid[MsrIndex]) {\r
1938 WorkingFixedSettings.Mtrr[MsrIndex] = AsmReadMsr64 (mMtrrLibFixedMtrrTable[MsrIndex].Msr);\r
1939 FixedSettingsValid[MsrIndex] = TRUE;\r
b970ed68 1940 }\r
8051302a
RN
1941 NewValue = (WorkingFixedSettings.Mtrr[MsrIndex] & ~ClearMask) | OrMask;\r
1942 if (WorkingFixedSettings.Mtrr[MsrIndex] != NewValue) {\r
1943 WorkingFixedSettings.Mtrr[MsrIndex] = NewValue;\r
1944 FixedSettingsModified[MsrIndex] = TRUE;\r
b970ed68 1945 }\r
fa25cf38 1946 }\r
85b7f65b 1947 }\r
85b7f65b 1948\r
fa25cf38
MK
1949 if (Length == 0) {\r
1950 //\r
1951 // A Length of 0 can only make sense for fixed MTTR ranges.\r
1952 // Since we just handled the fixed MTRRs, we can skip the\r
1953 // variable MTRR section.\r
1954 //\r
1955 goto Done;\r
1956 }\r
85b7f65b
MK
1957 }\r
1958\r
1959 //\r
8051302a 1960 // Read the default MTRR type\r
85b7f65b 1961 //\r
8051302a 1962 DefaultType = MtrrGetDefaultMemoryTypeWorker (MtrrSetting);\r
85b7f65b 1963\r
acf431e6 1964 //\r
8051302a 1965 // Read all variable MTRRs and convert to Ranges.\r
acf431e6 1966 //\r
8051302a
RN
1967 OriginalVariableMtrrCount = GetVariableMtrrCountWorker ();\r
1968 if (MtrrSetting == NULL) {\r
1969 ZeroMem (&OriginalVariableSettings, sizeof (OriginalVariableSettings));\r
1970 MtrrGetVariableMtrrWorker (NULL, OriginalVariableMtrrCount, &OriginalVariableSettings);\r
1971 VariableSettings = &OriginalVariableSettings;\r
b970ed68 1972 } else {\r
8051302a 1973 VariableSettings = &MtrrSetting->Variables;\r
e50466da 1974 }\r
8051302a
RN
1975 MtrrGetMemoryAttributeInVariableMtrrWorker (VariableSettings, OriginalVariableMtrrCount, MtrrValidBitsMask, MtrrValidAddressMask, OriginalVariableMtrr);\r
1976\r
1977 Status = MtrrLibGetMemoryTypes (\r
1978 DefaultType, MtrrValidBitsMask + 1, OriginalVariableMtrr, OriginalVariableMtrrCount,\r
1979 Ranges, 2 * OriginalVariableMtrrCount + 1, &RangeCount\r
1980 );\r
1981 ASSERT (Status == RETURN_SUCCESS);\r
1982\r
1983 FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCountWorker ();\r
1984 ASSERT (RangeCount <= 2 * FirmwareVariableMtrrCount + 1);\r
e50466da 1985\r
1986 //\r
8051302a 1987 // Force [0, 1M) to UC, so that it doesn't impact left subtraction algorithm.\r
e50466da 1988 //\r
8051302a
RN
1989 Status = MtrrLibSetMemoryType (Ranges, 2 * FirmwareVariableMtrrCount + 2, &RangeCount, 0, SIZE_1MB, CacheUncacheable);\r
1990 ASSERT (Status == RETURN_SUCCESS);\r
1991 //\r
1992 // Apply Type to [BaseAddress, BaseAddress + Length)\r
1993 //\r
1994 Status = MtrrLibSetMemoryType (Ranges, 2 * FirmwareVariableMtrrCount + 2, &RangeCount, BaseAddress, Length, Type);\r
1995 if (RETURN_ERROR (Status)) {\r
1996 return Status;\r
e50466da 1997 }\r
1998\r
8051302a
RN
1999 Alignment0 = LShiftU64 (1, (UINTN) HighBitSet64 (MtrrValidBitsMask));\r
2000 WorkingVariableMtrrCount = 0;\r
2001 ZeroMem (&WorkingVariableMtrr, sizeof (WorkingVariableMtrr));\r
2002 for (Index = 0; Index < RangeCount; Index++) {\r
2003 if (Ranges[Index].Type != DefaultType) {\r
2004 //\r
2005 // Maximum allowed MTRR count is (FirmwareVariableMtrrCount + 1)\r
2006 // Because potentially the range [0, 1MB) is not merged, but can be ignored because fixed MTRR covers that\r
2007 //\r
2008 Status = MtrrLibSetMemoryAttributeInVariableMtrr (\r
2009 Ranges, RangeCount,\r
2010 WorkingVariableMtrr, FirmwareVariableMtrrCount + 1, &WorkingVariableMtrrCount,\r
2011 Ranges[Index].BaseAddress, Ranges[Index].Length,\r
2012 Ranges[Index].Type, Alignment0\r
2013 );\r
2014 if (RETURN_ERROR (Status)) {\r
2015 return Status;\r
2016 }\r
2017 }\r
1a2ad6fc 2018 }\r
e50466da 2019\r
1a2ad6fc 2020 //\r
8051302a 2021 // Remove the [0, 1MB) MTRR if it still exists (not merged with other range)\r
1a2ad6fc 2022 //\r
8051302a
RN
2023 if (WorkingVariableMtrr[0].BaseAddress == 0 && WorkingVariableMtrr[0].Length == SIZE_1MB) {\r
2024 ASSERT (WorkingVariableMtrr[0].Type == CacheUncacheable);\r
2025 WorkingVariableMtrrCount--;\r
2026 CopyMem (&WorkingVariableMtrr[0], &WorkingVariableMtrr[1], WorkingVariableMtrrCount * sizeof (VARIABLE_MTRR));\r
2027 }\r
1a2ad6fc 2028\r
8051302a
RN
2029 if (WorkingVariableMtrrCount > FirmwareVariableMtrrCount) {\r
2030 return RETURN_OUT_OF_RESOURCES;\r
1a2ad6fc 2031 }\r
2032\r
8051302a
RN
2033 for (Index = 0; Index < OriginalVariableMtrrCount; Index++) {\r
2034 VariableSettingModified[Index] = FALSE;\r
1a2ad6fc 2035\r
8051302a
RN
2036 if (!OriginalVariableMtrr[Index].Valid) {\r
2037 continue;\r
2038 }\r
2039 for (WorkingIndex = 0; WorkingIndex < WorkingVariableMtrrCount; WorkingIndex++) {\r
2040 if (OriginalVariableMtrr[Index].BaseAddress == WorkingVariableMtrr[WorkingIndex].BaseAddress &&\r
2041 OriginalVariableMtrr[Index].Length == WorkingVariableMtrr[WorkingIndex].Length &&\r
2042 OriginalVariableMtrr[Index].Type == WorkingVariableMtrr[WorkingIndex].Type) {\r
1a2ad6fc 2043 break;\r
2044 }\r
8051302a 2045 }\r
1a2ad6fc 2046\r
8051302a 2047 if (WorkingIndex == WorkingVariableMtrrCount) {\r
1a2ad6fc 2048 //\r
8051302a 2049 // Remove the one from OriginalVariableMtrr which is not in WorkingVariableMtrr\r
1a2ad6fc 2050 //\r
8051302a
RN
2051 OriginalVariableMtrr[Index].Valid = FALSE;\r
2052 VariableSettingModified[Index] = TRUE;\r
2053 } else {\r
2054 //\r
2055 // Remove the one from WorkingVariableMtrr which is also in OriginalVariableMtrr\r
2056 //\r
2057 WorkingVariableMtrr[WorkingIndex].Valid = FALSE;\r
2058 }\r
2059 //\r
2060 // The above two operations cause that valid MTRR only exists in either OriginalVariableMtrr or WorkingVariableMtrr.\r
2061 //\r
2062 }\r
2063\r
2064 //\r
2065 // Merge remaining MTRRs from WorkingVariableMtrr to OriginalVariableMtrr\r
2066 //\r
2067 for (FreeVariableMtrrCount = 0, WorkingIndex = 0, Index = 0; Index < OriginalVariableMtrrCount; Index++) {\r
2068 if (!OriginalVariableMtrr[Index].Valid) {\r
2069 for (; WorkingIndex < WorkingVariableMtrrCount; WorkingIndex++) {\r
2070 if (WorkingVariableMtrr[WorkingIndex].Valid) {\r
1a2ad6fc 2071 break;\r
2072 }\r
2073 }\r
8051302a
RN
2074 if (WorkingIndex == WorkingVariableMtrrCount) {\r
2075 FreeVariableMtrrCount++;\r
2076 } else {\r
2077 CopyMem (&OriginalVariableMtrr[Index], &WorkingVariableMtrr[WorkingIndex], sizeof (VARIABLE_MTRR));\r
2078 VariableSettingModified[Index] = TRUE;\r
2079 WorkingIndex++;\r
2080 }\r
1a2ad6fc 2081 }\r
2082 }\r
8051302a 2083 ASSERT (OriginalVariableMtrrCount - FreeVariableMtrrCount <= FirmwareVariableMtrrCount);\r
1a2ad6fc 2084\r
8051302a
RN
2085 //\r
2086 // Move MTRRs after the FirmwraeVariableMtrrCount position to beginning\r
2087 //\r
2088 WorkingIndex = FirmwareVariableMtrrCount;\r
2089 for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) {\r
2090 if (!OriginalVariableMtrr[Index].Valid) {\r
2091 //\r
2092 // Found an empty MTRR in WorkingIndex position\r
2093 //\r
2094 for (; WorkingIndex < OriginalVariableMtrrCount; WorkingIndex++) {\r
2095 if (OriginalVariableMtrr[WorkingIndex].Valid) {\r
2096 break;\r
2097 }\r
2098 }\r
e50466da 2099\r
8051302a
RN
2100 if (WorkingIndex != OriginalVariableMtrrCount) {\r
2101 CopyMem (&OriginalVariableMtrr[Index], &OriginalVariableMtrr[WorkingIndex], sizeof (VARIABLE_MTRR));\r
2102 VariableSettingModified[Index] = TRUE;\r
2103 VariableSettingModified[WorkingIndex] = TRUE;\r
2104 OriginalVariableMtrr[WorkingIndex].Valid = FALSE;\r
85b7f65b
MK
2105 }\r
2106 }\r
e50466da 2107 }\r
2108\r
8051302a
RN
2109 //\r
2110 // Convert OriginalVariableMtrr to VariableSettings\r
2111 // NOTE: MTRR from FirmwareVariableMtrr to OriginalVariableMtrr need to update as well.\r
2112 //\r
2113 for (Index = 0; Index < OriginalVariableMtrrCount; Index++) {\r
2114 if (VariableSettingModified[Index]) {\r
2115 if (OriginalVariableMtrr[Index].Valid) {\r
2116 VariableSettings->Mtrr[Index].Base = (OriginalVariableMtrr[Index].BaseAddress & MtrrValidAddressMask) | (UINT8) OriginalVariableMtrr[Index].Type;\r
2117 VariableSettings->Mtrr[Index].Mask = (~(OriginalVariableMtrr[Index].Length - 1)) & MtrrValidAddressMask | BIT11;\r
2118 } else {\r
2119 VariableSettings->Mtrr[Index].Base = 0;\r
2120 VariableSettings->Mtrr[Index].Mask = 0;\r
85b7f65b
MK
2121 }\r
2122 }\r
8051302a 2123 }\r
85b7f65b
MK
2124\r
2125Done:\r
8051302a
RN
2126 if (MtrrSetting != NULL) {\r
2127 ((MSR_IA32_MTRR_DEF_TYPE_REGISTER *) &MtrrSetting->MtrrDefType)->Bits.E = 1;\r
2128 return RETURN_SUCCESS;\r
2129 }\r
fa25cf38 2130\r
8051302a 2131 MtrrContextValid = FALSE;\r
fa25cf38
MK
2132 //\r
2133 // Write fixed MTRRs that have been modified\r
2134 //\r
2135 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
2136 if (FixedSettingsModified[Index]) {\r
2137 if (!MtrrContextValid) {\r
b8f01599 2138 MtrrLibPreMtrrChange (&MtrrContext);\r
fa25cf38
MK
2139 MtrrContextValid = TRUE;\r
2140 }\r
2141 AsmWriteMsr64 (\r
2142 mMtrrLibFixedMtrrTable[Index].Msr,\r
2143 WorkingFixedSettings.Mtrr[Index]\r
2144 );\r
2145 }\r
2146 }\r
2147\r
b0fa5d29
MK
2148 //\r
2149 // Write variable MTRRs\r
2150 //\r
8051302a
RN
2151 for (Index = 0; Index < OriginalVariableMtrrCount; Index++) {\r
2152 if (VariableSettingModified[Index]) {\r
2153 if (!MtrrContextValid) {\r
2154 MtrrLibPreMtrrChange (&MtrrContext);\r
2155 MtrrContextValid = TRUE;\r
b0fa5d29 2156 }\r
8051302a
RN
2157 AsmWriteMsr64 (\r
2158 MSR_IA32_MTRR_PHYSBASE0 + (Index << 1),\r
2159 VariableSettings->Mtrr[Index].Base\r
2160 );\r
2161 AsmWriteMsr64 (\r
2162 MSR_IA32_MTRR_PHYSMASK0 + (Index << 1),\r
2163 VariableSettings->Mtrr[Index].Mask\r
2164 );\r
b0fa5d29
MK
2165 }\r
2166 }\r
fa25cf38 2167 if (MtrrContextValid) {\r
b8f01599 2168 MtrrLibPostMtrrChange (&MtrrContext);\r
fa25cf38
MK
2169 }\r
2170\r
85b7f65b 2171 return Status;\r
31b3597e 2172}\r
b970ed68
MK
2173\r
2174/**\r
2175 This function attempts to set the attributes for a memory range.\r
2176\r
2177 @param[in] BaseAddress The physical address that is the start\r
8051302a
RN
2178 address of a memory range.\r
2179 @param[in] Length The size in bytes of the memory range.\r
b970ed68 2180 @param[in] Attributes The bit mask of attributes to set for the\r
8051302a 2181 memory range.\r
b970ed68
MK
2182\r
2183 @retval RETURN_SUCCESS The attributes were set for the memory\r
8051302a 2184 range.\r
b970ed68
MK
2185 @retval RETURN_INVALID_PARAMETER Length is zero.\r
2186 @retval RETURN_UNSUPPORTED The processor does not support one or\r
2187 more bytes of the memory resource range\r
2188 specified by BaseAddress and Length.\r
2189 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support\r
2190 for the memory resource range specified\r
2191 by BaseAddress and Length.\r
2192 @retval RETURN_ACCESS_DENIED The attributes for the memory resource\r
2193 range specified by BaseAddress and Length\r
2194 cannot be modified.\r
2195 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to\r
2196 modify the attributes of the memory\r
2197 resource range.\r
2198\r
2199**/\r
2200RETURN_STATUS\r
2201EFIAPI\r
2202MtrrSetMemoryAttribute (\r
2203 IN PHYSICAL_ADDRESS BaseAddress,\r
2204 IN UINT64 Length,\r
2205 IN MTRR_MEMORY_CACHE_TYPE Attribute\r
2206 )\r
2207{\r
8051302a
RN
2208 RETURN_STATUS Status;\r
2209\r
2210 if (!IsMtrrSupported ()) {\r
2211 return RETURN_UNSUPPORTED;\r
2212 }\r
2213\r
2214 Status = MtrrSetMemoryAttributeWorker (NULL, BaseAddress, Length, Attribute);\r
2215 DEBUG ((DEBUG_CACHE, "MtrrSetMemoryAttribute() %a: [%016lx, %016lx) - %r\n",\r
2216 mMtrrMemoryCacheTypeShortName[Attribute], BaseAddress, BaseAddress + Length, Status));\r
2217\r
2218 if (!RETURN_ERROR (Status)) {\r
2219 MtrrDebugPrintAllMtrrsWorker (NULL);\r
2220 }\r
2221 return Status;\r
b970ed68
MK
2222}\r
2223\r
2224/**\r
2225 This function attempts to set the attributes into MTRR setting buffer for a memory range.\r
2226\r
2227 @param[in, out] MtrrSetting MTRR setting buffer to be set.\r
2228 @param[in] BaseAddress The physical address that is the start address\r
8051302a
RN
2229 of a memory range.\r
2230 @param[in] Length The size in bytes of the memory range.\r
b970ed68 2231 @param[in] Attribute The bit mask of attributes to set for the\r
8051302a 2232 memory range.\r
b970ed68 2233\r
8051302a 2234 @retval RETURN_SUCCESS The attributes were set for the memory range.\r
b970ed68
MK
2235 @retval RETURN_INVALID_PARAMETER Length is zero.\r
2236 @retval RETURN_UNSUPPORTED The processor does not support one or more bytes of the\r
2237 memory resource range specified by BaseAddress and Length.\r
2238 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support for the memory resource\r
2239 range specified by BaseAddress and Length.\r
2240 @retval RETURN_ACCESS_DENIED The attributes for the memory resource range specified by\r
2241 BaseAddress and Length cannot be modified.\r
2242 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of\r
2243 the memory resource range.\r
2244\r
2245**/\r
2246RETURN_STATUS\r
2247EFIAPI\r
2248MtrrSetMemoryAttributeInMtrrSettings (\r
2249 IN OUT MTRR_SETTINGS *MtrrSetting,\r
2250 IN PHYSICAL_ADDRESS BaseAddress,\r
2251 IN UINT64 Length,\r
2252 IN MTRR_MEMORY_CACHE_TYPE Attribute\r
2253 )\r
2254{\r
8051302a
RN
2255 RETURN_STATUS Status;\r
2256 Status = MtrrSetMemoryAttributeWorker (MtrrSetting, BaseAddress, Length, Attribute);\r
2257 DEBUG((DEBUG_CACHE, "MtrrSetMemoryAttributeMtrrSettings(%p) %a: [%016lx, %016lx) - %r\n",\r
2258 MtrrSetting, mMtrrMemoryCacheTypeShortName[Attribute], BaseAddress, BaseAddress + Length, Status));\r
2259\r
2260 if (!RETURN_ERROR (Status)) {\r
2261 MtrrDebugPrintAllMtrrsWorker (MtrrSetting);\r
2262 }\r
2263\r
2264 return Status;\r
b970ed68
MK
2265}\r
2266\r
e50466da 2267/**\r
2268 Worker function setting variable MTRRs\r
2269\r
76b4cae3 2270 @param[in] VariableSettings A buffer to hold variable MTRRs content.\r
e50466da 2271\r
2272**/\r
2273VOID\r
2274MtrrSetVariableMtrrWorker (\r
2275 IN MTRR_VARIABLE_SETTINGS *VariableSettings\r
2276 )\r
2277{\r
2278 UINT32 Index;\r
3b9be416 2279 UINT32 VariableMtrrCount;\r
e50466da 2280\r
acf431e6 2281 VariableMtrrCount = GetVariableMtrrCountWorker ();\r
5bdfa4e5 2282 ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);\r
2283\r
3b9be416 2284 for (Index = 0; Index < VariableMtrrCount; Index++) {\r
e50466da 2285 AsmWriteMsr64 (\r
2286 MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1),\r
2287 VariableSettings->Mtrr[Index].Base\r
2288 );\r
2289 AsmWriteMsr64 (\r
2290 MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1) + 1,\r
2291 VariableSettings->Mtrr[Index].Mask\r
2292 );\r
2293 }\r
2294}\r
2295\r
2296\r
2297/**\r
2298 This function sets variable MTRRs\r
2299\r
76b4cae3 2300 @param[in] VariableSettings A buffer to hold variable MTRRs content.\r
e50466da 2301\r
2302 @return The pointer of VariableSettings\r
2303\r
2304**/\r
2305MTRR_VARIABLE_SETTINGS*\r
2306EFIAPI\r
2307MtrrSetVariableMtrr (\r
2308 IN MTRR_VARIABLE_SETTINGS *VariableSettings\r
2309 )\r
2310{\r
c878cee4 2311 MTRR_CONTEXT MtrrContext;\r
e50466da 2312\r
947a573a 2313 if (!IsMtrrSupported ()) {\r
2314 return VariableSettings;\r
2315 }\r
2316\r
b8f01599 2317 MtrrLibPreMtrrChange (&MtrrContext);\r
e50466da 2318 MtrrSetVariableMtrrWorker (VariableSettings);\r
b8f01599 2319 MtrrLibPostMtrrChange (&MtrrContext);\r
e518b80d
MK
2320 MtrrDebugPrintAllMtrrs ();\r
2321\r
e50466da 2322 return VariableSettings;\r
2323}\r
2324\r
e50466da 2325/**\r
2326 Worker function setting fixed MTRRs\r
2327\r
acf431e6 2328 @param[in] FixedSettings A buffer to hold fixed MTRRs content.\r
e50466da 2329\r
2330**/\r
2331VOID\r
2332MtrrSetFixedMtrrWorker (\r
2333 IN MTRR_FIXED_SETTINGS *FixedSettings\r
2334 )\r
2335{\r
2336 UINT32 Index;\r
2337\r
2338 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
2339 AsmWriteMsr64 (\r
f877f300 2340 mMtrrLibFixedMtrrTable[Index].Msr,\r
e50466da 2341 FixedSettings->Mtrr[Index]\r
2342 );\r
2343 }\r
2344}\r
2345\r
2346\r
2347/**\r
2348 This function sets fixed MTRRs\r
2349\r
acf431e6 2350 @param[in] FixedSettings A buffer to hold fixed MTRRs content.\r
e50466da 2351\r
2352 @retval The pointer of FixedSettings\r
2353\r
2354**/\r
2355MTRR_FIXED_SETTINGS*\r
2356EFIAPI\r
2357MtrrSetFixedMtrr (\r
2358 IN MTRR_FIXED_SETTINGS *FixedSettings\r
2359 )\r
2360{\r
c878cee4 2361 MTRR_CONTEXT MtrrContext;\r
e50466da 2362\r
947a573a 2363 if (!IsMtrrSupported ()) {\r
2364 return FixedSettings;\r
2365 }\r
2366\r
b8f01599 2367 MtrrLibPreMtrrChange (&MtrrContext);\r
e50466da 2368 MtrrSetFixedMtrrWorker (FixedSettings);\r
b8f01599 2369 MtrrLibPostMtrrChange (&MtrrContext);\r
e518b80d 2370 MtrrDebugPrintAllMtrrs ();\r
e50466da 2371\r
2372 return FixedSettings;\r
2373}\r
2374\r
2375\r
2376/**\r
2377 This function gets the content in all MTRRs (variable and fixed)\r
2378\r
acf431e6 2379 @param[out] MtrrSetting A buffer to hold all MTRRs content.\r
e50466da 2380\r
2381 @retval the pointer of MtrrSetting\r
2382\r
2383**/\r
2384MTRR_SETTINGS *\r
2385EFIAPI\r
2386MtrrGetAllMtrrs (\r
2387 OUT MTRR_SETTINGS *MtrrSetting\r
2388 )\r
2389{\r
947a573a 2390 if (!IsMtrrSupported ()) {\r
2391 return MtrrSetting;\r
2392 }\r
2393\r
e50466da 2394 //\r
2395 // Get fixed MTRRs\r
2396 //\r
acf431e6 2397 MtrrGetFixedMtrrWorker (&MtrrSetting->Fixed);\r
e50466da 2398\r
2399 //\r
2400 // Get variable MTRRs\r
2401 //\r
acf431e6 2402 MtrrGetVariableMtrrWorker (\r
5abd5ed4 2403 NULL,\r
acf431e6
MK
2404 GetVariableMtrrCountWorker (),\r
2405 &MtrrSetting->Variables\r
2406 );\r
e50466da 2407\r
2408 //\r
2409 // Get MTRR_DEF_TYPE value\r
2410 //\r
2411 MtrrSetting->MtrrDefType = AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE);\r
2412\r
2413 return MtrrSetting;\r
2414}\r
2415\r
2416\r
2417/**\r
2418 This function sets all MTRRs (variable and fixed)\r
2419\r
76b4cae3 2420 @param[in] MtrrSetting A buffer holding all MTRRs content.\r
e50466da 2421\r
2422 @retval The pointer of MtrrSetting\r
2423\r
2424**/\r
2425MTRR_SETTINGS *\r
2426EFIAPI\r
2427MtrrSetAllMtrrs (\r
2428 IN MTRR_SETTINGS *MtrrSetting\r
2429 )\r
2430{\r
c878cee4 2431 MTRR_CONTEXT MtrrContext;\r
e50466da 2432\r
947a573a 2433 if (!IsMtrrSupported ()) {\r
2434 return MtrrSetting;\r
2435 }\r
2436\r
b8f01599 2437 MtrrLibPreMtrrChange (&MtrrContext);\r
e50466da 2438\r
2439 //\r
2440 // Set fixed MTRRs\r
2441 //\r
2442 MtrrSetFixedMtrrWorker (&MtrrSetting->Fixed);\r
2443\r
2444 //\r
2445 // Set variable MTRRs\r
2446 //\r
2447 MtrrSetVariableMtrrWorker (&MtrrSetting->Variables);\r
2448\r
2449 //\r
2450 // Set MTRR_DEF_TYPE value\r
2451 //\r
2452 AsmWriteMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE, MtrrSetting->MtrrDefType);\r
2453\r
b8f01599 2454 MtrrLibPostMtrrChangeEnableCache (&MtrrContext);\r
e50466da 2455\r
2456 return MtrrSetting;\r
2457}\r
2458\r
e518b80d 2459\r
947a573a 2460/**\r
2461 Checks if MTRR is supported.\r
2462\r
2463 @retval TRUE MTRR is supported.\r
2464 @retval FALSE MTRR is not supported.\r
2465\r
2466**/\r
2467BOOLEAN\r
2468EFIAPI\r
2469IsMtrrSupported (\r
2470 VOID\r
2471 )\r
2472{\r
3bb13d35
RN
2473 CPUID_VERSION_INFO_EDX Edx;\r
2474 MSR_IA32_MTRRCAP_REGISTER MtrrCap;\r
947a573a 2475\r
2476 //\r
2477 // Check CPUID(1).EDX[12] for MTRR capability\r
2478 //\r
3bb13d35
RN
2479 AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &Edx.Uint32);\r
2480 if (Edx.Bits.MTRR == 0) {\r
947a573a 2481 return FALSE;\r
2482 }\r
2483\r
2484 //\r
3bb13d35
RN
2485 // Check number of variable MTRRs and fixed MTRRs existence.\r
2486 // If number of variable MTRRs is zero, or fixed MTRRs do not\r
947a573a 2487 // exist, return false.\r
2488 //\r
3bb13d35
RN
2489 MtrrCap.Uint64 = AsmReadMsr64 (MSR_IA32_MTRRCAP);\r
2490 if ((MtrrCap.Bits.VCNT == 0) || (MtrrCap.Bits.FIX == 0)) {\r
947a573a 2491 return FALSE;\r
2492 }\r
947a573a 2493 return TRUE;\r
2494}\r
8051302a 2495\r