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