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