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