]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/Library/MtrrLib/MtrrLib.c
UefiCpuPkg/MtrrLib:Initialize local variables before use them
[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
462 UINT64 TempQword;\r
463 UINT64 OrMask;\r
464 UINT64 ClearMask;\r
465\r
466 TempQword = 0;\r
467 OrMask = 0;\r
468 ClearMask = 0;\r
469\r
470 for (MsrNum = 0; MsrNum < MTRR_NUMBER_OF_FIXED_MTRR; MsrNum++) {\r
f877f300 471 if ((*Base >= mMtrrLibFixedMtrrTable[MsrNum].BaseAddress) &&\r
e50466da 472 (*Base <\r
473 (\r
f877f300 474 mMtrrLibFixedMtrrTable[MsrNum].BaseAddress +\r
475 (8 * mMtrrLibFixedMtrrTable[MsrNum].Length)\r
e50466da 476 )\r
477 )\r
478 ) {\r
479 break;\r
480 }\r
481 }\r
482\r
483 if (MsrNum == MTRR_NUMBER_OF_FIXED_MTRR) {\r
484 return RETURN_UNSUPPORTED;\r
485 }\r
486\r
487 //\r
488 // We found the fixed MTRR to be programmed\r
489 //\r
490 for (ByteShift = 0; ByteShift < 8; ByteShift++) {\r
491 if (*Base ==\r
492 (\r
f877f300 493 mMtrrLibFixedMtrrTable[MsrNum].BaseAddress +\r
494 (ByteShift * mMtrrLibFixedMtrrTable[MsrNum].Length)\r
e50466da 495 )\r
496 ) {\r
497 break;\r
498 }\r
499 }\r
500\r
501 if (ByteShift == 8) {\r
502 return RETURN_UNSUPPORTED;\r
503 }\r
504\r
505 for (\r
506 ;\r
f877f300 507 ((ByteShift < 8) && (*Length >= mMtrrLibFixedMtrrTable[MsrNum].Length));\r
e50466da 508 ByteShift++\r
509 ) {\r
510 OrMask |= LShiftU64 ((UINT64) MemoryCacheType, (UINT32) (ByteShift * 8));\r
511 ClearMask |= LShiftU64 ((UINT64) 0xFF, (UINT32) (ByteShift * 8));\r
f877f300 512 *Length -= mMtrrLibFixedMtrrTable[MsrNum].Length;\r
513 *Base += mMtrrLibFixedMtrrTable[MsrNum].Length;\r
e50466da 514 }\r
515\r
516 if (ByteShift < 8 && (*Length != 0)) {\r
517 return RETURN_UNSUPPORTED;\r
518 }\r
519\r
fa25cf38
MK
520 *ReturnMsrNum = MsrNum;\r
521 *ReturnClearMask = ClearMask;\r
522 *ReturnOrMask = OrMask;\r
523\r
e50466da 524 return RETURN_SUCCESS;\r
525}\r
526\r
527\r
d0baed7d
MK
528/**\r
529 Worker function gets the attribute of variable MTRRs.\r
530\r
531 This function shadows the content of variable MTRRs into an\r
532 internal array: VariableMtrr.\r
533\r
534 @param[in] VariableSettings The variable MTRR values to shadow\r
535 @param[in] FirmwareVariableMtrrCount The number of variable MTRRs available to firmware\r
536 @param[in] MtrrValidBitsMask The mask for the valid bit of the MTRR\r
537 @param[in] MtrrValidAddressMask The valid address mask for MTRR\r
538 @param[out] VariableMtrr The array to shadow variable MTRRs content\r
539\r
540 @return The return value of this parameter indicates the\r
541 number of MTRRs which has been used.\r
542\r
543**/\r
544UINT32\r
545MtrrGetMemoryAttributeInVariableMtrrWorker (\r
546 IN MTRR_VARIABLE_SETTINGS *VariableSettings,\r
547 IN UINTN FirmwareVariableMtrrCount,\r
548 IN UINT64 MtrrValidBitsMask,\r
549 IN UINT64 MtrrValidAddressMask,\r
550 OUT VARIABLE_MTRR *VariableMtrr\r
551 )\r
552{\r
553 UINTN Index;\r
554 UINT32 UsedMtrr;\r
555\r
556 ZeroMem (VariableMtrr, sizeof (VARIABLE_MTRR) * MTRR_NUMBER_OF_VARIABLE_MTRR);\r
557 for (Index = 0, UsedMtrr = 0; Index < FirmwareVariableMtrrCount; Index++) {\r
558 if ((VariableSettings->Mtrr[Index].Mask & MTRR_LIB_CACHE_MTRR_ENABLED) != 0) {\r
559 VariableMtrr[Index].Msr = (UINT32)Index;\r
560 VariableMtrr[Index].BaseAddress = (VariableSettings->Mtrr[Index].Base & MtrrValidAddressMask);\r
561 VariableMtrr[Index].Length = ((~(VariableSettings->Mtrr[Index].Mask & MtrrValidAddressMask)) & MtrrValidBitsMask) + 1;\r
562 VariableMtrr[Index].Type = (VariableSettings->Mtrr[Index].Base & 0x0ff);\r
563 VariableMtrr[Index].Valid = TRUE;\r
564 VariableMtrr[Index].Used = TRUE;\r
565 UsedMtrr++;\r
566 }\r
567 }\r
568 return UsedMtrr;\r
569}\r
570\r
571\r
e50466da 572/**\r
76b4cae3 573 Gets the attribute of variable MTRRs.\r
e50466da 574\r
3ba736f3
JY
575 This function shadows the content of variable MTRRs into an\r
576 internal array: VariableMtrr.\r
e50466da 577\r
76b4cae3
MK
578 @param[in] MtrrValidBitsMask The mask for the valid bit of the MTRR\r
579 @param[in] MtrrValidAddressMask The valid address mask for MTRR\r
580 @param[out] VariableMtrr The array to shadow variable MTRRs content\r
e50466da 581\r
3ba736f3
JY
582 @return The return value of this paramter indicates the\r
583 number of MTRRs which has been used.\r
e50466da 584\r
585**/\r
3ba736f3 586UINT32\r
e50466da 587EFIAPI\r
588MtrrGetMemoryAttributeInVariableMtrr (\r
589 IN UINT64 MtrrValidBitsMask,\r
590 IN UINT64 MtrrValidAddressMask,\r
591 OUT VARIABLE_MTRR *VariableMtrr\r
592 )\r
593{\r
d0baed7d 594 MTRR_VARIABLE_SETTINGS VariableSettings;\r
3b9be416 595\r
947a573a 596 if (!IsMtrrSupported ()) {\r
597 return 0;\r
598 }\r
599\r
d0baed7d 600 MtrrGetVariableMtrrWorker (\r
5abd5ed4 601 NULL,\r
d0baed7d
MK
602 GetVariableMtrrCountWorker (),\r
603 &VariableSettings\r
604 );\r
e50466da 605\r
d0baed7d
MK
606 return MtrrGetMemoryAttributeInVariableMtrrWorker (\r
607 &VariableSettings,\r
608 GetFirmwareVariableMtrrCountWorker (),\r
609 MtrrValidBitsMask,\r
610 MtrrValidAddressMask,\r
611 VariableMtrr\r
612 );\r
e50466da 613}\r
614\r
615\r
616/**\r
617 Checks overlap between given memory range and MTRRs.\r
618\r
acf431e6
MK
619 @param[in] FirmwareVariableMtrrCount The number of variable MTRRs available\r
620 to firmware.\r
76b4cae3
MK
621 @param[in] Start The start address of memory range.\r
622 @param[in] End The end address of memory range.\r
623 @param[in] VariableMtrr The array to shadow variable MTRRs content\r
e50466da 624\r
625 @retval TRUE Overlap exists.\r
626 @retval FALSE No overlap.\r
627\r
628**/\r
629BOOLEAN\r
630CheckMemoryAttributeOverlap (\r
acf431e6
MK
631 IN UINTN FirmwareVariableMtrrCount,\r
632 IN PHYSICAL_ADDRESS Start,\r
633 IN PHYSICAL_ADDRESS End,\r
634 IN VARIABLE_MTRR *VariableMtrr\r
e50466da 635 )\r
636{\r
637 UINT32 Index;\r
638\r
acf431e6 639 for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) {\r
e50466da 640 if (\r
641 VariableMtrr[Index].Valid &&\r
642 !(\r
643 (Start > (VariableMtrr[Index].BaseAddress +\r
644 VariableMtrr[Index].Length - 1)\r
645 ) ||\r
646 (End < VariableMtrr[Index].BaseAddress)\r
647 )\r
648 ) {\r
649 return TRUE;\r
650 }\r
651 }\r
652\r
653 return FALSE;\r
654}\r
655\r
656\r
657/**\r
658 Marks a variable MTRR as non-valid.\r
659\r
76b4cae3
MK
660 @param[in] Index The index of the array VariableMtrr to be invalidated\r
661 @param[in] VariableMtrr The array to shadow variable MTRRs content\r
662 @param[out] UsedMtrr The number of MTRRs which has already been used\r
e50466da 663\r
664**/\r
665VOID\r
666InvalidateShadowMtrr (\r
667 IN UINTN Index,\r
668 IN VARIABLE_MTRR *VariableMtrr,\r
669 OUT UINT32 *UsedMtrr\r
670 )\r
671{\r
672 VariableMtrr[Index].Valid = FALSE;\r
673 *UsedMtrr = *UsedMtrr - 1;\r
674}\r
675\r
676\r
677/**\r
76b4cae3 678 Combines memory attributes.\r
e50466da 679\r
680 If overlap exists between given memory range and MTRRs, try to combine them.\r
681\r
acf431e6
MK
682 @param[in] FirmwareVariableMtrrCount The number of variable MTRRs\r
683 available to firmware.\r
76b4cae3
MK
684 @param[in] Attributes The memory type to set.\r
685 @param[in, out] Base The base address of memory range.\r
686 @param[in, out] Length The length of memory range.\r
687 @param[in] VariableMtrr The array to shadow variable MTRRs content\r
688 @param[in, out] UsedMtrr The number of MTRRs which has already been used\r
689 @param[out] OverwriteExistingMtrr Returns whether an existing MTRR was used\r
e50466da 690\r
691 @retval EFI_SUCCESS Memory region successfully combined.\r
692 @retval EFI_ACCESS_DENIED Memory region cannot be combined.\r
693\r
694**/\r
695RETURN_STATUS\r
696CombineMemoryAttribute (\r
acf431e6 697 IN UINT32 FirmwareVariableMtrrCount,\r
e50466da 698 IN UINT64 Attributes,\r
699 IN OUT UINT64 *Base,\r
700 IN OUT UINT64 *Length,\r
701 IN VARIABLE_MTRR *VariableMtrr,\r
702 IN OUT UINT32 *UsedMtrr,\r
703 OUT BOOLEAN *OverwriteExistingMtrr\r
704 )\r
705{\r
706 UINT32 Index;\r
707 UINT64 CombineStart;\r
708 UINT64 CombineEnd;\r
709 UINT64 MtrrEnd;\r
710 UINT64 EndAddress;\r
1e60a0ec 711 BOOLEAN CoveredByExistingMtrr;\r
3b9be416 712\r
e50466da 713 *OverwriteExistingMtrr = FALSE;\r
1e60a0ec 714 CoveredByExistingMtrr = FALSE;\r
e50466da 715 EndAddress = *Base +*Length - 1;\r
716\r
3b9be416 717 for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) {\r
e50466da 718\r
719 MtrrEnd = VariableMtrr[Index].BaseAddress + VariableMtrr[Index].Length - 1;\r
720 if (\r
721 !VariableMtrr[Index].Valid ||\r
722 (\r
723 *Base > (MtrrEnd) ||\r
724 (EndAddress < VariableMtrr[Index].BaseAddress)\r
725 )\r
726 ) {\r
727 continue;\r
728 }\r
729\r
730 //\r
731 // Combine same attribute MTRR range\r
732 //\r
733 if (Attributes == VariableMtrr[Index].Type) {\r
734 //\r
76b4cae3 735 // if the MTRR range contain the request range, set a flag, then continue to\r
1e60a0ec 736 // invalidate any MTRR of the same request range with higher priority cache type.\r
e50466da 737 //\r
738 if (VariableMtrr[Index].BaseAddress <= *Base && MtrrEnd >= EndAddress) {\r
1e60a0ec 739 CoveredByExistingMtrr = TRUE;\r
740 continue;\r
e50466da 741 }\r
742 //\r
743 // invalid this MTRR, and program the combine range\r
744 //\r
745 CombineStart =\r
746 (*Base) < VariableMtrr[Index].BaseAddress ?\r
747 (*Base) :\r
748 VariableMtrr[Index].BaseAddress;\r
749 CombineEnd = EndAddress > MtrrEnd ? EndAddress : MtrrEnd;\r
750\r
751 //\r
752 // Record the MTRR usage status in VariableMtrr array.\r
753 //\r
754 InvalidateShadowMtrr (Index, VariableMtrr, UsedMtrr);\r
755 *Base = CombineStart;\r
756 *Length = CombineEnd - CombineStart + 1;\r
757 EndAddress = CombineEnd;\r
758 *OverwriteExistingMtrr = TRUE;\r
759 continue;\r
760 } else {\r
761 //\r
762 // The cache type is different, but the range is convered by one MTRR\r
763 //\r
764 if (VariableMtrr[Index].BaseAddress == *Base && MtrrEnd == EndAddress) {\r
765 InvalidateShadowMtrr (Index, VariableMtrr, UsedMtrr);\r
766 continue;\r
767 }\r
768\r
769 }\r
770\r
771 if ((Attributes== MTRR_CACHE_WRITE_THROUGH &&\r
772 VariableMtrr[Index].Type == MTRR_CACHE_WRITE_BACK) ||\r
773 (Attributes == MTRR_CACHE_WRITE_BACK &&\r
774 VariableMtrr[Index].Type == MTRR_CACHE_WRITE_THROUGH) ||\r
775 (Attributes == MTRR_CACHE_UNCACHEABLE) ||\r
776 (VariableMtrr[Index].Type == MTRR_CACHE_UNCACHEABLE)\r
777 ) {\r
778 *OverwriteExistingMtrr = TRUE;\r
779 continue;\r
780 }\r
781 //\r
782 // Other type memory overlap is invalid\r
783 //\r
784 return RETURN_ACCESS_DENIED;\r
785 }\r
786\r
1e60a0ec 787 if (CoveredByExistingMtrr) {\r
788 *Length = 0;\r
789 }\r
790\r
e50466da 791 return RETURN_SUCCESS;\r
792}\r
793\r
794\r
795/**\r
76b4cae3
MK
796 Calculates the maximum value which is a power of 2, but less the MemoryLength.\r
797\r
798 @param[in] MemoryLength The number to pass in.\r
e50466da 799\r
e50466da 800 @return The maximum value which is align to power of 2 and less the MemoryLength\r
801\r
802**/\r
803UINT64\r
804Power2MaxMemory (\r
805 IN UINT64 MemoryLength\r
806 )\r
807{\r
808 UINT64 Result;\r
809\r
430fbbe0 810 if (RShiftU64 (MemoryLength, 32) != 0) {\r
e50466da 811 Result = LShiftU64 (\r
812 (UINT64) GetPowerOfTwo32 (\r
813 (UINT32) RShiftU64 (MemoryLength, 32)\r
814 ),\r
815 32\r
816 );\r
817 } else {\r
818 Result = (UINT64) GetPowerOfTwo32 ((UINT32) MemoryLength);\r
819 }\r
820\r
821 return Result;\r
822}\r
823\r
824\r
825/**\r
76b4cae3 826 Determines the MTRR numbers used to program a memory range.\r
e50466da 827\r
76b4cae3
MK
828 This function first checks the alignment of the base address.\r
829 If the alignment of the base address <= Length, cover the memory range\r
830 (BaseAddress, alignment) by a MTRR, then BaseAddress += alignment and\r
831 Length -= alignment. Repeat the step until alignment > Length.\r
e50466da 832\r
76b4cae3
MK
833 Then this function determines which direction of programming the variable\r
834 MTRRs for the remaining length will use fewer MTRRs.\r
1a2ad6fc 835\r
76b4cae3
MK
836 @param[in] BaseAddress Length of Memory to program MTRR\r
837 @param[in] Length Length of Memory to program MTRR\r
838 @param[in] MtrrNumber Pointer to the number of necessary MTRRs\r
e50466da 839\r
840 @retval TRUE Positive direction is better.\r
76b4cae3 841 FALSE Negative direction is better.\r
e50466da 842\r
843**/\r
844BOOLEAN\r
1a2ad6fc 845GetMtrrNumberAndDirection (\r
846 IN UINT64 BaseAddress,\r
847 IN UINT64 Length,\r
e50466da 848 IN UINTN *MtrrNumber\r
849 )\r
850{\r
851 UINT64 TempQword;\r
1a2ad6fc 852 UINT64 Alignment;\r
e50466da 853 UINT32 Positive;\r
854 UINT32 Subtractive;\r
855\r
1a2ad6fc 856 *MtrrNumber = 0;\r
857\r
858 if (BaseAddress != 0) {\r
859 do {\r
860 //\r
861 // Calculate the alignment of the base address.\r
862 //\r
863 Alignment = LShiftU64 (1, (UINTN)LowBitSet64 (BaseAddress));\r
864\r
865 if (Alignment > Length) {\r
866 break;\r
867 }\r
868\r
869 (*MtrrNumber)++;\r
870 BaseAddress += Alignment;\r
871 Length -= Alignment;\r
872 } while (TRUE);\r
873\r
874 if (Length == 0) {\r
875 return TRUE;\r
876 }\r
877 }\r
878\r
879 TempQword = Length;\r
e50466da 880 Positive = 0;\r
881 Subtractive = 0;\r
882\r
883 do {\r
884 TempQword -= Power2MaxMemory (TempQword);\r
885 Positive++;\r
886 } while (TempQword != 0);\r
887\r
1a2ad6fc 888 TempQword = Power2MaxMemory (LShiftU64 (Length, 1)) - Length;\r
e50466da 889 Subtractive++;\r
890 do {\r
891 TempQword -= Power2MaxMemory (TempQword);\r
892 Subtractive++;\r
893 } while (TempQword != 0);\r
894\r
895 if (Positive <= Subtractive) {\r
1a2ad6fc 896 *MtrrNumber += Positive;\r
e50466da 897 return TRUE;\r
898 } else {\r
1a2ad6fc 899 *MtrrNumber += Subtractive;\r
e50466da 900 return FALSE;\r
901 }\r
902}\r
903\r
904/**\r
905 Invalid variable MTRRs according to the value in the shadow array.\r
906\r
907 This function programs MTRRs according to the values specified\r
908 in the shadow array.\r
909\r
b0fa5d29 910 @param[in, out] VariableSettings Variable MTRR settings\r
acf431e6 911 @param[in] VariableMtrrCount Number of variable MTRRs\r
76b4cae3 912 @param[in, out] VariableMtrr Shadow of variable MTRR contents\r
e50466da 913\r
914**/\r
e50466da 915VOID\r
916InvalidateMtrr (\r
b0fa5d29 917 IN OUT MTRR_VARIABLE_SETTINGS *VariableSettings,\r
acf431e6 918 IN UINTN VariableMtrrCount,\r
76b4cae3
MK
919 IN OUT VARIABLE_MTRR *VariableMtrr\r
920 )\r
e50466da 921{\r
c878cee4 922 UINTN Index;\r
e50466da 923\r
b0fa5d29 924 for (Index = 0; Index < VariableMtrrCount; Index++) {\r
430fbbe0 925 if (!VariableMtrr[Index].Valid && VariableMtrr[Index].Used) {\r
b0fa5d29
MK
926 VariableSettings->Mtrr[Index].Base = 0;\r
927 VariableSettings->Mtrr[Index].Mask = 0;\r
e50466da 928 VariableMtrr[Index].Used = FALSE;\r
929 }\r
e50466da 930 }\r
e50466da 931}\r
932\r
933\r
934/**\r
935 Programs variable MTRRs\r
936\r
937 This function programs variable MTRRs\r
938\r
b0fa5d29 939 @param[in, out] VariableSettings Variable MTRR settings.\r
76b4cae3
MK
940 @param[in] MtrrNumber Index of MTRR to program.\r
941 @param[in] BaseAddress Base address of memory region.\r
942 @param[in] Length Length of memory region.\r
943 @param[in] MemoryCacheType Memory type to set.\r
944 @param[in] MtrrValidAddressMask The valid address mask for MTRR\r
e50466da 945\r
946**/\r
e50466da 947VOID\r
948ProgramVariableMtrr (\r
b0fa5d29
MK
949 IN OUT MTRR_VARIABLE_SETTINGS *VariableSettings,\r
950 IN UINTN MtrrNumber,\r
951 IN PHYSICAL_ADDRESS BaseAddress,\r
952 IN UINT64 Length,\r
953 IN UINT64 MemoryCacheType,\r
954 IN UINT64 MtrrValidAddressMask\r
e50466da 955 )\r
956{\r
c878cee4 957 UINT64 TempQword;\r
e50466da 958\r
959 //\r
960 // MTRR Physical Base\r
961 //\r
962 TempQword = (BaseAddress & MtrrValidAddressMask) | MemoryCacheType;\r
b0fa5d29 963 VariableSettings->Mtrr[MtrrNumber].Base = TempQword;\r
e50466da 964\r
965 //\r
966 // MTRR Physical Mask\r
967 //\r
968 TempQword = ~(Length - 1);\r
b0fa5d29 969 VariableSettings->Mtrr[MtrrNumber].Mask = (TempQword & MtrrValidAddressMask) | MTRR_LIB_CACHE_MTRR_ENABLED;\r
e50466da 970}\r
971\r
972\r
973/**\r
76b4cae3 974 Converts the Memory attribute value to MTRR_MEMORY_CACHE_TYPE.\r
e50466da 975\r
5abd5ed4
MK
976 If MtrrSetting is not NULL, gets the default memory attribute from input\r
977 MTRR settings buffer.\r
978 If MtrrSetting is NULL, gets the default memory attribute from MSR.\r
979\r
980 @param[in] MtrrSetting A buffer holding all MTRRs content.\r
76b4cae3 981 @param[in] MtrrType MTRR memory type\r
e50466da 982\r
983 @return The enum item in MTRR_MEMORY_CACHE_TYPE\r
984\r
985**/\r
e50466da 986MTRR_MEMORY_CACHE_TYPE\r
987GetMemoryCacheTypeFromMtrrType (\r
5abd5ed4 988 IN MTRR_SETTINGS *MtrrSetting,\r
e50466da 989 IN UINT64 MtrrType\r
990 )\r
991{\r
992 switch (MtrrType) {\r
993 case MTRR_CACHE_UNCACHEABLE:\r
994 return CacheUncacheable;\r
995 case MTRR_CACHE_WRITE_COMBINING:\r
996 return CacheWriteCombining;\r
997 case MTRR_CACHE_WRITE_THROUGH:\r
998 return CacheWriteThrough;\r
999 case MTRR_CACHE_WRITE_PROTECTED:\r
1000 return CacheWriteProtected;\r
1001 case MTRR_CACHE_WRITE_BACK:\r
1002 return CacheWriteBack;\r
1003 default:\r
1004 //\r
1005 // MtrrType is MTRR_CACHE_INVALID_TYPE, that means\r
76b4cae3 1006 // no MTRR covers the range\r
e50466da 1007 //\r
5abd5ed4 1008 return MtrrGetDefaultMemoryTypeWorker (MtrrSetting);\r
e50466da 1009 }\r
1010}\r
1011\r
1012/**\r
1013 Initializes the valid bits mask and valid address mask for MTRRs.\r
1014\r
1015 This function initializes the valid bits mask and valid address mask for MTRRs.\r
1016\r
76b4cae3
MK
1017 @param[out] MtrrValidBitsMask The mask for the valid bit of the MTRR\r
1018 @param[out] MtrrValidAddressMask The valid address mask for the MTRR\r
e50466da 1019\r
1020**/\r
e50466da 1021VOID\r
1022MtrrLibInitializeMtrrMask (\r
1023 OUT UINT64 *MtrrValidBitsMask,\r
1024 OUT UINT64 *MtrrValidAddressMask\r
1025 )\r
1026{\r
f877f300 1027 UINT32 RegEax;\r
1028 UINT8 PhysicalAddressBits;\r
e50466da 1029\r
1030 AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);\r
1031\r
1032 if (RegEax >= 0x80000008) {\r
1033 AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);\r
1034\r
1035 PhysicalAddressBits = (UINT8) RegEax;\r
1036\r
1037 *MtrrValidBitsMask = LShiftU64 (1, PhysicalAddressBits) - 1;\r
1038 *MtrrValidAddressMask = *MtrrValidBitsMask & 0xfffffffffffff000ULL;\r
1039 } else {\r
0a4f7aa0
JF
1040 *MtrrValidBitsMask = MTRR_LIB_MSR_VALID_MASK;\r
1041 *MtrrValidAddressMask = MTRR_LIB_CACHE_VALID_ADDRESS;\r
e50466da 1042 }\r
1043}\r
1044\r
1045\r
1046/**\r
76b4cae3 1047 Determines the real attribute of a memory range.\r
e50466da 1048\r
1049 This function is to arbitrate the real attribute of the memory when\r
76b4cae3 1050 there are 2 MTRRs covers the same memory range. For further details,\r
e50466da 1051 please refer the IA32 Software Developer's Manual, Volume 3,\r
1052 Section 10.11.4.1.\r
1053\r
76b4cae3
MK
1054 @param[in] MtrrType1 The first kind of Memory type\r
1055 @param[in] MtrrType2 The second kind of memory type\r
e50466da 1056\r
1057**/\r
1058UINT64\r
1059MtrrPrecedence (\r
76b4cae3
MK
1060 IN UINT64 MtrrType1,\r
1061 IN UINT64 MtrrType2\r
e50466da 1062 )\r
1063{\r
1064 UINT64 MtrrType;\r
1065\r
1066 MtrrType = MTRR_CACHE_INVALID_TYPE;\r
1067 switch (MtrrType1) {\r
1068 case MTRR_CACHE_UNCACHEABLE:\r
1069 MtrrType = MTRR_CACHE_UNCACHEABLE;\r
1070 break;\r
1071 case MTRR_CACHE_WRITE_COMBINING:\r
1072 if (\r
1073 MtrrType2==MTRR_CACHE_WRITE_COMBINING ||\r
1074 MtrrType2==MTRR_CACHE_UNCACHEABLE\r
1075 ) {\r
1076 MtrrType = MtrrType2;\r
1077 }\r
1078 break;\r
1079 case MTRR_CACHE_WRITE_THROUGH:\r
1080 if (\r
1081 MtrrType2==MTRR_CACHE_WRITE_THROUGH ||\r
1082 MtrrType2==MTRR_CACHE_WRITE_BACK\r
1083 ) {\r
1084 MtrrType = MTRR_CACHE_WRITE_THROUGH;\r
1085 } else if(MtrrType2==MTRR_CACHE_UNCACHEABLE) {\r
1086 MtrrType = MTRR_CACHE_UNCACHEABLE;\r
1087 }\r
1088 break;\r
1089 case MTRR_CACHE_WRITE_PROTECTED:\r
1090 if (MtrrType2 == MTRR_CACHE_WRITE_PROTECTED ||\r
1091 MtrrType2 == MTRR_CACHE_UNCACHEABLE) {\r
1092 MtrrType = MtrrType2;\r
1093 }\r
1094 break;\r
1095 case MTRR_CACHE_WRITE_BACK:\r
1096 if (\r
1097 MtrrType2== MTRR_CACHE_UNCACHEABLE ||\r
1098 MtrrType2==MTRR_CACHE_WRITE_THROUGH ||\r
1099 MtrrType2== MTRR_CACHE_WRITE_BACK\r
1100 ) {\r
1101 MtrrType = MtrrType2;\r
1102 }\r
1103 break;\r
1104 case MTRR_CACHE_INVALID_TYPE:\r
1105 MtrrType = MtrrType2;\r
1106 break;\r
1107 default:\r
1108 break;\r
1109 }\r
1110\r
1111 if (MtrrType2 == MTRR_CACHE_INVALID_TYPE) {\r
1112 MtrrType = MtrrType1;\r
1113 }\r
1114 return MtrrType;\r
1115}\r
1116\r
e50466da 1117/**\r
5abd5ed4 1118 Worker function will get the memory cache type of the specific address.\r
e50466da 1119\r
5abd5ed4
MK
1120 If MtrrSetting is not NULL, gets the memory cache type from input\r
1121 MTRR settings buffer.\r
1122 If MtrrSetting is NULL, gets the memory cache type from MTRRs.\r
e50466da 1123\r
5abd5ed4 1124 @param[in] MtrrSetting A buffer holding all MTRRs content.\r
85b7f65b
MK
1125 @param[in] Address The specific address\r
1126\r
1127 @return Memory cache type of the specific address\r
e50466da 1128\r
1129**/\r
85b7f65b 1130MTRR_MEMORY_CACHE_TYPE\r
5abd5ed4
MK
1131MtrrGetMemoryAttributeByAddressWorker (\r
1132 IN MTRR_SETTINGS *MtrrSetting,\r
85b7f65b 1133 IN PHYSICAL_ADDRESS Address\r
e50466da 1134 )\r
1135{\r
85b7f65b
MK
1136 UINT64 TempQword;\r
1137 UINTN Index;\r
1138 UINTN SubIndex;\r
1139 UINT64 MtrrType;\r
1140 UINT64 TempMtrrType;\r
1141 MTRR_MEMORY_CACHE_TYPE CacheType;\r
1142 VARIABLE_MTRR VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];\r
1143 UINT64 MtrrValidBitsMask;\r
1144 UINT64 MtrrValidAddressMask;\r
1145 UINTN VariableMtrrCount;\r
d0baed7d 1146 MTRR_VARIABLE_SETTINGS VariableSettings;\r
f877f300 1147\r
e50466da 1148 //\r
85b7f65b 1149 // Check if MTRR is enabled, if not, return UC as attribute\r
e50466da 1150 //\r
5abd5ed4
MK
1151 if (MtrrSetting == NULL) {\r
1152 TempQword = AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE);\r
1153 } else {\r
1154 TempQword = MtrrSetting->MtrrDefType;\r
1155 }\r
85b7f65b 1156 MtrrType = MTRR_CACHE_INVALID_TYPE;\r
e50466da 1157\r
85b7f65b
MK
1158 if ((TempQword & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
1159 return CacheUncacheable;\r
e50466da 1160 }\r
1161\r
1162 //\r
85b7f65b 1163 // If address is less than 1M, then try to go through the fixed MTRR\r
e50466da 1164 //\r
85b7f65b
MK
1165 if (Address < BASE_1MB) {\r
1166 if ((TempQword & MTRR_LIB_CACHE_FIXED_MTRR_ENABLED) != 0) {\r
1167 //\r
1168 // Go through the fixed MTRR\r
1169 //\r
1170 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
1171 if (Address >= mMtrrLibFixedMtrrTable[Index].BaseAddress &&\r
1172 Address < (\r
1173 mMtrrLibFixedMtrrTable[Index].BaseAddress +\r
1174 (mMtrrLibFixedMtrrTable[Index].Length * 8)\r
1175 )\r
1176 ) {\r
1177 SubIndex =\r
1178 ((UINTN)Address - mMtrrLibFixedMtrrTable[Index].BaseAddress) /\r
1179 mMtrrLibFixedMtrrTable[Index].Length;\r
5abd5ed4
MK
1180 if (MtrrSetting == NULL) {\r
1181 TempQword = AsmReadMsr64 (mMtrrLibFixedMtrrTable[Index].Msr);\r
1182 } else {\r
1183 TempQword = MtrrSetting->Fixed.Mtrr[Index];\r
1184 }\r
85b7f65b 1185 MtrrType = RShiftU64 (TempQword, SubIndex * 8) & 0xFF;\r
5abd5ed4 1186 return GetMemoryCacheTypeFromMtrrType (MtrrSetting, MtrrType);\r
85b7f65b
MK
1187 }\r
1188 }\r
e50466da 1189 }\r
1190 }\r
85b7f65b 1191 MtrrLibInitializeMtrrMask(&MtrrValidBitsMask, &MtrrValidAddressMask);\r
d0baed7d
MK
1192\r
1193 MtrrGetVariableMtrrWorker (\r
5abd5ed4 1194 MtrrSetting,\r
d0baed7d
MK
1195 GetVariableMtrrCountWorker (),\r
1196 &VariableSettings\r
85b7f65b 1197 );\r
e50466da 1198\r
d0baed7d
MK
1199 MtrrGetMemoryAttributeInVariableMtrrWorker (\r
1200 &VariableSettings,\r
1201 GetFirmwareVariableMtrrCountWorker (),\r
1202 MtrrValidBitsMask,\r
1203 MtrrValidAddressMask,\r
1204 VariableMtrr\r
1205 );\r
1206\r
e50466da 1207 //\r
85b7f65b 1208 // Go through the variable MTRR\r
e50466da 1209 //\r
acf431e6 1210 VariableMtrrCount = GetVariableMtrrCountWorker ();\r
85b7f65b
MK
1211 ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);\r
1212\r
1213 for (Index = 0; Index < VariableMtrrCount; Index++) {\r
1214 if (VariableMtrr[Index].Valid) {\r
1215 if (Address >= VariableMtrr[Index].BaseAddress &&\r
1216 Address < VariableMtrr[Index].BaseAddress+VariableMtrr[Index].Length) {\r
1217 TempMtrrType = VariableMtrr[Index].Type;\r
1218 MtrrType = MtrrPrecedence (MtrrType, TempMtrrType);\r
1219 }\r
1220 }\r
e50466da 1221 }\r
5abd5ed4 1222 CacheType = GetMemoryCacheTypeFromMtrrType (MtrrSetting, MtrrType);\r
e50466da 1223\r
85b7f65b
MK
1224 return CacheType;\r
1225}\r
1226\r
1227\r
5abd5ed4
MK
1228/**\r
1229 This function will get the memory cache type of the specific address.\r
1230\r
1231 This function is mainly for debug purpose.\r
1232\r
1233 @param[in] Address The specific address\r
1234\r
1235 @return Memory cache type of the specific address\r
1236\r
1237**/\r
1238MTRR_MEMORY_CACHE_TYPE\r
1239EFIAPI\r
1240MtrrGetMemoryAttribute (\r
1241 IN PHYSICAL_ADDRESS Address\r
1242 )\r
1243{\r
1244 if (!IsMtrrSupported ()) {\r
1245 return CacheUncacheable;\r
1246 }\r
1247\r
1248 return MtrrGetMemoryAttributeByAddressWorker (NULL, Address);\r
1249}\r
1250\r
85b7f65b 1251/**\r
16c2d37e
MK
1252 Worker function prints all MTRRs for debugging.\r
1253\r
1254 If MtrrSetting is not NULL, print MTRR settings from from input MTRR\r
1255 settings buffer.\r
1256 If MtrrSetting is NULL, print MTRR settings from MTRRs.\r
1257\r
1258 @param MtrrSetting A buffer holding all MTRRs content.\r
85b7f65b
MK
1259**/\r
1260VOID\r
16c2d37e
MK
1261MtrrDebugPrintAllMtrrsWorker (\r
1262 IN MTRR_SETTINGS *MtrrSetting\r
85b7f65b
MK
1263 )\r
1264{\r
1265 DEBUG_CODE (\r
16c2d37e
MK
1266 MTRR_SETTINGS LocalMtrrs;\r
1267 MTRR_SETTINGS *Mtrrs;\r
85b7f65b
MK
1268 UINTN Index;\r
1269 UINTN Index1;\r
1270 UINTN VariableMtrrCount;\r
1271 UINT64 Base;\r
1272 UINT64 Limit;\r
1273 UINT64 MtrrBase;\r
1274 UINT64 MtrrLimit;\r
1275 UINT64 RangeBase;\r
1276 UINT64 RangeLimit;\r
1277 UINT64 NoRangeBase;\r
1278 UINT64 NoRangeLimit;\r
1279 UINT32 RegEax;\r
1280 UINTN MemoryType;\r
1281 UINTN PreviousMemoryType;\r
1282 BOOLEAN Found;\r
1283\r
1284 if (!IsMtrrSupported ()) {\r
1285 return;\r
1286 }\r
1287\r
1288 DEBUG((DEBUG_CACHE, "MTRR Settings\n"));\r
1289 DEBUG((DEBUG_CACHE, "=============\n"));\r
1290\r
16c2d37e
MK
1291 if (MtrrSetting != NULL) {\r
1292 Mtrrs = MtrrSetting;\r
1293 } else {\r
1294 MtrrGetAllMtrrs (&LocalMtrrs);\r
1295 Mtrrs = &LocalMtrrs;\r
1296 }\r
1297\r
1298 DEBUG((DEBUG_CACHE, "MTRR Default Type: %016lx\n", Mtrrs->MtrrDefType));\r
85b7f65b 1299 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
16c2d37e 1300 DEBUG((DEBUG_CACHE, "Fixed MTRR[%02d] : %016lx\n", Index, Mtrrs->Fixed.Mtrr[Index]));\r
85b7f65b
MK
1301 }\r
1302\r
1303 VariableMtrrCount = GetVariableMtrrCount ();\r
1304 for (Index = 0; Index < VariableMtrrCount; Index++) {\r
1305 DEBUG((DEBUG_CACHE, "Variable MTRR[%02d]: Base=%016lx Mask=%016lx\n",\r
1306 Index,\r
16c2d37e
MK
1307 Mtrrs->Variables.Mtrr[Index].Base,\r
1308 Mtrrs->Variables.Mtrr[Index].Mask\r
85b7f65b
MK
1309 ));\r
1310 }\r
1311 DEBUG((DEBUG_CACHE, "\n"));\r
1312 DEBUG((DEBUG_CACHE, "MTRR Ranges\n"));\r
1313 DEBUG((DEBUG_CACHE, "====================================\n"));\r
1314\r
1315 Base = 0;\r
1316 PreviousMemoryType = MTRR_CACHE_INVALID_TYPE;\r
1317 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
1318 Base = mMtrrLibFixedMtrrTable[Index].BaseAddress;\r
1319 for (Index1 = 0; Index1 < 8; Index1++) {\r
16c2d37e 1320 MemoryType = (UINTN)(RShiftU64 (Mtrrs->Fixed.Mtrr[Index], Index1 * 8) & 0xff);\r
85b7f65b
MK
1321 if (MemoryType > CacheWriteBack) {\r
1322 MemoryType = MTRR_CACHE_INVALID_TYPE;\r
1323 }\r
1324 if (MemoryType != PreviousMemoryType) {\r
1325 if (PreviousMemoryType != MTRR_CACHE_INVALID_TYPE) {\r
1326 DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));\r
1327 }\r
1328 PreviousMemoryType = MemoryType;\r
1329 DEBUG((DEBUG_CACHE, "%a:%016lx-", mMtrrMemoryCacheTypeShortName[MemoryType], Base));\r
1330 }\r
1331 Base += mMtrrLibFixedMtrrTable[Index].Length;\r
1332 }\r
1333 }\r
1334 DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));\r
1335\r
1336 VariableMtrrCount = GetVariableMtrrCount ();\r
1337\r
1338 Limit = BIT36 - 1;\r
1339 AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);\r
1340 if (RegEax >= 0x80000008) {\r
1341 AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);\r
1342 Limit = LShiftU64 (1, RegEax & 0xff) - 1;\r
1343 }\r
1344 Base = BASE_1MB;\r
1345 PreviousMemoryType = MTRR_CACHE_INVALID_TYPE;\r
1346 do {\r
16c2d37e 1347 MemoryType = MtrrGetMemoryAttributeByAddressWorker (Mtrrs, Base);\r
85b7f65b
MK
1348 if (MemoryType > CacheWriteBack) {\r
1349 MemoryType = MTRR_CACHE_INVALID_TYPE;\r
1350 }\r
1351\r
1352 if (MemoryType != PreviousMemoryType) {\r
1353 if (PreviousMemoryType != MTRR_CACHE_INVALID_TYPE) {\r
1354 DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));\r
1355 }\r
1356 PreviousMemoryType = MemoryType;\r
1357 DEBUG((DEBUG_CACHE, "%a:%016lx-", mMtrrMemoryCacheTypeShortName[MemoryType], Base));\r
1358 }\r
1359\r
1360 RangeBase = BASE_1MB;\r
1361 NoRangeBase = BASE_1MB;\r
1362 RangeLimit = Limit;\r
1363 NoRangeLimit = Limit;\r
1364\r
1365 for (Index = 0, Found = FALSE; Index < VariableMtrrCount; Index++) {\r
16c2d37e 1366 if ((Mtrrs->Variables.Mtrr[Index].Mask & BIT11) == 0) {\r
85b7f65b
MK
1367 //\r
1368 // If mask is not valid, then do not display range\r
1369 //\r
1370 continue;\r
1371 }\r
16c2d37e
MK
1372 MtrrBase = (Mtrrs->Variables.Mtrr[Index].Base & (~(SIZE_4KB - 1)));\r
1373 MtrrLimit = MtrrBase + ((~(Mtrrs->Variables.Mtrr[Index].Mask & (~(SIZE_4KB - 1)))) & Limit);\r
85b7f65b
MK
1374\r
1375 if (Base >= MtrrBase && Base < MtrrLimit) {\r
1376 Found = TRUE;\r
1377 }\r
1378\r
1379 if (Base >= MtrrBase && MtrrBase > RangeBase) {\r
1380 RangeBase = MtrrBase;\r
1381 }\r
1382 if (Base > MtrrLimit && MtrrLimit > RangeBase) {\r
1383 RangeBase = MtrrLimit + 1;\r
1384 }\r
1385 if (Base < MtrrBase && MtrrBase < RangeLimit) {\r
1386 RangeLimit = MtrrBase - 1;\r
1387 }\r
1388 if (Base < MtrrLimit && MtrrLimit <= RangeLimit) {\r
1389 RangeLimit = MtrrLimit;\r
1390 }\r
1391\r
1392 if (Base > MtrrLimit && NoRangeBase < MtrrLimit) {\r
1393 NoRangeBase = MtrrLimit + 1;\r
1394 }\r
1395 if (Base < MtrrBase && NoRangeLimit > MtrrBase) {\r
1396 NoRangeLimit = MtrrBase - 1;\r
1397 }\r
1398 }\r
1399\r
1400 if (Found) {\r
1401 Base = RangeLimit + 1;\r
1402 } else {\r
1403 Base = NoRangeLimit + 1;\r
1404 }\r
1405 } while (Base < Limit);\r
1406 DEBUG((DEBUG_CACHE, "%016lx\n\n", Base - 1));\r
1407 );\r
1408}\r
16c2d37e
MK
1409\r
1410\r
1411/**\r
1412 This function prints all MTRRs for debugging.\r
1413**/\r
1414VOID\r
1415EFIAPI\r
1416MtrrDebugPrintAllMtrrs (\r
1417 VOID\r
1418 )\r
1419{\r
1420 MtrrDebugPrintAllMtrrsWorker (NULL);\r
1421}\r
1422\r
1423\r
85b7f65b 1424/**\r
16c2d37e 1425 Worker function attempts to set the attributes for a memory range.\r
85b7f65b 1426\r
b970ed68
MK
1427 If MtrrSettings is not NULL, set the attributes into the input MTRR\r
1428 settings buffer.\r
1429 If MtrrSettings is NULL, set the attributes into MTRRs registers.\r
1430\r
1431 @param[in, out] MtrrSetting A buffer holding all MTRRs content.\r
85b7f65b
MK
1432 @param[in] BaseAddress The physical address that is the start\r
1433 address of a memory region.\r
1434 @param[in] Length The size in bytes of the memory region.\r
1435 @param[in] Attribute The bit mask of attributes to set for the\r
1436 memory region.\r
1437\r
1438 @retval RETURN_SUCCESS The attributes were set for the memory\r
1439 region.\r
1440 @retval RETURN_INVALID_PARAMETER Length is zero.\r
1441 @retval RETURN_UNSUPPORTED The processor does not support one or\r
1442 more bytes of the memory resource range\r
1443 specified by BaseAddress and Length.\r
1444 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support\r
1445 for the memory resource range specified\r
1446 by BaseAddress and Length.\r
1447 @retval RETURN_ACCESS_DENIED The attributes for the memory resource\r
1448 range specified by BaseAddress and Length\r
1449 cannot be modified.\r
1450 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to\r
1451 modify the attributes of the memory\r
1452 resource range.\r
1453\r
1454**/\r
1455RETURN_STATUS\r
b970ed68
MK
1456MtrrSetMemoryAttributeWorker (\r
1457 IN OUT MTRR_SETTINGS *MtrrSetting,\r
1458 IN PHYSICAL_ADDRESS BaseAddress,\r
1459 IN UINT64 Length,\r
1460 IN MTRR_MEMORY_CACHE_TYPE Attribute\r
85b7f65b
MK
1461 )\r
1462{\r
1463 UINT64 TempQword;\r
1464 RETURN_STATUS Status;\r
1465 UINT64 MemoryType;\r
1466 UINT64 Alignment;\r
1467 BOOLEAN OverLap;\r
1468 BOOLEAN Positive;\r
1469 UINT32 MsrNum;\r
1470 UINTN MtrrNumber;\r
1471 VARIABLE_MTRR VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];\r
1472 UINT32 UsedMtrr;\r
1473 UINT64 MtrrValidBitsMask;\r
1474 UINT64 MtrrValidAddressMask;\r
1475 BOOLEAN OverwriteExistingMtrr;\r
1476 UINT32 FirmwareVariableMtrrCount;\r
85b7f65b 1477 MTRR_CONTEXT MtrrContext;\r
fa25cf38
MK
1478 BOOLEAN MtrrContextValid;\r
1479 BOOLEAN FixedSettingsValid[MTRR_NUMBER_OF_FIXED_MTRR];\r
1480 BOOLEAN FixedSettingsModified[MTRR_NUMBER_OF_FIXED_MTRR];\r
1481 MTRR_FIXED_SETTINGS WorkingFixedSettings;\r
acf431e6 1482 UINT32 VariableMtrrCount;\r
d0baed7d 1483 MTRR_VARIABLE_SETTINGS OriginalVariableSettings;\r
b0fa5d29 1484 BOOLEAN ProgramVariableSettings;\r
d0baed7d 1485 MTRR_VARIABLE_SETTINGS WorkingVariableSettings;\r
fa25cf38
MK
1486 UINT32 Index;\r
1487 UINT64 ClearMask;\r
1488 UINT64 OrMask;\r
1489 UINT64 NewValue;\r
d0baed7d 1490 MTRR_VARIABLE_SETTINGS *VariableSettings;\r
85b7f65b 1491\r
2d675c1c
JF
1492 MtrrContextValid = FALSE;\r
1493 VariableMtrrCount = 0;\r
1494 ZeroMem (&WorkingFixedSettings, sizeof (WorkingFixedSettings));\r
fa25cf38
MK
1495 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
1496 FixedSettingsValid[Index] = FALSE;\r
1497 FixedSettingsModified[Index] = FALSE;\r
1498 }\r
b0fa5d29 1499 ProgramVariableSettings = FALSE;\r
85b7f65b
MK
1500\r
1501 if (!IsMtrrSupported ()) {\r
1502 Status = RETURN_UNSUPPORTED;\r
1503 goto Done;\r
1504 }\r
1505\r
b0fa5d29 1506 MtrrLibInitializeMtrrMask (&MtrrValidBitsMask, &MtrrValidAddressMask);\r
85b7f65b
MK
1507\r
1508 TempQword = 0;\r
1509 MemoryType = (UINT64)Attribute;\r
1510 OverwriteExistingMtrr = FALSE;\r
1511\r
1512 //\r
1513 // Check for an invalid parameter\r
1514 //\r
1515 if (Length == 0) {\r
1516 Status = RETURN_INVALID_PARAMETER;\r
1517 goto Done;\r
1518 }\r
1519\r
1520 if (\r
1521 (BaseAddress & ~MtrrValidAddressMask) != 0 ||\r
1522 (Length & ~MtrrValidAddressMask) != 0\r
1523 ) {\r
1524 Status = RETURN_UNSUPPORTED;\r
1525 goto Done;\r
1526 }\r
1527\r
1528 //\r
1529 // Check if Fixed MTRR\r
1530 //\r
1531 Status = RETURN_SUCCESS;\r
fa25cf38
MK
1532 if (BaseAddress < BASE_1MB) {\r
1533 while ((BaseAddress < BASE_1MB) && (Length > 0) && Status == RETURN_SUCCESS) {\r
1534 Status = ProgramFixedMtrr (MemoryType, &BaseAddress, &Length, &MsrNum, &ClearMask, &OrMask);\r
1535 if (RETURN_ERROR (Status)) {\r
1536 goto Done;\r
1537 }\r
b970ed68
MK
1538 if (MtrrSetting != NULL) {\r
1539 MtrrSetting->Fixed.Mtrr[MsrNum] = (MtrrSetting->Fixed.Mtrr[MsrNum] & ~ClearMask) | OrMask;\r
1540 MtrrSetting->MtrrDefType |= MTRR_LIB_CACHE_FIXED_MTRR_ENABLED;\r
1541 } else {\r
1542 if (!FixedSettingsValid[MsrNum]) {\r
1543 WorkingFixedSettings.Mtrr[MsrNum] = AsmReadMsr64 (mMtrrLibFixedMtrrTable[MsrNum].Msr);\r
1544 FixedSettingsValid[MsrNum] = TRUE;\r
1545 }\r
1546 NewValue = (WorkingFixedSettings.Mtrr[MsrNum] & ~ClearMask) | OrMask;\r
1547 if (WorkingFixedSettings.Mtrr[MsrNum] != NewValue) {\r
1548 WorkingFixedSettings.Mtrr[MsrNum] = NewValue;\r
1549 FixedSettingsModified[MsrNum] = TRUE;\r
1550 }\r
fa25cf38 1551 }\r
85b7f65b 1552 }\r
85b7f65b 1553\r
fa25cf38
MK
1554 if (Length == 0) {\r
1555 //\r
1556 // A Length of 0 can only make sense for fixed MTTR ranges.\r
1557 // Since we just handled the fixed MTRRs, we can skip the\r
1558 // variable MTRR section.\r
1559 //\r
1560 goto Done;\r
1561 }\r
85b7f65b
MK
1562 }\r
1563\r
1564 //\r
1565 // Since memory ranges below 1MB will be overridden by the fixed MTRRs,\r
1566 // we can set the base to 0 to save variable MTRRs.\r
1567 //\r
1568 if (BaseAddress == BASE_1MB) {\r
1569 BaseAddress = 0;\r
1570 Length += SIZE_1MB;\r
1571 }\r
1572\r
acf431e6
MK
1573 //\r
1574 // Read all variable MTRRs\r
1575 //\r
1576 VariableMtrrCount = GetVariableMtrrCountWorker ();\r
b0fa5d29 1577 FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCountWorker ();\r
b970ed68
MK
1578 if (MtrrSetting != NULL) {\r
1579 VariableSettings = &MtrrSetting->Variables;\r
1580 } else {\r
1581 MtrrGetVariableMtrrWorker (NULL, VariableMtrrCount, &OriginalVariableSettings);\r
1582 CopyMem (&WorkingVariableSettings, &OriginalVariableSettings, sizeof (WorkingVariableSettings));\r
1583 ProgramVariableSettings = TRUE;\r
1584 VariableSettings = &WorkingVariableSettings;\r
1585 }\r
acf431e6 1586\r
85b7f65b
MK
1587 //\r
1588 // Check for overlap\r
1589 //\r
d0baed7d
MK
1590 UsedMtrr = MtrrGetMemoryAttributeInVariableMtrrWorker (\r
1591 VariableSettings,\r
1592 FirmwareVariableMtrrCount,\r
1593 MtrrValidBitsMask,\r
1594 MtrrValidAddressMask,\r
1595 VariableMtrr\r
1596 );\r
acf431e6
MK
1597 OverLap = CheckMemoryAttributeOverlap (\r
1598 FirmwareVariableMtrrCount,\r
1599 BaseAddress,\r
1600 BaseAddress + Length - 1,\r
1601 VariableMtrr\r
1602 );\r
85b7f65b 1603 if (OverLap) {\r
acf431e6
MK
1604 Status = CombineMemoryAttribute (\r
1605 FirmwareVariableMtrrCount,\r
1606 MemoryType,\r
1607 &BaseAddress,\r
1608 &Length,\r
1609 VariableMtrr,\r
1610 &UsedMtrr,\r
1611 &OverwriteExistingMtrr\r
1612 );\r
e50466da 1613 if (RETURN_ERROR (Status)) {\r
1614 goto Done;\r
1615 }\r
1616\r
1617 if (Length == 0) {\r
1618 //\r
1e60a0ec 1619 // Combined successfully, invalidate the now-unused MTRRs\r
e50466da 1620 //\r
b0fa5d29 1621 InvalidateMtrr (VariableSettings, VariableMtrrCount, VariableMtrr);\r
e50466da 1622 Status = RETURN_SUCCESS;\r
1623 goto Done;\r
1624 }\r
1625 }\r
e50466da 1626\r
1627 //\r
1628 // The memory type is the same with the type specified by\r
1629 // MTRR_LIB_IA32_MTRR_DEF_TYPE.\r
1630 //\r
b970ed68 1631 if ((!OverwriteExistingMtrr) && (Attribute == MtrrGetDefaultMemoryTypeWorker (MtrrSetting))) {\r
e50466da 1632 //\r
1633 // Invalidate the now-unused MTRRs\r
1634 //\r
b0fa5d29 1635 InvalidateMtrr (VariableSettings, VariableMtrrCount, VariableMtrr);\r
e50466da 1636 goto Done;\r
1637 }\r
1638\r
1a2ad6fc 1639 Positive = GetMtrrNumberAndDirection (BaseAddress, Length, &MtrrNumber);\r
e50466da 1640\r
1a2ad6fc 1641 if ((UsedMtrr + MtrrNumber) > FirmwareVariableMtrrCount) {\r
1642 Status = RETURN_OUT_OF_RESOURCES;\r
1643 goto Done;\r
1644 }\r
e50466da 1645\r
1a2ad6fc 1646 //\r
1647 // Invalidate the now-unused MTRRs\r
1648 //\r
b0fa5d29 1649 InvalidateMtrr (VariableSettings, VariableMtrrCount, VariableMtrr);\r
1a2ad6fc 1650\r
1651 //\r
1652 // Find first unused MTRR\r
1653 //\r
b0fa5d29
MK
1654 for (MsrNum = 0; MsrNum < VariableMtrrCount; MsrNum++) {\r
1655 if ((VariableSettings->Mtrr[MsrNum].Mask & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
1a2ad6fc 1656 break;\r
1657 }\r
1658 }\r
1659\r
1660 if (BaseAddress != 0) {\r
1661 do {\r
1662 //\r
1663 // Calculate the alignment of the base address.\r
1664 //\r
1665 Alignment = LShiftU64 (1, (UINTN)LowBitSet64 (BaseAddress));\r
1666\r
1667 if (Alignment > Length) {\r
1668 break;\r
1669 }\r
1670\r
1671 //\r
1672 // Find unused MTRR\r
1673 //\r
b0fa5d29
MK
1674 for (; MsrNum < VariableMtrrCount; MsrNum++) {\r
1675 if ((VariableSettings->Mtrr[MsrNum].Mask & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
1a2ad6fc 1676 break;\r
1677 }\r
1678 }\r
1679\r
1680 ProgramVariableMtrr (\r
b0fa5d29 1681 VariableSettings,\r
1a2ad6fc 1682 MsrNum,\r
1683 BaseAddress,\r
1684 Alignment,\r
1685 MemoryType,\r
1686 MtrrValidAddressMask\r
1687 );\r
1688 BaseAddress += Alignment;\r
1689 Length -= Alignment;\r
1690 } while (TRUE);\r
1691\r
1692 if (Length == 0) {\r
1693 goto Done;\r
1694 }\r
1695 }\r
1696\r
1697 TempQword = Length;\r
1698\r
1699 if (!Positive) {\r
1700 Length = Power2MaxMemory (LShiftU64 (TempQword, 1));\r
e50466da 1701\r
1702 //\r
1a2ad6fc 1703 // Find unused MTRR\r
e50466da 1704 //\r
b0fa5d29
MK
1705 for (; MsrNum < VariableMtrrCount; MsrNum++) {\r
1706 if ((VariableSettings->Mtrr[MsrNum].Mask & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
e50466da 1707 break;\r
85b7f65b
MK
1708 }\r
1709 }\r
1710\r
1711 ProgramVariableMtrr (\r
b0fa5d29 1712 VariableSettings,\r
85b7f65b
MK
1713 MsrNum,\r
1714 BaseAddress,\r
1715 Length,\r
1716 MemoryType,\r
1717 MtrrValidAddressMask\r
1718 );\r
1719 BaseAddress += Length;\r
1720 TempQword = Length - TempQword;\r
1721 MemoryType = MTRR_CACHE_UNCACHEABLE;\r
e50466da 1722 }\r
1723\r
85b7f65b
MK
1724 do {\r
1725 //\r
1726 // Find unused MTRR\r
1727 //\r
b0fa5d29
MK
1728 for (; MsrNum < VariableMtrrCount; MsrNum++) {\r
1729 if ((VariableSettings->Mtrr[MsrNum].Mask & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
85b7f65b
MK
1730 break;\r
1731 }\r
1732 }\r
e50466da 1733\r
85b7f65b
MK
1734 Length = Power2MaxMemory (TempQword);\r
1735 if (!Positive) {\r
1736 BaseAddress -= Length;\r
1737 }\r
31b3597e 1738\r
85b7f65b 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
31b3597e 1747\r
85b7f65b
MK
1748 if (Positive) {\r
1749 BaseAddress += Length;\r
1750 }\r
1751 TempQword -= Length;\r
31b3597e 1752\r
85b7f65b
MK
1753 } while (TempQword > 0);\r
1754\r
1755Done:\r
fa25cf38
MK
1756\r
1757 //\r
1758 // Write fixed MTRRs that have been modified\r
1759 //\r
1760 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
1761 if (FixedSettingsModified[Index]) {\r
1762 if (!MtrrContextValid) {\r
1763 PreMtrrChange (&MtrrContext);\r
1764 MtrrContextValid = TRUE;\r
1765 }\r
1766 AsmWriteMsr64 (\r
1767 mMtrrLibFixedMtrrTable[Index].Msr,\r
1768 WorkingFixedSettings.Mtrr[Index]\r
1769 );\r
1770 }\r
1771 }\r
1772\r
b0fa5d29
MK
1773 //\r
1774 // Write variable MTRRs\r
1775 //\r
1776 if (ProgramVariableSettings) {\r
1777 for (Index = 0; Index < VariableMtrrCount; Index++) {\r
1778 if (WorkingVariableSettings.Mtrr[Index].Base != OriginalVariableSettings.Mtrr[Index].Base ||\r
1779 WorkingVariableSettings.Mtrr[Index].Mask != OriginalVariableSettings.Mtrr[Index].Mask ) {\r
1780 if (!MtrrContextValid) {\r
1781 PreMtrrChange (&MtrrContext);\r
1782 MtrrContextValid = TRUE;\r
1783 }\r
1784 AsmWriteMsr64 (\r
1785 MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1),\r
1786 WorkingVariableSettings.Mtrr[Index].Base\r
1787 );\r
1788 AsmWriteMsr64 (\r
1789 MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1) + 1,\r
1790 WorkingVariableSettings.Mtrr[Index].Mask\r
1791 );\r
1792 }\r
1793 }\r
1794 }\r
fa25cf38
MK
1795 if (MtrrContextValid) {\r
1796 PostMtrrChange (&MtrrContext);\r
1797 }\r
1798\r
85b7f65b
MK
1799 DEBUG((DEBUG_CACHE, " Status = %r\n", Status));\r
1800 if (!RETURN_ERROR (Status)) {\r
b970ed68
MK
1801 if (MtrrSetting != NULL) {\r
1802 MtrrSetting->MtrrDefType |= MTRR_LIB_CACHE_MTRR_ENABLED;\r
1803 }\r
1804 MtrrDebugPrintAllMtrrsWorker (MtrrSetting);\r
31b3597e
MK
1805 }\r
1806\r
85b7f65b 1807 return Status;\r
31b3597e 1808}\r
b970ed68
MK
1809\r
1810/**\r
1811 This function attempts to set the attributes for a memory range.\r
1812\r
1813 @param[in] BaseAddress The physical address that is the start\r
1814 address of a memory region.\r
1815 @param[in] Length The size in bytes of the memory region.\r
1816 @param[in] Attributes The bit mask of attributes to set for the\r
1817 memory region.\r
1818\r
1819 @retval RETURN_SUCCESS The attributes were set for the memory\r
1820 region.\r
1821 @retval RETURN_INVALID_PARAMETER Length is zero.\r
1822 @retval RETURN_UNSUPPORTED The processor does not support one or\r
1823 more bytes of the memory resource range\r
1824 specified by BaseAddress and Length.\r
1825 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support\r
1826 for the memory resource range specified\r
1827 by BaseAddress and Length.\r
1828 @retval RETURN_ACCESS_DENIED The attributes for the memory resource\r
1829 range specified by BaseAddress and Length\r
1830 cannot be modified.\r
1831 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to\r
1832 modify the attributes of the memory\r
1833 resource range.\r
1834\r
1835**/\r
1836RETURN_STATUS\r
1837EFIAPI\r
1838MtrrSetMemoryAttribute (\r
1839 IN PHYSICAL_ADDRESS BaseAddress,\r
1840 IN UINT64 Length,\r
1841 IN MTRR_MEMORY_CACHE_TYPE Attribute\r
1842 )\r
1843{\r
1844 DEBUG((DEBUG_CACHE, "MtrrSetMemoryAttribute() %a:%016lx-%016lx\n", mMtrrMemoryCacheTypeShortName[Attribute], BaseAddress, Length));\r
1845 return MtrrSetMemoryAttributeWorker (\r
1846 NULL,\r
1847 BaseAddress,\r
1848 Length,\r
1849 Attribute\r
1850 );\r
1851}\r
1852\r
1853/**\r
1854 This function attempts to set the attributes into MTRR setting buffer for a memory range.\r
1855\r
1856 @param[in, out] MtrrSetting MTRR setting buffer to be set.\r
1857 @param[in] BaseAddress The physical address that is the start address\r
1858 of a memory region.\r
1859 @param[in] Length The size in bytes of the memory region.\r
1860 @param[in] Attribute The bit mask of attributes to set for the\r
1861 memory region.\r
1862\r
1863 @retval RETURN_SUCCESS The attributes were set for the memory region.\r
1864 @retval RETURN_INVALID_PARAMETER Length is zero.\r
1865 @retval RETURN_UNSUPPORTED The processor does not support one or more bytes of the\r
1866 memory resource range specified by BaseAddress and Length.\r
1867 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support for the memory resource\r
1868 range specified by BaseAddress and Length.\r
1869 @retval RETURN_ACCESS_DENIED The attributes for the memory resource range specified by\r
1870 BaseAddress and Length cannot be modified.\r
1871 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of\r
1872 the memory resource range.\r
1873\r
1874**/\r
1875RETURN_STATUS\r
1876EFIAPI\r
1877MtrrSetMemoryAttributeInMtrrSettings (\r
1878 IN OUT MTRR_SETTINGS *MtrrSetting,\r
1879 IN PHYSICAL_ADDRESS BaseAddress,\r
1880 IN UINT64 Length,\r
1881 IN MTRR_MEMORY_CACHE_TYPE Attribute\r
1882 )\r
1883{\r
1884 DEBUG((DEBUG_CACHE, "MtrrSetMemoryAttributeMtrrSettings(%p) %a:%016lx-%016lx\n", MtrrSetting, mMtrrMemoryCacheTypeShortName[Attribute], BaseAddress, Length));\r
1885 return MtrrSetMemoryAttributeWorker (\r
1886 MtrrSetting,\r
1887 BaseAddress,\r
1888 Length,\r
1889 Attribute\r
1890 );\r
1891}\r
1892\r
e50466da 1893/**\r
1894 Worker function setting variable MTRRs\r
1895\r
76b4cae3 1896 @param[in] VariableSettings A buffer to hold variable MTRRs content.\r
e50466da 1897\r
1898**/\r
1899VOID\r
1900MtrrSetVariableMtrrWorker (\r
1901 IN MTRR_VARIABLE_SETTINGS *VariableSettings\r
1902 )\r
1903{\r
1904 UINT32 Index;\r
3b9be416 1905 UINT32 VariableMtrrCount;\r
e50466da 1906\r
acf431e6 1907 VariableMtrrCount = GetVariableMtrrCountWorker ();\r
5bdfa4e5 1908 ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);\r
1909\r
3b9be416 1910 for (Index = 0; Index < VariableMtrrCount; Index++) {\r
e50466da 1911 AsmWriteMsr64 (\r
1912 MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1),\r
1913 VariableSettings->Mtrr[Index].Base\r
1914 );\r
1915 AsmWriteMsr64 (\r
1916 MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1) + 1,\r
1917 VariableSettings->Mtrr[Index].Mask\r
1918 );\r
1919 }\r
1920}\r
1921\r
1922\r
1923/**\r
1924 This function sets variable MTRRs\r
1925\r
76b4cae3 1926 @param[in] VariableSettings A buffer to hold variable MTRRs content.\r
e50466da 1927\r
1928 @return The pointer of VariableSettings\r
1929\r
1930**/\r
1931MTRR_VARIABLE_SETTINGS*\r
1932EFIAPI\r
1933MtrrSetVariableMtrr (\r
1934 IN MTRR_VARIABLE_SETTINGS *VariableSettings\r
1935 )\r
1936{\r
c878cee4 1937 MTRR_CONTEXT MtrrContext;\r
e50466da 1938\r
947a573a 1939 if (!IsMtrrSupported ()) {\r
1940 return VariableSettings;\r
1941 }\r
1942\r
c878cee4 1943 PreMtrrChange (&MtrrContext);\r
e50466da 1944 MtrrSetVariableMtrrWorker (VariableSettings);\r
c878cee4 1945 PostMtrrChange (&MtrrContext);\r
e518b80d
MK
1946 MtrrDebugPrintAllMtrrs ();\r
1947\r
e50466da 1948 return VariableSettings;\r
1949}\r
1950\r
e50466da 1951/**\r
1952 Worker function setting fixed MTRRs\r
1953\r
acf431e6 1954 @param[in] FixedSettings A buffer to hold fixed MTRRs content.\r
e50466da 1955\r
1956**/\r
1957VOID\r
1958MtrrSetFixedMtrrWorker (\r
1959 IN MTRR_FIXED_SETTINGS *FixedSettings\r
1960 )\r
1961{\r
1962 UINT32 Index;\r
1963\r
1964 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
1965 AsmWriteMsr64 (\r
f877f300 1966 mMtrrLibFixedMtrrTable[Index].Msr,\r
e50466da 1967 FixedSettings->Mtrr[Index]\r
1968 );\r
1969 }\r
1970}\r
1971\r
1972\r
1973/**\r
1974 This function sets fixed MTRRs\r
1975\r
acf431e6 1976 @param[in] FixedSettings A buffer to hold fixed MTRRs content.\r
e50466da 1977\r
1978 @retval The pointer of FixedSettings\r
1979\r
1980**/\r
1981MTRR_FIXED_SETTINGS*\r
1982EFIAPI\r
1983MtrrSetFixedMtrr (\r
1984 IN MTRR_FIXED_SETTINGS *FixedSettings\r
1985 )\r
1986{\r
c878cee4 1987 MTRR_CONTEXT MtrrContext;\r
e50466da 1988\r
947a573a 1989 if (!IsMtrrSupported ()) {\r
1990 return FixedSettings;\r
1991 }\r
1992\r
c878cee4 1993 PreMtrrChange (&MtrrContext);\r
e50466da 1994 MtrrSetFixedMtrrWorker (FixedSettings);\r
c878cee4 1995 PostMtrrChange (&MtrrContext);\r
e518b80d 1996 MtrrDebugPrintAllMtrrs ();\r
e50466da 1997\r
1998 return FixedSettings;\r
1999}\r
2000\r
2001\r
2002/**\r
2003 This function gets the content in all MTRRs (variable and fixed)\r
2004\r
acf431e6 2005 @param[out] MtrrSetting A buffer to hold all MTRRs content.\r
e50466da 2006\r
2007 @retval the pointer of MtrrSetting\r
2008\r
2009**/\r
2010MTRR_SETTINGS *\r
2011EFIAPI\r
2012MtrrGetAllMtrrs (\r
2013 OUT MTRR_SETTINGS *MtrrSetting\r
2014 )\r
2015{\r
947a573a 2016 if (!IsMtrrSupported ()) {\r
2017 return MtrrSetting;\r
2018 }\r
2019\r
e50466da 2020 //\r
2021 // Get fixed MTRRs\r
2022 //\r
acf431e6 2023 MtrrGetFixedMtrrWorker (&MtrrSetting->Fixed);\r
e50466da 2024\r
2025 //\r
2026 // Get variable MTRRs\r
2027 //\r
acf431e6 2028 MtrrGetVariableMtrrWorker (\r
5abd5ed4 2029 NULL,\r
acf431e6
MK
2030 GetVariableMtrrCountWorker (),\r
2031 &MtrrSetting->Variables\r
2032 );\r
e50466da 2033\r
2034 //\r
2035 // Get MTRR_DEF_TYPE value\r
2036 //\r
2037 MtrrSetting->MtrrDefType = AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE);\r
2038\r
2039 return MtrrSetting;\r
2040}\r
2041\r
2042\r
2043/**\r
2044 This function sets all MTRRs (variable and fixed)\r
2045\r
76b4cae3 2046 @param[in] MtrrSetting A buffer holding all MTRRs content.\r
e50466da 2047\r
2048 @retval The pointer of MtrrSetting\r
2049\r
2050**/\r
2051MTRR_SETTINGS *\r
2052EFIAPI\r
2053MtrrSetAllMtrrs (\r
2054 IN MTRR_SETTINGS *MtrrSetting\r
2055 )\r
2056{\r
c878cee4 2057 MTRR_CONTEXT MtrrContext;\r
e50466da 2058\r
947a573a 2059 if (!IsMtrrSupported ()) {\r
2060 return MtrrSetting;\r
2061 }\r
2062\r
c878cee4 2063 PreMtrrChange (&MtrrContext);\r
e50466da 2064\r
2065 //\r
2066 // Set fixed MTRRs\r
2067 //\r
2068 MtrrSetFixedMtrrWorker (&MtrrSetting->Fixed);\r
2069\r
2070 //\r
2071 // Set variable MTRRs\r
2072 //\r
2073 MtrrSetVariableMtrrWorker (&MtrrSetting->Variables);\r
2074\r
2075 //\r
2076 // Set MTRR_DEF_TYPE value\r
2077 //\r
2078 AsmWriteMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE, MtrrSetting->MtrrDefType);\r
2079\r
c878cee4 2080 PostMtrrChangeEnableCache (&MtrrContext);\r
e50466da 2081\r
e518b80d
MK
2082 MtrrDebugPrintAllMtrrs ();\r
2083\r
e50466da 2084 return MtrrSetting;\r
2085}\r
2086\r
e518b80d 2087\r
947a573a 2088/**\r
2089 Checks if MTRR is supported.\r
2090\r
2091 @retval TRUE MTRR is supported.\r
2092 @retval FALSE MTRR is not supported.\r
2093\r
2094**/\r
2095BOOLEAN\r
2096EFIAPI\r
2097IsMtrrSupported (\r
2098 VOID\r
2099 )\r
2100{\r
2101 UINT32 RegEdx;\r
2102 UINT64 MtrrCap;\r
2103\r
2104 //\r
2105 // Check CPUID(1).EDX[12] for MTRR capability\r
2106 //\r
2107 AsmCpuid (1, NULL, NULL, NULL, &RegEdx);\r
2108 if (BitFieldRead32 (RegEdx, 12, 12) == 0) {\r
2109 return FALSE;\r
2110 }\r
2111\r
2112 //\r
2113 // Check IA32_MTRRCAP.[0..7] for number of variable MTRRs and IA32_MTRRCAP[8] for\r
2114 // fixed MTRRs existence. If number of variable MTRRs is zero, or fixed MTRRs do not\r
2115 // exist, return false.\r
2116 //\r
2117 MtrrCap = AsmReadMsr64 (MTRR_LIB_IA32_MTRR_CAP);\r
2118 if ((BitFieldRead64 (MtrrCap, 0, 7) == 0) || (BitFieldRead64 (MtrrCap, 8, 8) == 0)) {\r
2119 return FALSE;\r
2120 }\r
2121\r
2122 return TRUE;\r
2123}\r