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