]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/Library/MtrrLib/MtrrLib.c
UefiCpuPkg/MtrrLib: Refine MtrrGetMemoryAttributeByAddressWorker
[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
10c361ad
RN
571 @param[in] VariableSettings The variable MTRR values to shadow\r
572 @param[in] VariableMtrrCount The number of variable MTRRs\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
d0baed7d 576\r
10c361ad 577 @return Number of MTRRs which has been used.\r
d0baed7d
MK
578\r
579**/\r
580UINT32\r
581MtrrGetMemoryAttributeInVariableMtrrWorker (\r
582 IN MTRR_VARIABLE_SETTINGS *VariableSettings,\r
10c361ad 583 IN UINTN VariableMtrrCount,\r
d0baed7d
MK
584 IN UINT64 MtrrValidBitsMask,\r
585 IN UINT64 MtrrValidAddressMask,\r
586 OUT VARIABLE_MTRR *VariableMtrr\r
587 )\r
588{\r
589 UINTN Index;\r
590 UINT32 UsedMtrr;\r
591\r
592 ZeroMem (VariableMtrr, sizeof (VARIABLE_MTRR) * MTRR_NUMBER_OF_VARIABLE_MTRR);\r
10c361ad 593 for (Index = 0, UsedMtrr = 0; Index < VariableMtrrCount; Index++) {\r
d0baed7d
MK
594 if ((VariableSettings->Mtrr[Index].Mask & MTRR_LIB_CACHE_MTRR_ENABLED) != 0) {\r
595 VariableMtrr[Index].Msr = (UINT32)Index;\r
596 VariableMtrr[Index].BaseAddress = (VariableSettings->Mtrr[Index].Base & MtrrValidAddressMask);\r
597 VariableMtrr[Index].Length = ((~(VariableSettings->Mtrr[Index].Mask & MtrrValidAddressMask)) & MtrrValidBitsMask) + 1;\r
598 VariableMtrr[Index].Type = (VariableSettings->Mtrr[Index].Base & 0x0ff);\r
599 VariableMtrr[Index].Valid = TRUE;\r
600 VariableMtrr[Index].Used = TRUE;\r
601 UsedMtrr++;\r
602 }\r
603 }\r
604 return UsedMtrr;\r
605}\r
606\r
607\r
e50466da 608/**\r
76b4cae3 609 Gets the attribute of variable MTRRs.\r
e50466da 610\r
3ba736f3
JY
611 This function shadows the content of variable MTRRs into an\r
612 internal array: VariableMtrr.\r
e50466da 613\r
76b4cae3
MK
614 @param[in] MtrrValidBitsMask The mask for the valid bit of the MTRR\r
615 @param[in] MtrrValidAddressMask The valid address mask for MTRR\r
616 @param[out] VariableMtrr The array to shadow variable MTRRs content\r
e50466da 617\r
438f1766 618 @return The return value of this parameter indicates the\r
3ba736f3 619 number of MTRRs which has been used.\r
e50466da 620\r
621**/\r
3ba736f3 622UINT32\r
e50466da 623EFIAPI\r
624MtrrGetMemoryAttributeInVariableMtrr (\r
625 IN UINT64 MtrrValidBitsMask,\r
626 IN UINT64 MtrrValidAddressMask,\r
627 OUT VARIABLE_MTRR *VariableMtrr\r
628 )\r
629{\r
d0baed7d 630 MTRR_VARIABLE_SETTINGS VariableSettings;\r
3b9be416 631\r
947a573a 632 if (!IsMtrrSupported ()) {\r
633 return 0;\r
634 }\r
635\r
d0baed7d 636 MtrrGetVariableMtrrWorker (\r
5abd5ed4 637 NULL,\r
d0baed7d
MK
638 GetVariableMtrrCountWorker (),\r
639 &VariableSettings\r
640 );\r
e50466da 641\r
d0baed7d
MK
642 return MtrrGetMemoryAttributeInVariableMtrrWorker (\r
643 &VariableSettings,\r
644 GetFirmwareVariableMtrrCountWorker (),\r
645 MtrrValidBitsMask,\r
646 MtrrValidAddressMask,\r
647 VariableMtrr\r
648 );\r
e50466da 649}\r
650\r
e50466da 651/**\r
8051302a 652 Return the least alignment of address.\r
e50466da 653\r
8051302a
RN
654 @param Address The address to return the alignment.\r
655 @param Alignment0 The alignment to return when Address is 0.\r
e50466da 656\r
8051302a 657 @return The least alignment of the Address.\r
e50466da 658**/\r
8051302a
RN
659UINT64\r
660MtrrLibLeastAlignment (\r
661 UINT64 Address,\r
662 UINT64 Alignment0\r
663)\r
e50466da 664{\r
8051302a
RN
665 if (Address == 0) {\r
666 return Alignment0;\r
e50466da 667 }\r
668\r
8051302a 669 return LShiftU64 (1, (UINTN) LowBitSet64 (Address));\r
e50466da 670}\r
671\r
e50466da 672/**\r
8051302a
RN
673 Return the number of required variable MTRRs to positively cover the\r
674 specified range.\r
e50466da 675\r
8051302a
RN
676 @param BaseAddress Base address of the range.\r
677 @param Length Length of the range.\r
678 @param Alignment0 Alignment of 0.\r
e50466da 679\r
8051302a 680 @return The number of the required variable MTRRs.\r
e50466da 681**/\r
8051302a
RN
682UINT32\r
683MtrrLibGetPositiveMtrrNumber (\r
684 IN UINT64 BaseAddress,\r
685 IN UINT64 Length,\r
686 IN UINT64 Alignment0\r
687)\r
e50466da 688{\r
8051302a
RN
689 UINT64 SubLength;\r
690 UINT32 MtrrNumber;\r
691 BOOLEAN UseLeastAlignment;\r
e50466da 692\r
8051302a 693 UseLeastAlignment = TRUE;\r
e50466da 694\r
8051302a
RN
695 //\r
696 // Calculate the alignment of the base address.\r
697 //\r
698 for (MtrrNumber = 0; Length != 0; MtrrNumber++) {\r
699 if (UseLeastAlignment) {\r
700 SubLength = MtrrLibLeastAlignment (BaseAddress, Alignment0);\r
e50466da 701\r
8051302a
RN
702 if (SubLength > Length) {\r
703 //\r
704 // Set a flag when remaining length is too small\r
705 // so that MtrrLibLeastAlignment() is not called in following loops.\r
706 //\r
707 UseLeastAlignment = FALSE;\r
e50466da 708 }\r
e50466da 709 }\r
710\r
8051302a
RN
711 if (!UseLeastAlignment) {\r
712 SubLength = GetPowerOfTwo64 (Length);\r
e50466da 713 }\r
e50466da 714\r
8051302a
RN
715 BaseAddress += SubLength;\r
716 Length -= SubLength;\r
1e60a0ec 717 }\r
718\r
8051302a 719 return MtrrNumber;\r
e50466da 720}\r
721\r
e50466da 722/**\r
8051302a 723 Return whether the left MTRR type precedes the right MTRR type.\r
76b4cae3 724\r
8051302a 725 The MTRR type precedence rules are:\r
10c361ad
RN
726 1. UC precedes any other type\r
727 2. WT precedes WB\r
728 For further details, please refer the IA32 Software Developer's Manual,\r
729 Volume 3, Section "MTRR Precedences".\r
e50466da 730\r
8051302a
RN
731 @param Left The left MTRR type.\r
732 @param Right The right MTRR type.\r
e50466da 733\r
8051302a
RN
734 @retval TRUE Left precedes Right.\r
735 @retval FALSE Left doesn't precede Right.\r
e50466da 736**/\r
8051302a
RN
737BOOLEAN\r
738MtrrLibTypeLeftPrecedeRight (\r
739 IN MTRR_MEMORY_CACHE_TYPE Left,\r
740 IN MTRR_MEMORY_CACHE_TYPE Right\r
741)\r
e50466da 742{\r
8051302a 743 return (BOOLEAN) (Left == CacheUncacheable || (Left == CacheWriteThrough && Right == CacheWriteBack));\r
e50466da 744}\r
745\r
746\r
747/**\r
8051302a
RN
748 Return whether the type of the specified range can precede the specified type.\r
749\r
750 @param Ranges Memory range array holding memory type settings for all\r
751 the memory address.\r
752 @param RangeCount Count of memory ranges.\r
753 @param Type Type to check precedence.\r
754 @param SubBase Base address of the specified range.\r
755 @param SubLength Length of the specified range.\r
756\r
757 @retval TRUE The type of the specified range can precede the Type.\r
758 @retval FALSE The type of the specified range cannot precede the Type.\r
759 So the subtraction is not applicable.\r
760**/\r
761BOOLEAN\r
762MtrrLibSubstractable (\r
763 IN CONST MEMORY_RANGE *Ranges,\r
764 IN UINT32 RangeCount,\r
765 IN MTRR_MEMORY_CACHE_TYPE Type,\r
766 IN UINT64 SubBase,\r
767 IN UINT64 SubLength\r
768)\r
769{\r
770 UINT32 Index;\r
771 UINT64 Length;\r
772 // WT > WB\r
773 // UC > *\r
774 for (Index = 0; Index < RangeCount; Index++) {\r
775 if (Ranges[Index].BaseAddress <= SubBase && SubBase < Ranges[Index].BaseAddress + Ranges[Index].Length) {\r
e50466da 776\r
8051302a
RN
777 if (Ranges[Index].BaseAddress + Ranges[Index].Length >= SubBase + SubLength) {\r
778 return MtrrLibTypeLeftPrecedeRight (Ranges[Index].Type, Type);\r
e50466da 779\r
8051302a
RN
780 } else {\r
781 if (!MtrrLibTypeLeftPrecedeRight (Ranges[Index].Type, Type)) {\r
782 return FALSE;\r
783 }\r
1a2ad6fc 784\r
8051302a
RN
785 Length = Ranges[Index].BaseAddress + Ranges[Index].Length - SubBase;\r
786 SubBase += Length;\r
787 SubLength -= Length;\r
788 }\r
789 }\r
790 }\r
e50466da 791\r
8051302a
RN
792 ASSERT (FALSE);\r
793 return FALSE;\r
794}\r
e50466da 795\r
8051302a
RN
796/**\r
797 Return the number of required variable MTRRs to cover the specified range.\r
798\r
799 The routine considers subtraction in the both side of the range to find out\r
800 the most optimal solution (which uses the least MTRRs).\r
801\r
802 @param Ranges Array holding memory type settings of all memory\r
803 address.\r
804 @param RangeCount Count of memory ranges.\r
805 @param VariableMtrr Array holding allocated variable MTRRs.\r
806 @param VariableMtrrCount Count of allocated variable MTRRs.\r
807 @param BaseAddress Base address of the specified range.\r
808 @param Length Length of the specified range.\r
809 @param Type MTRR type of the specified range.\r
810 @param Alignment0 Alignment of 0.\r
811 @param SubLeft Return the count of left subtraction.\r
812 @param SubRight Return the count of right subtraction.\r
813\r
814 @return Number of required variable MTRRs.\r
e50466da 815**/\r
8051302a
RN
816UINT32\r
817MtrrLibGetMtrrNumber (\r
818 IN CONST MEMORY_RANGE *Ranges,\r
819 IN UINT32 RangeCount,\r
820 IN CONST VARIABLE_MTRR *VariableMtrr,\r
821 IN UINT32 VariableMtrrCount,\r
822 IN UINT64 BaseAddress,\r
823 IN UINT64 Length,\r
824 IN MTRR_MEMORY_CACHE_TYPE Type,\r
825 IN UINT64 Alignment0,\r
826 OUT UINT32 *SubLeft, // subtractive from BaseAddress to get more aligned address, to save MTRR\r
827 OUT UINT32 *SubRight // subtractive from BaseAddress + Length, to save MTRR\r
828)\r
e50466da 829{\r
1a2ad6fc 830 UINT64 Alignment;\r
8051302a
RN
831 UINT32 LeastLeftMtrrNumber;\r
832 UINT32 MiddleMtrrNumber;\r
833 UINT32 LeastRightMtrrNumber;\r
834 UINT32 CurrentMtrrNumber;\r
835 UINT32 SubtractiveCount;\r
836 UINT32 SubtractiveMtrrNumber;\r
837 UINT32 LeastSubtractiveMtrrNumber;\r
838 UINT64 SubtractiveBaseAddress;\r
839 UINT64 SubtractiveLength;\r
840 UINT64 BaseAlignment;\r
841 UINT32 Index;\r
e50466da 842\r
8051302a
RN
843 *SubLeft = 0;\r
844 *SubRight = 0;\r
845 LeastSubtractiveMtrrNumber = 0;\r
1a2ad6fc 846\r
8051302a
RN
847 //\r
848 // Get the optimal left subtraction solution.\r
849 //\r
1a2ad6fc 850 if (BaseAddress != 0) {\r
8051302a
RN
851 //\r
852 // Get the MTRR number needed without left subtraction.\r
853 //\r
854 LeastLeftMtrrNumber = MtrrLibGetPositiveMtrrNumber (BaseAddress, Length, Alignment0);\r
855\r
856 //\r
857 // Left subtraction bit by bit, to find the optimal left subtraction solution.\r
858 //\r
859 for (SubtractiveMtrrNumber = 0, SubtractiveCount = 1; BaseAddress != 0; SubtractiveCount++) {\r
860 Alignment = MtrrLibLeastAlignment (BaseAddress, Alignment0);\r
861\r
1a2ad6fc 862 //\r
8051302a
RN
863 // Check whether the memory type of [BaseAddress - Alignment, BaseAddress) can override Type.\r
864 // IA32 Manual defines the following override rules:\r
865 // WT > WB\r
866 // UC > * (any)\r
1a2ad6fc 867 //\r
8051302a 868 if (!MtrrLibSubstractable (Ranges, RangeCount, Type, BaseAddress - Alignment, Alignment)) {\r
1a2ad6fc 869 break;\r
870 }\r
871\r
8051302a
RN
872 for (Index = 0; Index < VariableMtrrCount; Index++) {\r
873 if ((VariableMtrr[Index].BaseAddress == BaseAddress - Alignment) &&\r
874 (VariableMtrr[Index].Length == Alignment)) {\r
875 break;\r
876 }\r
877 }\r
878 if (Index == VariableMtrrCount) {\r
879 //\r
880 // Increment SubtractiveMtrrNumber when [BaseAddress - Alignment, BaseAddress) is not be planed as a MTRR\r
881 //\r
882 SubtractiveMtrrNumber++;\r
883 }\r
e50466da 884\r
8051302a
RN
885 BaseAddress -= Alignment;\r
886 Length += Alignment;\r
e50466da 887\r
8051302a
RN
888 CurrentMtrrNumber = SubtractiveMtrrNumber + MtrrLibGetPositiveMtrrNumber (BaseAddress, Length, Alignment0);\r
889 if (CurrentMtrrNumber <= LeastLeftMtrrNumber) {\r
890 LeastLeftMtrrNumber = CurrentMtrrNumber;\r
891 LeastSubtractiveMtrrNumber = SubtractiveMtrrNumber;\r
892 *SubLeft = SubtractiveCount;\r
893 SubtractiveBaseAddress = BaseAddress;\r
894 SubtractiveLength = Length;\r
895 }\r
896 }\r
e50466da 897\r
8051302a
RN
898 //\r
899 // If left subtraction is better, subtract BaseAddress to left, and enlarge Length\r
900 //\r
901 if (*SubLeft != 0) {\r
902 BaseAddress = SubtractiveBaseAddress;\r
903 Length = SubtractiveLength;\r
904 }\r
e50466da 905 }\r
e50466da 906\r
8051302a
RN
907 //\r
908 // Increment BaseAddress greedily until (BaseAddress + Alignment) exceeds (BaseAddress + Length)\r
909 //\r
910 MiddleMtrrNumber = 0;\r
911 while (Length != 0) {\r
912 BaseAlignment = MtrrLibLeastAlignment (BaseAddress, Alignment0);\r
913 if (BaseAlignment > Length) {\r
914 break;\r
e50466da 915 }\r
8051302a
RN
916 BaseAddress += BaseAlignment;\r
917 Length -= BaseAlignment;\r
918 MiddleMtrrNumber++;\r
e50466da 919 }\r
e50466da 920\r
921\r
8051302a
RN
922 if (Length == 0) {\r
923 return LeastSubtractiveMtrrNumber + MiddleMtrrNumber;\r
924 }\r
e50466da 925\r
e50466da 926\r
927 //\r
8051302a 928 // Get the optimal right subtraction solution.\r
e50466da 929 //\r
e50466da 930\r
931 //\r
8051302a 932 // Get the MTRR number needed without right subtraction.\r
e50466da 933 //\r
8051302a
RN
934 LeastRightMtrrNumber = MtrrLibGetPositiveMtrrNumber (BaseAddress, Length, Alignment0);\r
935\r
936 for (SubtractiveCount = 1; Length < BaseAlignment; SubtractiveCount++) {\r
937 Alignment = MtrrLibLeastAlignment (BaseAddress + Length, Alignment0);\r
938 if (!MtrrLibSubstractable (Ranges, RangeCount, Type, BaseAddress + Length, Alignment)) {\r
939 break;\r
940 }\r
941\r
942 Length += Alignment;\r
943\r
944 //\r
945 // SubtractiveCount = Number of MTRRs used for subtraction\r
946 //\r
947 CurrentMtrrNumber = SubtractiveCount + MtrrLibGetPositiveMtrrNumber (BaseAddress, Length, Alignment0);\r
948 if (CurrentMtrrNumber <= LeastRightMtrrNumber) {\r
949 LeastRightMtrrNumber = CurrentMtrrNumber;\r
950 *SubRight = SubtractiveCount;\r
951 SubtractiveLength = Length;\r
952 }\r
953 }\r
954\r
955 return LeastSubtractiveMtrrNumber + MiddleMtrrNumber + LeastRightMtrrNumber;\r
e50466da 956}\r
957\r
e50466da 958/**\r
959 Initializes the valid bits mask and valid address mask for MTRRs.\r
960\r
961 This function initializes the valid bits mask and valid address mask for MTRRs.\r
962\r
76b4cae3
MK
963 @param[out] MtrrValidBitsMask The mask for the valid bit of the MTRR\r
964 @param[out] MtrrValidAddressMask The valid address mask for the MTRR\r
e50466da 965\r
966**/\r
e50466da 967VOID\r
968MtrrLibInitializeMtrrMask (\r
969 OUT UINT64 *MtrrValidBitsMask,\r
970 OUT UINT64 *MtrrValidAddressMask\r
971 )\r
972{\r
012f4054
RN
973 UINT32 MaxExtendedFunction;\r
974 CPUID_VIR_PHY_ADDRESS_SIZE_EAX VirPhyAddressSize;\r
e50466da 975\r
e50466da 976\r
012f4054 977 AsmCpuid (CPUID_EXTENDED_FUNCTION, &MaxExtendedFunction, NULL, NULL, NULL);\r
e50466da 978\r
012f4054
RN
979 if (MaxExtendedFunction >= CPUID_VIR_PHY_ADDRESS_SIZE) {\r
980 AsmCpuid (CPUID_VIR_PHY_ADDRESS_SIZE, &VirPhyAddressSize.Uint32, NULL, NULL, NULL);\r
e50466da 981 } else {\r
012f4054 982 VirPhyAddressSize.Bits.PhysicalAddressBits = 36;\r
e50466da 983 }\r
012f4054
RN
984\r
985 *MtrrValidBitsMask = LShiftU64 (1, VirPhyAddressSize.Bits.PhysicalAddressBits) - 1;\r
986 *MtrrValidAddressMask = *MtrrValidBitsMask & 0xfffffffffffff000ULL;\r
e50466da 987}\r
988\r
989\r
990/**\r
76b4cae3 991 Determines the real attribute of a memory range.\r
e50466da 992\r
993 This function is to arbitrate the real attribute of the memory when\r
10c361ad 994 there are 2 MTRRs covers the same memory range. For further details,\r
e50466da 995 please refer the IA32 Software Developer's Manual, Volume 3,\r
10c361ad 996 Section "MTRR Precedences".\r
e50466da 997\r
76b4cae3
MK
998 @param[in] MtrrType1 The first kind of Memory type\r
999 @param[in] MtrrType2 The second kind of memory type\r
e50466da 1000\r
1001**/\r
10c361ad 1002MTRR_MEMORY_CACHE_TYPE\r
b8f01599 1003MtrrLibPrecedence (\r
10c361ad
RN
1004 IN MTRR_MEMORY_CACHE_TYPE MtrrType1,\r
1005 IN MTRR_MEMORY_CACHE_TYPE MtrrType2\r
e50466da 1006 )\r
1007{\r
10c361ad
RN
1008 if (MtrrType1 == MtrrType2) {\r
1009 return MtrrType1;\r
e50466da 1010 }\r
1011\r
10c361ad
RN
1012 ASSERT (\r
1013 MtrrLibTypeLeftPrecedeRight (MtrrType1, MtrrType2) ||\r
1014 MtrrLibTypeLeftPrecedeRight (MtrrType2, MtrrType1)\r
1015 );\r
1016\r
1017 if (MtrrLibTypeLeftPrecedeRight (MtrrType1, MtrrType2)) {\r
1018 return MtrrType1;\r
1019 } else {\r
1020 return MtrrType2;\r
e50466da 1021 }\r
e50466da 1022}\r
1023\r
e50466da 1024/**\r
5abd5ed4 1025 Worker function will get the memory cache type of the specific address.\r
e50466da 1026\r
5abd5ed4
MK
1027 If MtrrSetting is not NULL, gets the memory cache type from input\r
1028 MTRR settings buffer.\r
1029 If MtrrSetting is NULL, gets the memory cache type from MTRRs.\r
e50466da 1030\r
5abd5ed4 1031 @param[in] MtrrSetting A buffer holding all MTRRs content.\r
85b7f65b
MK
1032 @param[in] Address The specific address\r
1033\r
1034 @return Memory cache type of the specific address\r
e50466da 1035\r
1036**/\r
85b7f65b 1037MTRR_MEMORY_CACHE_TYPE\r
5abd5ed4
MK
1038MtrrGetMemoryAttributeByAddressWorker (\r
1039 IN MTRR_SETTINGS *MtrrSetting,\r
85b7f65b 1040 IN PHYSICAL_ADDRESS Address\r
e50466da 1041 )\r
1042{\r
10c361ad
RN
1043 MSR_IA32_MTRR_DEF_TYPE_REGISTER DefType;\r
1044 UINT64 FixedMtrr;\r
1045 UINTN Index;\r
1046 UINTN SubIndex;\r
1047 MTRR_MEMORY_CACHE_TYPE MtrrType;\r
1048 VARIABLE_MTRR VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];\r
1049 UINT64 MtrrValidBitsMask;\r
1050 UINT64 MtrrValidAddressMask;\r
1051 UINT32 VariableMtrrCount;\r
1052 MTRR_VARIABLE_SETTINGS VariableSettings;\r
f877f300 1053\r
e50466da 1054 //\r
85b7f65b 1055 // Check if MTRR is enabled, if not, return UC as attribute\r
e50466da 1056 //\r
5abd5ed4 1057 if (MtrrSetting == NULL) {\r
10c361ad 1058 DefType.Uint64 = AsmReadMsr64 (MSR_IA32_MTRR_DEF_TYPE);\r
5abd5ed4 1059 } else {\r
10c361ad 1060 DefType.Uint64 = MtrrSetting->MtrrDefType;\r
5abd5ed4 1061 }\r
e50466da 1062\r
10c361ad 1063 if (DefType.Bits.E == 0) {\r
85b7f65b 1064 return CacheUncacheable;\r
e50466da 1065 }\r
1066\r
1067 //\r
85b7f65b 1068 // If address is less than 1M, then try to go through the fixed MTRR\r
e50466da 1069 //\r
85b7f65b 1070 if (Address < BASE_1MB) {\r
10c361ad 1071 if (DefType.Bits.FE != 0) {\r
85b7f65b
MK
1072 //\r
1073 // Go through the fixed MTRR\r
1074 //\r
1075 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
10c361ad
RN
1076 if (Address >= mMtrrLibFixedMtrrTable[Index].BaseAddress &&\r
1077 Address < mMtrrLibFixedMtrrTable[Index].BaseAddress +\r
1078 (mMtrrLibFixedMtrrTable[Index].Length * 8)) {\r
1079 SubIndex =\r
1080 ((UINTN) Address - mMtrrLibFixedMtrrTable[Index].BaseAddress) /\r
1081 mMtrrLibFixedMtrrTable[Index].Length;\r
1082 if (MtrrSetting == NULL) {\r
1083 FixedMtrr = AsmReadMsr64 (mMtrrLibFixedMtrrTable[Index].Msr);\r
1084 } else {\r
1085 FixedMtrr = MtrrSetting->Fixed.Mtrr[Index];\r
1086 }\r
1087 return (MTRR_MEMORY_CACHE_TYPE) (RShiftU64 (FixedMtrr, SubIndex * 8) & 0xFF);\r
1088 }\r
85b7f65b 1089 }\r
e50466da 1090 }\r
1091 }\r
d0baed7d 1092\r
10c361ad
RN
1093 VariableMtrrCount = GetVariableMtrrCountWorker ();\r
1094 ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);\r
1095 MtrrGetVariableMtrrWorker (MtrrSetting, VariableMtrrCount, &VariableSettings);\r
e50466da 1096\r
10c361ad 1097 MtrrLibInitializeMtrrMask (&MtrrValidBitsMask, &MtrrValidAddressMask);\r
d0baed7d 1098 MtrrGetMemoryAttributeInVariableMtrrWorker (\r
10c361ad
RN
1099 &VariableSettings,\r
1100 VariableMtrrCount,\r
1101 MtrrValidBitsMask,\r
1102 MtrrValidAddressMask,\r
1103 VariableMtrr\r
1104 );\r
d0baed7d 1105\r
e50466da 1106 //\r
85b7f65b 1107 // Go through the variable MTRR\r
e50466da 1108 //\r
10c361ad 1109 MtrrType = CacheInvalid;\r
85b7f65b
MK
1110 for (Index = 0; Index < VariableMtrrCount; Index++) {\r
1111 if (VariableMtrr[Index].Valid) {\r
1112 if (Address >= VariableMtrr[Index].BaseAddress &&\r
10c361ad
RN
1113 Address < VariableMtrr[Index].BaseAddress + VariableMtrr[Index].Length) {\r
1114 if (MtrrType == CacheInvalid) {\r
1115 MtrrType = (MTRR_MEMORY_CACHE_TYPE) VariableMtrr[Index].Type;\r
1116 } else {\r
1117 MtrrType = MtrrLibPrecedence (MtrrType, (MTRR_MEMORY_CACHE_TYPE) VariableMtrr[Index].Type);\r
1118 }\r
85b7f65b
MK
1119 }\r
1120 }\r
e50466da 1121 }\r
1122\r
10c361ad
RN
1123 //\r
1124 // If there is no MTRR which covers the Address, use the default MTRR type.\r
1125 //\r
1126 if (MtrrType == CacheInvalid) {\r
1127 MtrrType = (MTRR_MEMORY_CACHE_TYPE) DefType.Bits.Type;\r
1128 }\r
1129\r
1130 return MtrrType;\r
85b7f65b
MK
1131}\r
1132\r
1133\r
5abd5ed4
MK
1134/**\r
1135 This function will get the memory cache type of the specific address.\r
1136\r
1137 This function is mainly for debug purpose.\r
1138\r
1139 @param[in] Address The specific address\r
1140\r
1141 @return Memory cache type of the specific address\r
1142\r
1143**/\r
1144MTRR_MEMORY_CACHE_TYPE\r
1145EFIAPI\r
1146MtrrGetMemoryAttribute (\r
1147 IN PHYSICAL_ADDRESS Address\r
1148 )\r
1149{\r
1150 if (!IsMtrrSupported ()) {\r
1151 return CacheUncacheable;\r
1152 }\r
1153\r
1154 return MtrrGetMemoryAttributeByAddressWorker (NULL, Address);\r
1155}\r
1156\r
85b7f65b 1157/**\r
16c2d37e
MK
1158 Worker function prints all MTRRs for debugging.\r
1159\r
341fea64 1160 If MtrrSetting is not NULL, print MTRR settings from input MTRR\r
16c2d37e
MK
1161 settings buffer.\r
1162 If MtrrSetting is NULL, print MTRR settings from MTRRs.\r
1163\r
1164 @param MtrrSetting A buffer holding all MTRRs content.\r
85b7f65b
MK
1165**/\r
1166VOID\r
16c2d37e
MK
1167MtrrDebugPrintAllMtrrsWorker (\r
1168 IN MTRR_SETTINGS *MtrrSetting\r
85b7f65b
MK
1169 )\r
1170{\r
1171 DEBUG_CODE (\r
16c2d37e
MK
1172 MTRR_SETTINGS LocalMtrrs;\r
1173 MTRR_SETTINGS *Mtrrs;\r
85b7f65b
MK
1174 UINTN Index;\r
1175 UINTN Index1;\r
1176 UINTN VariableMtrrCount;\r
1177 UINT64 Base;\r
1178 UINT64 Limit;\r
1179 UINT64 MtrrBase;\r
1180 UINT64 MtrrLimit;\r
1181 UINT64 RangeBase;\r
1182 UINT64 RangeLimit;\r
1183 UINT64 NoRangeBase;\r
1184 UINT64 NoRangeLimit;\r
1185 UINT32 RegEax;\r
1186 UINTN MemoryType;\r
1187 UINTN PreviousMemoryType;\r
1188 BOOLEAN Found;\r
1189\r
1190 if (!IsMtrrSupported ()) {\r
1191 return;\r
1192 }\r
1193\r
1194 DEBUG((DEBUG_CACHE, "MTRR Settings\n"));\r
1195 DEBUG((DEBUG_CACHE, "=============\n"));\r
1196\r
16c2d37e
MK
1197 if (MtrrSetting != NULL) {\r
1198 Mtrrs = MtrrSetting;\r
1199 } else {\r
1200 MtrrGetAllMtrrs (&LocalMtrrs);\r
1201 Mtrrs = &LocalMtrrs;\r
1202 }\r
1203\r
1204 DEBUG((DEBUG_CACHE, "MTRR Default Type: %016lx\n", Mtrrs->MtrrDefType));\r
85b7f65b 1205 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
16c2d37e 1206 DEBUG((DEBUG_CACHE, "Fixed MTRR[%02d] : %016lx\n", Index, Mtrrs->Fixed.Mtrr[Index]));\r
85b7f65b
MK
1207 }\r
1208\r
1209 VariableMtrrCount = GetVariableMtrrCount ();\r
1210 for (Index = 0; Index < VariableMtrrCount; Index++) {\r
1211 DEBUG((DEBUG_CACHE, "Variable MTRR[%02d]: Base=%016lx Mask=%016lx\n",\r
1212 Index,\r
16c2d37e
MK
1213 Mtrrs->Variables.Mtrr[Index].Base,\r
1214 Mtrrs->Variables.Mtrr[Index].Mask\r
85b7f65b
MK
1215 ));\r
1216 }\r
1217 DEBUG((DEBUG_CACHE, "\n"));\r
1218 DEBUG((DEBUG_CACHE, "MTRR Ranges\n"));\r
1219 DEBUG((DEBUG_CACHE, "====================================\n"));\r
1220\r
1221 Base = 0;\r
1222 PreviousMemoryType = MTRR_CACHE_INVALID_TYPE;\r
1223 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
1224 Base = mMtrrLibFixedMtrrTable[Index].BaseAddress;\r
1225 for (Index1 = 0; Index1 < 8; Index1++) {\r
16c2d37e 1226 MemoryType = (UINTN)(RShiftU64 (Mtrrs->Fixed.Mtrr[Index], Index1 * 8) & 0xff);\r
85b7f65b
MK
1227 if (MemoryType > CacheWriteBack) {\r
1228 MemoryType = MTRR_CACHE_INVALID_TYPE;\r
1229 }\r
1230 if (MemoryType != PreviousMemoryType) {\r
1231 if (PreviousMemoryType != MTRR_CACHE_INVALID_TYPE) {\r
1232 DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));\r
1233 }\r
1234 PreviousMemoryType = MemoryType;\r
1235 DEBUG((DEBUG_CACHE, "%a:%016lx-", mMtrrMemoryCacheTypeShortName[MemoryType], Base));\r
1236 }\r
1237 Base += mMtrrLibFixedMtrrTable[Index].Length;\r
1238 }\r
1239 }\r
1240 DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));\r
1241\r
1242 VariableMtrrCount = GetVariableMtrrCount ();\r
1243\r
1244 Limit = BIT36 - 1;\r
1245 AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);\r
1246 if (RegEax >= 0x80000008) {\r
1247 AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);\r
1248 Limit = LShiftU64 (1, RegEax & 0xff) - 1;\r
1249 }\r
1250 Base = BASE_1MB;\r
1251 PreviousMemoryType = MTRR_CACHE_INVALID_TYPE;\r
1252 do {\r
16c2d37e 1253 MemoryType = MtrrGetMemoryAttributeByAddressWorker (Mtrrs, Base);\r
85b7f65b
MK
1254 if (MemoryType > CacheWriteBack) {\r
1255 MemoryType = MTRR_CACHE_INVALID_TYPE;\r
1256 }\r
1257\r
1258 if (MemoryType != PreviousMemoryType) {\r
1259 if (PreviousMemoryType != MTRR_CACHE_INVALID_TYPE) {\r
1260 DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));\r
1261 }\r
1262 PreviousMemoryType = MemoryType;\r
1263 DEBUG((DEBUG_CACHE, "%a:%016lx-", mMtrrMemoryCacheTypeShortName[MemoryType], Base));\r
1264 }\r
1265\r
1266 RangeBase = BASE_1MB;\r
1267 NoRangeBase = BASE_1MB;\r
1268 RangeLimit = Limit;\r
1269 NoRangeLimit = Limit;\r
1270\r
1271 for (Index = 0, Found = FALSE; Index < VariableMtrrCount; Index++) {\r
16c2d37e 1272 if ((Mtrrs->Variables.Mtrr[Index].Mask & BIT11) == 0) {\r
85b7f65b
MK
1273 //\r
1274 // If mask is not valid, then do not display range\r
1275 //\r
1276 continue;\r
1277 }\r
16c2d37e
MK
1278 MtrrBase = (Mtrrs->Variables.Mtrr[Index].Base & (~(SIZE_4KB - 1)));\r
1279 MtrrLimit = MtrrBase + ((~(Mtrrs->Variables.Mtrr[Index].Mask & (~(SIZE_4KB - 1)))) & Limit);\r
85b7f65b
MK
1280\r
1281 if (Base >= MtrrBase && Base < MtrrLimit) {\r
1282 Found = TRUE;\r
1283 }\r
1284\r
1285 if (Base >= MtrrBase && MtrrBase > RangeBase) {\r
1286 RangeBase = MtrrBase;\r
1287 }\r
1288 if (Base > MtrrLimit && MtrrLimit > RangeBase) {\r
1289 RangeBase = MtrrLimit + 1;\r
1290 }\r
1291 if (Base < MtrrBase && MtrrBase < RangeLimit) {\r
1292 RangeLimit = MtrrBase - 1;\r
1293 }\r
1294 if (Base < MtrrLimit && MtrrLimit <= RangeLimit) {\r
1295 RangeLimit = MtrrLimit;\r
1296 }\r
1297\r
1298 if (Base > MtrrLimit && NoRangeBase < MtrrLimit) {\r
1299 NoRangeBase = MtrrLimit + 1;\r
1300 }\r
1301 if (Base < MtrrBase && NoRangeLimit > MtrrBase) {\r
1302 NoRangeLimit = MtrrBase - 1;\r
1303 }\r
1304 }\r
1305\r
1306 if (Found) {\r
1307 Base = RangeLimit + 1;\r
1308 } else {\r
1309 Base = NoRangeLimit + 1;\r
1310 }\r
1311 } while (Base < Limit);\r
1312 DEBUG((DEBUG_CACHE, "%016lx\n\n", Base - 1));\r
1313 );\r
1314}\r
16c2d37e
MK
1315\r
1316\r
1317/**\r
1318 This function prints all MTRRs for debugging.\r
1319**/\r
1320VOID\r
1321EFIAPI\r
1322MtrrDebugPrintAllMtrrs (\r
1323 VOID\r
1324 )\r
1325{\r
1326 MtrrDebugPrintAllMtrrsWorker (NULL);\r
1327}\r
1328\r
8051302a
RN
1329/**\r
1330 Update the Ranges array to change the specified range identified by\r
1331 BaseAddress and Length to Type.\r
1332\r
1333 @param Ranges Array holding memory type settings for all memory regions.\r
1334 @param Capacity The maximum count of memory ranges the array can hold.\r
1335 @param Count Return the new memory range count in the array.\r
1336 @param BaseAddress The base address of the memory range to change type.\r
1337 @param Length The length of the memory range to change type.\r
1338 @param Type The new type of the specified memory range.\r
1339\r
1340 @retval RETURN_SUCCESS The type of the specified memory range is\r
1341 changed successfully.\r
1342 @retval RETURN_OUT_OF_RESOURCES The new type set causes the count of memory\r
1343 range exceeds capacity.\r
1344**/\r
1345RETURN_STATUS\r
1346MtrrLibSetMemoryType (\r
1347 IN MEMORY_RANGE *Ranges,\r
1348 IN UINT32 Capacity,\r
1349 IN OUT UINT32 *Count,\r
1350 IN UINT64 BaseAddress,\r
1351 IN UINT64 Length,\r
1352 IN MTRR_MEMORY_CACHE_TYPE Type\r
1353 )\r
1354{\r
1355 UINT32 Index;\r
1356 UINT64 Limit;\r
1357 UINT64 LengthLeft;\r
1358 UINT64 LengthRight;\r
1359 UINT32 StartIndex;\r
1360 UINT32 EndIndex;\r
1361 UINT32 DeltaCount;\r
1362\r
1363 Limit = BaseAddress + Length;\r
1364 StartIndex = *Count;\r
1365 EndIndex = *Count;\r
1366 for (Index = 0; Index < *Count; Index++) {\r
1367 if ((StartIndex == *Count) &&\r
1368 (Ranges[Index].BaseAddress <= BaseAddress) &&\r
1369 (BaseAddress < Ranges[Index].BaseAddress + Ranges[Index].Length)) {\r
1370 StartIndex = Index;\r
1371 LengthLeft = BaseAddress - Ranges[Index].BaseAddress;\r
1372 }\r
1373\r
1374 if ((EndIndex == *Count) &&\r
1375 (Ranges[Index].BaseAddress < Limit) &&\r
1376 (Limit <= Ranges[Index].BaseAddress + Ranges[Index].Length)) {\r
1377 EndIndex = Index;\r
1378 LengthRight = Ranges[Index].BaseAddress + Ranges[Index].Length - Limit;\r
1379 break;\r
1380 }\r
1381 }\r
1382\r
1383 ASSERT (StartIndex != *Count && EndIndex != *Count);\r
1384 if (StartIndex == EndIndex && Ranges[StartIndex].Type == Type) {\r
1385 return RETURN_SUCCESS;\r
1386 }\r
1387\r
1388 //\r
1389 // The type change may cause merging with previous range or next range.\r
1390 // Update the StartIndex, EndIndex, BaseAddress, Length so that following\r
1391 // logic doesn't need to consider merging.\r
1392 //\r
1393 if (StartIndex != 0) {\r
1394 if (LengthLeft == 0 && Ranges[StartIndex - 1].Type == Type) {\r
1395 StartIndex--;\r
1396 Length += Ranges[StartIndex].Length;\r
1397 BaseAddress -= Ranges[StartIndex].Length;\r
1398 }\r
1399 }\r
1400 if (EndIndex != (*Count) - 1) {\r
1401 if (LengthRight == 0 && Ranges[EndIndex + 1].Type == Type) {\r
1402 EndIndex++;\r
1403 Length += Ranges[EndIndex].Length;\r
1404 }\r
1405 }\r
1406\r
1407 //\r
1408 // |- 0 -|- 1 -|- 2 -|- 3 -| StartIndex EndIndex DeltaCount Count (Count = 4)\r
1409 // |++++++++++++++++++| 0 3 1=3-0-2 3\r
1410 // |+++++++| 0 1 -1=1-0-2 5\r
1411 // |+| 0 0 -2=0-0-2 6\r
1412 // |+++| 0 0 -1=0-0-2+1 5\r
1413 //\r
1414 //\r
1415 DeltaCount = EndIndex - StartIndex - 2;\r
1416 if (LengthLeft == 0) {\r
1417 DeltaCount++;\r
1418 }\r
1419 if (LengthRight == 0) {\r
1420 DeltaCount++;\r
1421 }\r
1422 if (*Count - DeltaCount > Capacity) {\r
1423 return RETURN_OUT_OF_RESOURCES;\r
1424 }\r
1425\r
1426 //\r
1427 // Reserve (-DeltaCount) space\r
1428 //\r
1429 CopyMem (&Ranges[EndIndex + 1 - DeltaCount], &Ranges[EndIndex + 1], (*Count - EndIndex - 1) * sizeof (Ranges[0]));\r
1430 *Count -= DeltaCount;\r
1431\r
1432 if (LengthLeft != 0) {\r
1433 Ranges[StartIndex].Length = LengthLeft;\r
1434 StartIndex++;\r
1435 }\r
1436 if (LengthRight != 0) {\r
1437 Ranges[EndIndex - DeltaCount].BaseAddress = BaseAddress + Length;\r
1438 Ranges[EndIndex - DeltaCount].Length = LengthRight;\r
1439 Ranges[EndIndex - DeltaCount].Type = Ranges[EndIndex].Type;\r
1440 }\r
1441 Ranges[StartIndex].BaseAddress = BaseAddress;\r
1442 Ranges[StartIndex].Length = Length;\r
1443 Ranges[StartIndex].Type = Type;\r
1444 return RETURN_SUCCESS;\r
1445}\r
1446\r
1447/**\r
1448 Allocate one or more variable MTRR to cover the range identified by\r
1449 BaseAddress and Length.\r
1450\r
1451 @param Ranges Memory range array holding the memory type\r
1452 settings for all memory address.\r
1453 @param RangeCount Count of memory ranges.\r
1454 @param VariableMtrr Variable MTRR array.\r
1455 @param VariableMtrrCapacity Capacity of variable MTRR array.\r
1456 @param VariableMtrrCount Count of variable MTRR.\r
1457 @param BaseAddress Base address of the memory range.\r
1458 @param Length Length of the memory range.\r
1459 @param Type MTRR type of the memory range.\r
1460 @param Alignment0 Alignment of 0.\r
1461\r
1462 @retval RETURN_SUCCESS Variable MTRRs are allocated successfully.\r
1463 @retval RETURN_OUT_OF_RESOURCES Count of variable MTRRs exceeds capacity.\r
1464**/\r
1465RETURN_STATUS\r
1466MtrrLibSetMemoryAttributeInVariableMtrr (\r
1467 IN CONST MEMORY_RANGE *Ranges,\r
1468 IN UINT32 RangeCount,\r
1469 IN OUT VARIABLE_MTRR *VariableMtrr,\r
1470 IN UINT32 VariableMtrrCapacity,\r
1471 IN OUT UINT32 *VariableMtrrCount,\r
1472 IN UINT64 BaseAddress,\r
1473 IN UINT64 Length,\r
1474 IN MTRR_MEMORY_CACHE_TYPE Type,\r
1475 IN UINT64 Alignment0\r
1476 );\r
1477\r
1478/**\r
1479 Allocate one or more variable MTRR to cover the range identified by\r
1480 BaseAddress and Length.\r
1481\r
1482 The routine recursively calls MtrrLibSetMemoryAttributeInVariableMtrr()\r
1483 to allocate variable MTRRs when the range contains several sub-ranges\r
1484 with different attributes.\r
1485\r
1486 @param Ranges Memory range array holding the memory type\r
1487 settings for all memory address.\r
1488 @param RangeCount Count of memory ranges.\r
1489 @param VariableMtrr Variable MTRR array.\r
1490 @param VariableMtrrCapacity Capacity of variable MTRR array.\r
1491 @param VariableMtrrCount Count of variable MTRR.\r
1492 @param BaseAddress Base address of the memory range.\r
1493 @param Length Length of the memory range.\r
1494 @param Type MTRR type of the range.\r
1495 If it's CacheInvalid, the memory range may\r
1496 contains several sub-ranges with different\r
1497 attributes.\r
1498 @param Alignment0 Alignment of 0.\r
1499\r
1500 @retval RETURN_SUCCESS Variable MTRRs are allocated successfully.\r
1501 @retval RETURN_OUT_OF_RESOURCES Count of variable MTRRs exceeds capacity.\r
1502**/\r
1503RETURN_STATUS\r
1504MtrrLibAddVariableMtrr (\r
1505 IN CONST MEMORY_RANGE *Ranges,\r
1506 IN UINT32 RangeCount,\r
1507 IN OUT VARIABLE_MTRR *VariableMtrr,\r
1508 IN UINT32 VariableMtrrCapacity,\r
1509 IN OUT UINT32 *VariableMtrrCount,\r
1510 IN PHYSICAL_ADDRESS BaseAddress,\r
1511 IN UINT64 Length,\r
1512 IN MTRR_MEMORY_CACHE_TYPE Type,\r
1513 IN UINT64 Alignment0\r
1514)\r
1515{\r
1516 RETURN_STATUS Status;\r
1517 UINT32 Index;\r
1518 UINT64 SubLength;\r
1519\r
1520 MTRR_LIB_ASSERT_ALIGNED (BaseAddress, Length);\r
1521 if (Type == CacheInvalid) {\r
1522 for (Index = 0; Index < RangeCount; Index++) {\r
1523 if (Ranges[Index].BaseAddress <= BaseAddress && BaseAddress < Ranges[Index].BaseAddress + Ranges[Index].Length) {\r
1524\r
1525 //\r
1526 // Because the Length may not be aligned to BaseAddress, below code calls\r
1527 // MtrrLibSetMemoryAttributeInVariableMtrr() instead of itself.\r
1528 // MtrrLibSetMemoryAttributeInVariableMtrr() splits the range to several\r
1529 // aligned ranges.\r
1530 //\r
1531 if (Ranges[Index].BaseAddress + Ranges[Index].Length >= BaseAddress + Length) {\r
1532 return MtrrLibSetMemoryAttributeInVariableMtrr (\r
1533 Ranges, RangeCount, VariableMtrr, VariableMtrrCapacity, VariableMtrrCount,\r
1534 BaseAddress, Length, Ranges[Index].Type, Alignment0\r
1535 );\r
1536 } else {\r
1537 SubLength = Ranges[Index].BaseAddress + Ranges[Index].Length - BaseAddress;\r
1538 Status = MtrrLibSetMemoryAttributeInVariableMtrr (\r
1539 Ranges, RangeCount, VariableMtrr, VariableMtrrCapacity, VariableMtrrCount,\r
1540 BaseAddress, SubLength, Ranges[Index].Type, Alignment0\r
1541 );\r
1542 if (RETURN_ERROR (Status)) {\r
1543 return Status;\r
1544 }\r
1545 BaseAddress += SubLength;\r
1546 Length -= SubLength;\r
1547 }\r
1548 }\r
1549 }\r
1550\r
1551 //\r
1552 // Because memory ranges cover all the memory addresses, it's impossible to be here.\r
1553 //\r
1554 ASSERT (FALSE);\r
1555 return RETURN_DEVICE_ERROR;\r
1556 } else {\r
1557 for (Index = 0; Index < *VariableMtrrCount; Index++) {\r
1558 if (VariableMtrr[Index].BaseAddress == BaseAddress && VariableMtrr[Index].Length == Length) {\r
1559 ASSERT (VariableMtrr[Index].Type == Type);\r
1560 break;\r
1561 }\r
1562 }\r
1563 if (Index == *VariableMtrrCount) {\r
1564 if (*VariableMtrrCount == VariableMtrrCapacity) {\r
1565 return RETURN_OUT_OF_RESOURCES;\r
1566 }\r
1567 VariableMtrr[Index].BaseAddress = BaseAddress;\r
1568 VariableMtrr[Index].Length = Length;\r
1569 VariableMtrr[Index].Type = Type;\r
1570 VariableMtrr[Index].Valid = TRUE;\r
1571 VariableMtrr[Index].Used = TRUE;\r
1572 (*VariableMtrrCount)++;\r
1573 }\r
1574 return RETURN_SUCCESS;\r
1575 }\r
1576}\r
1577\r
1578/**\r
1579 Allocate one or more variable MTRR to cover the range identified by\r
1580 BaseAddress and Length.\r
1581\r
1582 @param Ranges Memory range array holding the memory type\r
1583 settings for all memory address.\r
1584 @param RangeCount Count of memory ranges.\r
1585 @param VariableMtrr Variable MTRR array.\r
1586 @param VariableMtrrCapacity Capacity of variable MTRR array.\r
1587 @param VariableMtrrCount Count of variable MTRR.\r
1588 @param BaseAddress Base address of the memory range.\r
1589 @param Length Length of the memory range.\r
1590 @param Type MTRR type of the memory range.\r
1591 @param Alignment0 Alignment of 0.\r
1592\r
1593 @retval RETURN_SUCCESS Variable MTRRs are allocated successfully.\r
1594 @retval RETURN_OUT_OF_RESOURCES Count of variable MTRRs exceeds capacity.\r
1595**/\r
1596RETURN_STATUS\r
1597MtrrLibSetMemoryAttributeInVariableMtrr (\r
1598 IN CONST MEMORY_RANGE *Ranges,\r
1599 IN UINT32 RangeCount,\r
1600 IN OUT VARIABLE_MTRR *VariableMtrr,\r
1601 IN UINT32 VariableMtrrCapacity,\r
1602 IN OUT UINT32 *VariableMtrrCount,\r
1603 IN UINT64 BaseAddress,\r
1604 IN UINT64 Length,\r
1605 IN MTRR_MEMORY_CACHE_TYPE Type,\r
1606 IN UINT64 Alignment0\r
1607)\r
1608{\r
1609 UINT64 Alignment;\r
1610 UINT32 MtrrNumber;\r
1611 UINT32 SubtractiveLeft;\r
1612 UINT32 SubtractiveRight;\r
1613 BOOLEAN UseLeastAlignment;\r
1614\r
1615 MtrrNumber = MtrrLibGetMtrrNumber (Ranges, RangeCount, VariableMtrr, *VariableMtrrCount,\r
1616 BaseAddress, Length, Type, Alignment0, &SubtractiveLeft, &SubtractiveRight);\r
1617\r
1618 if (MtrrNumber + *VariableMtrrCount > VariableMtrrCapacity) {\r
1619 return RETURN_OUT_OF_RESOURCES;\r
1620 }\r
1621\r
1622 while (SubtractiveLeft-- != 0) {\r
1623 Alignment = MtrrLibLeastAlignment (BaseAddress, Alignment0);\r
1624 ASSERT (Alignment <= Length);\r
1625\r
1626 MtrrLibAddVariableMtrr (Ranges, RangeCount, VariableMtrr, VariableMtrrCapacity, VariableMtrrCount,\r
1627 BaseAddress - Alignment, Alignment, CacheInvalid, Alignment0);\r
1628 BaseAddress -= Alignment;\r
1629 Length += Alignment;\r
1630 }\r
1631\r
1632 while (Length != 0) {\r
1633 Alignment = MtrrLibLeastAlignment (BaseAddress, Alignment0);\r
1634 if (Alignment > Length) {\r
1635 break;\r
1636 }\r
1637 MtrrLibAddVariableMtrr (NULL, 0, VariableMtrr, VariableMtrrCapacity, VariableMtrrCount,\r
1638 BaseAddress, Alignment, Type, Alignment0);\r
1639 BaseAddress += Alignment;\r
1640 Length -= Alignment;\r
1641 }\r
1642\r
1643 while (SubtractiveRight-- != 0) {\r
1644 Alignment = MtrrLibLeastAlignment (BaseAddress + Length, Alignment0);\r
1645 MtrrLibAddVariableMtrr (Ranges, RangeCount, VariableMtrr, VariableMtrrCapacity, VariableMtrrCount,\r
1646 BaseAddress + Length, Alignment, CacheInvalid, Alignment0);\r
1647 Length += Alignment;\r
1648 }\r
1649\r
1650 UseLeastAlignment = TRUE;\r
1651 while (Length != 0) {\r
1652 if (UseLeastAlignment) {\r
1653 Alignment = MtrrLibLeastAlignment (BaseAddress, Alignment0);\r
1654 if (Alignment > Length) {\r
1655 UseLeastAlignment = FALSE;\r
1656 }\r
1657 }\r
1658\r
1659 if (!UseLeastAlignment) {\r
1660 Alignment = GetPowerOfTwo64 (Length);\r
1661 }\r
1662\r
1663 MtrrLibAddVariableMtrr (NULL, 0, VariableMtrr, VariableMtrrCapacity, VariableMtrrCount,\r
1664 BaseAddress, Alignment, Type, Alignment0);\r
1665 BaseAddress += Alignment;\r
1666 Length -= Alignment;\r
1667 }\r
1668 return RETURN_SUCCESS;\r
1669}\r
1670\r
1671/**\r
1672 Return an array of memory ranges holding memory type settings for all memory\r
1673 address.\r
1674\r
1675 @param DefaultType The default memory type.\r
1676 @param TotalLength The total length of the memory.\r
1677 @param VariableMtrr The variable MTRR array.\r
1678 @param VariableMtrrCount The count of variable MTRRs.\r
1679 @param Ranges Return the memory range array holding memory type\r
1680 settings for all memory address.\r
1681 @param RangeCapacity The capacity of memory range array.\r
1682 @param RangeCount Return the count of memory range.\r
1683\r
1684 @retval RETURN_SUCCESS The memory range array is returned successfully.\r
1685 @retval RETURN_OUT_OF_RESOURCES The count of memory ranges exceeds capacity.\r
1686**/\r
1687RETURN_STATUS\r
1688MtrrLibGetMemoryTypes (\r
1689 IN MTRR_MEMORY_CACHE_TYPE DefaultType,\r
1690 IN UINT64 TotalLength,\r
1691 IN CONST VARIABLE_MTRR *VariableMtrr,\r
1692 IN UINT32 VariableMtrrCount,\r
1693 OUT MEMORY_RANGE *Ranges,\r
1694 IN UINT32 RangeCapacity,\r
1695 OUT UINT32 *RangeCount\r
1696)\r
1697{\r
1698 RETURN_STATUS Status;\r
1699 UINTN Index;\r
1700\r
1701 //\r
1702 // WT > WB\r
1703 // UC > *\r
1704 // UC > * (except WB, UC) > WB\r
1705 //\r
1706\r
1707 //\r
1708 // 0. Set whole range as DefaultType\r
1709 //\r
1710 *RangeCount = 1;\r
1711 Ranges[0].BaseAddress = 0;\r
1712 Ranges[0].Length = TotalLength;\r
1713 Ranges[0].Type = DefaultType;\r
1714\r
1715 //\r
1716 // 1. Set WB\r
1717 //\r
1718 for (Index = 0; Index < VariableMtrrCount; Index++) {\r
1719 if (VariableMtrr[Index].Valid && VariableMtrr[Index].Type == CacheWriteBack) {\r
1720 Status = MtrrLibSetMemoryType (\r
1721 Ranges, RangeCapacity, RangeCount,\r
1722 VariableMtrr[Index].BaseAddress, VariableMtrr[Index].Length, (MTRR_MEMORY_CACHE_TYPE) VariableMtrr[Index].Type\r
1723 );\r
1724 if (RETURN_ERROR (Status)) {\r
1725 return Status;\r
1726 }\r
1727 }\r
1728 }\r
1729\r
1730 //\r
1731 // 2. Set other types than WB or UC\r
1732 //\r
1733 for (Index = 0; Index < VariableMtrrCount; Index++) {\r
1734 if (VariableMtrr[Index].Valid && VariableMtrr[Index].Type != CacheWriteBack && VariableMtrr[Index].Type != CacheUncacheable) {\r
1735 Status = MtrrLibSetMemoryType (\r
1736 Ranges, RangeCapacity, RangeCount,\r
1737 VariableMtrr[Index].BaseAddress, VariableMtrr[Index].Length, (MTRR_MEMORY_CACHE_TYPE) VariableMtrr[Index].Type\r
1738 );\r
1739 if (RETURN_ERROR (Status)) {\r
1740 return Status;\r
1741 }\r
1742 }\r
1743 }\r
1744\r
1745 //\r
1746 // 3. Set UC\r
1747 //\r
1748 for (Index = 0; Index < VariableMtrrCount; Index++) {\r
1749 if (VariableMtrr[Index].Valid && VariableMtrr[Index].Type == CacheUncacheable) {\r
1750 Status = MtrrLibSetMemoryType (\r
1751 Ranges, RangeCapacity, RangeCount,\r
1752 VariableMtrr[Index].BaseAddress, VariableMtrr[Index].Length, (MTRR_MEMORY_CACHE_TYPE) VariableMtrr[Index].Type\r
1753 );\r
1754 if (RETURN_ERROR (Status)) {\r
1755 return Status;\r
1756 }\r
1757 }\r
1758 }\r
1759 return RETURN_SUCCESS;\r
1760}\r
16c2d37e 1761\r
85b7f65b 1762/**\r
16c2d37e 1763 Worker function attempts to set the attributes for a memory range.\r
85b7f65b 1764\r
8051302a 1765 If MtrrSetting is not NULL, set the attributes into the input MTRR\r
b970ed68 1766 settings buffer.\r
8051302a 1767 If MtrrSetting is NULL, set the attributes into MTRRs registers.\r
b970ed68
MK
1768\r
1769 @param[in, out] MtrrSetting A buffer holding all MTRRs content.\r
85b7f65b 1770 @param[in] BaseAddress The physical address that is the start\r
8051302a
RN
1771 address of a memory range.\r
1772 @param[in] Length The size in bytes of the memory range.\r
1773 @param[in] Type The MTRR type to set for the memory range.\r
85b7f65b
MK
1774\r
1775 @retval RETURN_SUCCESS The attributes were set for the memory\r
8051302a 1776 range.\r
85b7f65b
MK
1777 @retval RETURN_INVALID_PARAMETER Length is zero.\r
1778 @retval RETURN_UNSUPPORTED The processor does not support one or\r
1779 more bytes of the memory resource range\r
1780 specified by BaseAddress and Length.\r
8051302a
RN
1781 @retval RETURN_UNSUPPORTED The MTRR type is not support for the\r
1782 memory resource range specified\r
85b7f65b 1783 by BaseAddress and Length.\r
85b7f65b
MK
1784 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to\r
1785 modify the attributes of the memory\r
1786 resource range.\r
1787\r
1788**/\r
1789RETURN_STATUS\r
b970ed68
MK
1790MtrrSetMemoryAttributeWorker (\r
1791 IN OUT MTRR_SETTINGS *MtrrSetting,\r
1792 IN PHYSICAL_ADDRESS BaseAddress,\r
1793 IN UINT64 Length,\r
8051302a 1794 IN MTRR_MEMORY_CACHE_TYPE Type\r
85b7f65b
MK
1795 )\r
1796{\r
85b7f65b 1797 RETURN_STATUS Status;\r
8051302a
RN
1798 UINT32 Index;\r
1799 UINT32 WorkingIndex;\r
1800 //\r
1801 // N variable MTRRs can maximumly separate (2N + 1) Ranges, plus 1 range for [0, 1M).\r
1802 //\r
1803 MEMORY_RANGE Ranges[MTRR_NUMBER_OF_VARIABLE_MTRR * 2 + 2];\r
1804 UINT32 RangeCount;\r
85b7f65b
MK
1805 UINT64 MtrrValidBitsMask;\r
1806 UINT64 MtrrValidAddressMask;\r
8051302a 1807 UINT64 Alignment0;\r
85b7f65b 1808 MTRR_CONTEXT MtrrContext;\r
fa25cf38 1809 BOOLEAN MtrrContextValid;\r
8051302a
RN
1810\r
1811 MTRR_MEMORY_CACHE_TYPE DefaultType;\r
1812\r
1813 UINT32 MsrIndex;\r
fa25cf38
MK
1814 UINT64 ClearMask;\r
1815 UINT64 OrMask;\r
1816 UINT64 NewValue;\r
8051302a
RN
1817 BOOLEAN FixedSettingsValid[MTRR_NUMBER_OF_FIXED_MTRR];\r
1818 BOOLEAN FixedSettingsModified[MTRR_NUMBER_OF_FIXED_MTRR];\r
1819 MTRR_FIXED_SETTINGS WorkingFixedSettings;\r
85b7f65b 1820\r
8051302a
RN
1821 UINT32 FirmwareVariableMtrrCount;\r
1822 MTRR_VARIABLE_SETTINGS *VariableSettings;\r
1823 MTRR_VARIABLE_SETTINGS OriginalVariableSettings;\r
1824 UINT32 OriginalVariableMtrrCount;\r
1825 VARIABLE_MTRR OriginalVariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];\r
1826 UINT32 WorkingVariableMtrrCount;\r
1827 VARIABLE_MTRR WorkingVariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];\r
1828 BOOLEAN VariableSettingModified[MTRR_NUMBER_OF_VARIABLE_MTRR];\r
1829 UINTN FreeVariableMtrrCount;\r
85b7f65b 1830\r
8051302a
RN
1831 if (Length == 0) {\r
1832 return RETURN_INVALID_PARAMETER;\r
85b7f65b
MK
1833 }\r
1834\r
b0fa5d29 1835 MtrrLibInitializeMtrrMask (&MtrrValidBitsMask, &MtrrValidAddressMask);\r
8051302a
RN
1836 if (((BaseAddress & ~MtrrValidAddressMask) != 0) || (Length & ~MtrrValidAddressMask) != 0) {\r
1837 return RETURN_UNSUPPORTED;\r
85b7f65b
MK
1838 }\r
1839\r
8051302a
RN
1840 ZeroMem (&WorkingFixedSettings, sizeof (WorkingFixedSettings));\r
1841 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
1842 FixedSettingsValid[Index] = FALSE;\r
1843 FixedSettingsModified[Index] = FALSE;\r
85b7f65b
MK
1844 }\r
1845\r
1846 //\r
1847 // Check if Fixed MTRR\r
1848 //\r
fa25cf38 1849 if (BaseAddress < BASE_1MB) {\r
8051302a
RN
1850 MsrIndex = (UINT32)-1;\r
1851 while ((BaseAddress < BASE_1MB) && (Length != 0)) {\r
1852 Status = MtrrLibProgramFixedMtrr (Type, &BaseAddress, &Length, &MsrIndex, &ClearMask, &OrMask);\r
fa25cf38 1853 if (RETURN_ERROR (Status)) {\r
8051302a 1854 return Status;\r
fa25cf38 1855 }\r
b970ed68 1856 if (MtrrSetting != NULL) {\r
8051302a
RN
1857 MtrrSetting->Fixed.Mtrr[MsrIndex] = (MtrrSetting->Fixed.Mtrr[MsrIndex] & ~ClearMask) | OrMask;\r
1858 ((MSR_IA32_MTRR_DEF_TYPE_REGISTER *) &MtrrSetting->MtrrDefType)->Bits.FE = 1;\r
b970ed68 1859 } else {\r
8051302a
RN
1860 if (!FixedSettingsValid[MsrIndex]) {\r
1861 WorkingFixedSettings.Mtrr[MsrIndex] = AsmReadMsr64 (mMtrrLibFixedMtrrTable[MsrIndex].Msr);\r
1862 FixedSettingsValid[MsrIndex] = TRUE;\r
b970ed68 1863 }\r
8051302a
RN
1864 NewValue = (WorkingFixedSettings.Mtrr[MsrIndex] & ~ClearMask) | OrMask;\r
1865 if (WorkingFixedSettings.Mtrr[MsrIndex] != NewValue) {\r
1866 WorkingFixedSettings.Mtrr[MsrIndex] = NewValue;\r
1867 FixedSettingsModified[MsrIndex] = TRUE;\r
b970ed68 1868 }\r
fa25cf38 1869 }\r
85b7f65b 1870 }\r
85b7f65b 1871\r
fa25cf38
MK
1872 if (Length == 0) {\r
1873 //\r
1874 // A Length of 0 can only make sense for fixed MTTR ranges.\r
1875 // Since we just handled the fixed MTRRs, we can skip the\r
1876 // variable MTRR section.\r
1877 //\r
1878 goto Done;\r
1879 }\r
85b7f65b
MK
1880 }\r
1881\r
1882 //\r
8051302a 1883 // Read the default MTRR type\r
85b7f65b 1884 //\r
8051302a 1885 DefaultType = MtrrGetDefaultMemoryTypeWorker (MtrrSetting);\r
85b7f65b 1886\r
acf431e6 1887 //\r
8051302a 1888 // Read all variable MTRRs and convert to Ranges.\r
acf431e6 1889 //\r
8051302a
RN
1890 OriginalVariableMtrrCount = GetVariableMtrrCountWorker ();\r
1891 if (MtrrSetting == NULL) {\r
1892 ZeroMem (&OriginalVariableSettings, sizeof (OriginalVariableSettings));\r
1893 MtrrGetVariableMtrrWorker (NULL, OriginalVariableMtrrCount, &OriginalVariableSettings);\r
1894 VariableSettings = &OriginalVariableSettings;\r
b970ed68 1895 } else {\r
8051302a 1896 VariableSettings = &MtrrSetting->Variables;\r
e50466da 1897 }\r
8051302a
RN
1898 MtrrGetMemoryAttributeInVariableMtrrWorker (VariableSettings, OriginalVariableMtrrCount, MtrrValidBitsMask, MtrrValidAddressMask, OriginalVariableMtrr);\r
1899\r
1900 Status = MtrrLibGetMemoryTypes (\r
1901 DefaultType, MtrrValidBitsMask + 1, OriginalVariableMtrr, OriginalVariableMtrrCount,\r
1902 Ranges, 2 * OriginalVariableMtrrCount + 1, &RangeCount\r
1903 );\r
1904 ASSERT (Status == RETURN_SUCCESS);\r
1905\r
1906 FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCountWorker ();\r
1907 ASSERT (RangeCount <= 2 * FirmwareVariableMtrrCount + 1);\r
e50466da 1908\r
1909 //\r
8051302a 1910 // Force [0, 1M) to UC, so that it doesn't impact left subtraction algorithm.\r
e50466da 1911 //\r
8051302a
RN
1912 Status = MtrrLibSetMemoryType (Ranges, 2 * FirmwareVariableMtrrCount + 2, &RangeCount, 0, SIZE_1MB, CacheUncacheable);\r
1913 ASSERT (Status == RETURN_SUCCESS);\r
1914 //\r
1915 // Apply Type to [BaseAddress, BaseAddress + Length)\r
1916 //\r
1917 Status = MtrrLibSetMemoryType (Ranges, 2 * FirmwareVariableMtrrCount + 2, &RangeCount, BaseAddress, Length, Type);\r
1918 if (RETURN_ERROR (Status)) {\r
1919 return Status;\r
e50466da 1920 }\r
1921\r
8051302a
RN
1922 Alignment0 = LShiftU64 (1, (UINTN) HighBitSet64 (MtrrValidBitsMask));\r
1923 WorkingVariableMtrrCount = 0;\r
1924 ZeroMem (&WorkingVariableMtrr, sizeof (WorkingVariableMtrr));\r
1925 for (Index = 0; Index < RangeCount; Index++) {\r
1926 if (Ranges[Index].Type != DefaultType) {\r
1927 //\r
1928 // Maximum allowed MTRR count is (FirmwareVariableMtrrCount + 1)\r
1929 // Because potentially the range [0, 1MB) is not merged, but can be ignored because fixed MTRR covers that\r
1930 //\r
1931 Status = MtrrLibSetMemoryAttributeInVariableMtrr (\r
1932 Ranges, RangeCount,\r
1933 WorkingVariableMtrr, FirmwareVariableMtrrCount + 1, &WorkingVariableMtrrCount,\r
1934 Ranges[Index].BaseAddress, Ranges[Index].Length,\r
1935 Ranges[Index].Type, Alignment0\r
1936 );\r
1937 if (RETURN_ERROR (Status)) {\r
1938 return Status;\r
1939 }\r
1940 }\r
1a2ad6fc 1941 }\r
e50466da 1942\r
1a2ad6fc 1943 //\r
8051302a 1944 // Remove the [0, 1MB) MTRR if it still exists (not merged with other range)\r
1a2ad6fc 1945 //\r
8051302a
RN
1946 if (WorkingVariableMtrr[0].BaseAddress == 0 && WorkingVariableMtrr[0].Length == SIZE_1MB) {\r
1947 ASSERT (WorkingVariableMtrr[0].Type == CacheUncacheable);\r
1948 WorkingVariableMtrrCount--;\r
1949 CopyMem (&WorkingVariableMtrr[0], &WorkingVariableMtrr[1], WorkingVariableMtrrCount * sizeof (VARIABLE_MTRR));\r
1950 }\r
1a2ad6fc 1951\r
8051302a
RN
1952 if (WorkingVariableMtrrCount > FirmwareVariableMtrrCount) {\r
1953 return RETURN_OUT_OF_RESOURCES;\r
1a2ad6fc 1954 }\r
1955\r
8051302a
RN
1956 for (Index = 0; Index < OriginalVariableMtrrCount; Index++) {\r
1957 VariableSettingModified[Index] = FALSE;\r
1a2ad6fc 1958\r
8051302a
RN
1959 if (!OriginalVariableMtrr[Index].Valid) {\r
1960 continue;\r
1961 }\r
1962 for (WorkingIndex = 0; WorkingIndex < WorkingVariableMtrrCount; WorkingIndex++) {\r
1963 if (OriginalVariableMtrr[Index].BaseAddress == WorkingVariableMtrr[WorkingIndex].BaseAddress &&\r
1964 OriginalVariableMtrr[Index].Length == WorkingVariableMtrr[WorkingIndex].Length &&\r
1965 OriginalVariableMtrr[Index].Type == WorkingVariableMtrr[WorkingIndex].Type) {\r
1a2ad6fc 1966 break;\r
1967 }\r
8051302a 1968 }\r
1a2ad6fc 1969\r
8051302a 1970 if (WorkingIndex == WorkingVariableMtrrCount) {\r
1a2ad6fc 1971 //\r
8051302a 1972 // Remove the one from OriginalVariableMtrr which is not in WorkingVariableMtrr\r
1a2ad6fc 1973 //\r
8051302a
RN
1974 OriginalVariableMtrr[Index].Valid = FALSE;\r
1975 VariableSettingModified[Index] = TRUE;\r
1976 } else {\r
1977 //\r
1978 // Remove the one from WorkingVariableMtrr which is also in OriginalVariableMtrr\r
1979 //\r
1980 WorkingVariableMtrr[WorkingIndex].Valid = FALSE;\r
1981 }\r
1982 //\r
1983 // The above two operations cause that valid MTRR only exists in either OriginalVariableMtrr or WorkingVariableMtrr.\r
1984 //\r
1985 }\r
1986\r
1987 //\r
1988 // Merge remaining MTRRs from WorkingVariableMtrr to OriginalVariableMtrr\r
1989 //\r
1990 for (FreeVariableMtrrCount = 0, WorkingIndex = 0, Index = 0; Index < OriginalVariableMtrrCount; Index++) {\r
1991 if (!OriginalVariableMtrr[Index].Valid) {\r
1992 for (; WorkingIndex < WorkingVariableMtrrCount; WorkingIndex++) {\r
1993 if (WorkingVariableMtrr[WorkingIndex].Valid) {\r
1a2ad6fc 1994 break;\r
1995 }\r
1996 }\r
8051302a
RN
1997 if (WorkingIndex == WorkingVariableMtrrCount) {\r
1998 FreeVariableMtrrCount++;\r
1999 } else {\r
2000 CopyMem (&OriginalVariableMtrr[Index], &WorkingVariableMtrr[WorkingIndex], sizeof (VARIABLE_MTRR));\r
2001 VariableSettingModified[Index] = TRUE;\r
2002 WorkingIndex++;\r
2003 }\r
1a2ad6fc 2004 }\r
2005 }\r
8051302a 2006 ASSERT (OriginalVariableMtrrCount - FreeVariableMtrrCount <= FirmwareVariableMtrrCount);\r
1a2ad6fc 2007\r
8051302a
RN
2008 //\r
2009 // Move MTRRs after the FirmwraeVariableMtrrCount position to beginning\r
2010 //\r
2011 WorkingIndex = FirmwareVariableMtrrCount;\r
2012 for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) {\r
2013 if (!OriginalVariableMtrr[Index].Valid) {\r
2014 //\r
2015 // Found an empty MTRR in WorkingIndex position\r
2016 //\r
2017 for (; WorkingIndex < OriginalVariableMtrrCount; WorkingIndex++) {\r
2018 if (OriginalVariableMtrr[WorkingIndex].Valid) {\r
2019 break;\r
2020 }\r
2021 }\r
e50466da 2022\r
8051302a
RN
2023 if (WorkingIndex != OriginalVariableMtrrCount) {\r
2024 CopyMem (&OriginalVariableMtrr[Index], &OriginalVariableMtrr[WorkingIndex], sizeof (VARIABLE_MTRR));\r
2025 VariableSettingModified[Index] = TRUE;\r
2026 VariableSettingModified[WorkingIndex] = TRUE;\r
2027 OriginalVariableMtrr[WorkingIndex].Valid = FALSE;\r
85b7f65b
MK
2028 }\r
2029 }\r
e50466da 2030 }\r
2031\r
8051302a
RN
2032 //\r
2033 // Convert OriginalVariableMtrr to VariableSettings\r
2034 // NOTE: MTRR from FirmwareVariableMtrr to OriginalVariableMtrr need to update as well.\r
2035 //\r
2036 for (Index = 0; Index < OriginalVariableMtrrCount; Index++) {\r
2037 if (VariableSettingModified[Index]) {\r
2038 if (OriginalVariableMtrr[Index].Valid) {\r
2039 VariableSettings->Mtrr[Index].Base = (OriginalVariableMtrr[Index].BaseAddress & MtrrValidAddressMask) | (UINT8) OriginalVariableMtrr[Index].Type;\r
2040 VariableSettings->Mtrr[Index].Mask = (~(OriginalVariableMtrr[Index].Length - 1)) & MtrrValidAddressMask | BIT11;\r
2041 } else {\r
2042 VariableSettings->Mtrr[Index].Base = 0;\r
2043 VariableSettings->Mtrr[Index].Mask = 0;\r
85b7f65b
MK
2044 }\r
2045 }\r
8051302a 2046 }\r
85b7f65b
MK
2047\r
2048Done:\r
8051302a
RN
2049 if (MtrrSetting != NULL) {\r
2050 ((MSR_IA32_MTRR_DEF_TYPE_REGISTER *) &MtrrSetting->MtrrDefType)->Bits.E = 1;\r
2051 return RETURN_SUCCESS;\r
2052 }\r
fa25cf38 2053\r
8051302a 2054 MtrrContextValid = FALSE;\r
fa25cf38
MK
2055 //\r
2056 // Write fixed MTRRs that have been modified\r
2057 //\r
2058 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
2059 if (FixedSettingsModified[Index]) {\r
2060 if (!MtrrContextValid) {\r
b8f01599 2061 MtrrLibPreMtrrChange (&MtrrContext);\r
fa25cf38
MK
2062 MtrrContextValid = TRUE;\r
2063 }\r
2064 AsmWriteMsr64 (\r
2065 mMtrrLibFixedMtrrTable[Index].Msr,\r
2066 WorkingFixedSettings.Mtrr[Index]\r
2067 );\r
2068 }\r
2069 }\r
2070\r
b0fa5d29
MK
2071 //\r
2072 // Write variable MTRRs\r
2073 //\r
8051302a
RN
2074 for (Index = 0; Index < OriginalVariableMtrrCount; Index++) {\r
2075 if (VariableSettingModified[Index]) {\r
2076 if (!MtrrContextValid) {\r
2077 MtrrLibPreMtrrChange (&MtrrContext);\r
2078 MtrrContextValid = TRUE;\r
b0fa5d29 2079 }\r
8051302a
RN
2080 AsmWriteMsr64 (\r
2081 MSR_IA32_MTRR_PHYSBASE0 + (Index << 1),\r
2082 VariableSettings->Mtrr[Index].Base\r
2083 );\r
2084 AsmWriteMsr64 (\r
2085 MSR_IA32_MTRR_PHYSMASK0 + (Index << 1),\r
2086 VariableSettings->Mtrr[Index].Mask\r
2087 );\r
b0fa5d29
MK
2088 }\r
2089 }\r
fa25cf38 2090 if (MtrrContextValid) {\r
b8f01599 2091 MtrrLibPostMtrrChange (&MtrrContext);\r
fa25cf38
MK
2092 }\r
2093\r
85b7f65b 2094 return Status;\r
31b3597e 2095}\r
b970ed68
MK
2096\r
2097/**\r
2098 This function attempts to set the attributes for a memory range.\r
2099\r
2100 @param[in] BaseAddress The physical address that is the start\r
8051302a
RN
2101 address of a memory range.\r
2102 @param[in] Length The size in bytes of the memory range.\r
b970ed68 2103 @param[in] Attributes The bit mask of attributes to set for the\r
8051302a 2104 memory range.\r
b970ed68
MK
2105\r
2106 @retval RETURN_SUCCESS The attributes were set for the memory\r
8051302a 2107 range.\r
b970ed68
MK
2108 @retval RETURN_INVALID_PARAMETER Length is zero.\r
2109 @retval RETURN_UNSUPPORTED The processor does not support one or\r
2110 more bytes of the memory resource range\r
2111 specified by BaseAddress and Length.\r
2112 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support\r
2113 for the memory resource range specified\r
2114 by BaseAddress and Length.\r
2115 @retval RETURN_ACCESS_DENIED The attributes for the memory resource\r
2116 range specified by BaseAddress and Length\r
2117 cannot be modified.\r
2118 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to\r
2119 modify the attributes of the memory\r
2120 resource range.\r
2121\r
2122**/\r
2123RETURN_STATUS\r
2124EFIAPI\r
2125MtrrSetMemoryAttribute (\r
2126 IN PHYSICAL_ADDRESS BaseAddress,\r
2127 IN UINT64 Length,\r
2128 IN MTRR_MEMORY_CACHE_TYPE Attribute\r
2129 )\r
2130{\r
8051302a
RN
2131 RETURN_STATUS Status;\r
2132\r
2133 if (!IsMtrrSupported ()) {\r
2134 return RETURN_UNSUPPORTED;\r
2135 }\r
2136\r
2137 Status = MtrrSetMemoryAttributeWorker (NULL, BaseAddress, Length, Attribute);\r
2138 DEBUG ((DEBUG_CACHE, "MtrrSetMemoryAttribute() %a: [%016lx, %016lx) - %r\n",\r
2139 mMtrrMemoryCacheTypeShortName[Attribute], BaseAddress, BaseAddress + Length, Status));\r
2140\r
2141 if (!RETURN_ERROR (Status)) {\r
2142 MtrrDebugPrintAllMtrrsWorker (NULL);\r
2143 }\r
2144 return Status;\r
b970ed68
MK
2145}\r
2146\r
2147/**\r
2148 This function attempts to set the attributes into MTRR setting buffer for a memory range.\r
2149\r
2150 @param[in, out] MtrrSetting MTRR setting buffer to be set.\r
2151 @param[in] BaseAddress The physical address that is the start address\r
8051302a
RN
2152 of a memory range.\r
2153 @param[in] Length The size in bytes of the memory range.\r
b970ed68 2154 @param[in] Attribute The bit mask of attributes to set for the\r
8051302a 2155 memory range.\r
b970ed68 2156\r
8051302a 2157 @retval RETURN_SUCCESS The attributes were set for the memory range.\r
b970ed68
MK
2158 @retval RETURN_INVALID_PARAMETER Length is zero.\r
2159 @retval RETURN_UNSUPPORTED The processor does not support one or more bytes of the\r
2160 memory resource range specified by BaseAddress and Length.\r
2161 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support for the memory resource\r
2162 range specified by BaseAddress and Length.\r
2163 @retval RETURN_ACCESS_DENIED The attributes for the memory resource range specified by\r
2164 BaseAddress and Length cannot be modified.\r
2165 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of\r
2166 the memory resource range.\r
2167\r
2168**/\r
2169RETURN_STATUS\r
2170EFIAPI\r
2171MtrrSetMemoryAttributeInMtrrSettings (\r
2172 IN OUT MTRR_SETTINGS *MtrrSetting,\r
2173 IN PHYSICAL_ADDRESS BaseAddress,\r
2174 IN UINT64 Length,\r
2175 IN MTRR_MEMORY_CACHE_TYPE Attribute\r
2176 )\r
2177{\r
8051302a
RN
2178 RETURN_STATUS Status;\r
2179 Status = MtrrSetMemoryAttributeWorker (MtrrSetting, BaseAddress, Length, Attribute);\r
2180 DEBUG((DEBUG_CACHE, "MtrrSetMemoryAttributeMtrrSettings(%p) %a: [%016lx, %016lx) - %r\n",\r
2181 MtrrSetting, mMtrrMemoryCacheTypeShortName[Attribute], BaseAddress, BaseAddress + Length, Status));\r
2182\r
2183 if (!RETURN_ERROR (Status)) {\r
2184 MtrrDebugPrintAllMtrrsWorker (MtrrSetting);\r
2185 }\r
2186\r
2187 return Status;\r
b970ed68
MK
2188}\r
2189\r
e50466da 2190/**\r
2191 Worker function setting variable MTRRs\r
2192\r
76b4cae3 2193 @param[in] VariableSettings A buffer to hold variable MTRRs content.\r
e50466da 2194\r
2195**/\r
2196VOID\r
2197MtrrSetVariableMtrrWorker (\r
2198 IN MTRR_VARIABLE_SETTINGS *VariableSettings\r
2199 )\r
2200{\r
2201 UINT32 Index;\r
3b9be416 2202 UINT32 VariableMtrrCount;\r
e50466da 2203\r
acf431e6 2204 VariableMtrrCount = GetVariableMtrrCountWorker ();\r
5bdfa4e5 2205 ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);\r
2206\r
3b9be416 2207 for (Index = 0; Index < VariableMtrrCount; Index++) {\r
e50466da 2208 AsmWriteMsr64 (\r
2209 MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1),\r
2210 VariableSettings->Mtrr[Index].Base\r
2211 );\r
2212 AsmWriteMsr64 (\r
2213 MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1) + 1,\r
2214 VariableSettings->Mtrr[Index].Mask\r
2215 );\r
2216 }\r
2217}\r
2218\r
2219\r
2220/**\r
2221 This function sets variable MTRRs\r
2222\r
76b4cae3 2223 @param[in] VariableSettings A buffer to hold variable MTRRs content.\r
e50466da 2224\r
2225 @return The pointer of VariableSettings\r
2226\r
2227**/\r
2228MTRR_VARIABLE_SETTINGS*\r
2229EFIAPI\r
2230MtrrSetVariableMtrr (\r
2231 IN MTRR_VARIABLE_SETTINGS *VariableSettings\r
2232 )\r
2233{\r
c878cee4 2234 MTRR_CONTEXT MtrrContext;\r
e50466da 2235\r
947a573a 2236 if (!IsMtrrSupported ()) {\r
2237 return VariableSettings;\r
2238 }\r
2239\r
b8f01599 2240 MtrrLibPreMtrrChange (&MtrrContext);\r
e50466da 2241 MtrrSetVariableMtrrWorker (VariableSettings);\r
b8f01599 2242 MtrrLibPostMtrrChange (&MtrrContext);\r
e518b80d
MK
2243 MtrrDebugPrintAllMtrrs ();\r
2244\r
e50466da 2245 return VariableSettings;\r
2246}\r
2247\r
e50466da 2248/**\r
2249 Worker function setting fixed MTRRs\r
2250\r
acf431e6 2251 @param[in] FixedSettings A buffer to hold fixed MTRRs content.\r
e50466da 2252\r
2253**/\r
2254VOID\r
2255MtrrSetFixedMtrrWorker (\r
2256 IN MTRR_FIXED_SETTINGS *FixedSettings\r
2257 )\r
2258{\r
2259 UINT32 Index;\r
2260\r
2261 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
2262 AsmWriteMsr64 (\r
f877f300 2263 mMtrrLibFixedMtrrTable[Index].Msr,\r
e50466da 2264 FixedSettings->Mtrr[Index]\r
2265 );\r
2266 }\r
2267}\r
2268\r
2269\r
2270/**\r
2271 This function sets fixed MTRRs\r
2272\r
acf431e6 2273 @param[in] FixedSettings A buffer to hold fixed MTRRs content.\r
e50466da 2274\r
2275 @retval The pointer of FixedSettings\r
2276\r
2277**/\r
2278MTRR_FIXED_SETTINGS*\r
2279EFIAPI\r
2280MtrrSetFixedMtrr (\r
2281 IN MTRR_FIXED_SETTINGS *FixedSettings\r
2282 )\r
2283{\r
c878cee4 2284 MTRR_CONTEXT MtrrContext;\r
e50466da 2285\r
947a573a 2286 if (!IsMtrrSupported ()) {\r
2287 return FixedSettings;\r
2288 }\r
2289\r
b8f01599 2290 MtrrLibPreMtrrChange (&MtrrContext);\r
e50466da 2291 MtrrSetFixedMtrrWorker (FixedSettings);\r
b8f01599 2292 MtrrLibPostMtrrChange (&MtrrContext);\r
e518b80d 2293 MtrrDebugPrintAllMtrrs ();\r
e50466da 2294\r
2295 return FixedSettings;\r
2296}\r
2297\r
2298\r
2299/**\r
2300 This function gets the content in all MTRRs (variable and fixed)\r
2301\r
acf431e6 2302 @param[out] MtrrSetting A buffer to hold all MTRRs content.\r
e50466da 2303\r
2304 @retval the pointer of MtrrSetting\r
2305\r
2306**/\r
2307MTRR_SETTINGS *\r
2308EFIAPI\r
2309MtrrGetAllMtrrs (\r
2310 OUT MTRR_SETTINGS *MtrrSetting\r
2311 )\r
2312{\r
947a573a 2313 if (!IsMtrrSupported ()) {\r
2314 return MtrrSetting;\r
2315 }\r
2316\r
e50466da 2317 //\r
2318 // Get fixed MTRRs\r
2319 //\r
acf431e6 2320 MtrrGetFixedMtrrWorker (&MtrrSetting->Fixed);\r
e50466da 2321\r
2322 //\r
2323 // Get variable MTRRs\r
2324 //\r
acf431e6 2325 MtrrGetVariableMtrrWorker (\r
5abd5ed4 2326 NULL,\r
acf431e6
MK
2327 GetVariableMtrrCountWorker (),\r
2328 &MtrrSetting->Variables\r
2329 );\r
e50466da 2330\r
2331 //\r
2332 // Get MTRR_DEF_TYPE value\r
2333 //\r
2334 MtrrSetting->MtrrDefType = AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE);\r
2335\r
2336 return MtrrSetting;\r
2337}\r
2338\r
2339\r
2340/**\r
2341 This function sets all MTRRs (variable and fixed)\r
2342\r
76b4cae3 2343 @param[in] MtrrSetting A buffer holding all MTRRs content.\r
e50466da 2344\r
2345 @retval The pointer of MtrrSetting\r
2346\r
2347**/\r
2348MTRR_SETTINGS *\r
2349EFIAPI\r
2350MtrrSetAllMtrrs (\r
2351 IN MTRR_SETTINGS *MtrrSetting\r
2352 )\r
2353{\r
c878cee4 2354 MTRR_CONTEXT MtrrContext;\r
e50466da 2355\r
947a573a 2356 if (!IsMtrrSupported ()) {\r
2357 return MtrrSetting;\r
2358 }\r
2359\r
b8f01599 2360 MtrrLibPreMtrrChange (&MtrrContext);\r
e50466da 2361\r
2362 //\r
2363 // Set fixed MTRRs\r
2364 //\r
2365 MtrrSetFixedMtrrWorker (&MtrrSetting->Fixed);\r
2366\r
2367 //\r
2368 // Set variable MTRRs\r
2369 //\r
2370 MtrrSetVariableMtrrWorker (&MtrrSetting->Variables);\r
2371\r
2372 //\r
2373 // Set MTRR_DEF_TYPE value\r
2374 //\r
2375 AsmWriteMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE, MtrrSetting->MtrrDefType);\r
2376\r
b8f01599 2377 MtrrLibPostMtrrChangeEnableCache (&MtrrContext);\r
e50466da 2378\r
2379 return MtrrSetting;\r
2380}\r
2381\r
e518b80d 2382\r
947a573a 2383/**\r
2384 Checks if MTRR is supported.\r
2385\r
2386 @retval TRUE MTRR is supported.\r
2387 @retval FALSE MTRR is not supported.\r
2388\r
2389**/\r
2390BOOLEAN\r
2391EFIAPI\r
2392IsMtrrSupported (\r
2393 VOID\r
2394 )\r
2395{\r
3bb13d35
RN
2396 CPUID_VERSION_INFO_EDX Edx;\r
2397 MSR_IA32_MTRRCAP_REGISTER MtrrCap;\r
947a573a 2398\r
2399 //\r
2400 // Check CPUID(1).EDX[12] for MTRR capability\r
2401 //\r
3bb13d35
RN
2402 AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &Edx.Uint32);\r
2403 if (Edx.Bits.MTRR == 0) {\r
947a573a 2404 return FALSE;\r
2405 }\r
2406\r
2407 //\r
3bb13d35
RN
2408 // Check number of variable MTRRs and fixed MTRRs existence.\r
2409 // If number of variable MTRRs is zero, or fixed MTRRs do not\r
947a573a 2410 // exist, return false.\r
2411 //\r
3bb13d35
RN
2412 MtrrCap.Uint64 = AsmReadMsr64 (MSR_IA32_MTRRCAP);\r
2413 if ((MtrrCap.Bits.VCNT == 0) || (MtrrCap.Bits.FIX == 0)) {\r
947a573a 2414 return FALSE;\r
2415 }\r
947a573a 2416 return TRUE;\r
2417}\r
8051302a 2418\r