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