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