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