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