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