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