]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/Library/MtrrLib/MtrrLib.c
BaseTools: Update Brotli and BrotliCompress mode and format
[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
0f354122 8 Copyright (c) 2008 - 2016, 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
21#include <Library/MtrrLib.h>\r
22#include <Library/BaseLib.h>\r
23#include <Library/CpuLib.h>\r
24#include <Library/BaseMemoryLib.h>\r
25#include <Library/DebugLib.h>\r
26\r
eecad349
JF
27#define OR_SEED 0x0101010101010101ull\r
28#define CLEAR_SEED 0xFFFFFFFFFFFFFFFFull\r
07e88920 29\r
c878cee4 30//\r
31// Context to save and restore when MTRRs are programmed\r
32//\r
33typedef struct {\r
34 UINTN Cr4;\r
35 BOOLEAN InterruptState;\r
36} MTRR_CONTEXT;\r
37\r
e50466da 38//\r
39// This table defines the offset, base and length of the fixed MTRRs\r
40//\r
f877f300 41CONST FIXED_MTRR mMtrrLibFixedMtrrTable[] = {\r
e50466da 42 {\r
43 MTRR_LIB_IA32_MTRR_FIX64K_00000,\r
44 0,\r
45 SIZE_64KB\r
46 },\r
47 {\r
48 MTRR_LIB_IA32_MTRR_FIX16K_80000,\r
49 0x80000,\r
50 SIZE_16KB\r
51 },\r
52 {\r
53 MTRR_LIB_IA32_MTRR_FIX16K_A0000,\r
54 0xA0000,\r
55 SIZE_16KB\r
56 },\r
57 {\r
58 MTRR_LIB_IA32_MTRR_FIX4K_C0000,\r
59 0xC0000,\r
60 SIZE_4KB\r
61 },\r
62 {\r
63 MTRR_LIB_IA32_MTRR_FIX4K_C8000,\r
64 0xC8000,\r
65 SIZE_4KB\r
66 },\r
67 {\r
68 MTRR_LIB_IA32_MTRR_FIX4K_D0000,\r
69 0xD0000,\r
70 SIZE_4KB\r
71 },\r
72 {\r
73 MTRR_LIB_IA32_MTRR_FIX4K_D8000,\r
74 0xD8000,\r
75 SIZE_4KB\r
76 },\r
77 {\r
78 MTRR_LIB_IA32_MTRR_FIX4K_E0000,\r
79 0xE0000,\r
80 SIZE_4KB\r
81 },\r
82 {\r
83 MTRR_LIB_IA32_MTRR_FIX4K_E8000,\r
84 0xE8000,\r
85 SIZE_4KB\r
86 },\r
87 {\r
88 MTRR_LIB_IA32_MTRR_FIX4K_F0000,\r
89 0xF0000,\r
90 SIZE_4KB\r
91 },\r
92 {\r
93 MTRR_LIB_IA32_MTRR_FIX4K_F8000,\r
94 0xF8000,\r
95 SIZE_4KB\r
76b4cae3 96 }\r
e50466da 97};\r
98\r
f877f300 99//\r
100// Lookup table used to print MTRRs\r
101//\r
102GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 *mMtrrMemoryCacheTypeShortName[] = {\r
103 "UC", // CacheUncacheable\r
104 "WC", // CacheWriteCombining\r
105 "R*", // Invalid\r
106 "R*", // Invalid\r
107 "WT", // CacheWriteThrough\r
108 "WP", // CacheWriteProtected\r
109 "WB", // CacheWriteBack\r
110 "R*" // Invalid\r
111};\r
112\r
31b3597e
MK
113/**\r
114 Worker function returns the variable MTRR count for the CPU.\r
115\r
116 @return Variable MTRR count\r
117\r
118**/\r
119UINT32\r
120GetVariableMtrrCountWorker (\r
121 VOID\r
122 )\r
123{\r
124 UINT32 VariableMtrrCount;\r
125\r
126 VariableMtrrCount = (UINT32)(AsmReadMsr64 (MTRR_LIB_IA32_MTRR_CAP) & MTRR_LIB_IA32_MTRR_CAP_VCNT_MASK);\r
127 ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);\r
128 return VariableMtrrCount;\r
129}\r
130\r
3b9be416
JY
131/**\r
132 Returns the variable MTRR count for the CPU.\r
133\r
134 @return Variable MTRR count\r
135\r
136**/\r
137UINT32\r
ed8dfd7b 138EFIAPI\r
3b9be416
JY
139GetVariableMtrrCount (\r
140 VOID\r
141 )\r
142{\r
947a573a 143 if (!IsMtrrSupported ()) {\r
144 return 0;\r
145 }\r
31b3597e 146 return GetVariableMtrrCountWorker ();\r
3b9be416
JY
147}\r
148\r
149/**\r
31b3597e 150 Worker function returns the firmware usable variable MTRR count for the CPU.\r
3b9be416
JY
151\r
152 @return Firmware usable variable MTRR count\r
153\r
154**/\r
155UINT32\r
31b3597e 156GetFirmwareVariableMtrrCountWorker (\r
3b9be416
JY
157 VOID\r
158 )\r
159{\r
947a573a 160 UINT32 VariableMtrrCount;\r
46309b11 161 UINT32 ReservedMtrrNumber;\r
947a573a 162\r
31b3597e 163 VariableMtrrCount = GetVariableMtrrCountWorker ();\r
46309b11
JF
164 ReservedMtrrNumber = PcdGet32 (PcdCpuNumberOfReservedVariableMtrrs);\r
165 if (VariableMtrrCount < ReservedMtrrNumber) {\r
947a573a 166 return 0;\r
167 }\r
168\r
46309b11 169 return VariableMtrrCount - ReservedMtrrNumber;\r
3b9be416 170}\r
e50466da 171\r
31b3597e
MK
172/**\r
173 Returns the firmware usable variable MTRR count for the CPU.\r
174\r
175 @return Firmware usable variable MTRR count\r
176\r
177**/\r
178UINT32\r
179EFIAPI\r
180GetFirmwareVariableMtrrCount (\r
181 VOID\r
182 )\r
183{\r
184 if (!IsMtrrSupported ()) {\r
185 return 0;\r
186 }\r
187 return GetFirmwareVariableMtrrCountWorker ();\r
188}\r
189\r
190/**\r
191 Worker function returns the default MTRR cache type for the system.\r
192\r
5abd5ed4
MK
193 If MtrrSetting is not NULL, returns the default MTRR cache type from input\r
194 MTRR settings buffer.\r
195 If MtrrSetting is NULL, returns the default MTRR cache type from MSR.\r
196\r
197 @param[in] MtrrSetting A buffer holding all MTRRs content.\r
198\r
31b3597e
MK
199 @return The default MTRR cache type.\r
200\r
201**/\r
202MTRR_MEMORY_CACHE_TYPE\r
203MtrrGetDefaultMemoryTypeWorker (\r
5abd5ed4 204 IN MTRR_SETTINGS *MtrrSetting\r
31b3597e
MK
205 )\r
206{\r
5abd5ed4
MK
207 if (MtrrSetting == NULL) {\r
208 return (MTRR_MEMORY_CACHE_TYPE) (AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE) & 0x7);\r
209 } else {\r
210 return (MTRR_MEMORY_CACHE_TYPE) (MtrrSetting->MtrrDefType & 0x7);\r
211 }\r
31b3597e
MK
212}\r
213\r
214\r
e50466da 215/**\r
216 Returns the default MTRR cache type for the system.\r
217\r
91ec7824 218 @return The default MTRR cache type.\r
e50466da 219\r
220**/\r
91ec7824 221MTRR_MEMORY_CACHE_TYPE\r
222EFIAPI\r
223MtrrGetDefaultMemoryType (\r
e50466da 224 VOID\r
91ec7824 225 )\r
e50466da 226{\r
91ec7824 227 if (!IsMtrrSupported ()) {\r
228 return CacheUncacheable;\r
229 }\r
5abd5ed4 230 return MtrrGetDefaultMemoryTypeWorker (NULL);\r
91ec7824 231}\r
e50466da 232\r
233/**\r
234 Preparation before programming MTRR.\r
235\r
236 This function will do some preparation for programming MTRRs:\r
237 disable cache, invalid cache and disable MTRR caching functionality\r
238\r
a5953380 239 @param[out] MtrrContext Pointer to context to save\r
e50466da 240\r
241**/\r
c878cee4 242VOID\r
e50466da 243PreMtrrChange (\r
c878cee4 244 OUT MTRR_CONTEXT *MtrrContext\r
e50466da 245 )\r
246{\r
c878cee4 247 //\r
248 // Disable interrupts and save current interrupt state\r
249 //\r
250 MtrrContext->InterruptState = SaveAndDisableInterrupts();\r
76b4cae3 251\r
e50466da 252 //\r
253 // Enter no fill cache mode, CD=1(Bit30), NW=0 (Bit29)\r
254 //\r
58b23d90 255 AsmDisableCache ();\r
256\r
e50466da 257 //\r
58b23d90 258 // Save original CR4 value and clear PGE flag (Bit 7)\r
e50466da 259 //\r
c878cee4 260 MtrrContext->Cr4 = AsmReadCr4 ();\r
261 AsmWriteCr4 (MtrrContext->Cr4 & (~BIT7));\r
58b23d90 262\r
e50466da 263 //\r
264 // Flush all TLBs\r
265 //\r
266 CpuFlushTlb ();\r
58b23d90 267\r
e50466da 268 //\r
76b4cae3 269 // Disable MTRRs\r
e50466da 270 //\r
271 AsmMsrBitFieldWrite64 (MTRR_LIB_IA32_MTRR_DEF_TYPE, 10, 11, 0);\r
e50466da 272}\r
273\r
e50466da 274/**\r
275 Cleaning up after programming MTRRs.\r
276\r
277 This function will do some clean up after programming MTRRs:\r
0779e5bf 278 Flush all TLBs, re-enable caching, restore CR4.\r
e50466da 279\r
a5953380 280 @param[in] MtrrContext Pointer to context to restore\r
e50466da 281\r
282**/\r
283VOID\r
0779e5bf 284PostMtrrChangeEnableCache (\r
c878cee4 285 IN MTRR_CONTEXT *MtrrContext\r
e50466da 286 )\r
287{\r
e50466da 288 //\r
76b4cae3 289 // Flush all TLBs\r
e50466da 290 //\r
e50466da 291 CpuFlushTlb ();\r
292\r
293 //\r
294 // Enable Normal Mode caching CD=NW=0, CD(Bit30), NW(Bit29)\r
295 //\r
58b23d90 296 AsmEnableCache ();\r
e50466da 297\r
58b23d90 298 //\r
299 // Restore original CR4 value\r
300 //\r
c878cee4 301 AsmWriteCr4 (MtrrContext->Cr4);\r
76b4cae3 302\r
c878cee4 303 //\r
304 // Restore original interrupt state\r
305 //\r
306 SetInterruptState (MtrrContext->InterruptState);\r
e50466da 307}\r
308\r
0779e5bf 309/**\r
310 Cleaning up after programming MTRRs.\r
311\r
312 This function will do some clean up after programming MTRRs:\r
313 enable MTRR caching functionality, and enable cache\r
314\r
a5953380 315 @param[in] MtrrContext Pointer to context to restore\r
0779e5bf 316\r
317**/\r
318VOID\r
319PostMtrrChange (\r
c878cee4 320 IN MTRR_CONTEXT *MtrrContext\r
0779e5bf 321 )\r
322{\r
323 //\r
324 // Enable Cache MTRR\r
325 //\r
326 AsmMsrBitFieldWrite64 (MTRR_LIB_IA32_MTRR_DEF_TYPE, 10, 11, 3);\r
327\r
c878cee4 328 PostMtrrChangeEnableCache (MtrrContext);\r
0779e5bf 329}\r
330\r
85b7f65b
MK
331/**\r
332 Worker function gets the content in fixed MTRRs\r
333\r
334 @param[out] FixedSettings A buffer to hold fixed MTRRs content.\r
335\r
336 @retval The pointer of FixedSettings\r
337\r
338**/\r
339MTRR_FIXED_SETTINGS*\r
340MtrrGetFixedMtrrWorker (\r
341 OUT MTRR_FIXED_SETTINGS *FixedSettings\r
342 )\r
343{\r
344 UINT32 Index;\r
345\r
346 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
347 FixedSettings->Mtrr[Index] =\r
348 AsmReadMsr64 (mMtrrLibFixedMtrrTable[Index].Msr);\r
349 }\r
350\r
351 return FixedSettings;\r
352}\r
353\r
354\r
355/**\r
356 This function gets the content in fixed MTRRs\r
357\r
358 @param[out] FixedSettings A buffer to hold fixed MTRRs content.\r
359\r
360 @retval The pointer of FixedSettings\r
361\r
362**/\r
363MTRR_FIXED_SETTINGS*\r
364EFIAPI\r
365MtrrGetFixedMtrr (\r
366 OUT MTRR_FIXED_SETTINGS *FixedSettings\r
367 )\r
368{\r
369 if (!IsMtrrSupported ()) {\r
370 return FixedSettings;\r
371 }\r
372\r
373 return MtrrGetFixedMtrrWorker (FixedSettings);\r
374}\r
375\r
376\r
377/**\r
378 Worker function will get the raw value in variable MTRRs\r
379\r
5abd5ed4
MK
380 If MtrrSetting is not NULL, gets the variable MTRRs raw value from input\r
381 MTRR settings buffer.\r
382 If MtrrSetting is NULL, gets the variable MTRRs raw value from MTRRs.\r
383\r
384 @param[in] MtrrSetting A buffer holding all MTRRs content.\r
385 @param[in] VariableMtrrCount Number of variable MTRRs.\r
85b7f65b
MK
386 @param[out] VariableSettings A buffer to hold variable MTRRs content.\r
387\r
388 @return The VariableSettings input pointer\r
389\r
390**/\r
391MTRR_VARIABLE_SETTINGS*\r
392MtrrGetVariableMtrrWorker (\r
5abd5ed4 393 IN MTRR_SETTINGS *MtrrSetting,\r
acf431e6 394 IN UINT32 VariableMtrrCount,\r
85b7f65b
MK
395 OUT MTRR_VARIABLE_SETTINGS *VariableSettings\r
396 )\r
397{\r
398 UINT32 Index;\r
85b7f65b 399\r
85b7f65b
MK
400 ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);\r
401\r
402 for (Index = 0; Index < VariableMtrrCount; Index++) {\r
5abd5ed4
MK
403 if (MtrrSetting == NULL) {\r
404 VariableSettings->Mtrr[Index].Base =\r
405 AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1));\r
406 VariableSettings->Mtrr[Index].Mask =\r
407 AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1) + 1);\r
408 } else {\r
409 VariableSettings->Mtrr[Index].Base = MtrrSetting->Variables.Mtrr[Index].Base;\r
410 VariableSettings->Mtrr[Index].Mask = MtrrSetting->Variables.Mtrr[Index].Mask;\r
411 }\r
85b7f65b
MK
412 }\r
413\r
414 return VariableSettings;\r
415}\r
416\r
417/**\r
418 This function will get the raw value in variable MTRRs\r
419\r
420 @param[out] VariableSettings A buffer to hold variable MTRRs content.\r
421\r
422 @return The VariableSettings input pointer\r
423\r
424**/\r
425MTRR_VARIABLE_SETTINGS*\r
426EFIAPI\r
427MtrrGetVariableMtrr (\r
428 OUT MTRR_VARIABLE_SETTINGS *VariableSettings\r
429 )\r
430{\r
431 if (!IsMtrrSupported ()) {\r
432 return VariableSettings;\r
433 }\r
434\r
435 return MtrrGetVariableMtrrWorker (\r
5abd5ed4 436 NULL,\r
acf431e6 437 GetVariableMtrrCountWorker (),\r
85b7f65b
MK
438 VariableSettings\r
439 );\r
440}\r
e50466da 441\r
442/**\r
443 Programs fixed MTRRs registers.\r
444\r
76b4cae3
MK
445 @param[in] MemoryCacheType The memory type to set.\r
446 @param[in, out] Base The base address of memory range.\r
447 @param[in, out] Length The length of memory range.\r
0f354122
JF
448 @param[in, out] LastMsrNum On input, the last index of the fixed MTRR MSR to program.\r
449 On return, the current index of the fixed MTRR MSR to program.\r
fa25cf38
MK
450 @param[out] ReturnClearMask The bits to clear in the fixed MTRR MSR.\r
451 @param[out] ReturnOrMask The bits to set in the fixed MTRR MSR.\r
e50466da 452\r
453 @retval RETURN_SUCCESS The cache type was updated successfully\r
454 @retval RETURN_UNSUPPORTED The requested range or cache type was invalid\r
455 for the fixed MTRRs.\r
456\r
457**/\r
458RETURN_STATUS\r
459ProgramFixedMtrr (\r
fa25cf38
MK
460 IN UINT64 MemoryCacheType,\r
461 IN OUT UINT64 *Base,\r
462 IN OUT UINT64 *Length,\r
0f354122 463 IN OUT UINT32 *LastMsrNum,\r
fa25cf38
MK
464 OUT UINT64 *ReturnClearMask,\r
465 OUT UINT64 *ReturnOrMask\r
e50466da 466 )\r
467{\r
468 UINT32 MsrNum;\r
eecad349
JF
469 UINT32 LeftByteShift;\r
470 UINT32 RightByteShift;\r
471 UINT64 OrMask;\r
472 UINT64 ClearMask;\r
07e88920 473 UINT64 SubLength;\r
e50466da 474\r
eecad349
JF
475 //\r
476 // Find the fixed MTRR index to be programmed\r
477 //\r
0f354122 478 for (MsrNum = *LastMsrNum + 1; MsrNum < MTRR_NUMBER_OF_FIXED_MTRR; MsrNum++) {\r
f877f300 479 if ((*Base >= mMtrrLibFixedMtrrTable[MsrNum].BaseAddress) &&\r
e50466da 480 (*Base <\r
481 (\r
f877f300 482 mMtrrLibFixedMtrrTable[MsrNum].BaseAddress +\r
483 (8 * mMtrrLibFixedMtrrTable[MsrNum].Length)\r
e50466da 484 )\r
485 )\r
486 ) {\r
487 break;\r
488 }\r
489 }\r
490\r
0f354122 491 if (MsrNum >= MTRR_NUMBER_OF_FIXED_MTRR) {\r
e50466da 492 return RETURN_UNSUPPORTED;\r
493 }\r
494\r
495 //\r
eecad349 496 // Find the begin offset in fixed MTRR and calculate byte offset of left shift\r
e50466da 497 //\r
eecad349 498 LeftByteShift = ((UINT32)*Base - mMtrrLibFixedMtrrTable[MsrNum].BaseAddress)\r
aaa1e579 499 / mMtrrLibFixedMtrrTable[MsrNum].Length;\r
e50466da 500\r
eecad349 501 if (LeftByteShift >= 8) {\r
e50466da 502 return RETURN_UNSUPPORTED;\r
503 }\r
504\r
eecad349
JF
505 //\r
506 // Find the end offset in fixed MTRR and calculate byte offset of right shift\r
507 //\r
508 SubLength = mMtrrLibFixedMtrrTable[MsrNum].Length * (8 - LeftByteShift);\r
509 if (*Length >= SubLength) {\r
510 RightByteShift = 0;\r
07e88920 511 } else {\r
eecad349
JF
512 RightByteShift = 8 - LeftByteShift -\r
513 (UINT32)(*Length) / mMtrrLibFixedMtrrTable[MsrNum].Length;\r
514 if ((LeftByteShift >= 8) ||\r
515 (((UINT32)(*Length) % mMtrrLibFixedMtrrTable[MsrNum].Length) != 0)\r
516 ) {\r
517 return RETURN_UNSUPPORTED;\r
518 }\r
519 //\r
520 // Update SubLength by actual length\r
521 //\r
522 SubLength = *Length;\r
e50466da 523 }\r
524\r
eecad349
JF
525 ClearMask = CLEAR_SEED;\r
526 OrMask = MultU64x32 (OR_SEED, (UINT32)MemoryCacheType);\r
527\r
528 if (LeftByteShift != 0) {\r
529 //\r
530 // Clear the low bits by LeftByteShift\r
531 //\r
532 ClearMask &= LShiftU64 (ClearMask, LeftByteShift * 8);\r
533 OrMask &= LShiftU64 (OrMask, LeftByteShift * 8);\r
534 }\r
535\r
536 if (RightByteShift != 0) {\r
537 //\r
538 // Clear the high bits by RightByteShift\r
539 //\r
540 ClearMask &= RShiftU64 (ClearMask, RightByteShift * 8);\r
541 OrMask &= RShiftU64 (OrMask, RightByteShift * 8);\r
e50466da 542 }\r
543\r
07e88920
JF
544 *Length -= SubLength;\r
545 *Base += SubLength;\r
546\r
0f354122 547 *LastMsrNum = MsrNum;\r
eecad349
JF
548 *ReturnClearMask = ClearMask;\r
549 *ReturnOrMask = OrMask;\r
fa25cf38 550\r
e50466da 551 return RETURN_SUCCESS;\r
552}\r
553\r
554\r
d0baed7d
MK
555/**\r
556 Worker function gets the attribute of variable MTRRs.\r
557\r
558 This function shadows the content of variable MTRRs into an\r
559 internal array: VariableMtrr.\r
560\r
561 @param[in] VariableSettings The variable MTRR values to shadow\r
562 @param[in] FirmwareVariableMtrrCount The number of variable MTRRs available to firmware\r
563 @param[in] MtrrValidBitsMask The mask for the valid bit of the MTRR\r
564 @param[in] MtrrValidAddressMask The valid address mask for MTRR\r
565 @param[out] VariableMtrr The array to shadow variable MTRRs content\r
566\r
567 @return The return value of this parameter indicates the\r
568 number of MTRRs which has been used.\r
569\r
570**/\r
571UINT32\r
572MtrrGetMemoryAttributeInVariableMtrrWorker (\r
573 IN MTRR_VARIABLE_SETTINGS *VariableSettings,\r
574 IN UINTN FirmwareVariableMtrrCount,\r
575 IN UINT64 MtrrValidBitsMask,\r
576 IN UINT64 MtrrValidAddressMask,\r
577 OUT VARIABLE_MTRR *VariableMtrr\r
578 )\r
579{\r
580 UINTN Index;\r
581 UINT32 UsedMtrr;\r
582\r
583 ZeroMem (VariableMtrr, sizeof (VARIABLE_MTRR) * MTRR_NUMBER_OF_VARIABLE_MTRR);\r
584 for (Index = 0, UsedMtrr = 0; Index < FirmwareVariableMtrrCount; Index++) {\r
585 if ((VariableSettings->Mtrr[Index].Mask & MTRR_LIB_CACHE_MTRR_ENABLED) != 0) {\r
586 VariableMtrr[Index].Msr = (UINT32)Index;\r
587 VariableMtrr[Index].BaseAddress = (VariableSettings->Mtrr[Index].Base & MtrrValidAddressMask);\r
588 VariableMtrr[Index].Length = ((~(VariableSettings->Mtrr[Index].Mask & MtrrValidAddressMask)) & MtrrValidBitsMask) + 1;\r
589 VariableMtrr[Index].Type = (VariableSettings->Mtrr[Index].Base & 0x0ff);\r
590 VariableMtrr[Index].Valid = TRUE;\r
591 VariableMtrr[Index].Used = TRUE;\r
592 UsedMtrr++;\r
593 }\r
594 }\r
595 return UsedMtrr;\r
596}\r
597\r
598\r
e50466da 599/**\r
76b4cae3 600 Gets the attribute of variable MTRRs.\r
e50466da 601\r
3ba736f3
JY
602 This function shadows the content of variable MTRRs into an\r
603 internal array: VariableMtrr.\r
e50466da 604\r
76b4cae3
MK
605 @param[in] MtrrValidBitsMask The mask for the valid bit of the MTRR\r
606 @param[in] MtrrValidAddressMask The valid address mask for MTRR\r
607 @param[out] VariableMtrr The array to shadow variable MTRRs content\r
e50466da 608\r
438f1766 609 @return The return value of this parameter indicates the\r
3ba736f3 610 number of MTRRs which has been used.\r
e50466da 611\r
612**/\r
3ba736f3 613UINT32\r
e50466da 614EFIAPI\r
615MtrrGetMemoryAttributeInVariableMtrr (\r
616 IN UINT64 MtrrValidBitsMask,\r
617 IN UINT64 MtrrValidAddressMask,\r
618 OUT VARIABLE_MTRR *VariableMtrr\r
619 )\r
620{\r
d0baed7d 621 MTRR_VARIABLE_SETTINGS VariableSettings;\r
3b9be416 622\r
947a573a 623 if (!IsMtrrSupported ()) {\r
624 return 0;\r
625 }\r
626\r
d0baed7d 627 MtrrGetVariableMtrrWorker (\r
5abd5ed4 628 NULL,\r
d0baed7d
MK
629 GetVariableMtrrCountWorker (),\r
630 &VariableSettings\r
631 );\r
e50466da 632\r
d0baed7d
MK
633 return MtrrGetMemoryAttributeInVariableMtrrWorker (\r
634 &VariableSettings,\r
635 GetFirmwareVariableMtrrCountWorker (),\r
636 MtrrValidBitsMask,\r
637 MtrrValidAddressMask,\r
638 VariableMtrr\r
639 );\r
e50466da 640}\r
641\r
642\r
643/**\r
644 Checks overlap between given memory range and MTRRs.\r
645\r
acf431e6
MK
646 @param[in] FirmwareVariableMtrrCount The number of variable MTRRs available\r
647 to firmware.\r
76b4cae3
MK
648 @param[in] Start The start address of memory range.\r
649 @param[in] End The end address of memory range.\r
650 @param[in] VariableMtrr The array to shadow variable MTRRs content\r
e50466da 651\r
652 @retval TRUE Overlap exists.\r
653 @retval FALSE No overlap.\r
654\r
655**/\r
656BOOLEAN\r
657CheckMemoryAttributeOverlap (\r
acf431e6
MK
658 IN UINTN FirmwareVariableMtrrCount,\r
659 IN PHYSICAL_ADDRESS Start,\r
660 IN PHYSICAL_ADDRESS End,\r
661 IN VARIABLE_MTRR *VariableMtrr\r
e50466da 662 )\r
663{\r
664 UINT32 Index;\r
665\r
acf431e6 666 for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) {\r
e50466da 667 if (\r
668 VariableMtrr[Index].Valid &&\r
669 !(\r
670 (Start > (VariableMtrr[Index].BaseAddress +\r
671 VariableMtrr[Index].Length - 1)\r
672 ) ||\r
673 (End < VariableMtrr[Index].BaseAddress)\r
674 )\r
675 ) {\r
676 return TRUE;\r
677 }\r
678 }\r
679\r
680 return FALSE;\r
681}\r
682\r
683\r
684/**\r
685 Marks a variable MTRR as non-valid.\r
686\r
76b4cae3
MK
687 @param[in] Index The index of the array VariableMtrr to be invalidated\r
688 @param[in] VariableMtrr The array to shadow variable MTRRs content\r
689 @param[out] UsedMtrr The number of MTRRs which has already been used\r
e50466da 690\r
691**/\r
692VOID\r
693InvalidateShadowMtrr (\r
694 IN UINTN Index,\r
695 IN VARIABLE_MTRR *VariableMtrr,\r
696 OUT UINT32 *UsedMtrr\r
697 )\r
698{\r
699 VariableMtrr[Index].Valid = FALSE;\r
700 *UsedMtrr = *UsedMtrr - 1;\r
701}\r
702\r
703\r
704/**\r
76b4cae3 705 Combines memory attributes.\r
e50466da 706\r
707 If overlap exists between given memory range and MTRRs, try to combine them.\r
708\r
acf431e6
MK
709 @param[in] FirmwareVariableMtrrCount The number of variable MTRRs\r
710 available to firmware.\r
76b4cae3
MK
711 @param[in] Attributes The memory type to set.\r
712 @param[in, out] Base The base address of memory range.\r
713 @param[in, out] Length The length of memory range.\r
714 @param[in] VariableMtrr The array to shadow variable MTRRs content\r
715 @param[in, out] UsedMtrr The number of MTRRs which has already been used\r
716 @param[out] OverwriteExistingMtrr Returns whether an existing MTRR was used\r
e50466da 717\r
718 @retval EFI_SUCCESS Memory region successfully combined.\r
719 @retval EFI_ACCESS_DENIED Memory region cannot be combined.\r
720\r
721**/\r
722RETURN_STATUS\r
723CombineMemoryAttribute (\r
acf431e6 724 IN UINT32 FirmwareVariableMtrrCount,\r
e50466da 725 IN UINT64 Attributes,\r
726 IN OUT UINT64 *Base,\r
727 IN OUT UINT64 *Length,\r
728 IN VARIABLE_MTRR *VariableMtrr,\r
729 IN OUT UINT32 *UsedMtrr,\r
730 OUT BOOLEAN *OverwriteExistingMtrr\r
731 )\r
732{\r
733 UINT32 Index;\r
734 UINT64 CombineStart;\r
735 UINT64 CombineEnd;\r
736 UINT64 MtrrEnd;\r
737 UINT64 EndAddress;\r
1e60a0ec 738 BOOLEAN CoveredByExistingMtrr;\r
3b9be416 739\r
e50466da 740 *OverwriteExistingMtrr = FALSE;\r
1e60a0ec 741 CoveredByExistingMtrr = FALSE;\r
e50466da 742 EndAddress = *Base +*Length - 1;\r
743\r
3b9be416 744 for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) {\r
e50466da 745\r
746 MtrrEnd = VariableMtrr[Index].BaseAddress + VariableMtrr[Index].Length - 1;\r
747 if (\r
748 !VariableMtrr[Index].Valid ||\r
749 (\r
750 *Base > (MtrrEnd) ||\r
751 (EndAddress < VariableMtrr[Index].BaseAddress)\r
752 )\r
753 ) {\r
754 continue;\r
755 }\r
756\r
757 //\r
758 // Combine same attribute MTRR range\r
759 //\r
760 if (Attributes == VariableMtrr[Index].Type) {\r
761 //\r
76b4cae3 762 // if the MTRR range contain the request range, set a flag, then continue to\r
1e60a0ec 763 // invalidate any MTRR of the same request range with higher priority cache type.\r
e50466da 764 //\r
765 if (VariableMtrr[Index].BaseAddress <= *Base && MtrrEnd >= EndAddress) {\r
1e60a0ec 766 CoveredByExistingMtrr = TRUE;\r
767 continue;\r
e50466da 768 }\r
769 //\r
770 // invalid this MTRR, and program the combine range\r
771 //\r
772 CombineStart =\r
773 (*Base) < VariableMtrr[Index].BaseAddress ?\r
774 (*Base) :\r
775 VariableMtrr[Index].BaseAddress;\r
776 CombineEnd = EndAddress > MtrrEnd ? EndAddress : MtrrEnd;\r
777\r
778 //\r
779 // Record the MTRR usage status in VariableMtrr array.\r
780 //\r
781 InvalidateShadowMtrr (Index, VariableMtrr, UsedMtrr);\r
782 *Base = CombineStart;\r
783 *Length = CombineEnd - CombineStart + 1;\r
784 EndAddress = CombineEnd;\r
785 *OverwriteExistingMtrr = TRUE;\r
786 continue;\r
787 } else {\r
788 //\r
789 // The cache type is different, but the range is convered by one MTRR\r
790 //\r
791 if (VariableMtrr[Index].BaseAddress == *Base && MtrrEnd == EndAddress) {\r
792 InvalidateShadowMtrr (Index, VariableMtrr, UsedMtrr);\r
793 continue;\r
794 }\r
795\r
796 }\r
797\r
798 if ((Attributes== MTRR_CACHE_WRITE_THROUGH &&\r
799 VariableMtrr[Index].Type == MTRR_CACHE_WRITE_BACK) ||\r
800 (Attributes == MTRR_CACHE_WRITE_BACK &&\r
801 VariableMtrr[Index].Type == MTRR_CACHE_WRITE_THROUGH) ||\r
802 (Attributes == MTRR_CACHE_UNCACHEABLE) ||\r
803 (VariableMtrr[Index].Type == MTRR_CACHE_UNCACHEABLE)\r
804 ) {\r
805 *OverwriteExistingMtrr = TRUE;\r
806 continue;\r
807 }\r
808 //\r
809 // Other type memory overlap is invalid\r
810 //\r
811 return RETURN_ACCESS_DENIED;\r
812 }\r
813\r
1e60a0ec 814 if (CoveredByExistingMtrr) {\r
815 *Length = 0;\r
816 }\r
817\r
e50466da 818 return RETURN_SUCCESS;\r
819}\r
820\r
821\r
822/**\r
76b4cae3
MK
823 Calculates the maximum value which is a power of 2, but less the MemoryLength.\r
824\r
825 @param[in] MemoryLength The number to pass in.\r
e50466da 826\r
e50466da 827 @return The maximum value which is align to power of 2 and less the MemoryLength\r
828\r
829**/\r
830UINT64\r
831Power2MaxMemory (\r
832 IN UINT64 MemoryLength\r
833 )\r
834{\r
835 UINT64 Result;\r
836\r
430fbbe0 837 if (RShiftU64 (MemoryLength, 32) != 0) {\r
e50466da 838 Result = LShiftU64 (\r
839 (UINT64) GetPowerOfTwo32 (\r
840 (UINT32) RShiftU64 (MemoryLength, 32)\r
841 ),\r
842 32\r
843 );\r
844 } else {\r
845 Result = (UINT64) GetPowerOfTwo32 ((UINT32) MemoryLength);\r
846 }\r
847\r
848 return Result;\r
849}\r
850\r
851\r
852/**\r
76b4cae3 853 Determines the MTRR numbers used to program a memory range.\r
e50466da 854\r
76b4cae3
MK
855 This function first checks the alignment of the base address.\r
856 If the alignment of the base address <= Length, cover the memory range\r
857 (BaseAddress, alignment) by a MTRR, then BaseAddress += alignment and\r
858 Length -= alignment. Repeat the step until alignment > Length.\r
e50466da 859\r
76b4cae3
MK
860 Then this function determines which direction of programming the variable\r
861 MTRRs for the remaining length will use fewer MTRRs.\r
1a2ad6fc 862\r
76b4cae3
MK
863 @param[in] BaseAddress Length of Memory to program MTRR\r
864 @param[in] Length Length of Memory to program MTRR\r
865 @param[in] MtrrNumber Pointer to the number of necessary MTRRs\r
e50466da 866\r
867 @retval TRUE Positive direction is better.\r
76b4cae3 868 FALSE Negative direction is better.\r
e50466da 869\r
870**/\r
871BOOLEAN\r
1a2ad6fc 872GetMtrrNumberAndDirection (\r
873 IN UINT64 BaseAddress,\r
874 IN UINT64 Length,\r
e50466da 875 IN UINTN *MtrrNumber\r
876 )\r
877{\r
878 UINT64 TempQword;\r
1a2ad6fc 879 UINT64 Alignment;\r
e50466da 880 UINT32 Positive;\r
881 UINT32 Subtractive;\r
882\r
1a2ad6fc 883 *MtrrNumber = 0;\r
884\r
885 if (BaseAddress != 0) {\r
886 do {\r
887 //\r
888 // Calculate the alignment of the base address.\r
889 //\r
890 Alignment = LShiftU64 (1, (UINTN)LowBitSet64 (BaseAddress));\r
891\r
892 if (Alignment > Length) {\r
893 break;\r
894 }\r
895\r
896 (*MtrrNumber)++;\r
897 BaseAddress += Alignment;\r
898 Length -= Alignment;\r
899 } while (TRUE);\r
900\r
901 if (Length == 0) {\r
902 return TRUE;\r
903 }\r
904 }\r
905\r
906 TempQword = Length;\r
e50466da 907 Positive = 0;\r
908 Subtractive = 0;\r
909\r
910 do {\r
911 TempQword -= Power2MaxMemory (TempQword);\r
912 Positive++;\r
913 } while (TempQword != 0);\r
914\r
1a2ad6fc 915 TempQword = Power2MaxMemory (LShiftU64 (Length, 1)) - Length;\r
e50466da 916 Subtractive++;\r
917 do {\r
918 TempQword -= Power2MaxMemory (TempQword);\r
919 Subtractive++;\r
920 } while (TempQword != 0);\r
921\r
922 if (Positive <= Subtractive) {\r
1a2ad6fc 923 *MtrrNumber += Positive;\r
e50466da 924 return TRUE;\r
925 } else {\r
1a2ad6fc 926 *MtrrNumber += Subtractive;\r
e50466da 927 return FALSE;\r
928 }\r
929}\r
930\r
931/**\r
932 Invalid variable MTRRs according to the value in the shadow array.\r
933\r
934 This function programs MTRRs according to the values specified\r
935 in the shadow array.\r
936\r
b0fa5d29 937 @param[in, out] VariableSettings Variable MTRR settings\r
acf431e6 938 @param[in] VariableMtrrCount Number of variable MTRRs\r
76b4cae3 939 @param[in, out] VariableMtrr Shadow of variable MTRR contents\r
e50466da 940\r
941**/\r
e50466da 942VOID\r
943InvalidateMtrr (\r
b0fa5d29 944 IN OUT MTRR_VARIABLE_SETTINGS *VariableSettings,\r
acf431e6 945 IN UINTN VariableMtrrCount,\r
76b4cae3
MK
946 IN OUT VARIABLE_MTRR *VariableMtrr\r
947 )\r
e50466da 948{\r
c878cee4 949 UINTN Index;\r
e50466da 950\r
b0fa5d29 951 for (Index = 0; Index < VariableMtrrCount; Index++) {\r
430fbbe0 952 if (!VariableMtrr[Index].Valid && VariableMtrr[Index].Used) {\r
b0fa5d29
MK
953 VariableSettings->Mtrr[Index].Base = 0;\r
954 VariableSettings->Mtrr[Index].Mask = 0;\r
e50466da 955 VariableMtrr[Index].Used = FALSE;\r
956 }\r
e50466da 957 }\r
e50466da 958}\r
959\r
960\r
961/**\r
962 Programs variable MTRRs\r
963\r
964 This function programs variable MTRRs\r
965\r
b0fa5d29 966 @param[in, out] VariableSettings Variable MTRR settings.\r
76b4cae3
MK
967 @param[in] MtrrNumber Index of MTRR to program.\r
968 @param[in] BaseAddress Base address of memory region.\r
969 @param[in] Length Length of memory region.\r
970 @param[in] MemoryCacheType Memory type to set.\r
971 @param[in] MtrrValidAddressMask The valid address mask for MTRR\r
e50466da 972\r
973**/\r
e50466da 974VOID\r
975ProgramVariableMtrr (\r
b0fa5d29
MK
976 IN OUT MTRR_VARIABLE_SETTINGS *VariableSettings,\r
977 IN UINTN MtrrNumber,\r
978 IN PHYSICAL_ADDRESS BaseAddress,\r
979 IN UINT64 Length,\r
980 IN UINT64 MemoryCacheType,\r
981 IN UINT64 MtrrValidAddressMask\r
e50466da 982 )\r
983{\r
c878cee4 984 UINT64 TempQword;\r
e50466da 985\r
986 //\r
987 // MTRR Physical Base\r
988 //\r
989 TempQword = (BaseAddress & MtrrValidAddressMask) | MemoryCacheType;\r
b0fa5d29 990 VariableSettings->Mtrr[MtrrNumber].Base = TempQword;\r
e50466da 991\r
992 //\r
993 // MTRR Physical Mask\r
994 //\r
995 TempQword = ~(Length - 1);\r
b0fa5d29 996 VariableSettings->Mtrr[MtrrNumber].Mask = (TempQword & MtrrValidAddressMask) | MTRR_LIB_CACHE_MTRR_ENABLED;\r
e50466da 997}\r
998\r
999\r
1000/**\r
76b4cae3 1001 Converts the Memory attribute value to MTRR_MEMORY_CACHE_TYPE.\r
e50466da 1002\r
5abd5ed4
MK
1003 If MtrrSetting is not NULL, gets the default memory attribute from input\r
1004 MTRR settings buffer.\r
1005 If MtrrSetting is NULL, gets the default memory attribute from MSR.\r
1006\r
1007 @param[in] MtrrSetting A buffer holding all MTRRs content.\r
76b4cae3 1008 @param[in] MtrrType MTRR memory type\r
e50466da 1009\r
1010 @return The enum item in MTRR_MEMORY_CACHE_TYPE\r
1011\r
1012**/\r
e50466da 1013MTRR_MEMORY_CACHE_TYPE\r
1014GetMemoryCacheTypeFromMtrrType (\r
5abd5ed4 1015 IN MTRR_SETTINGS *MtrrSetting,\r
e50466da 1016 IN UINT64 MtrrType\r
1017 )\r
1018{\r
1019 switch (MtrrType) {\r
1020 case MTRR_CACHE_UNCACHEABLE:\r
1021 return CacheUncacheable;\r
1022 case MTRR_CACHE_WRITE_COMBINING:\r
1023 return CacheWriteCombining;\r
1024 case MTRR_CACHE_WRITE_THROUGH:\r
1025 return CacheWriteThrough;\r
1026 case MTRR_CACHE_WRITE_PROTECTED:\r
1027 return CacheWriteProtected;\r
1028 case MTRR_CACHE_WRITE_BACK:\r
1029 return CacheWriteBack;\r
1030 default:\r
1031 //\r
1032 // MtrrType is MTRR_CACHE_INVALID_TYPE, that means\r
76b4cae3 1033 // no MTRR covers the range\r
e50466da 1034 //\r
5abd5ed4 1035 return MtrrGetDefaultMemoryTypeWorker (MtrrSetting);\r
e50466da 1036 }\r
1037}\r
1038\r
1039/**\r
1040 Initializes the valid bits mask and valid address mask for MTRRs.\r
1041\r
1042 This function initializes the valid bits mask and valid address mask for MTRRs.\r
1043\r
76b4cae3
MK
1044 @param[out] MtrrValidBitsMask The mask for the valid bit of the MTRR\r
1045 @param[out] MtrrValidAddressMask The valid address mask for the MTRR\r
e50466da 1046\r
1047**/\r
e50466da 1048VOID\r
1049MtrrLibInitializeMtrrMask (\r
1050 OUT UINT64 *MtrrValidBitsMask,\r
1051 OUT UINT64 *MtrrValidAddressMask\r
1052 )\r
1053{\r
f877f300 1054 UINT32 RegEax;\r
1055 UINT8 PhysicalAddressBits;\r
e50466da 1056\r
1057 AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);\r
1058\r
1059 if (RegEax >= 0x80000008) {\r
1060 AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);\r
1061\r
1062 PhysicalAddressBits = (UINT8) RegEax;\r
1063\r
1064 *MtrrValidBitsMask = LShiftU64 (1, PhysicalAddressBits) - 1;\r
1065 *MtrrValidAddressMask = *MtrrValidBitsMask & 0xfffffffffffff000ULL;\r
1066 } else {\r
0a4f7aa0
JF
1067 *MtrrValidBitsMask = MTRR_LIB_MSR_VALID_MASK;\r
1068 *MtrrValidAddressMask = MTRR_LIB_CACHE_VALID_ADDRESS;\r
e50466da 1069 }\r
1070}\r
1071\r
1072\r
1073/**\r
76b4cae3 1074 Determines the real attribute of a memory range.\r
e50466da 1075\r
1076 This function is to arbitrate the real attribute of the memory when\r
76b4cae3 1077 there are 2 MTRRs covers the same memory range. For further details,\r
e50466da 1078 please refer the IA32 Software Developer's Manual, Volume 3,\r
1079 Section 10.11.4.1.\r
1080\r
76b4cae3
MK
1081 @param[in] MtrrType1 The first kind of Memory type\r
1082 @param[in] MtrrType2 The second kind of memory type\r
e50466da 1083\r
1084**/\r
1085UINT64\r
1086MtrrPrecedence (\r
76b4cae3
MK
1087 IN UINT64 MtrrType1,\r
1088 IN UINT64 MtrrType2\r
e50466da 1089 )\r
1090{\r
1091 UINT64 MtrrType;\r
1092\r
1093 MtrrType = MTRR_CACHE_INVALID_TYPE;\r
1094 switch (MtrrType1) {\r
1095 case MTRR_CACHE_UNCACHEABLE:\r
1096 MtrrType = MTRR_CACHE_UNCACHEABLE;\r
1097 break;\r
1098 case MTRR_CACHE_WRITE_COMBINING:\r
1099 if (\r
1100 MtrrType2==MTRR_CACHE_WRITE_COMBINING ||\r
1101 MtrrType2==MTRR_CACHE_UNCACHEABLE\r
1102 ) {\r
1103 MtrrType = MtrrType2;\r
1104 }\r
1105 break;\r
1106 case MTRR_CACHE_WRITE_THROUGH:\r
1107 if (\r
1108 MtrrType2==MTRR_CACHE_WRITE_THROUGH ||\r
1109 MtrrType2==MTRR_CACHE_WRITE_BACK\r
1110 ) {\r
1111 MtrrType = MTRR_CACHE_WRITE_THROUGH;\r
1112 } else if(MtrrType2==MTRR_CACHE_UNCACHEABLE) {\r
1113 MtrrType = MTRR_CACHE_UNCACHEABLE;\r
1114 }\r
1115 break;\r
1116 case MTRR_CACHE_WRITE_PROTECTED:\r
1117 if (MtrrType2 == MTRR_CACHE_WRITE_PROTECTED ||\r
1118 MtrrType2 == MTRR_CACHE_UNCACHEABLE) {\r
1119 MtrrType = MtrrType2;\r
1120 }\r
1121 break;\r
1122 case MTRR_CACHE_WRITE_BACK:\r
1123 if (\r
1124 MtrrType2== MTRR_CACHE_UNCACHEABLE ||\r
1125 MtrrType2==MTRR_CACHE_WRITE_THROUGH ||\r
1126 MtrrType2== MTRR_CACHE_WRITE_BACK\r
1127 ) {\r
1128 MtrrType = MtrrType2;\r
1129 }\r
1130 break;\r
1131 case MTRR_CACHE_INVALID_TYPE:\r
1132 MtrrType = MtrrType2;\r
1133 break;\r
1134 default:\r
1135 break;\r
1136 }\r
1137\r
1138 if (MtrrType2 == MTRR_CACHE_INVALID_TYPE) {\r
1139 MtrrType = MtrrType1;\r
1140 }\r
1141 return MtrrType;\r
1142}\r
1143\r
e50466da 1144/**\r
5abd5ed4 1145 Worker function will get the memory cache type of the specific address.\r
e50466da 1146\r
5abd5ed4
MK
1147 If MtrrSetting is not NULL, gets the memory cache type from input\r
1148 MTRR settings buffer.\r
1149 If MtrrSetting is NULL, gets the memory cache type from MTRRs.\r
e50466da 1150\r
5abd5ed4 1151 @param[in] MtrrSetting A buffer holding all MTRRs content.\r
85b7f65b
MK
1152 @param[in] Address The specific address\r
1153\r
1154 @return Memory cache type of the specific address\r
e50466da 1155\r
1156**/\r
85b7f65b 1157MTRR_MEMORY_CACHE_TYPE\r
5abd5ed4
MK
1158MtrrGetMemoryAttributeByAddressWorker (\r
1159 IN MTRR_SETTINGS *MtrrSetting,\r
85b7f65b 1160 IN PHYSICAL_ADDRESS Address\r
e50466da 1161 )\r
1162{\r
85b7f65b
MK
1163 UINT64 TempQword;\r
1164 UINTN Index;\r
1165 UINTN SubIndex;\r
1166 UINT64 MtrrType;\r
1167 UINT64 TempMtrrType;\r
1168 MTRR_MEMORY_CACHE_TYPE CacheType;\r
1169 VARIABLE_MTRR VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];\r
1170 UINT64 MtrrValidBitsMask;\r
1171 UINT64 MtrrValidAddressMask;\r
1172 UINTN VariableMtrrCount;\r
d0baed7d 1173 MTRR_VARIABLE_SETTINGS VariableSettings;\r
f877f300 1174\r
e50466da 1175 //\r
85b7f65b 1176 // Check if MTRR is enabled, if not, return UC as attribute\r
e50466da 1177 //\r
5abd5ed4
MK
1178 if (MtrrSetting == NULL) {\r
1179 TempQword = AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE);\r
1180 } else {\r
1181 TempQword = MtrrSetting->MtrrDefType;\r
1182 }\r
85b7f65b 1183 MtrrType = MTRR_CACHE_INVALID_TYPE;\r
e50466da 1184\r
85b7f65b
MK
1185 if ((TempQword & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
1186 return CacheUncacheable;\r
e50466da 1187 }\r
1188\r
1189 //\r
85b7f65b 1190 // If address is less than 1M, then try to go through the fixed MTRR\r
e50466da 1191 //\r
85b7f65b
MK
1192 if (Address < BASE_1MB) {\r
1193 if ((TempQword & MTRR_LIB_CACHE_FIXED_MTRR_ENABLED) != 0) {\r
1194 //\r
1195 // Go through the fixed MTRR\r
1196 //\r
1197 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
1198 if (Address >= mMtrrLibFixedMtrrTable[Index].BaseAddress &&\r
1199 Address < (\r
1200 mMtrrLibFixedMtrrTable[Index].BaseAddress +\r
1201 (mMtrrLibFixedMtrrTable[Index].Length * 8)\r
1202 )\r
1203 ) {\r
1204 SubIndex =\r
1205 ((UINTN)Address - mMtrrLibFixedMtrrTable[Index].BaseAddress) /\r
1206 mMtrrLibFixedMtrrTable[Index].Length;\r
5abd5ed4
MK
1207 if (MtrrSetting == NULL) {\r
1208 TempQword = AsmReadMsr64 (mMtrrLibFixedMtrrTable[Index].Msr);\r
1209 } else {\r
1210 TempQword = MtrrSetting->Fixed.Mtrr[Index];\r
1211 }\r
85b7f65b 1212 MtrrType = RShiftU64 (TempQword, SubIndex * 8) & 0xFF;\r
5abd5ed4 1213 return GetMemoryCacheTypeFromMtrrType (MtrrSetting, MtrrType);\r
85b7f65b
MK
1214 }\r
1215 }\r
e50466da 1216 }\r
1217 }\r
85b7f65b 1218 MtrrLibInitializeMtrrMask(&MtrrValidBitsMask, &MtrrValidAddressMask);\r
d0baed7d
MK
1219\r
1220 MtrrGetVariableMtrrWorker (\r
5abd5ed4 1221 MtrrSetting,\r
d0baed7d
MK
1222 GetVariableMtrrCountWorker (),\r
1223 &VariableSettings\r
85b7f65b 1224 );\r
e50466da 1225\r
d0baed7d
MK
1226 MtrrGetMemoryAttributeInVariableMtrrWorker (\r
1227 &VariableSettings,\r
1228 GetFirmwareVariableMtrrCountWorker (),\r
1229 MtrrValidBitsMask,\r
1230 MtrrValidAddressMask,\r
1231 VariableMtrr\r
1232 );\r
1233\r
e50466da 1234 //\r
85b7f65b 1235 // Go through the variable MTRR\r
e50466da 1236 //\r
acf431e6 1237 VariableMtrrCount = GetVariableMtrrCountWorker ();\r
85b7f65b
MK
1238 ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);\r
1239\r
1240 for (Index = 0; Index < VariableMtrrCount; Index++) {\r
1241 if (VariableMtrr[Index].Valid) {\r
1242 if (Address >= VariableMtrr[Index].BaseAddress &&\r
1243 Address < VariableMtrr[Index].BaseAddress+VariableMtrr[Index].Length) {\r
1244 TempMtrrType = VariableMtrr[Index].Type;\r
1245 MtrrType = MtrrPrecedence (MtrrType, TempMtrrType);\r
1246 }\r
1247 }\r
e50466da 1248 }\r
5abd5ed4 1249 CacheType = GetMemoryCacheTypeFromMtrrType (MtrrSetting, MtrrType);\r
e50466da 1250\r
85b7f65b
MK
1251 return CacheType;\r
1252}\r
1253\r
1254\r
5abd5ed4
MK
1255/**\r
1256 This function will get the memory cache type of the specific address.\r
1257\r
1258 This function is mainly for debug purpose.\r
1259\r
1260 @param[in] Address The specific address\r
1261\r
1262 @return Memory cache type of the specific address\r
1263\r
1264**/\r
1265MTRR_MEMORY_CACHE_TYPE\r
1266EFIAPI\r
1267MtrrGetMemoryAttribute (\r
1268 IN PHYSICAL_ADDRESS Address\r
1269 )\r
1270{\r
1271 if (!IsMtrrSupported ()) {\r
1272 return CacheUncacheable;\r
1273 }\r
1274\r
1275 return MtrrGetMemoryAttributeByAddressWorker (NULL, Address);\r
1276}\r
1277\r
85b7f65b 1278/**\r
16c2d37e
MK
1279 Worker function prints all MTRRs for debugging.\r
1280\r
1281 If MtrrSetting is not NULL, print MTRR settings from from input MTRR\r
1282 settings buffer.\r
1283 If MtrrSetting is NULL, print MTRR settings from MTRRs.\r
1284\r
1285 @param MtrrSetting A buffer holding all MTRRs content.\r
85b7f65b
MK
1286**/\r
1287VOID\r
16c2d37e
MK
1288MtrrDebugPrintAllMtrrsWorker (\r
1289 IN MTRR_SETTINGS *MtrrSetting\r
85b7f65b
MK
1290 )\r
1291{\r
1292 DEBUG_CODE (\r
16c2d37e
MK
1293 MTRR_SETTINGS LocalMtrrs;\r
1294 MTRR_SETTINGS *Mtrrs;\r
85b7f65b
MK
1295 UINTN Index;\r
1296 UINTN Index1;\r
1297 UINTN VariableMtrrCount;\r
1298 UINT64 Base;\r
1299 UINT64 Limit;\r
1300 UINT64 MtrrBase;\r
1301 UINT64 MtrrLimit;\r
1302 UINT64 RangeBase;\r
1303 UINT64 RangeLimit;\r
1304 UINT64 NoRangeBase;\r
1305 UINT64 NoRangeLimit;\r
1306 UINT32 RegEax;\r
1307 UINTN MemoryType;\r
1308 UINTN PreviousMemoryType;\r
1309 BOOLEAN Found;\r
1310\r
1311 if (!IsMtrrSupported ()) {\r
1312 return;\r
1313 }\r
1314\r
1315 DEBUG((DEBUG_CACHE, "MTRR Settings\n"));\r
1316 DEBUG((DEBUG_CACHE, "=============\n"));\r
1317\r
16c2d37e
MK
1318 if (MtrrSetting != NULL) {\r
1319 Mtrrs = MtrrSetting;\r
1320 } else {\r
1321 MtrrGetAllMtrrs (&LocalMtrrs);\r
1322 Mtrrs = &LocalMtrrs;\r
1323 }\r
1324\r
1325 DEBUG((DEBUG_CACHE, "MTRR Default Type: %016lx\n", Mtrrs->MtrrDefType));\r
85b7f65b 1326 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
16c2d37e 1327 DEBUG((DEBUG_CACHE, "Fixed MTRR[%02d] : %016lx\n", Index, Mtrrs->Fixed.Mtrr[Index]));\r
85b7f65b
MK
1328 }\r
1329\r
1330 VariableMtrrCount = GetVariableMtrrCount ();\r
1331 for (Index = 0; Index < VariableMtrrCount; Index++) {\r
1332 DEBUG((DEBUG_CACHE, "Variable MTRR[%02d]: Base=%016lx Mask=%016lx\n",\r
1333 Index,\r
16c2d37e
MK
1334 Mtrrs->Variables.Mtrr[Index].Base,\r
1335 Mtrrs->Variables.Mtrr[Index].Mask\r
85b7f65b
MK
1336 ));\r
1337 }\r
1338 DEBUG((DEBUG_CACHE, "\n"));\r
1339 DEBUG((DEBUG_CACHE, "MTRR Ranges\n"));\r
1340 DEBUG((DEBUG_CACHE, "====================================\n"));\r
1341\r
1342 Base = 0;\r
1343 PreviousMemoryType = MTRR_CACHE_INVALID_TYPE;\r
1344 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
1345 Base = mMtrrLibFixedMtrrTable[Index].BaseAddress;\r
1346 for (Index1 = 0; Index1 < 8; Index1++) {\r
16c2d37e 1347 MemoryType = (UINTN)(RShiftU64 (Mtrrs->Fixed.Mtrr[Index], Index1 * 8) & 0xff);\r
85b7f65b
MK
1348 if (MemoryType > CacheWriteBack) {\r
1349 MemoryType = MTRR_CACHE_INVALID_TYPE;\r
1350 }\r
1351 if (MemoryType != PreviousMemoryType) {\r
1352 if (PreviousMemoryType != MTRR_CACHE_INVALID_TYPE) {\r
1353 DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));\r
1354 }\r
1355 PreviousMemoryType = MemoryType;\r
1356 DEBUG((DEBUG_CACHE, "%a:%016lx-", mMtrrMemoryCacheTypeShortName[MemoryType], Base));\r
1357 }\r
1358 Base += mMtrrLibFixedMtrrTable[Index].Length;\r
1359 }\r
1360 }\r
1361 DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));\r
1362\r
1363 VariableMtrrCount = GetVariableMtrrCount ();\r
1364\r
1365 Limit = BIT36 - 1;\r
1366 AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);\r
1367 if (RegEax >= 0x80000008) {\r
1368 AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);\r
1369 Limit = LShiftU64 (1, RegEax & 0xff) - 1;\r
1370 }\r
1371 Base = BASE_1MB;\r
1372 PreviousMemoryType = MTRR_CACHE_INVALID_TYPE;\r
1373 do {\r
16c2d37e 1374 MemoryType = MtrrGetMemoryAttributeByAddressWorker (Mtrrs, Base);\r
85b7f65b
MK
1375 if (MemoryType > CacheWriteBack) {\r
1376 MemoryType = MTRR_CACHE_INVALID_TYPE;\r
1377 }\r
1378\r
1379 if (MemoryType != PreviousMemoryType) {\r
1380 if (PreviousMemoryType != MTRR_CACHE_INVALID_TYPE) {\r
1381 DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));\r
1382 }\r
1383 PreviousMemoryType = MemoryType;\r
1384 DEBUG((DEBUG_CACHE, "%a:%016lx-", mMtrrMemoryCacheTypeShortName[MemoryType], Base));\r
1385 }\r
1386\r
1387 RangeBase = BASE_1MB;\r
1388 NoRangeBase = BASE_1MB;\r
1389 RangeLimit = Limit;\r
1390 NoRangeLimit = Limit;\r
1391\r
1392 for (Index = 0, Found = FALSE; Index < VariableMtrrCount; Index++) {\r
16c2d37e 1393 if ((Mtrrs->Variables.Mtrr[Index].Mask & BIT11) == 0) {\r
85b7f65b
MK
1394 //\r
1395 // If mask is not valid, then do not display range\r
1396 //\r
1397 continue;\r
1398 }\r
16c2d37e
MK
1399 MtrrBase = (Mtrrs->Variables.Mtrr[Index].Base & (~(SIZE_4KB - 1)));\r
1400 MtrrLimit = MtrrBase + ((~(Mtrrs->Variables.Mtrr[Index].Mask & (~(SIZE_4KB - 1)))) & Limit);\r
85b7f65b
MK
1401\r
1402 if (Base >= MtrrBase && Base < MtrrLimit) {\r
1403 Found = TRUE;\r
1404 }\r
1405\r
1406 if (Base >= MtrrBase && MtrrBase > RangeBase) {\r
1407 RangeBase = MtrrBase;\r
1408 }\r
1409 if (Base > MtrrLimit && MtrrLimit > RangeBase) {\r
1410 RangeBase = MtrrLimit + 1;\r
1411 }\r
1412 if (Base < MtrrBase && MtrrBase < RangeLimit) {\r
1413 RangeLimit = MtrrBase - 1;\r
1414 }\r
1415 if (Base < MtrrLimit && MtrrLimit <= RangeLimit) {\r
1416 RangeLimit = MtrrLimit;\r
1417 }\r
1418\r
1419 if (Base > MtrrLimit && NoRangeBase < MtrrLimit) {\r
1420 NoRangeBase = MtrrLimit + 1;\r
1421 }\r
1422 if (Base < MtrrBase && NoRangeLimit > MtrrBase) {\r
1423 NoRangeLimit = MtrrBase - 1;\r
1424 }\r
1425 }\r
1426\r
1427 if (Found) {\r
1428 Base = RangeLimit + 1;\r
1429 } else {\r
1430 Base = NoRangeLimit + 1;\r
1431 }\r
1432 } while (Base < Limit);\r
1433 DEBUG((DEBUG_CACHE, "%016lx\n\n", Base - 1));\r
1434 );\r
1435}\r
16c2d37e
MK
1436\r
1437\r
1438/**\r
1439 This function prints all MTRRs for debugging.\r
1440**/\r
1441VOID\r
1442EFIAPI\r
1443MtrrDebugPrintAllMtrrs (\r
1444 VOID\r
1445 )\r
1446{\r
1447 MtrrDebugPrintAllMtrrsWorker (NULL);\r
1448}\r
1449\r
1450\r
85b7f65b 1451/**\r
16c2d37e 1452 Worker function attempts to set the attributes for a memory range.\r
85b7f65b 1453\r
b970ed68
MK
1454 If MtrrSettings is not NULL, set the attributes into the input MTRR\r
1455 settings buffer.\r
1456 If MtrrSettings is NULL, set the attributes into MTRRs registers.\r
1457\r
1458 @param[in, out] MtrrSetting A buffer holding all MTRRs content.\r
85b7f65b
MK
1459 @param[in] BaseAddress The physical address that is the start\r
1460 address of a memory region.\r
1461 @param[in] Length The size in bytes of the memory region.\r
1462 @param[in] Attribute The bit mask of attributes to set for the\r
1463 memory region.\r
1464\r
1465 @retval RETURN_SUCCESS The attributes were set for the memory\r
1466 region.\r
1467 @retval RETURN_INVALID_PARAMETER Length is zero.\r
1468 @retval RETURN_UNSUPPORTED The processor does not support one or\r
1469 more bytes of the memory resource range\r
1470 specified by BaseAddress and Length.\r
1471 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support\r
1472 for the memory resource range specified\r
1473 by BaseAddress and Length.\r
1474 @retval RETURN_ACCESS_DENIED The attributes for the memory resource\r
1475 range specified by BaseAddress and Length\r
1476 cannot be modified.\r
1477 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to\r
1478 modify the attributes of the memory\r
1479 resource range.\r
1480\r
1481**/\r
1482RETURN_STATUS\r
b970ed68
MK
1483MtrrSetMemoryAttributeWorker (\r
1484 IN OUT MTRR_SETTINGS *MtrrSetting,\r
1485 IN PHYSICAL_ADDRESS BaseAddress,\r
1486 IN UINT64 Length,\r
1487 IN MTRR_MEMORY_CACHE_TYPE Attribute\r
85b7f65b
MK
1488 )\r
1489{\r
1490 UINT64 TempQword;\r
1491 RETURN_STATUS Status;\r
1492 UINT64 MemoryType;\r
1493 UINT64 Alignment;\r
1494 BOOLEAN OverLap;\r
1495 BOOLEAN Positive;\r
1496 UINT32 MsrNum;\r
1497 UINTN MtrrNumber;\r
1498 VARIABLE_MTRR VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];\r
1499 UINT32 UsedMtrr;\r
1500 UINT64 MtrrValidBitsMask;\r
1501 UINT64 MtrrValidAddressMask;\r
1502 BOOLEAN OverwriteExistingMtrr;\r
1503 UINT32 FirmwareVariableMtrrCount;\r
85b7f65b 1504 MTRR_CONTEXT MtrrContext;\r
fa25cf38
MK
1505 BOOLEAN MtrrContextValid;\r
1506 BOOLEAN FixedSettingsValid[MTRR_NUMBER_OF_FIXED_MTRR];\r
1507 BOOLEAN FixedSettingsModified[MTRR_NUMBER_OF_FIXED_MTRR];\r
1508 MTRR_FIXED_SETTINGS WorkingFixedSettings;\r
acf431e6 1509 UINT32 VariableMtrrCount;\r
d0baed7d 1510 MTRR_VARIABLE_SETTINGS OriginalVariableSettings;\r
b0fa5d29 1511 BOOLEAN ProgramVariableSettings;\r
d0baed7d 1512 MTRR_VARIABLE_SETTINGS WorkingVariableSettings;\r
fa25cf38
MK
1513 UINT32 Index;\r
1514 UINT64 ClearMask;\r
1515 UINT64 OrMask;\r
1516 UINT64 NewValue;\r
d0baed7d 1517 MTRR_VARIABLE_SETTINGS *VariableSettings;\r
85b7f65b 1518\r
2d675c1c
JF
1519 MtrrContextValid = FALSE;\r
1520 VariableMtrrCount = 0;\r
1521 ZeroMem (&WorkingFixedSettings, sizeof (WorkingFixedSettings));\r
fa25cf38
MK
1522 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
1523 FixedSettingsValid[Index] = FALSE;\r
1524 FixedSettingsModified[Index] = FALSE;\r
1525 }\r
b0fa5d29 1526 ProgramVariableSettings = FALSE;\r
85b7f65b
MK
1527\r
1528 if (!IsMtrrSupported ()) {\r
1529 Status = RETURN_UNSUPPORTED;\r
1530 goto Done;\r
1531 }\r
1532\r
b0fa5d29 1533 MtrrLibInitializeMtrrMask (&MtrrValidBitsMask, &MtrrValidAddressMask);\r
85b7f65b
MK
1534\r
1535 TempQword = 0;\r
1536 MemoryType = (UINT64)Attribute;\r
1537 OverwriteExistingMtrr = FALSE;\r
1538\r
1539 //\r
1540 // Check for an invalid parameter\r
1541 //\r
1542 if (Length == 0) {\r
1543 Status = RETURN_INVALID_PARAMETER;\r
1544 goto Done;\r
1545 }\r
1546\r
1547 if (\r
1548 (BaseAddress & ~MtrrValidAddressMask) != 0 ||\r
1549 (Length & ~MtrrValidAddressMask) != 0\r
1550 ) {\r
1551 Status = RETURN_UNSUPPORTED;\r
1552 goto Done;\r
1553 }\r
1554\r
1555 //\r
1556 // Check if Fixed MTRR\r
1557 //\r
1558 Status = RETURN_SUCCESS;\r
fa25cf38 1559 if (BaseAddress < BASE_1MB) {\r
0f354122 1560 MsrNum = (UINT32)-1;\r
fa25cf38
MK
1561 while ((BaseAddress < BASE_1MB) && (Length > 0) && Status == RETURN_SUCCESS) {\r
1562 Status = ProgramFixedMtrr (MemoryType, &BaseAddress, &Length, &MsrNum, &ClearMask, &OrMask);\r
1563 if (RETURN_ERROR (Status)) {\r
1564 goto Done;\r
1565 }\r
b970ed68
MK
1566 if (MtrrSetting != NULL) {\r
1567 MtrrSetting->Fixed.Mtrr[MsrNum] = (MtrrSetting->Fixed.Mtrr[MsrNum] & ~ClearMask) | OrMask;\r
1568 MtrrSetting->MtrrDefType |= MTRR_LIB_CACHE_FIXED_MTRR_ENABLED;\r
1569 } else {\r
1570 if (!FixedSettingsValid[MsrNum]) {\r
1571 WorkingFixedSettings.Mtrr[MsrNum] = AsmReadMsr64 (mMtrrLibFixedMtrrTable[MsrNum].Msr);\r
1572 FixedSettingsValid[MsrNum] = TRUE;\r
1573 }\r
1574 NewValue = (WorkingFixedSettings.Mtrr[MsrNum] & ~ClearMask) | OrMask;\r
1575 if (WorkingFixedSettings.Mtrr[MsrNum] != NewValue) {\r
1576 WorkingFixedSettings.Mtrr[MsrNum] = NewValue;\r
1577 FixedSettingsModified[MsrNum] = TRUE;\r
1578 }\r
fa25cf38 1579 }\r
85b7f65b 1580 }\r
85b7f65b 1581\r
fa25cf38
MK
1582 if (Length == 0) {\r
1583 //\r
1584 // A Length of 0 can only make sense for fixed MTTR ranges.\r
1585 // Since we just handled the fixed MTRRs, we can skip the\r
1586 // variable MTRR section.\r
1587 //\r
1588 goto Done;\r
1589 }\r
85b7f65b
MK
1590 }\r
1591\r
1592 //\r
1593 // Since memory ranges below 1MB will be overridden by the fixed MTRRs,\r
1594 // we can set the base to 0 to save variable MTRRs.\r
1595 //\r
1596 if (BaseAddress == BASE_1MB) {\r
1597 BaseAddress = 0;\r
1598 Length += SIZE_1MB;\r
1599 }\r
1600\r
acf431e6
MK
1601 //\r
1602 // Read all variable MTRRs\r
1603 //\r
1604 VariableMtrrCount = GetVariableMtrrCountWorker ();\r
b0fa5d29 1605 FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCountWorker ();\r
b970ed68
MK
1606 if (MtrrSetting != NULL) {\r
1607 VariableSettings = &MtrrSetting->Variables;\r
1608 } else {\r
1609 MtrrGetVariableMtrrWorker (NULL, VariableMtrrCount, &OriginalVariableSettings);\r
1610 CopyMem (&WorkingVariableSettings, &OriginalVariableSettings, sizeof (WorkingVariableSettings));\r
1611 ProgramVariableSettings = TRUE;\r
1612 VariableSettings = &WorkingVariableSettings;\r
1613 }\r
acf431e6 1614\r
85b7f65b
MK
1615 //\r
1616 // Check for overlap\r
1617 //\r
d0baed7d
MK
1618 UsedMtrr = MtrrGetMemoryAttributeInVariableMtrrWorker (\r
1619 VariableSettings,\r
1620 FirmwareVariableMtrrCount,\r
1621 MtrrValidBitsMask,\r
1622 MtrrValidAddressMask,\r
1623 VariableMtrr\r
1624 );\r
acf431e6
MK
1625 OverLap = CheckMemoryAttributeOverlap (\r
1626 FirmwareVariableMtrrCount,\r
1627 BaseAddress,\r
1628 BaseAddress + Length - 1,\r
1629 VariableMtrr\r
1630 );\r
85b7f65b 1631 if (OverLap) {\r
acf431e6
MK
1632 Status = CombineMemoryAttribute (\r
1633 FirmwareVariableMtrrCount,\r
1634 MemoryType,\r
1635 &BaseAddress,\r
1636 &Length,\r
1637 VariableMtrr,\r
1638 &UsedMtrr,\r
1639 &OverwriteExistingMtrr\r
1640 );\r
e50466da 1641 if (RETURN_ERROR (Status)) {\r
1642 goto Done;\r
1643 }\r
1644\r
1645 if (Length == 0) {\r
1646 //\r
1e60a0ec 1647 // Combined successfully, invalidate the now-unused MTRRs\r
e50466da 1648 //\r
b0fa5d29 1649 InvalidateMtrr (VariableSettings, VariableMtrrCount, VariableMtrr);\r
e50466da 1650 Status = RETURN_SUCCESS;\r
1651 goto Done;\r
1652 }\r
1653 }\r
e50466da 1654\r
1655 //\r
1656 // The memory type is the same with the type specified by\r
1657 // MTRR_LIB_IA32_MTRR_DEF_TYPE.\r
1658 //\r
b970ed68 1659 if ((!OverwriteExistingMtrr) && (Attribute == MtrrGetDefaultMemoryTypeWorker (MtrrSetting))) {\r
e50466da 1660 //\r
1661 // Invalidate the now-unused MTRRs\r
1662 //\r
b0fa5d29 1663 InvalidateMtrr (VariableSettings, VariableMtrrCount, VariableMtrr);\r
e50466da 1664 goto Done;\r
1665 }\r
1666\r
1a2ad6fc 1667 Positive = GetMtrrNumberAndDirection (BaseAddress, Length, &MtrrNumber);\r
e50466da 1668\r
1a2ad6fc 1669 if ((UsedMtrr + MtrrNumber) > FirmwareVariableMtrrCount) {\r
1670 Status = RETURN_OUT_OF_RESOURCES;\r
1671 goto Done;\r
1672 }\r
e50466da 1673\r
1a2ad6fc 1674 //\r
1675 // Invalidate the now-unused MTRRs\r
1676 //\r
b0fa5d29 1677 InvalidateMtrr (VariableSettings, VariableMtrrCount, VariableMtrr);\r
1a2ad6fc 1678\r
1679 //\r
1680 // Find first unused MTRR\r
1681 //\r
b0fa5d29
MK
1682 for (MsrNum = 0; MsrNum < VariableMtrrCount; MsrNum++) {\r
1683 if ((VariableSettings->Mtrr[MsrNum].Mask & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
1a2ad6fc 1684 break;\r
1685 }\r
1686 }\r
1687\r
1688 if (BaseAddress != 0) {\r
1689 do {\r
1690 //\r
1691 // Calculate the alignment of the base address.\r
1692 //\r
1693 Alignment = LShiftU64 (1, (UINTN)LowBitSet64 (BaseAddress));\r
1694\r
1695 if (Alignment > Length) {\r
1696 break;\r
1697 }\r
1698\r
1699 //\r
1700 // Find unused MTRR\r
1701 //\r
b0fa5d29
MK
1702 for (; MsrNum < VariableMtrrCount; MsrNum++) {\r
1703 if ((VariableSettings->Mtrr[MsrNum].Mask & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
1a2ad6fc 1704 break;\r
1705 }\r
1706 }\r
1707\r
1708 ProgramVariableMtrr (\r
b0fa5d29 1709 VariableSettings,\r
1a2ad6fc 1710 MsrNum,\r
1711 BaseAddress,\r
1712 Alignment,\r
1713 MemoryType,\r
1714 MtrrValidAddressMask\r
1715 );\r
1716 BaseAddress += Alignment;\r
1717 Length -= Alignment;\r
1718 } while (TRUE);\r
1719\r
1720 if (Length == 0) {\r
1721 goto Done;\r
1722 }\r
1723 }\r
1724\r
1725 TempQword = Length;\r
1726\r
1727 if (!Positive) {\r
1728 Length = Power2MaxMemory (LShiftU64 (TempQword, 1));\r
e50466da 1729\r
1730 //\r
1a2ad6fc 1731 // Find unused MTRR\r
e50466da 1732 //\r
b0fa5d29
MK
1733 for (; MsrNum < VariableMtrrCount; MsrNum++) {\r
1734 if ((VariableSettings->Mtrr[MsrNum].Mask & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
e50466da 1735 break;\r
85b7f65b
MK
1736 }\r
1737 }\r
1738\r
1739 ProgramVariableMtrr (\r
b0fa5d29 1740 VariableSettings,\r
85b7f65b
MK
1741 MsrNum,\r
1742 BaseAddress,\r
1743 Length,\r
1744 MemoryType,\r
1745 MtrrValidAddressMask\r
1746 );\r
1747 BaseAddress += Length;\r
1748 TempQword = Length - TempQword;\r
1749 MemoryType = MTRR_CACHE_UNCACHEABLE;\r
e50466da 1750 }\r
1751\r
85b7f65b
MK
1752 do {\r
1753 //\r
1754 // Find unused MTRR\r
1755 //\r
b0fa5d29
MK
1756 for (; MsrNum < VariableMtrrCount; MsrNum++) {\r
1757 if ((VariableSettings->Mtrr[MsrNum].Mask & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
85b7f65b
MK
1758 break;\r
1759 }\r
1760 }\r
e50466da 1761\r
85b7f65b
MK
1762 Length = Power2MaxMemory (TempQword);\r
1763 if (!Positive) {\r
1764 BaseAddress -= Length;\r
1765 }\r
31b3597e 1766\r
85b7f65b 1767 ProgramVariableMtrr (\r
b0fa5d29 1768 VariableSettings,\r
85b7f65b
MK
1769 MsrNum,\r
1770 BaseAddress,\r
1771 Length,\r
1772 MemoryType,\r
1773 MtrrValidAddressMask\r
1774 );\r
31b3597e 1775\r
85b7f65b
MK
1776 if (Positive) {\r
1777 BaseAddress += Length;\r
1778 }\r
1779 TempQword -= Length;\r
31b3597e 1780\r
85b7f65b
MK
1781 } while (TempQword > 0);\r
1782\r
1783Done:\r
fa25cf38
MK
1784\r
1785 //\r
1786 // Write fixed MTRRs that have been modified\r
1787 //\r
1788 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
1789 if (FixedSettingsModified[Index]) {\r
1790 if (!MtrrContextValid) {\r
1791 PreMtrrChange (&MtrrContext);\r
1792 MtrrContextValid = TRUE;\r
1793 }\r
1794 AsmWriteMsr64 (\r
1795 mMtrrLibFixedMtrrTable[Index].Msr,\r
1796 WorkingFixedSettings.Mtrr[Index]\r
1797 );\r
1798 }\r
1799 }\r
1800\r
b0fa5d29
MK
1801 //\r
1802 // Write variable MTRRs\r
1803 //\r
1804 if (ProgramVariableSettings) {\r
1805 for (Index = 0; Index < VariableMtrrCount; Index++) {\r
1806 if (WorkingVariableSettings.Mtrr[Index].Base != OriginalVariableSettings.Mtrr[Index].Base ||\r
1807 WorkingVariableSettings.Mtrr[Index].Mask != OriginalVariableSettings.Mtrr[Index].Mask ) {\r
1808 if (!MtrrContextValid) {\r
1809 PreMtrrChange (&MtrrContext);\r
1810 MtrrContextValid = TRUE;\r
1811 }\r
1812 AsmWriteMsr64 (\r
1813 MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1),\r
1814 WorkingVariableSettings.Mtrr[Index].Base\r
1815 );\r
1816 AsmWriteMsr64 (\r
1817 MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1) + 1,\r
1818 WorkingVariableSettings.Mtrr[Index].Mask\r
1819 );\r
1820 }\r
1821 }\r
1822 }\r
fa25cf38
MK
1823 if (MtrrContextValid) {\r
1824 PostMtrrChange (&MtrrContext);\r
1825 }\r
1826\r
85b7f65b
MK
1827 DEBUG((DEBUG_CACHE, " Status = %r\n", Status));\r
1828 if (!RETURN_ERROR (Status)) {\r
b970ed68
MK
1829 if (MtrrSetting != NULL) {\r
1830 MtrrSetting->MtrrDefType |= MTRR_LIB_CACHE_MTRR_ENABLED;\r
1831 }\r
1832 MtrrDebugPrintAllMtrrsWorker (MtrrSetting);\r
31b3597e
MK
1833 }\r
1834\r
85b7f65b 1835 return Status;\r
31b3597e 1836}\r
b970ed68
MK
1837\r
1838/**\r
1839 This function attempts to set the attributes for a memory range.\r
1840\r
1841 @param[in] BaseAddress The physical address that is the start\r
1842 address of a memory region.\r
1843 @param[in] Length The size in bytes of the memory region.\r
1844 @param[in] Attributes The bit mask of attributes to set for the\r
1845 memory region.\r
1846\r
1847 @retval RETURN_SUCCESS The attributes were set for the memory\r
1848 region.\r
1849 @retval RETURN_INVALID_PARAMETER Length is zero.\r
1850 @retval RETURN_UNSUPPORTED The processor does not support one or\r
1851 more bytes of the memory resource range\r
1852 specified by BaseAddress and Length.\r
1853 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support\r
1854 for the memory resource range specified\r
1855 by BaseAddress and Length.\r
1856 @retval RETURN_ACCESS_DENIED The attributes for the memory resource\r
1857 range specified by BaseAddress and Length\r
1858 cannot be modified.\r
1859 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to\r
1860 modify the attributes of the memory\r
1861 resource range.\r
1862\r
1863**/\r
1864RETURN_STATUS\r
1865EFIAPI\r
1866MtrrSetMemoryAttribute (\r
1867 IN PHYSICAL_ADDRESS BaseAddress,\r
1868 IN UINT64 Length,\r
1869 IN MTRR_MEMORY_CACHE_TYPE Attribute\r
1870 )\r
1871{\r
1872 DEBUG((DEBUG_CACHE, "MtrrSetMemoryAttribute() %a:%016lx-%016lx\n", mMtrrMemoryCacheTypeShortName[Attribute], BaseAddress, Length));\r
1873 return MtrrSetMemoryAttributeWorker (\r
1874 NULL,\r
1875 BaseAddress,\r
1876 Length,\r
1877 Attribute\r
1878 );\r
1879}\r
1880\r
1881/**\r
1882 This function attempts to set the attributes into MTRR setting buffer for a memory range.\r
1883\r
1884 @param[in, out] MtrrSetting MTRR setting buffer to be set.\r
1885 @param[in] BaseAddress The physical address that is the start address\r
1886 of a memory region.\r
1887 @param[in] Length The size in bytes of the memory region.\r
1888 @param[in] Attribute The bit mask of attributes to set for the\r
1889 memory region.\r
1890\r
1891 @retval RETURN_SUCCESS The attributes were set for the memory region.\r
1892 @retval RETURN_INVALID_PARAMETER Length is zero.\r
1893 @retval RETURN_UNSUPPORTED The processor does not support one or more bytes of the\r
1894 memory resource range specified by BaseAddress and Length.\r
1895 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support for the memory resource\r
1896 range specified by BaseAddress and Length.\r
1897 @retval RETURN_ACCESS_DENIED The attributes for the memory resource range specified by\r
1898 BaseAddress and Length cannot be modified.\r
1899 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of\r
1900 the memory resource range.\r
1901\r
1902**/\r
1903RETURN_STATUS\r
1904EFIAPI\r
1905MtrrSetMemoryAttributeInMtrrSettings (\r
1906 IN OUT MTRR_SETTINGS *MtrrSetting,\r
1907 IN PHYSICAL_ADDRESS BaseAddress,\r
1908 IN UINT64 Length,\r
1909 IN MTRR_MEMORY_CACHE_TYPE Attribute\r
1910 )\r
1911{\r
1912 DEBUG((DEBUG_CACHE, "MtrrSetMemoryAttributeMtrrSettings(%p) %a:%016lx-%016lx\n", MtrrSetting, mMtrrMemoryCacheTypeShortName[Attribute], BaseAddress, Length));\r
1913 return MtrrSetMemoryAttributeWorker (\r
1914 MtrrSetting,\r
1915 BaseAddress,\r
1916 Length,\r
1917 Attribute\r
1918 );\r
1919}\r
1920\r
e50466da 1921/**\r
1922 Worker function setting variable MTRRs\r
1923\r
76b4cae3 1924 @param[in] VariableSettings A buffer to hold variable MTRRs content.\r
e50466da 1925\r
1926**/\r
1927VOID\r
1928MtrrSetVariableMtrrWorker (\r
1929 IN MTRR_VARIABLE_SETTINGS *VariableSettings\r
1930 )\r
1931{\r
1932 UINT32 Index;\r
3b9be416 1933 UINT32 VariableMtrrCount;\r
e50466da 1934\r
acf431e6 1935 VariableMtrrCount = GetVariableMtrrCountWorker ();\r
5bdfa4e5 1936 ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);\r
1937\r
3b9be416 1938 for (Index = 0; Index < VariableMtrrCount; Index++) {\r
e50466da 1939 AsmWriteMsr64 (\r
1940 MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1),\r
1941 VariableSettings->Mtrr[Index].Base\r
1942 );\r
1943 AsmWriteMsr64 (\r
1944 MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1) + 1,\r
1945 VariableSettings->Mtrr[Index].Mask\r
1946 );\r
1947 }\r
1948}\r
1949\r
1950\r
1951/**\r
1952 This function sets variable MTRRs\r
1953\r
76b4cae3 1954 @param[in] VariableSettings A buffer to hold variable MTRRs content.\r
e50466da 1955\r
1956 @return The pointer of VariableSettings\r
1957\r
1958**/\r
1959MTRR_VARIABLE_SETTINGS*\r
1960EFIAPI\r
1961MtrrSetVariableMtrr (\r
1962 IN MTRR_VARIABLE_SETTINGS *VariableSettings\r
1963 )\r
1964{\r
c878cee4 1965 MTRR_CONTEXT MtrrContext;\r
e50466da 1966\r
947a573a 1967 if (!IsMtrrSupported ()) {\r
1968 return VariableSettings;\r
1969 }\r
1970\r
c878cee4 1971 PreMtrrChange (&MtrrContext);\r
e50466da 1972 MtrrSetVariableMtrrWorker (VariableSettings);\r
c878cee4 1973 PostMtrrChange (&MtrrContext);\r
e518b80d
MK
1974 MtrrDebugPrintAllMtrrs ();\r
1975\r
e50466da 1976 return VariableSettings;\r
1977}\r
1978\r
e50466da 1979/**\r
1980 Worker function setting fixed MTRRs\r
1981\r
acf431e6 1982 @param[in] FixedSettings A buffer to hold fixed MTRRs content.\r
e50466da 1983\r
1984**/\r
1985VOID\r
1986MtrrSetFixedMtrrWorker (\r
1987 IN MTRR_FIXED_SETTINGS *FixedSettings\r
1988 )\r
1989{\r
1990 UINT32 Index;\r
1991\r
1992 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
1993 AsmWriteMsr64 (\r
f877f300 1994 mMtrrLibFixedMtrrTable[Index].Msr,\r
e50466da 1995 FixedSettings->Mtrr[Index]\r
1996 );\r
1997 }\r
1998}\r
1999\r
2000\r
2001/**\r
2002 This function sets fixed MTRRs\r
2003\r
acf431e6 2004 @param[in] FixedSettings A buffer to hold fixed MTRRs content.\r
e50466da 2005\r
2006 @retval The pointer of FixedSettings\r
2007\r
2008**/\r
2009MTRR_FIXED_SETTINGS*\r
2010EFIAPI\r
2011MtrrSetFixedMtrr (\r
2012 IN MTRR_FIXED_SETTINGS *FixedSettings\r
2013 )\r
2014{\r
c878cee4 2015 MTRR_CONTEXT MtrrContext;\r
e50466da 2016\r
947a573a 2017 if (!IsMtrrSupported ()) {\r
2018 return FixedSettings;\r
2019 }\r
2020\r
c878cee4 2021 PreMtrrChange (&MtrrContext);\r
e50466da 2022 MtrrSetFixedMtrrWorker (FixedSettings);\r
c878cee4 2023 PostMtrrChange (&MtrrContext);\r
e518b80d 2024 MtrrDebugPrintAllMtrrs ();\r
e50466da 2025\r
2026 return FixedSettings;\r
2027}\r
2028\r
2029\r
2030/**\r
2031 This function gets the content in all MTRRs (variable and fixed)\r
2032\r
acf431e6 2033 @param[out] MtrrSetting A buffer to hold all MTRRs content.\r
e50466da 2034\r
2035 @retval the pointer of MtrrSetting\r
2036\r
2037**/\r
2038MTRR_SETTINGS *\r
2039EFIAPI\r
2040MtrrGetAllMtrrs (\r
2041 OUT MTRR_SETTINGS *MtrrSetting\r
2042 )\r
2043{\r
947a573a 2044 if (!IsMtrrSupported ()) {\r
2045 return MtrrSetting;\r
2046 }\r
2047\r
e50466da 2048 //\r
2049 // Get fixed MTRRs\r
2050 //\r
acf431e6 2051 MtrrGetFixedMtrrWorker (&MtrrSetting->Fixed);\r
e50466da 2052\r
2053 //\r
2054 // Get variable MTRRs\r
2055 //\r
acf431e6 2056 MtrrGetVariableMtrrWorker (\r
5abd5ed4 2057 NULL,\r
acf431e6
MK
2058 GetVariableMtrrCountWorker (),\r
2059 &MtrrSetting->Variables\r
2060 );\r
e50466da 2061\r
2062 //\r
2063 // Get MTRR_DEF_TYPE value\r
2064 //\r
2065 MtrrSetting->MtrrDefType = AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE);\r
2066\r
2067 return MtrrSetting;\r
2068}\r
2069\r
2070\r
2071/**\r
2072 This function sets all MTRRs (variable and fixed)\r
2073\r
76b4cae3 2074 @param[in] MtrrSetting A buffer holding all MTRRs content.\r
e50466da 2075\r
2076 @retval The pointer of MtrrSetting\r
2077\r
2078**/\r
2079MTRR_SETTINGS *\r
2080EFIAPI\r
2081MtrrSetAllMtrrs (\r
2082 IN MTRR_SETTINGS *MtrrSetting\r
2083 )\r
2084{\r
c878cee4 2085 MTRR_CONTEXT MtrrContext;\r
e50466da 2086\r
947a573a 2087 if (!IsMtrrSupported ()) {\r
2088 return MtrrSetting;\r
2089 }\r
2090\r
c878cee4 2091 PreMtrrChange (&MtrrContext);\r
e50466da 2092\r
2093 //\r
2094 // Set fixed MTRRs\r
2095 //\r
2096 MtrrSetFixedMtrrWorker (&MtrrSetting->Fixed);\r
2097\r
2098 //\r
2099 // Set variable MTRRs\r
2100 //\r
2101 MtrrSetVariableMtrrWorker (&MtrrSetting->Variables);\r
2102\r
2103 //\r
2104 // Set MTRR_DEF_TYPE value\r
2105 //\r
2106 AsmWriteMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE, MtrrSetting->MtrrDefType);\r
2107\r
c878cee4 2108 PostMtrrChangeEnableCache (&MtrrContext);\r
e50466da 2109\r
2110 return MtrrSetting;\r
2111}\r
2112\r
e518b80d 2113\r
947a573a 2114/**\r
2115 Checks if MTRR is supported.\r
2116\r
2117 @retval TRUE MTRR is supported.\r
2118 @retval FALSE MTRR is not supported.\r
2119\r
2120**/\r
2121BOOLEAN\r
2122EFIAPI\r
2123IsMtrrSupported (\r
2124 VOID\r
2125 )\r
2126{\r
2127 UINT32 RegEdx;\r
2128 UINT64 MtrrCap;\r
2129\r
2130 //\r
2131 // Check CPUID(1).EDX[12] for MTRR capability\r
2132 //\r
2133 AsmCpuid (1, NULL, NULL, NULL, &RegEdx);\r
2134 if (BitFieldRead32 (RegEdx, 12, 12) == 0) {\r
2135 return FALSE;\r
2136 }\r
2137\r
2138 //\r
2139 // Check IA32_MTRRCAP.[0..7] for number of variable MTRRs and IA32_MTRRCAP[8] for\r
2140 // fixed MTRRs existence. If number of variable MTRRs is zero, or fixed MTRRs do not\r
2141 // exist, return false.\r
2142 //\r
2143 MtrrCap = AsmReadMsr64 (MTRR_LIB_IA32_MTRR_CAP);\r
2144 if ((BitFieldRead64 (MtrrCap, 0, 7) == 0) || (BitFieldRead64 (MtrrCap, 8, 8) == 0)) {\r
2145 return FALSE;\r
2146 }\r
2147\r
2148 return TRUE;\r
2149}\r