]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - UefiCpuPkg/Library/MtrrLib/MtrrLib.c
MdeModulePkg/MdeModulePkg.uni: clarify Heap Guard usage
[mirror_edk2.git] / UefiCpuPkg / Library / MtrrLib / MtrrLib.c
... / ...
CommitLineData
1/** @file\r
2 MTRR setting library\r
3\r
4 @par Note: \r
5 Most of services in this library instance are suggested to be invoked by BSP only,\r
6 except for MtrrSetAllMtrrs() which is used to sync BSP's MTRR setting to APs.\r
7\r
8 Copyright (c) 2008 - 2017, Intel Corporation. All rights reserved.<BR>\r
9 This program and the accompanying materials\r
10 are licensed and made available under the terms and conditions of the BSD License\r
11 which accompanies this distribution. The full text of the license may be found at\r
12 http://opensource.org/licenses/bsd-license.php\r
13\r
14 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
15 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
16\r
17**/\r
18\r
19#include <Uefi.h>\r
20#include <Register/Cpuid.h>\r
21#include <Register/Msr.h>\r
22\r
23#include <Library/MtrrLib.h>\r
24#include <Library/BaseLib.h>\r
25#include <Library/CpuLib.h>\r
26#include <Library/BaseMemoryLib.h>\r
27#include <Library/DebugLib.h>\r
28\r
29#define OR_SEED 0x0101010101010101ull\r
30#define CLEAR_SEED 0xFFFFFFFFFFFFFFFFull\r
31#define MAX_WEIGHT MAX_UINT8\r
32#define SCRATCH_BUFFER_SIZE (4 * SIZE_4KB)\r
33#define MTRR_LIB_ASSERT_ALIGNED(B, L) ASSERT ((B & ~(L - 1)) == B);\r
34\r
35#define M(x,y) ((x) * VectorCount + (y))\r
36#define O(x,y) ((y) * VectorCount + (x))\r
37\r
38//\r
39// Context to save and restore when MTRRs are programmed\r
40//\r
41typedef struct {\r
42 UINTN Cr4;\r
43 BOOLEAN InterruptState;\r
44} MTRR_CONTEXT;\r
45\r
46typedef struct {\r
47 UINT64 Address;\r
48 UINT64 Alignment;\r
49 UINT64 Length;\r
50 UINT8 Type : 7;\r
51\r
52 //\r
53 // Temprary use for calculating the best MTRR settings.\r
54 //\r
55 BOOLEAN Visited : 1;\r
56 UINT8 Weight;\r
57 UINT16 Previous;\r
58} MTRR_LIB_ADDRESS;\r
59\r
60//\r
61// This table defines the offset, base and length of the fixed MTRRs\r
62//\r
63CONST FIXED_MTRR mMtrrLibFixedMtrrTable[] = {\r
64 {\r
65 MSR_IA32_MTRR_FIX64K_00000,\r
66 0,\r
67 SIZE_64KB\r
68 },\r
69 {\r
70 MSR_IA32_MTRR_FIX16K_80000,\r
71 0x80000,\r
72 SIZE_16KB\r
73 },\r
74 {\r
75 MSR_IA32_MTRR_FIX16K_A0000,\r
76 0xA0000,\r
77 SIZE_16KB\r
78 },\r
79 {\r
80 MSR_IA32_MTRR_FIX4K_C0000,\r
81 0xC0000,\r
82 SIZE_4KB\r
83 },\r
84 {\r
85 MSR_IA32_MTRR_FIX4K_C8000,\r
86 0xC8000,\r
87 SIZE_4KB\r
88 },\r
89 {\r
90 MSR_IA32_MTRR_FIX4K_D0000,\r
91 0xD0000,\r
92 SIZE_4KB\r
93 },\r
94 {\r
95 MSR_IA32_MTRR_FIX4K_D8000,\r
96 0xD8000,\r
97 SIZE_4KB\r
98 },\r
99 {\r
100 MSR_IA32_MTRR_FIX4K_E0000,\r
101 0xE0000,\r
102 SIZE_4KB\r
103 },\r
104 {\r
105 MSR_IA32_MTRR_FIX4K_E8000,\r
106 0xE8000,\r
107 SIZE_4KB\r
108 },\r
109 {\r
110 MSR_IA32_MTRR_FIX4K_F0000,\r
111 0xF0000,\r
112 SIZE_4KB\r
113 },\r
114 {\r
115 MSR_IA32_MTRR_FIX4K_F8000,\r
116 0xF8000,\r
117 SIZE_4KB\r
118 }\r
119};\r
120\r
121//\r
122// Lookup table used to print MTRRs\r
123//\r
124GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 *mMtrrMemoryCacheTypeShortName[] = {\r
125 "UC", // CacheUncacheable\r
126 "WC", // CacheWriteCombining\r
127 "R*", // Invalid\r
128 "R*", // Invalid\r
129 "WT", // CacheWriteThrough\r
130 "WP", // CacheWriteProtected\r
131 "WB", // CacheWriteBack\r
132 "R*" // Invalid\r
133};\r
134\r
135\r
136/**\r
137 Worker function prints all MTRRs for debugging.\r
138\r
139 If MtrrSetting is not NULL, print MTRR settings from input MTRR\r
140 settings buffer.\r
141 If MtrrSetting is NULL, print MTRR settings from MTRRs.\r
142\r
143 @param MtrrSetting A buffer holding all MTRRs content.\r
144**/\r
145VOID\r
146MtrrDebugPrintAllMtrrsWorker (\r
147 IN MTRR_SETTINGS *MtrrSetting\r
148 );\r
149\r
150/**\r
151 Worker function returns the variable MTRR count for the CPU.\r
152\r
153 @return Variable MTRR count\r
154\r
155**/\r
156UINT32\r
157GetVariableMtrrCountWorker (\r
158 VOID\r
159 )\r
160{\r
161 MSR_IA32_MTRRCAP_REGISTER MtrrCap;\r
162\r
163 MtrrCap.Uint64 = AsmReadMsr64 (MSR_IA32_MTRRCAP);\r
164 ASSERT (MtrrCap.Bits.VCNT <= ARRAY_SIZE (((MTRR_VARIABLE_SETTINGS *) 0)->Mtrr));\r
165 return MtrrCap.Bits.VCNT;\r
166}\r
167\r
168/**\r
169 Returns the variable MTRR count for the CPU.\r
170\r
171 @return Variable MTRR count\r
172\r
173**/\r
174UINT32\r
175EFIAPI\r
176GetVariableMtrrCount (\r
177 VOID\r
178 )\r
179{\r
180 if (!IsMtrrSupported ()) {\r
181 return 0;\r
182 }\r
183 return GetVariableMtrrCountWorker ();\r
184}\r
185\r
186/**\r
187 Worker function returns the firmware usable variable MTRR count for the CPU.\r
188\r
189 @return Firmware usable variable MTRR count\r
190\r
191**/\r
192UINT32\r
193GetFirmwareVariableMtrrCountWorker (\r
194 VOID\r
195 )\r
196{\r
197 UINT32 VariableMtrrCount;\r
198 UINT32 ReservedMtrrNumber;\r
199\r
200 VariableMtrrCount = GetVariableMtrrCountWorker ();\r
201 ReservedMtrrNumber = PcdGet32 (PcdCpuNumberOfReservedVariableMtrrs);\r
202 if (VariableMtrrCount < ReservedMtrrNumber) {\r
203 return 0;\r
204 }\r
205\r
206 return VariableMtrrCount - ReservedMtrrNumber;\r
207}\r
208\r
209/**\r
210 Returns the firmware usable variable MTRR count for the CPU.\r
211\r
212 @return Firmware usable variable MTRR count\r
213\r
214**/\r
215UINT32\r
216EFIAPI\r
217GetFirmwareVariableMtrrCount (\r
218 VOID\r
219 )\r
220{\r
221 if (!IsMtrrSupported ()) {\r
222 return 0;\r
223 }\r
224 return GetFirmwareVariableMtrrCountWorker ();\r
225}\r
226\r
227/**\r
228 Worker function returns the default MTRR cache type for the system.\r
229\r
230 If MtrrSetting is not NULL, returns the default MTRR cache type from input\r
231 MTRR settings buffer.\r
232 If MtrrSetting is NULL, returns the default MTRR cache type from MSR.\r
233\r
234 @param[in] MtrrSetting A buffer holding all MTRRs content.\r
235\r
236 @return The default MTRR cache type.\r
237\r
238**/\r
239MTRR_MEMORY_CACHE_TYPE\r
240MtrrGetDefaultMemoryTypeWorker (\r
241 IN MTRR_SETTINGS *MtrrSetting\r
242 )\r
243{\r
244 MSR_IA32_MTRR_DEF_TYPE_REGISTER DefType;\r
245\r
246 if (MtrrSetting == NULL) {\r
247 DefType.Uint64 = AsmReadMsr64 (MSR_IA32_MTRR_DEF_TYPE);\r
248 } else {\r
249 DefType.Uint64 = MtrrSetting->MtrrDefType;\r
250 }\r
251\r
252 return (MTRR_MEMORY_CACHE_TYPE) DefType.Bits.Type;\r
253}\r
254\r
255\r
256/**\r
257 Returns the default MTRR cache type for the system.\r
258\r
259 @return The default MTRR cache type.\r
260\r
261**/\r
262MTRR_MEMORY_CACHE_TYPE\r
263EFIAPI\r
264MtrrGetDefaultMemoryType (\r
265 VOID\r
266 )\r
267{\r
268 if (!IsMtrrSupported ()) {\r
269 return CacheUncacheable;\r
270 }\r
271 return MtrrGetDefaultMemoryTypeWorker (NULL);\r
272}\r
273\r
274/**\r
275 Preparation before programming MTRR.\r
276\r
277 This function will do some preparation for programming MTRRs:\r
278 disable cache, invalid cache and disable MTRR caching functionality\r
279\r
280 @param[out] MtrrContext Pointer to context to save\r
281\r
282**/\r
283VOID\r
284MtrrLibPreMtrrChange (\r
285 OUT MTRR_CONTEXT *MtrrContext\r
286 )\r
287{\r
288 MSR_IA32_MTRR_DEF_TYPE_REGISTER DefType;\r
289 //\r
290 // Disable interrupts and save current interrupt state\r
291 //\r
292 MtrrContext->InterruptState = SaveAndDisableInterrupts();\r
293\r
294 //\r
295 // Enter no fill cache mode, CD=1(Bit30), NW=0 (Bit29)\r
296 //\r
297 AsmDisableCache ();\r
298\r
299 //\r
300 // Save original CR4 value and clear PGE flag (Bit 7)\r
301 //\r
302 MtrrContext->Cr4 = AsmReadCr4 ();\r
303 AsmWriteCr4 (MtrrContext->Cr4 & (~BIT7));\r
304\r
305 //\r
306 // Flush all TLBs\r
307 //\r
308 CpuFlushTlb ();\r
309\r
310 //\r
311 // Disable MTRRs\r
312 //\r
313 DefType.Uint64 = AsmReadMsr64 (MSR_IA32_MTRR_DEF_TYPE);\r
314 DefType.Bits.E = 0;\r
315 AsmWriteMsr64 (MSR_IA32_MTRR_DEF_TYPE, DefType.Uint64);\r
316}\r
317\r
318/**\r
319 Cleaning up after programming MTRRs.\r
320\r
321 This function will do some clean up after programming MTRRs:\r
322 Flush all TLBs, re-enable caching, restore CR4.\r
323\r
324 @param[in] MtrrContext Pointer to context to restore\r
325\r
326**/\r
327VOID\r
328MtrrLibPostMtrrChangeEnableCache (\r
329 IN MTRR_CONTEXT *MtrrContext\r
330 )\r
331{\r
332 //\r
333 // Flush all TLBs\r
334 //\r
335 CpuFlushTlb ();\r
336\r
337 //\r
338 // Enable Normal Mode caching CD=NW=0, CD(Bit30), NW(Bit29)\r
339 //\r
340 AsmEnableCache ();\r
341\r
342 //\r
343 // Restore original CR4 value\r
344 //\r
345 AsmWriteCr4 (MtrrContext->Cr4);\r
346\r
347 //\r
348 // Restore original interrupt state\r
349 //\r
350 SetInterruptState (MtrrContext->InterruptState);\r
351}\r
352\r
353/**\r
354 Cleaning up after programming MTRRs.\r
355\r
356 This function will do some clean up after programming MTRRs:\r
357 enable MTRR caching functionality, and enable cache\r
358\r
359 @param[in] MtrrContext Pointer to context to restore\r
360\r
361**/\r
362VOID\r
363MtrrLibPostMtrrChange (\r
364 IN MTRR_CONTEXT *MtrrContext\r
365 )\r
366{\r
367 MSR_IA32_MTRR_DEF_TYPE_REGISTER DefType;\r
368 //\r
369 // Enable Cache MTRR\r
370 //\r
371 DefType.Uint64 = AsmReadMsr64 (MSR_IA32_MTRR_DEF_TYPE);\r
372 DefType.Bits.E = 1;\r
373 DefType.Bits.FE = 1;\r
374 AsmWriteMsr64 (MSR_IA32_MTRR_DEF_TYPE, DefType.Uint64);\r
375\r
376 MtrrLibPostMtrrChangeEnableCache (MtrrContext);\r
377}\r
378\r
379/**\r
380 Worker function gets the content in fixed MTRRs\r
381\r
382 @param[out] FixedSettings A buffer to hold fixed MTRRs content.\r
383\r
384 @retval The pointer of FixedSettings\r
385\r
386**/\r
387MTRR_FIXED_SETTINGS*\r
388MtrrGetFixedMtrrWorker (\r
389 OUT MTRR_FIXED_SETTINGS *FixedSettings\r
390 )\r
391{\r
392 UINT32 Index;\r
393\r
394 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
395 FixedSettings->Mtrr[Index] =\r
396 AsmReadMsr64 (mMtrrLibFixedMtrrTable[Index].Msr);\r
397 }\r
398\r
399 return FixedSettings;\r
400}\r
401\r
402\r
403/**\r
404 This function gets the content in fixed MTRRs\r
405\r
406 @param[out] FixedSettings A buffer to hold fixed MTRRs content.\r
407\r
408 @retval The pointer of FixedSettings\r
409\r
410**/\r
411MTRR_FIXED_SETTINGS*\r
412EFIAPI\r
413MtrrGetFixedMtrr (\r
414 OUT MTRR_FIXED_SETTINGS *FixedSettings\r
415 )\r
416{\r
417 if (!IsMtrrSupported ()) {\r
418 return FixedSettings;\r
419 }\r
420\r
421 return MtrrGetFixedMtrrWorker (FixedSettings);\r
422}\r
423\r
424\r
425/**\r
426 Worker function will get the raw value in variable MTRRs\r
427\r
428 If MtrrSetting is not NULL, gets the variable MTRRs raw value from input\r
429 MTRR settings buffer.\r
430 If MtrrSetting is NULL, gets the variable MTRRs raw value from MTRRs.\r
431\r
432 @param[in] MtrrSetting A buffer holding all MTRRs content.\r
433 @param[in] VariableMtrrCount Number of variable MTRRs.\r
434 @param[out] VariableSettings A buffer to hold variable MTRRs content.\r
435\r
436 @return The VariableSettings input pointer\r
437\r
438**/\r
439MTRR_VARIABLE_SETTINGS*\r
440MtrrGetVariableMtrrWorker (\r
441 IN MTRR_SETTINGS *MtrrSetting,\r
442 IN UINT32 VariableMtrrCount,\r
443 OUT MTRR_VARIABLE_SETTINGS *VariableSettings\r
444 )\r
445{\r
446 UINT32 Index;\r
447\r
448 ASSERT (VariableMtrrCount <= ARRAY_SIZE (VariableSettings->Mtrr));\r
449\r
450 for (Index = 0; Index < VariableMtrrCount; Index++) {\r
451 if (MtrrSetting == NULL) {\r
452 VariableSettings->Mtrr[Index].Mask = AsmReadMsr64 (MSR_IA32_MTRR_PHYSMASK0 + (Index << 1));\r
453 //\r
454 // Skip to read the Base MSR when the Mask.V is not set.\r
455 //\r
456 if (((MSR_IA32_MTRR_PHYSMASK_REGISTER *)&VariableSettings->Mtrr[Index].Mask)->Bits.V != 0) {\r
457 VariableSettings->Mtrr[Index].Base = AsmReadMsr64 (MSR_IA32_MTRR_PHYSBASE0 + (Index << 1));\r
458 }\r
459 } else {\r
460 VariableSettings->Mtrr[Index].Base = MtrrSetting->Variables.Mtrr[Index].Base;\r
461 VariableSettings->Mtrr[Index].Mask = MtrrSetting->Variables.Mtrr[Index].Mask;\r
462 }\r
463 }\r
464\r
465 return VariableSettings;\r
466}\r
467\r
468/**\r
469 This function will get the raw value in variable MTRRs\r
470\r
471 @param[out] VariableSettings A buffer to hold variable MTRRs content.\r
472\r
473 @return The VariableSettings input pointer\r
474\r
475**/\r
476MTRR_VARIABLE_SETTINGS*\r
477EFIAPI\r
478MtrrGetVariableMtrr (\r
479 OUT MTRR_VARIABLE_SETTINGS *VariableSettings\r
480 )\r
481{\r
482 if (!IsMtrrSupported ()) {\r
483 return VariableSettings;\r
484 }\r
485\r
486 return MtrrGetVariableMtrrWorker (\r
487 NULL,\r
488 GetVariableMtrrCountWorker (),\r
489 VariableSettings\r
490 );\r
491}\r
492\r
493/**\r
494 Programs fixed MTRRs registers.\r
495\r
496 @param[in] Type The memory type to set.\r
497 @param[in, out] Base The base address of memory range.\r
498 @param[in, out] Length The length of memory range.\r
499 @param[in, out] LastMsrIndex On input, the last index of the fixed MTRR MSR to program.\r
500 On return, the current index of the fixed MTRR MSR to program.\r
501 @param[out] ClearMask The bits to clear in the fixed MTRR MSR.\r
502 @param[out] OrMask The bits to set in the fixed MTRR MSR.\r
503\r
504 @retval RETURN_SUCCESS The cache type was updated successfully\r
505 @retval RETURN_UNSUPPORTED The requested range or cache type was invalid\r
506 for the fixed MTRRs.\r
507\r
508**/\r
509RETURN_STATUS\r
510MtrrLibProgramFixedMtrr (\r
511 IN MTRR_MEMORY_CACHE_TYPE Type,\r
512 IN OUT UINT64 *Base,\r
513 IN OUT UINT64 *Length,\r
514 IN OUT UINT32 *LastMsrIndex,\r
515 OUT UINT64 *ClearMask,\r
516 OUT UINT64 *OrMask\r
517 )\r
518{\r
519 UINT32 MsrIndex;\r
520 UINT32 LeftByteShift;\r
521 UINT32 RightByteShift;\r
522 UINT64 SubLength;\r
523\r
524 //\r
525 // Find the fixed MTRR index to be programmed\r
526 //\r
527 for (MsrIndex = *LastMsrIndex + 1; MsrIndex < ARRAY_SIZE (mMtrrLibFixedMtrrTable); MsrIndex++) {\r
528 if ((*Base >= mMtrrLibFixedMtrrTable[MsrIndex].BaseAddress) &&\r
529 (*Base <\r
530 (\r
531 mMtrrLibFixedMtrrTable[MsrIndex].BaseAddress +\r
532 (8 * mMtrrLibFixedMtrrTable[MsrIndex].Length)\r
533 )\r
534 )\r
535 ) {\r
536 break;\r
537 }\r
538 }\r
539\r
540 ASSERT (MsrIndex != ARRAY_SIZE (mMtrrLibFixedMtrrTable));\r
541\r
542 //\r
543 // Find the begin offset in fixed MTRR and calculate byte offset of left shift\r
544 //\r
545 if ((((UINT32)*Base - mMtrrLibFixedMtrrTable[MsrIndex].BaseAddress) % mMtrrLibFixedMtrrTable[MsrIndex].Length) != 0) {\r
546 //\r
547 // Base address should be aligned to the begin of a certain Fixed MTRR range.\r
548 //\r
549 return RETURN_UNSUPPORTED;\r
550 }\r
551 LeftByteShift = ((UINT32)*Base - mMtrrLibFixedMtrrTable[MsrIndex].BaseAddress) / mMtrrLibFixedMtrrTable[MsrIndex].Length;\r
552 ASSERT (LeftByteShift < 8);\r
553\r
554 //\r
555 // Find the end offset in fixed MTRR and calculate byte offset of right shift\r
556 //\r
557 SubLength = mMtrrLibFixedMtrrTable[MsrIndex].Length * (8 - LeftByteShift);\r
558 if (*Length >= SubLength) {\r
559 RightByteShift = 0;\r
560 } else {\r
561 if (((UINT32)(*Length) % mMtrrLibFixedMtrrTable[MsrIndex].Length) != 0) {\r
562 //\r
563 // Length should be aligned to the end of a certain Fixed MTRR range.\r
564 //\r
565 return RETURN_UNSUPPORTED;\r
566 }\r
567 RightByteShift = 8 - LeftByteShift - (UINT32)(*Length) / mMtrrLibFixedMtrrTable[MsrIndex].Length;\r
568 //\r
569 // Update SubLength by actual length\r
570 //\r
571 SubLength = *Length;\r
572 }\r
573\r
574 *ClearMask = CLEAR_SEED;\r
575 *OrMask = MultU64x32 (OR_SEED, (UINT32) Type);\r
576\r
577 if (LeftByteShift != 0) {\r
578 //\r
579 // Clear the low bits by LeftByteShift\r
580 //\r
581 *ClearMask &= LShiftU64 (*ClearMask, LeftByteShift * 8);\r
582 *OrMask &= LShiftU64 (*OrMask, LeftByteShift * 8);\r
583 }\r
584\r
585 if (RightByteShift != 0) {\r
586 //\r
587 // Clear the high bits by RightByteShift\r
588 //\r
589 *ClearMask &= RShiftU64 (*ClearMask, RightByteShift * 8);\r
590 *OrMask &= RShiftU64 (*OrMask, RightByteShift * 8);\r
591 }\r
592\r
593 *Length -= SubLength;\r
594 *Base += SubLength;\r
595\r
596 *LastMsrIndex = MsrIndex;\r
597\r
598 return RETURN_SUCCESS;\r
599}\r
600\r
601\r
602/**\r
603 Worker function gets the attribute of variable MTRRs.\r
604\r
605 This function shadows the content of variable MTRRs into an\r
606 internal array: VariableMtrr.\r
607\r
608 @param[in] VariableSettings The variable MTRR values to shadow\r
609 @param[in] VariableMtrrCount The number of variable MTRRs\r
610 @param[in] MtrrValidBitsMask The mask for the valid bit of the MTRR\r
611 @param[in] MtrrValidAddressMask The valid address mask for MTRR\r
612 @param[out] VariableMtrr The array to shadow variable MTRRs content\r
613\r
614 @return Number of MTRRs which has been used.\r
615\r
616**/\r
617UINT32\r
618MtrrGetMemoryAttributeInVariableMtrrWorker (\r
619 IN MTRR_VARIABLE_SETTINGS *VariableSettings,\r
620 IN UINTN VariableMtrrCount,\r
621 IN UINT64 MtrrValidBitsMask,\r
622 IN UINT64 MtrrValidAddressMask,\r
623 OUT VARIABLE_MTRR *VariableMtrr\r
624 )\r
625{\r
626 UINTN Index;\r
627 UINT32 UsedMtrr;\r
628\r
629 ZeroMem (VariableMtrr, sizeof (VARIABLE_MTRR) * ARRAY_SIZE (VariableSettings->Mtrr));\r
630 for (Index = 0, UsedMtrr = 0; Index < VariableMtrrCount; Index++) {\r
631 if (((MSR_IA32_MTRR_PHYSMASK_REGISTER *) &VariableSettings->Mtrr[Index].Mask)->Bits.V != 0) {\r
632 VariableMtrr[Index].Msr = (UINT32)Index;\r
633 VariableMtrr[Index].BaseAddress = (VariableSettings->Mtrr[Index].Base & MtrrValidAddressMask);\r
634 VariableMtrr[Index].Length =\r
635 ((~(VariableSettings->Mtrr[Index].Mask & MtrrValidAddressMask)) & MtrrValidBitsMask) + 1;\r
636 VariableMtrr[Index].Type = (VariableSettings->Mtrr[Index].Base & 0x0ff);\r
637 VariableMtrr[Index].Valid = TRUE;\r
638 VariableMtrr[Index].Used = TRUE;\r
639 UsedMtrr++;\r
640 }\r
641 }\r
642 return UsedMtrr;\r
643}\r
644\r
645/**\r
646 Convert variable MTRRs to a RAW MTRR_MEMORY_RANGE array.\r
647 One MTRR_MEMORY_RANGE element is created for each MTRR setting.\r
648 The routine doesn't remove the overlap or combine the near-by region.\r
649\r
650 @param[in] VariableSettings The variable MTRR values to shadow\r
651 @param[in] VariableMtrrCount The number of variable MTRRs\r
652 @param[in] MtrrValidBitsMask The mask for the valid bit of the MTRR\r
653 @param[in] MtrrValidAddressMask The valid address mask for MTRR\r
654 @param[out] VariableMtrr The array to shadow variable MTRRs content\r
655\r
656 @return Number of MTRRs which has been used.\r
657\r
658**/\r
659UINT32\r
660MtrrLibGetRawVariableRanges (\r
661 IN MTRR_VARIABLE_SETTINGS *VariableSettings,\r
662 IN UINTN VariableMtrrCount,\r
663 IN UINT64 MtrrValidBitsMask,\r
664 IN UINT64 MtrrValidAddressMask,\r
665 OUT MTRR_MEMORY_RANGE *VariableMtrr\r
666 )\r
667{\r
668 UINTN Index;\r
669 UINT32 UsedMtrr;\r
670\r
671 ZeroMem (VariableMtrr, sizeof (MTRR_MEMORY_RANGE) * ARRAY_SIZE (VariableSettings->Mtrr));\r
672 for (Index = 0, UsedMtrr = 0; Index < VariableMtrrCount; Index++) {\r
673 if (((MSR_IA32_MTRR_PHYSMASK_REGISTER *) &VariableSettings->Mtrr[Index].Mask)->Bits.V != 0) {\r
674 VariableMtrr[Index].BaseAddress = (VariableSettings->Mtrr[Index].Base & MtrrValidAddressMask);\r
675 VariableMtrr[Index].Length =\r
676 ((~(VariableSettings->Mtrr[Index].Mask & MtrrValidAddressMask)) & MtrrValidBitsMask) + 1;\r
677 VariableMtrr[Index].Type = (MTRR_MEMORY_CACHE_TYPE)(VariableSettings->Mtrr[Index].Base & 0x0ff);\r
678 UsedMtrr++;\r
679 }\r
680 }\r
681 return UsedMtrr;\r
682}\r
683\r
684/**\r
685 Gets the attribute of variable MTRRs.\r
686\r
687 This function shadows the content of variable MTRRs into an\r
688 internal array: VariableMtrr.\r
689\r
690 @param[in] MtrrValidBitsMask The mask for the valid bit of the MTRR\r
691 @param[in] MtrrValidAddressMask The valid address mask for MTRR\r
692 @param[out] VariableMtrr The array to shadow variable MTRRs content\r
693\r
694 @return The return value of this parameter indicates the\r
695 number of MTRRs which has been used.\r
696\r
697**/\r
698UINT32\r
699EFIAPI\r
700MtrrGetMemoryAttributeInVariableMtrr (\r
701 IN UINT64 MtrrValidBitsMask,\r
702 IN UINT64 MtrrValidAddressMask,\r
703 OUT VARIABLE_MTRR *VariableMtrr\r
704 )\r
705{\r
706 MTRR_VARIABLE_SETTINGS VariableSettings;\r
707\r
708 if (!IsMtrrSupported ()) {\r
709 return 0;\r
710 }\r
711\r
712 MtrrGetVariableMtrrWorker (\r
713 NULL,\r
714 GetVariableMtrrCountWorker (),\r
715 &VariableSettings\r
716 );\r
717\r
718 return MtrrGetMemoryAttributeInVariableMtrrWorker (\r
719 &VariableSettings,\r
720 GetFirmwareVariableMtrrCountWorker (),\r
721 MtrrValidBitsMask,\r
722 MtrrValidAddressMask,\r
723 VariableMtrr\r
724 );\r
725}\r
726\r
727/**\r
728 Return the biggest alignment (lowest set bit) of address.\r
729 The function is equivalent to: 1 << LowBitSet64 (Address).\r
730\r
731 @param Address The address to return the alignment.\r
732 @param Alignment0 The alignment to return when Address is 0.\r
733\r
734 @return The least alignment of the Address.\r
735**/\r
736UINT64\r
737MtrrLibBiggestAlignment (\r
738 UINT64 Address,\r
739 UINT64 Alignment0\r
740)\r
741{\r
742 if (Address == 0) {\r
743 return Alignment0;\r
744 }\r
745\r
746 return Address & ((~Address) + 1);\r
747}\r
748\r
749/**\r
750 Return whether the left MTRR type precedes the right MTRR type.\r
751\r
752 The MTRR type precedence rules are:\r
753 1. UC precedes any other type\r
754 2. WT precedes WB\r
755 For further details, please refer the IA32 Software Developer's Manual,\r
756 Volume 3, Section "MTRR Precedences".\r
757\r
758 @param Left The left MTRR type.\r
759 @param Right The right MTRR type.\r
760\r
761 @retval TRUE Left precedes Right.\r
762 @retval FALSE Left doesn't precede Right.\r
763**/\r
764BOOLEAN\r
765MtrrLibTypeLeftPrecedeRight (\r
766 IN MTRR_MEMORY_CACHE_TYPE Left,\r
767 IN MTRR_MEMORY_CACHE_TYPE Right\r
768)\r
769{\r
770 return (BOOLEAN) (Left == CacheUncacheable || (Left == CacheWriteThrough && Right == CacheWriteBack));\r
771}\r
772\r
773/**\r
774 Initializes the valid bits mask and valid address mask for MTRRs.\r
775\r
776 This function initializes the valid bits mask and valid address mask for MTRRs.\r
777\r
778 @param[out] MtrrValidBitsMask The mask for the valid bit of the MTRR\r
779 @param[out] MtrrValidAddressMask The valid address mask for the MTRR\r
780\r
781**/\r
782VOID\r
783MtrrLibInitializeMtrrMask (\r
784 OUT UINT64 *MtrrValidBitsMask,\r
785 OUT UINT64 *MtrrValidAddressMask\r
786 )\r
787{\r
788 UINT32 MaxExtendedFunction;\r
789 CPUID_VIR_PHY_ADDRESS_SIZE_EAX VirPhyAddressSize;\r
790\r
791\r
792 AsmCpuid (CPUID_EXTENDED_FUNCTION, &MaxExtendedFunction, NULL, NULL, NULL);\r
793\r
794 if (MaxExtendedFunction >= CPUID_VIR_PHY_ADDRESS_SIZE) {\r
795 AsmCpuid (CPUID_VIR_PHY_ADDRESS_SIZE, &VirPhyAddressSize.Uint32, NULL, NULL, NULL);\r
796 } else {\r
797 VirPhyAddressSize.Bits.PhysicalAddressBits = 36;\r
798 }\r
799\r
800 *MtrrValidBitsMask = LShiftU64 (1, VirPhyAddressSize.Bits.PhysicalAddressBits) - 1;\r
801 *MtrrValidAddressMask = *MtrrValidBitsMask & 0xfffffffffffff000ULL;\r
802}\r
803\r
804\r
805/**\r
806 Determines the real attribute of a memory range.\r
807\r
808 This function is to arbitrate the real attribute of the memory when\r
809 there are 2 MTRRs covers the same memory range. For further details,\r
810 please refer the IA32 Software Developer's Manual, Volume 3,\r
811 Section "MTRR Precedences".\r
812\r
813 @param[in] MtrrType1 The first kind of Memory type\r
814 @param[in] MtrrType2 The second kind of memory type\r
815\r
816**/\r
817MTRR_MEMORY_CACHE_TYPE\r
818MtrrLibPrecedence (\r
819 IN MTRR_MEMORY_CACHE_TYPE MtrrType1,\r
820 IN MTRR_MEMORY_CACHE_TYPE MtrrType2\r
821 )\r
822{\r
823 if (MtrrType1 == MtrrType2) {\r
824 return MtrrType1;\r
825 }\r
826\r
827 ASSERT (\r
828 MtrrLibTypeLeftPrecedeRight (MtrrType1, MtrrType2) ||\r
829 MtrrLibTypeLeftPrecedeRight (MtrrType2, MtrrType1)\r
830 );\r
831\r
832 if (MtrrLibTypeLeftPrecedeRight (MtrrType1, MtrrType2)) {\r
833 return MtrrType1;\r
834 } else {\r
835 return MtrrType2;\r
836 }\r
837}\r
838\r
839/**\r
840 Worker function will get the memory cache type of the specific address.\r
841\r
842 If MtrrSetting is not NULL, gets the memory cache type from input\r
843 MTRR settings buffer.\r
844 If MtrrSetting is NULL, gets the memory cache type from MTRRs.\r
845\r
846 @param[in] MtrrSetting A buffer holding all MTRRs content.\r
847 @param[in] Address The specific address\r
848\r
849 @return Memory cache type of the specific address\r
850\r
851**/\r
852MTRR_MEMORY_CACHE_TYPE\r
853MtrrGetMemoryAttributeByAddressWorker (\r
854 IN MTRR_SETTINGS *MtrrSetting,\r
855 IN PHYSICAL_ADDRESS Address\r
856 )\r
857{\r
858 MSR_IA32_MTRR_DEF_TYPE_REGISTER DefType;\r
859 UINT64 FixedMtrr;\r
860 UINTN Index;\r
861 UINTN SubIndex;\r
862 MTRR_MEMORY_CACHE_TYPE MtrrType;\r
863 MTRR_MEMORY_RANGE VariableMtrr[ARRAY_SIZE (MtrrSetting->Variables.Mtrr)];\r
864 UINT64 MtrrValidBitsMask;\r
865 UINT64 MtrrValidAddressMask;\r
866 UINT32 VariableMtrrCount;\r
867 MTRR_VARIABLE_SETTINGS VariableSettings;\r
868\r
869 //\r
870 // Check if MTRR is enabled, if not, return UC as attribute\r
871 //\r
872 if (MtrrSetting == NULL) {\r
873 DefType.Uint64 = AsmReadMsr64 (MSR_IA32_MTRR_DEF_TYPE);\r
874 } else {\r
875 DefType.Uint64 = MtrrSetting->MtrrDefType;\r
876 }\r
877\r
878 if (DefType.Bits.E == 0) {\r
879 return CacheUncacheable;\r
880 }\r
881\r
882 //\r
883 // If address is less than 1M, then try to go through the fixed MTRR\r
884 //\r
885 if (Address < BASE_1MB) {\r
886 if (DefType.Bits.FE != 0) {\r
887 //\r
888 // Go through the fixed MTRR\r
889 //\r
890 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
891 if (Address >= mMtrrLibFixedMtrrTable[Index].BaseAddress &&\r
892 Address < mMtrrLibFixedMtrrTable[Index].BaseAddress +\r
893 (mMtrrLibFixedMtrrTable[Index].Length * 8)) {\r
894 SubIndex =\r
895 ((UINTN) Address - mMtrrLibFixedMtrrTable[Index].BaseAddress) /\r
896 mMtrrLibFixedMtrrTable[Index].Length;\r
897 if (MtrrSetting == NULL) {\r
898 FixedMtrr = AsmReadMsr64 (mMtrrLibFixedMtrrTable[Index].Msr);\r
899 } else {\r
900 FixedMtrr = MtrrSetting->Fixed.Mtrr[Index];\r
901 }\r
902 return (MTRR_MEMORY_CACHE_TYPE) (RShiftU64 (FixedMtrr, SubIndex * 8) & 0xFF);\r
903 }\r
904 }\r
905 }\r
906 }\r
907\r
908 VariableMtrrCount = GetVariableMtrrCountWorker ();\r
909 ASSERT (VariableMtrrCount <= ARRAY_SIZE (MtrrSetting->Variables.Mtrr));\r
910 MtrrGetVariableMtrrWorker (MtrrSetting, VariableMtrrCount, &VariableSettings);\r
911\r
912 MtrrLibInitializeMtrrMask (&MtrrValidBitsMask, &MtrrValidAddressMask);\r
913 MtrrLibGetRawVariableRanges (\r
914 &VariableSettings,\r
915 VariableMtrrCount,\r
916 MtrrValidBitsMask,\r
917 MtrrValidAddressMask,\r
918 VariableMtrr\r
919 );\r
920\r
921 //\r
922 // Go through the variable MTRR\r
923 //\r
924 MtrrType = CacheInvalid;\r
925 for (Index = 0; Index < VariableMtrrCount; Index++) {\r
926 if (VariableMtrr[Index].Length != 0) {\r
927 if (Address >= VariableMtrr[Index].BaseAddress &&\r
928 Address < VariableMtrr[Index].BaseAddress + VariableMtrr[Index].Length) {\r
929 if (MtrrType == CacheInvalid) {\r
930 MtrrType = (MTRR_MEMORY_CACHE_TYPE) VariableMtrr[Index].Type;\r
931 } else {\r
932 MtrrType = MtrrLibPrecedence (MtrrType, (MTRR_MEMORY_CACHE_TYPE) VariableMtrr[Index].Type);\r
933 }\r
934 }\r
935 }\r
936 }\r
937\r
938 //\r
939 // If there is no MTRR which covers the Address, use the default MTRR type.\r
940 //\r
941 if (MtrrType == CacheInvalid) {\r
942 MtrrType = (MTRR_MEMORY_CACHE_TYPE) DefType.Bits.Type;\r
943 }\r
944\r
945 return MtrrType;\r
946}\r
947\r
948\r
949/**\r
950 This function will get the memory cache type of the specific address.\r
951\r
952 This function is mainly for debug purpose.\r
953\r
954 @param[in] Address The specific address\r
955\r
956 @return Memory cache type of the specific address\r
957\r
958**/\r
959MTRR_MEMORY_CACHE_TYPE\r
960EFIAPI\r
961MtrrGetMemoryAttribute (\r
962 IN PHYSICAL_ADDRESS Address\r
963 )\r
964{\r
965 if (!IsMtrrSupported ()) {\r
966 return CacheUncacheable;\r
967 }\r
968\r
969 return MtrrGetMemoryAttributeByAddressWorker (NULL, Address);\r
970}\r
971\r
972/**\r
973 Update the Ranges array to change the specified range identified by\r
974 BaseAddress and Length to Type.\r
975\r
976 @param Ranges Array holding memory type settings for all memory regions.\r
977 @param Capacity The maximum count of memory ranges the array can hold.\r
978 @param Count Return the new memory range count in the array.\r
979 @param BaseAddress The base address of the memory range to change type.\r
980 @param Length The length of the memory range to change type.\r
981 @param Type The new type of the specified memory range.\r
982\r
983 @retval RETURN_SUCCESS The type of the specified memory range is\r
984 changed successfully.\r
985 @retval RETURN_ALREADY_STARTED The type of the specified memory range equals\r
986 to the desired type.\r
987 @retval RETURN_OUT_OF_RESOURCES The new type set causes the count of memory\r
988 range exceeds capacity.\r
989**/\r
990RETURN_STATUS\r
991MtrrLibSetMemoryType (\r
992 IN MTRR_MEMORY_RANGE *Ranges,\r
993 IN UINTN Capacity,\r
994 IN OUT UINTN *Count,\r
995 IN UINT64 BaseAddress,\r
996 IN UINT64 Length,\r
997 IN MTRR_MEMORY_CACHE_TYPE Type\r
998 )\r
999{\r
1000 UINTN Index;\r
1001 UINT64 Limit;\r
1002 UINT64 LengthLeft;\r
1003 UINT64 LengthRight;\r
1004 UINTN StartIndex;\r
1005 UINTN EndIndex;\r
1006 UINTN DeltaCount;\r
1007\r
1008 LengthRight = 0;\r
1009 LengthLeft = 0;\r
1010 Limit = BaseAddress + Length;\r
1011 StartIndex = *Count;\r
1012 EndIndex = *Count;\r
1013 for (Index = 0; Index < *Count; Index++) {\r
1014 if ((StartIndex == *Count) &&\r
1015 (Ranges[Index].BaseAddress <= BaseAddress) &&\r
1016 (BaseAddress < Ranges[Index].BaseAddress + Ranges[Index].Length)) {\r
1017 StartIndex = Index;\r
1018 LengthLeft = BaseAddress - Ranges[Index].BaseAddress;\r
1019 }\r
1020\r
1021 if ((EndIndex == *Count) &&\r
1022 (Ranges[Index].BaseAddress < Limit) &&\r
1023 (Limit <= Ranges[Index].BaseAddress + Ranges[Index].Length)) {\r
1024 EndIndex = Index;\r
1025 LengthRight = Ranges[Index].BaseAddress + Ranges[Index].Length - Limit;\r
1026 break;\r
1027 }\r
1028 }\r
1029\r
1030 ASSERT (StartIndex != *Count && EndIndex != *Count);\r
1031 if (StartIndex == EndIndex && Ranges[StartIndex].Type == Type) {\r
1032 return RETURN_ALREADY_STARTED;\r
1033 }\r
1034\r
1035 //\r
1036 // The type change may cause merging with previous range or next range.\r
1037 // Update the StartIndex, EndIndex, BaseAddress, Length so that following\r
1038 // logic doesn't need to consider merging.\r
1039 //\r
1040 if (StartIndex != 0) {\r
1041 if (LengthLeft == 0 && Ranges[StartIndex - 1].Type == Type) {\r
1042 StartIndex--;\r
1043 Length += Ranges[StartIndex].Length;\r
1044 BaseAddress -= Ranges[StartIndex].Length;\r
1045 }\r
1046 }\r
1047 if (EndIndex != (*Count) - 1) {\r
1048 if (LengthRight == 0 && Ranges[EndIndex + 1].Type == Type) {\r
1049 EndIndex++;\r
1050 Length += Ranges[EndIndex].Length;\r
1051 }\r
1052 }\r
1053\r
1054 //\r
1055 // |- 0 -|- 1 -|- 2 -|- 3 -| StartIndex EndIndex DeltaCount Count (Count = 4)\r
1056 // |++++++++++++++++++| 0 3 1=3-0-2 3\r
1057 // |+++++++| 0 1 -1=1-0-2 5\r
1058 // |+| 0 0 -2=0-0-2 6\r
1059 // |+++| 0 0 -1=0-0-2+1 5\r
1060 //\r
1061 //\r
1062 DeltaCount = EndIndex - StartIndex - 2;\r
1063 if (LengthLeft == 0) {\r
1064 DeltaCount++;\r
1065 }\r
1066 if (LengthRight == 0) {\r
1067 DeltaCount++;\r
1068 }\r
1069 if (*Count - DeltaCount > Capacity) {\r
1070 return RETURN_OUT_OF_RESOURCES;\r
1071 }\r
1072\r
1073 //\r
1074 // Reserve (-DeltaCount) space\r
1075 //\r
1076 CopyMem (&Ranges[EndIndex + 1 - DeltaCount], &Ranges[EndIndex + 1], (*Count - EndIndex - 1) * sizeof (Ranges[0]));\r
1077 *Count -= DeltaCount;\r
1078\r
1079 if (LengthLeft != 0) {\r
1080 Ranges[StartIndex].Length = LengthLeft;\r
1081 StartIndex++;\r
1082 }\r
1083 if (LengthRight != 0) {\r
1084 Ranges[EndIndex - DeltaCount].BaseAddress = BaseAddress + Length;\r
1085 Ranges[EndIndex - DeltaCount].Length = LengthRight;\r
1086 Ranges[EndIndex - DeltaCount].Type = Ranges[EndIndex].Type;\r
1087 }\r
1088 Ranges[StartIndex].BaseAddress = BaseAddress;\r
1089 Ranges[StartIndex].Length = Length;\r
1090 Ranges[StartIndex].Type = Type;\r
1091 return RETURN_SUCCESS;\r
1092}\r
1093\r
1094/**\r
1095 Return the number of memory types in range [BaseAddress, BaseAddress + Length).\r
1096\r
1097 @param Ranges Array holding memory type settings for all memory regions.\r
1098 @param RangeCount The count of memory ranges the array holds.\r
1099 @param BaseAddress Base address.\r
1100 @param Length Length.\r
1101 @param Types Return bit mask to indicate all memory types in the specified range.\r
1102\r
1103 @retval Number of memory types.\r
1104**/\r
1105UINT8\r
1106MtrrLibGetNumberOfTypes (\r
1107 IN CONST MTRR_MEMORY_RANGE *Ranges,\r
1108 IN UINTN RangeCount,\r
1109 IN UINT64 BaseAddress,\r
1110 IN UINT64 Length,\r
1111 IN OUT UINT8 *Types OPTIONAL\r
1112 )\r
1113{\r
1114 UINTN Index;\r
1115 UINT8 TypeCount;\r
1116 UINT8 LocalTypes;\r
1117\r
1118 TypeCount = 0;\r
1119 LocalTypes = 0;\r
1120 for (Index = 0; Index < RangeCount; Index++) {\r
1121 if ((Ranges[Index].BaseAddress <= BaseAddress) &&\r
1122 (BaseAddress < Ranges[Index].BaseAddress + Ranges[Index].Length)\r
1123 ) {\r
1124 if ((LocalTypes & (1 << Ranges[Index].Type)) == 0) {\r
1125 LocalTypes |= (UINT8)(1 << Ranges[Index].Type);\r
1126 TypeCount++;\r
1127 }\r
1128\r
1129 if (BaseAddress + Length > Ranges[Index].BaseAddress + Ranges[Index].Length) {\r
1130 Length -= Ranges[Index].BaseAddress + Ranges[Index].Length - BaseAddress;\r
1131 BaseAddress = Ranges[Index].BaseAddress + Ranges[Index].Length;\r
1132 } else {\r
1133 break;\r
1134 }\r
1135 }\r
1136 }\r
1137\r
1138 if (Types != NULL) {\r
1139 *Types = LocalTypes;\r
1140 }\r
1141 return TypeCount;\r
1142}\r
1143\r
1144/**\r
1145 Calculate the least MTRR number from vector Start to Stop and update\r
1146 the Previous of all vectors from Start to Stop is updated to reflect\r
1147 how the memory range is covered by MTRR.\r
1148\r
1149 @param VectorCount The count of vectors in the graph.\r
1150 @param Vector Array holding all vectors.\r
1151 @param Weight 2-dimention array holding weights between vectors.\r
1152 @param Start Start vector.\r
1153 @param Stop Stop vector.\r
1154 @param IncludeOptional TRUE to count the optional weight.\r
1155**/\r
1156VOID\r
1157MtrrLibCalculateLeastMtrrs (\r
1158 IN UINT16 VectorCount,\r
1159 IN MTRR_LIB_ADDRESS *Vector,\r
1160 IN OUT CONST UINT8 *Weight,\r
1161 IN UINT16 Start,\r
1162 IN UINT16 Stop,\r
1163 IN BOOLEAN IncludeOptional\r
1164 )\r
1165{\r
1166 UINT16 Index;\r
1167 UINT8 MinWeight;\r
1168 UINT16 MinI;\r
1169 UINT8 Mandatory;\r
1170 UINT8 Optional;\r
1171\r
1172 for (Index = Start; Index <= Stop; Index++) {\r
1173 Vector[Index].Visited = FALSE;\r
1174 Vector[Index].Previous = VectorCount;\r
1175 Mandatory = Weight[M(Start,Index)];\r
1176 Vector[Index].Weight = Mandatory;\r
1177 if (Mandatory != MAX_WEIGHT) {\r
1178 Optional = IncludeOptional ? Weight[O(Start, Index)] : 0;\r
1179 Vector[Index].Weight += Optional;\r
1180 ASSERT (Vector[Index].Weight >= Optional);\r
1181 }\r
1182 }\r
1183\r
1184 MinI = Start;\r
1185 MinWeight = 0;\r
1186 while (!Vector[Stop].Visited) {\r
1187 //\r
1188 // Update the weight from the shortest vector to other unvisited vectors\r
1189 //\r
1190 for (Index = Start + 1; Index <= Stop; Index++) {\r
1191 if (!Vector[Index].Visited) {\r
1192 Mandatory = Weight[M(MinI, Index)];\r
1193 if (Mandatory != MAX_WEIGHT) {\r
1194 Optional = IncludeOptional ? Weight[O(MinI, Index)] : 0;\r
1195 if (MinWeight + Mandatory + Optional <= Vector[Index].Weight) {\r
1196 Vector[Index].Weight = MinWeight + Mandatory + Optional;\r
1197 Vector[Index].Previous = MinI; // Previous is Start based.\r
1198 }\r
1199 }\r
1200 }\r
1201 }\r
1202\r
1203 //\r
1204 // Find the shortest vector from Start\r
1205 //\r
1206 MinI = VectorCount;\r
1207 MinWeight = MAX_WEIGHT;\r
1208 for (Index = Start + 1; Index <= Stop; Index++) {\r
1209 if (!Vector[Index].Visited && MinWeight > Vector[Index].Weight) {\r
1210 MinI = Index;\r
1211 MinWeight = Vector[Index].Weight;\r
1212 }\r
1213 }\r
1214\r
1215 //\r
1216 // Mark the shortest vector from Start as visited\r
1217 //\r
1218 Vector[MinI].Visited = TRUE;\r
1219 }\r
1220}\r
1221\r
1222/**\r
1223 Append the MTRR setting to MTRR setting array.\r
1224\r
1225 @param Mtrrs Array holding all MTRR settings.\r
1226 @param MtrrCapacity Capacity of the MTRR array.\r
1227 @param MtrrCount The count of MTRR settings in array.\r
1228 @param BaseAddress Base address.\r
1229 @param Length Length.\r
1230 @param Type Memory type.\r
1231\r
1232 @retval RETURN_SUCCESS MTRR setting is appended to array.\r
1233 @retval RETURN_OUT_OF_RESOURCES Array is full.\r
1234**/\r
1235RETURN_STATUS\r
1236MtrrLibAppendVariableMtrr (\r
1237 IN OUT MTRR_MEMORY_RANGE *Mtrrs,\r
1238 IN UINT32 MtrrCapacity,\r
1239 IN OUT UINT32 *MtrrCount,\r
1240 IN UINT64 BaseAddress,\r
1241 IN UINT64 Length,\r
1242 IN MTRR_MEMORY_CACHE_TYPE Type\r
1243 )\r
1244{\r
1245 if (*MtrrCount == MtrrCapacity) {\r
1246 return RETURN_OUT_OF_RESOURCES;\r
1247 }\r
1248\r
1249 Mtrrs[*MtrrCount].BaseAddress = BaseAddress;\r
1250 Mtrrs[*MtrrCount].Length = Length;\r
1251 Mtrrs[*MtrrCount].Type = Type;\r
1252 (*MtrrCount)++;\r
1253 return RETURN_SUCCESS;\r
1254}\r
1255\r
1256/**\r
1257 Return the memory type that has the least precedence.\r
1258\r
1259 @param TypeBits Bit mask of memory type.\r
1260\r
1261 @retval Memory type that has the least precedence.\r
1262**/\r
1263MTRR_MEMORY_CACHE_TYPE\r
1264MtrrLibLowestType (\r
1265 IN UINT8 TypeBits\r
1266)\r
1267{\r
1268 INT8 Type;\r
1269\r
1270 ASSERT (TypeBits != 0);\r
1271 for (Type = 7; (INT8)TypeBits > 0; Type--, TypeBits <<= 1);\r
1272 return (MTRR_MEMORY_CACHE_TYPE)Type;\r
1273}\r
1274\r
1275/**\r
1276 Return TRUE when the Operand is exactly power of 2.\r
1277\r
1278 @retval TRUE Operand is exactly power of 2.\r
1279 @retval FALSE Operand is not power of 2.\r
1280**/\r
1281BOOLEAN\r
1282MtrrLibIsPowerOfTwo (\r
1283 IN UINT64 Operand\r
1284)\r
1285{\r
1286 ASSERT (Operand != 0);\r
1287 return (BOOLEAN) ((Operand & (Operand - 1)) == 0);\r
1288}\r
1289\r
1290/**\r
1291 Calculate the subtractive path from vector Start to Stop.\r
1292\r
1293 @param DefaultType Default memory type.\r
1294 @param A0 Alignment to use when base address is 0.\r
1295 @param Ranges Array holding memory type settings for all memory regions.\r
1296 @param RangeCount The count of memory ranges the array holds.\r
1297 @param VectorCount The count of vectors in the graph.\r
1298 @param Vector Array holding all vectors.\r
1299 @param Weight 2-dimention array holding weights between vectors.\r
1300 @param Start Start vector.\r
1301 @param Stop Stop vector.\r
1302 @param Types Type bit mask of memory range from Start to Stop.\r
1303 @param TypeCount Number of different memory types from Start to Stop.\r
1304 @param Mtrrs Array holding all MTRR settings.\r
1305 @param MtrrCapacity Capacity of the MTRR array.\r
1306 @param MtrrCount The count of MTRR settings in array.\r
1307\r
1308 @retval RETURN_SUCCESS The subtractive path is calculated successfully.\r
1309 @retval RETURN_OUT_OF_RESOURCES The MTRR setting array is full.\r
1310\r
1311**/\r
1312RETURN_STATUS\r
1313MtrrLibCalculateSubtractivePath (\r
1314 IN MTRR_MEMORY_CACHE_TYPE DefaultType,\r
1315 IN UINT64 A0,\r
1316 IN CONST MTRR_MEMORY_RANGE *Ranges,\r
1317 IN UINTN RangeCount,\r
1318 IN UINT16 VectorCount,\r
1319 IN MTRR_LIB_ADDRESS *Vector,\r
1320 IN OUT UINT8 *Weight,\r
1321 IN UINT16 Start,\r
1322 IN UINT16 Stop,\r
1323 IN UINT8 Types,\r
1324 IN UINT8 TypeCount,\r
1325 IN OUT MTRR_MEMORY_RANGE *Mtrrs, OPTIONAL\r
1326 IN UINT32 MtrrCapacity, OPTIONAL\r
1327 IN OUT UINT32 *MtrrCount OPTIONAL\r
1328 )\r
1329{\r
1330 RETURN_STATUS Status;\r
1331 UINT64 Base;\r
1332 UINT64 Length;\r
1333 UINT8 PrecedentTypes;\r
1334 UINTN Index;\r
1335 UINT64 HBase;\r
1336 UINT64 HLength;\r
1337 UINT64 SubLength;\r
1338 UINT16 SubStart;\r
1339 UINT16 SubStop;\r
1340 UINT16 Cur;\r
1341 UINT16 Pre;\r
1342 MTRR_MEMORY_CACHE_TYPE LowestType;\r
1343 MTRR_MEMORY_CACHE_TYPE LowestPrecedentType;\r
1344\r
1345 Base = Vector[Start].Address;\r
1346 Length = Vector[Stop].Address - Base;\r
1347\r
1348 LowestType = MtrrLibLowestType (Types);\r
1349\r
1350 //\r
1351 // Clear the lowest type (highest bit) to get the precedent types\r
1352 //\r
1353 PrecedentTypes = ~(1 << LowestType) & Types;\r
1354 LowestPrecedentType = MtrrLibLowestType (PrecedentTypes);\r
1355\r
1356 if (Mtrrs == NULL) {\r
1357 Weight[M(Start, Stop)] = ((LowestType == DefaultType) ? 0 : 1);\r
1358 Weight[O(Start, Stop)] = ((LowestType == DefaultType) ? 1 : 0);\r
1359 }\r
1360\r
1361 // Add all high level ranges\r
1362 HBase = MAX_UINT64;\r
1363 HLength = 0;\r
1364 for (Index = 0; Index < RangeCount; Index++) {\r
1365 if (Length == 0) {\r
1366 break;\r
1367 }\r
1368 if ((Base < Ranges[Index].BaseAddress) || (Ranges[Index].BaseAddress + Ranges[Index].Length <= Base)) {\r
1369 continue;\r
1370 }\r
1371\r
1372 //\r
1373 // Base is in the Range[Index]\r
1374 //\r
1375 if (Base + Length > Ranges[Index].BaseAddress + Ranges[Index].Length) {\r
1376 SubLength = Ranges[Index].BaseAddress + Ranges[Index].Length - Base;\r
1377 } else {\r
1378 SubLength = Length;\r
1379 }\r
1380 if (((1 << Ranges[Index].Type) & PrecedentTypes) != 0) {\r
1381 //\r
1382 // Meet a range whose types take precedence.\r
1383 // Update the [HBase, HBase + HLength) to include the range,\r
1384 // [HBase, HBase + HLength) may contain sub ranges with 2 different types, and both take precedence.\r
1385 //\r
1386 if (HBase == MAX_UINT64) {\r
1387 HBase = Base;\r
1388 }\r
1389 HLength += SubLength;\r
1390 }\r
1391\r
1392 Base += SubLength;\r
1393 Length -= SubLength;\r
1394\r
1395 if (HLength == 0) {\r
1396 continue;\r
1397 }\r
1398\r
1399 if ((Ranges[Index].Type == LowestType) || (Length == 0)) { // meet low type or end\r
1400\r
1401 //\r
1402 // Add the MTRRs for each high priority type range\r
1403 // the range[HBase, HBase + HLength) contains only two types.\r
1404 // We might use positive or subtractive, depending on which way uses less MTRR\r
1405 //\r
1406 for (SubStart = Start; SubStart <= Stop; SubStart++) {\r
1407 if (Vector[SubStart].Address == HBase) {\r
1408 break;\r
1409 }\r
1410 }\r
1411\r
1412 for (SubStop = SubStart; SubStop <= Stop; SubStop++) {\r
1413 if (Vector[SubStop].Address == HBase + HLength) {\r
1414 break;\r
1415 }\r
1416 }\r
1417 ASSERT (Vector[SubStart].Address == HBase);\r
1418 ASSERT (Vector[SubStop].Address == HBase + HLength);\r
1419\r
1420 if ((TypeCount == 2) || (SubStart == SubStop - 1)) {\r
1421 //\r
1422 // add subtractive MTRRs for [HBase, HBase + HLength)\r
1423 // [HBase, HBase + HLength) contains only one type.\r
1424 // while - loop is to split the range to MTRR - compliant aligned range.\r
1425 //\r
1426 if (Mtrrs == NULL) {\r
1427 Weight[M (Start, Stop)] += (UINT8)(SubStop - SubStart);\r
1428 } else {\r
1429 while (SubStart != SubStop) {\r
1430 Status = MtrrLibAppendVariableMtrr (\r
1431 Mtrrs, MtrrCapacity, MtrrCount,\r
1432 Vector[SubStart].Address, Vector[SubStart].Length, (MTRR_MEMORY_CACHE_TYPE) Vector[SubStart].Type\r
1433 );\r
1434 if (RETURN_ERROR (Status)) {\r
1435 return Status;\r
1436 }\r
1437 SubStart++;\r
1438 }\r
1439 }\r
1440 } else {\r
1441 ASSERT (TypeCount == 3);\r
1442 MtrrLibCalculateLeastMtrrs (VectorCount, Vector, Weight, SubStart, SubStop, TRUE);\r
1443\r
1444 if (Mtrrs == NULL) {\r
1445 Weight[M (Start, Stop)] += Vector[SubStop].Weight;\r
1446 } else {\r
1447 // When we need to collect the optimal path from SubStart to SubStop\r
1448 while (SubStop != SubStart) {\r
1449 Cur = SubStop;\r
1450 Pre = Vector[Cur].Previous;\r
1451 SubStop = Pre;\r
1452\r
1453 if (Weight[M (Pre, Cur)] != 0) {\r
1454 Status = MtrrLibAppendVariableMtrr (\r
1455 Mtrrs, MtrrCapacity, MtrrCount,\r
1456 Vector[Pre].Address, Vector[Cur].Address - Vector[Pre].Address, LowestPrecedentType\r
1457 );\r
1458 if (RETURN_ERROR (Status)) {\r
1459 return Status;\r
1460 }\r
1461 }\r
1462 if (Pre != Cur - 1) {\r
1463 Status = MtrrLibCalculateSubtractivePath (\r
1464 DefaultType, A0,\r
1465 Ranges, RangeCount,\r
1466 VectorCount, Vector, Weight,\r
1467 Pre, Cur, PrecedentTypes, 2,\r
1468 Mtrrs, MtrrCapacity, MtrrCount\r
1469 );\r
1470 if (RETURN_ERROR (Status)) {\r
1471 return Status;\r
1472 }\r
1473 }\r
1474 }\r
1475 }\r
1476\r
1477 }\r
1478 //\r
1479 // Reset HBase, HLength\r
1480 //\r
1481 HBase = MAX_UINT64;\r
1482 HLength = 0;\r
1483 }\r
1484 }\r
1485 return RETURN_SUCCESS;\r
1486}\r
1487\r
1488/**\r
1489 Calculate MTRR settings to cover the specified memory ranges.\r
1490\r
1491 @param DefaultType Default memory type.\r
1492 @param A0 Alignment to use when base address is 0.\r
1493 @param Ranges Memory range array holding the memory type\r
1494 settings for all memory address.\r
1495 @param RangeCount Count of memory ranges.\r
1496 @param Scratch A temporary scratch buffer that is used to perform the calculation.\r
1497 This is an optional parameter that may be NULL.\r
1498 @param ScratchSize Pointer to the size in bytes of the scratch buffer.\r
1499 It may be updated to the actual required size when the calculation\r
1500 needs more scratch buffer.\r
1501 @param Mtrrs Array holding all MTRR settings.\r
1502 @param MtrrCapacity Capacity of the MTRR array.\r
1503 @param MtrrCount The count of MTRR settings in array.\r
1504\r
1505 @retval RETURN_SUCCESS Variable MTRRs are allocated successfully.\r
1506 @retval RETURN_OUT_OF_RESOURCES Count of variable MTRRs exceeds capacity.\r
1507 @retval RETURN_BUFFER_TOO_SMALL The scratch buffer is too small for MTRR calculation.\r
1508**/\r
1509RETURN_STATUS\r
1510MtrrLibCalculateMtrrs (\r
1511 IN MTRR_MEMORY_CACHE_TYPE DefaultType,\r
1512 IN UINT64 A0,\r
1513 IN CONST MTRR_MEMORY_RANGE *Ranges,\r
1514 IN UINTN RangeCount,\r
1515 IN VOID *Scratch,\r
1516 IN OUT UINTN *ScratchSize,\r
1517 IN OUT MTRR_MEMORY_RANGE *Mtrrs,\r
1518 IN UINT32 MtrrCapacity,\r
1519 IN OUT UINT32 *MtrrCount\r
1520 )\r
1521{\r
1522 UINT64 Base0;\r
1523 UINT64 Base1;\r
1524 UINTN Index;\r
1525 UINT64 Base;\r
1526 UINT64 Length;\r
1527 UINT64 Alignment;\r
1528 UINT64 SubLength;\r
1529 MTRR_LIB_ADDRESS *Vector;\r
1530 UINT8 *Weight;\r
1531 UINT32 VectorIndex;\r
1532 UINT32 VectorCount;\r
1533 UINTN RequiredScratchSize;\r
1534 UINT8 TypeCount;\r
1535 UINT16 Start;\r
1536 UINT16 Stop;\r
1537 UINT8 Type;\r
1538 RETURN_STATUS Status;\r
1539\r
1540 Base0 = Ranges[0].BaseAddress;\r
1541 Base1 = Ranges[RangeCount - 1].BaseAddress + Ranges[RangeCount - 1].Length;\r
1542 MTRR_LIB_ASSERT_ALIGNED (Base0, Base1 - Base0);\r
1543\r
1544 //\r
1545 // Count the number of vectors.\r
1546 //\r
1547 Vector = (MTRR_LIB_ADDRESS*)Scratch;\r
1548 for (VectorIndex = 0, Index = 0; Index < RangeCount; Index++) {\r
1549 Base = Ranges[Index].BaseAddress;\r
1550 Length = Ranges[Index].Length;\r
1551 while (Length != 0) {\r
1552 Alignment = MtrrLibBiggestAlignment (Base, A0);\r
1553 SubLength = Alignment;\r
1554 if (SubLength > Length) {\r
1555 SubLength = GetPowerOfTwo64 (Length);\r
1556 }\r
1557 if (VectorIndex < *ScratchSize / sizeof (*Vector)) {\r
1558 Vector[VectorIndex].Address = Base;\r
1559 Vector[VectorIndex].Alignment = Alignment;\r
1560 Vector[VectorIndex].Type = Ranges[Index].Type;\r
1561 Vector[VectorIndex].Length = SubLength;\r
1562 }\r
1563 Base += SubLength;\r
1564 Length -= SubLength;\r
1565 VectorIndex++;\r
1566 }\r
1567 }\r
1568 //\r
1569 // Vector[VectorIndex] = Base1, so whole vector count is (VectorIndex + 1).\r
1570 //\r
1571 VectorCount = VectorIndex + 1;\r
1572 DEBUG ((\r
1573 DEBUG_CACHE, "VectorCount (%016lx - %016lx) = %d\n", \r
1574 Ranges[0].BaseAddress, Ranges[RangeCount - 1].BaseAddress + Ranges[RangeCount - 1].Length, VectorCount\r
1575 ));\r
1576 ASSERT (VectorCount < MAX_UINT16);\r
1577\r
1578 RequiredScratchSize = VectorCount * sizeof (*Vector) + VectorCount * VectorCount * sizeof (*Weight);\r
1579 if (*ScratchSize < RequiredScratchSize) {\r
1580 *ScratchSize = RequiredScratchSize;\r
1581 return RETURN_BUFFER_TOO_SMALL;\r
1582 }\r
1583 Vector[VectorCount - 1].Address = Base1;\r
1584\r
1585 Weight = (UINT8 *) &Vector[VectorCount];\r
1586 //\r
1587 // Set mandatory weight between any vector to max\r
1588 // Set optional weight and between any vector and self->self to 0\r
1589 // E.g.:\r
1590 // 00 FF FF FF\r
1591 // 00 00 FF FF\r
1592 // 00 00 00 FF\r
1593 // 00 00 00 00\r
1594 //\r
1595 for (VectorIndex = 0; VectorIndex < VectorCount; VectorIndex++) {\r
1596 SetMem (&Weight[M(VectorIndex, 0)], VectorIndex + 1, 0);\r
1597 if (VectorIndex != VectorCount - 1) {\r
1598 Weight[M (VectorIndex, VectorIndex + 1)] = (DefaultType == Vector[VectorIndex].Type) ? 0 : 1;\r
1599 SetMem (&Weight[M (VectorIndex, VectorIndex + 2)], VectorCount - VectorIndex - 2, MAX_WEIGHT);\r
1600 }\r
1601 }\r
1602\r
1603 for (TypeCount = 2; TypeCount <= 3; TypeCount++) {\r
1604 for (Start = 0; Start < VectorCount; Start++) {\r
1605 for (Stop = Start + 2; Stop < VectorCount; Stop++) {\r
1606 ASSERT (Vector[Stop].Address > Vector[Start].Address);\r
1607 Length = Vector[Stop].Address - Vector[Start].Address;\r
1608 if (Length > Vector[Start].Alignment) {\r
1609 //\r
1610 // Pickup a new Start when [Start, Stop) cannot be described by one MTRR.\r
1611 //\r
1612 break;\r
1613 }\r
1614 if ((Weight[M(Start, Stop)] == MAX_WEIGHT) && MtrrLibIsPowerOfTwo (Length)) {\r
1615 if (MtrrLibGetNumberOfTypes (\r
1616 Ranges, RangeCount, Vector[Start].Address, Vector[Stop].Address - Vector[Start].Address, &Type\r
1617 ) == TypeCount) {\r
1618 //\r
1619 // Update the Weight[Start, Stop] using subtractive path.\r
1620 //\r
1621 MtrrLibCalculateSubtractivePath (\r
1622 DefaultType, A0,\r
1623 Ranges, RangeCount,\r
1624 (UINT16)VectorCount, Vector, Weight,\r
1625 Start, Stop, Type, TypeCount,\r
1626 NULL, 0, NULL\r
1627 );\r
1628 } else if (TypeCount == 2) {\r
1629 //\r
1630 // Pick up a new Start when we expect 2-type range, but 3-type range is met.\r
1631 // Because no matter how Stop is increased, we always meet 3-type range.\r
1632 //\r
1633 break;\r
1634 }\r
1635 }\r
1636 }\r
1637 }\r
1638 }\r
1639\r
1640 Status = RETURN_SUCCESS;\r
1641 MtrrLibCalculateLeastMtrrs ((UINT16) VectorCount, Vector, Weight, 0, (UINT16) VectorCount - 1, FALSE);\r
1642 Stop = (UINT16) VectorCount - 1;\r
1643 while (Stop != 0) {\r
1644 Start = Vector[Stop].Previous;\r
1645 TypeCount = MAX_UINT8;\r
1646 Type = 0;\r
1647 if (Weight[M(Start, Stop)] != 0) {\r
1648 TypeCount = MtrrLibGetNumberOfTypes (Ranges, RangeCount, Vector[Start].Address, Vector[Stop].Address - Vector[Start].Address, &Type);\r
1649 Status = MtrrLibAppendVariableMtrr (\r
1650 Mtrrs, MtrrCapacity, MtrrCount,\r
1651 Vector[Start].Address, Vector[Stop].Address - Vector[Start].Address, \r
1652 MtrrLibLowestType (Type)\r
1653 );\r
1654 if (RETURN_ERROR (Status)) {\r
1655 break;\r
1656 }\r
1657 }\r
1658\r
1659 if (Start != Stop - 1) {\r
1660 //\r
1661 // substractive path\r
1662 //\r
1663 if (TypeCount == MAX_UINT8) {\r
1664 TypeCount = MtrrLibGetNumberOfTypes (\r
1665 Ranges, RangeCount, Vector[Start].Address, Vector[Stop].Address - Vector[Start].Address, &Type\r
1666 );\r
1667 }\r
1668 Status = MtrrLibCalculateSubtractivePath (\r
1669 DefaultType, A0,\r
1670 Ranges, RangeCount,\r
1671 (UINT16) VectorCount, Vector, Weight, Start, Stop,\r
1672 Type, TypeCount,\r
1673 Mtrrs, MtrrCapacity, MtrrCount\r
1674 );\r
1675 if (RETURN_ERROR (Status)) {\r
1676 break;\r
1677 }\r
1678 }\r
1679 Stop = Start;\r
1680 }\r
1681 return Status;\r
1682}\r
1683\r
1684\r
1685/**\r
1686 Apply the fixed MTRR settings to memory range array.\r
1687\r
1688 @param Fixed The fixed MTRR settings.\r
1689 @param Ranges Return the memory range array holding memory type\r
1690 settings for all memory address.\r
1691 @param RangeCapacity The capacity of memory range array.\r
1692 @param RangeCount Return the count of memory range.\r
1693\r
1694 @retval RETURN_SUCCESS The memory range array is returned successfully.\r
1695 @retval RETURN_OUT_OF_RESOURCES The count of memory ranges exceeds capacity.\r
1696**/\r
1697RETURN_STATUS\r
1698MtrrLibApplyFixedMtrrs (\r
1699 IN MTRR_FIXED_SETTINGS *Fixed,\r
1700 IN OUT MTRR_MEMORY_RANGE *Ranges,\r
1701 IN UINTN RangeCapacity,\r
1702 IN OUT UINTN *RangeCount\r
1703 )\r
1704{\r
1705 RETURN_STATUS Status;\r
1706 UINTN MsrIndex;\r
1707 UINTN Index;\r
1708 MTRR_MEMORY_CACHE_TYPE MemoryType;\r
1709 UINT64 Base;\r
1710\r
1711 Base = 0;\r
1712 for (MsrIndex = 0; MsrIndex < ARRAY_SIZE (mMtrrLibFixedMtrrTable); MsrIndex++) {\r
1713 ASSERT (Base == mMtrrLibFixedMtrrTable[MsrIndex].BaseAddress);\r
1714 for (Index = 0; Index < sizeof (UINT64); Index++) {\r
1715 MemoryType = (MTRR_MEMORY_CACHE_TYPE)((UINT8 *)(&Fixed->Mtrr[MsrIndex]))[Index];\r
1716 Status = MtrrLibSetMemoryType (\r
1717 Ranges, RangeCapacity, RangeCount, Base, mMtrrLibFixedMtrrTable[MsrIndex].Length, MemoryType\r
1718 );\r
1719 if (Status == RETURN_OUT_OF_RESOURCES) {\r
1720 return Status;\r
1721 }\r
1722 Base += mMtrrLibFixedMtrrTable[MsrIndex].Length;\r
1723 }\r
1724 }\r
1725 ASSERT (Base == BASE_1MB);\r
1726 return RETURN_SUCCESS;\r
1727}\r
1728\r
1729/**\r
1730 Apply the variable MTRR settings to memory range array.\r
1731\r
1732 @param VariableMtrr The variable MTRR array.\r
1733 @param VariableMtrrCount The count of variable MTRRs.\r
1734 @param Ranges Return the memory range array with new MTRR settings applied.\r
1735 @param RangeCapacity The capacity of memory range array.\r
1736 @param RangeCount Return the count of memory range.\r
1737\r
1738 @retval RETURN_SUCCESS The memory range array is returned successfully.\r
1739 @retval RETURN_OUT_OF_RESOURCES The count of memory ranges exceeds capacity.\r
1740**/\r
1741RETURN_STATUS\r
1742MtrrLibApplyVariableMtrrs (\r
1743 IN CONST MTRR_MEMORY_RANGE *VariableMtrr,\r
1744 IN UINT32 VariableMtrrCount,\r
1745 IN OUT MTRR_MEMORY_RANGE *Ranges,\r
1746 IN UINTN RangeCapacity,\r
1747 IN OUT UINTN *RangeCount\r
1748 )\r
1749{\r
1750 RETURN_STATUS Status;\r
1751 UINTN Index;\r
1752\r
1753 //\r
1754 // WT > WB\r
1755 // UC > *\r
1756 // UC > * (except WB, UC) > WB\r
1757 //\r
1758\r
1759 //\r
1760 // 1. Set WB\r
1761 //\r
1762 for (Index = 0; Index < VariableMtrrCount; Index++) {\r
1763 if ((VariableMtrr[Index].Length != 0) && (VariableMtrr[Index].Type == CacheWriteBack)) {\r
1764 Status = MtrrLibSetMemoryType (\r
1765 Ranges, RangeCapacity, RangeCount,\r
1766 VariableMtrr[Index].BaseAddress, VariableMtrr[Index].Length, VariableMtrr[Index].Type\r
1767 );\r
1768 if (Status == RETURN_OUT_OF_RESOURCES) {\r
1769 return Status;\r
1770 }\r
1771 }\r
1772 }\r
1773\r
1774 //\r
1775 // 2. Set other types than WB or UC\r
1776 //\r
1777 for (Index = 0; Index < VariableMtrrCount; Index++) {\r
1778 if ((VariableMtrr[Index].Length != 0) && \r
1779 (VariableMtrr[Index].Type != CacheWriteBack) && (VariableMtrr[Index].Type != CacheUncacheable)) {\r
1780 Status = MtrrLibSetMemoryType (\r
1781 Ranges, RangeCapacity, RangeCount,\r
1782 VariableMtrr[Index].BaseAddress, VariableMtrr[Index].Length, VariableMtrr[Index].Type\r
1783 );\r
1784 if (Status == RETURN_OUT_OF_RESOURCES) {\r
1785 return Status;\r
1786 }\r
1787 }\r
1788 }\r
1789\r
1790 //\r
1791 // 3. Set UC\r
1792 //\r
1793 for (Index = 0; Index < VariableMtrrCount; Index++) {\r
1794 if (VariableMtrr[Index].Length != 0 && VariableMtrr[Index].Type == CacheUncacheable) {\r
1795 Status = MtrrLibSetMemoryType (\r
1796 Ranges, RangeCapacity, RangeCount,\r
1797 VariableMtrr[Index].BaseAddress, VariableMtrr[Index].Length, VariableMtrr[Index].Type\r
1798 );\r
1799 if (Status == RETURN_OUT_OF_RESOURCES) {\r
1800 return Status;\r
1801 }\r
1802 }\r
1803 }\r
1804 return RETURN_SUCCESS;\r
1805}\r
1806\r
1807/**\r
1808 Return the memory type bit mask that's compatible to first type in the Ranges.\r
1809\r
1810 @param Ranges Memory range array holding the memory type\r
1811 settings for all memory address.\r
1812 @param RangeCount Count of memory ranges.\r
1813\r
1814 @return Compatible memory type bit mask.\r
1815**/\r
1816UINT8\r
1817MtrrLibGetCompatibleTypes (\r
1818 IN CONST MTRR_MEMORY_RANGE *Ranges,\r
1819 IN UINTN RangeCount\r
1820 )\r
1821{\r
1822 ASSERT (RangeCount != 0);\r
1823\r
1824 switch (Ranges[0].Type) {\r
1825 case CacheWriteBack:\r
1826 case CacheWriteThrough:\r
1827 return (1 << CacheWriteBack) | (1 << CacheWriteThrough) | (1 << CacheUncacheable);\r
1828 break;\r
1829\r
1830 case CacheWriteCombining:\r
1831 case CacheWriteProtected:\r
1832 return (1 << Ranges[0].Type) | (1 << CacheUncacheable);\r
1833 break;\r
1834\r
1835 case CacheUncacheable:\r
1836 if (RangeCount == 1) {\r
1837 return (1 << CacheUncacheable);\r
1838 }\r
1839 return MtrrLibGetCompatibleTypes (&Ranges[1], RangeCount - 1);\r
1840 break;\r
1841\r
1842 case CacheInvalid:\r
1843 default:\r
1844 ASSERT (FALSE);\r
1845 break;\r
1846 }\r
1847 return 0;\r
1848}\r
1849\r
1850/**\r
1851 Overwrite the destination MTRR settings with the source MTRR settings.\r
1852 This routine is to make sure the modification to destination MTRR settings\r
1853 is as small as possible.\r
1854\r
1855 @param DstMtrrs Destination MTRR settings.\r
1856 @param DstMtrrCount Count of destination MTRR settings.\r
1857 @param SrcMtrrs Source MTRR settings.\r
1858 @param SrcMtrrCount Count of source MTRR settings.\r
1859 @param Modified Flag array to indicate which destination MTRR setting is modified.\r
1860**/\r
1861VOID\r
1862MtrrLibMergeVariableMtrr (\r
1863 MTRR_MEMORY_RANGE *DstMtrrs,\r
1864 UINT32 DstMtrrCount,\r
1865 MTRR_MEMORY_RANGE *SrcMtrrs,\r
1866 UINT32 SrcMtrrCount,\r
1867 BOOLEAN *Modified\r
1868 )\r
1869{\r
1870 UINT32 DstIndex;\r
1871 UINT32 SrcIndex;\r
1872\r
1873 ASSERT (SrcMtrrCount <= DstMtrrCount);\r
1874\r
1875 for (DstIndex = 0; DstIndex < DstMtrrCount; DstIndex++) {\r
1876 Modified[DstIndex] = FALSE;\r
1877\r
1878 if (DstMtrrs[DstIndex].Length == 0) {\r
1879 continue;\r
1880 }\r
1881 for (SrcIndex = 0; SrcIndex < SrcMtrrCount; SrcIndex++) {\r
1882 if (DstMtrrs[DstIndex].BaseAddress == SrcMtrrs[SrcIndex].BaseAddress &&\r
1883 DstMtrrs[DstIndex].Length == SrcMtrrs[SrcIndex].Length &&\r
1884 DstMtrrs[DstIndex].Type == SrcMtrrs[SrcIndex].Type) {\r
1885 break;\r
1886 }\r
1887 }\r
1888\r
1889 if (SrcIndex == SrcMtrrCount) {\r
1890 //\r
1891 // Remove the one from DstMtrrs which is not in SrcMtrrs\r
1892 //\r
1893 DstMtrrs[DstIndex].Length = 0;\r
1894 Modified[DstIndex] = TRUE;\r
1895 } else {\r
1896 //\r
1897 // Remove the one from SrcMtrrs which is also in DstMtrrs\r
1898 //\r
1899 SrcMtrrs[SrcIndex].Length = 0;\r
1900 }\r
1901 }\r
1902\r
1903 //\r
1904 // Now valid MTRR only exists in either DstMtrrs or SrcMtrrs.\r
1905 // Merge MTRRs from SrcMtrrs to DstMtrrs\r
1906 //\r
1907 DstIndex = 0;\r
1908 for (SrcIndex = 0; SrcIndex < SrcMtrrCount; SrcIndex++) {\r
1909 if (SrcMtrrs[SrcIndex].Length != 0) {\r
1910\r
1911 //\r
1912 // Find the empty slot in DstMtrrs\r
1913 //\r
1914 while (DstIndex < DstMtrrCount) {\r
1915 if (DstMtrrs[DstIndex].Length == 0) {\r
1916 break;\r
1917 }\r
1918 DstIndex++;\r
1919 }\r
1920 ASSERT (DstIndex < DstMtrrCount);\r
1921 CopyMem (&DstMtrrs[DstIndex], &SrcMtrrs[SrcIndex], sizeof (SrcMtrrs[0]));\r
1922 Modified[DstIndex] = TRUE;\r
1923 }\r
1924 }\r
1925}\r
1926\r
1927/**\r
1928 Calculate the variable MTRR settings for all memory ranges.\r
1929\r
1930 @param DefaultType Default memory type.\r
1931 @param A0 Alignment to use when base address is 0.\r
1932 @param Ranges Memory range array holding the memory type\r
1933 settings for all memory address.\r
1934 @param RangeCount Count of memory ranges.\r
1935 @param Scratch Scratch buffer to be used in MTRR calculation.\r
1936 @param ScratchSize Pointer to the size of scratch buffer.\r
1937 @param VariableMtrr Array holding all MTRR settings.\r
1938 @param VariableMtrrCapacity Capacity of the MTRR array.\r
1939 @param VariableMtrrCount The count of MTRR settings in array.\r
1940\r
1941 @retval RETURN_SUCCESS Variable MTRRs are allocated successfully.\r
1942 @retval RETURN_OUT_OF_RESOURCES Count of variable MTRRs exceeds capacity.\r
1943 @retval RETURN_BUFFER_TOO_SMALL The scratch buffer is too small for MTRR calculation.\r
1944 The required scratch buffer size is returned through ScratchSize.\r
1945**/\r
1946RETURN_STATUS\r
1947MtrrLibSetMemoryRanges (\r
1948 IN MTRR_MEMORY_CACHE_TYPE DefaultType,\r
1949 IN UINT64 A0,\r
1950 IN MTRR_MEMORY_RANGE *Ranges,\r
1951 IN UINTN RangeCount,\r
1952 IN VOID *Scratch,\r
1953 IN OUT UINTN *ScratchSize,\r
1954 OUT MTRR_MEMORY_RANGE *VariableMtrr,\r
1955 IN UINT32 VariableMtrrCapacity,\r
1956 OUT UINT32 *VariableMtrrCount\r
1957 )\r
1958{\r
1959 RETURN_STATUS Status;\r
1960 UINT32 Index;\r
1961 UINT64 Base0;\r
1962 UINT64 Base1;\r
1963 UINT64 Alignment;\r
1964 UINT8 CompatibleTypes;\r
1965 UINT64 Length;\r
1966 UINT32 End;\r
1967 UINTN ActualScratchSize;\r
1968 UINTN BiggestScratchSize;\r
1969\r
1970 *VariableMtrrCount = 0;\r
1971 \r
1972 //\r
1973 // Since the whole ranges need multiple calls of MtrrLibCalculateMtrrs().\r
1974 // Each call needs different scratch buffer size.\r
1975 // When the provided scratch buffer size is not sufficient in any call,\r
1976 // set the GetActualScratchSize to TRUE, and following calls will only\r
1977 // calculate the actual scratch size for the caller.\r
1978 //\r
1979 BiggestScratchSize = 0;\r
1980\r
1981 for (Index = 0; Index < RangeCount;) {\r
1982 Base0 = Ranges[Index].BaseAddress;\r
1983\r
1984 //\r
1985 // Full step is optimal\r
1986 //\r
1987 while (Index < RangeCount) {\r
1988 ASSERT (Ranges[Index].BaseAddress == Base0);\r
1989 Alignment = MtrrLibBiggestAlignment (Base0, A0);\r
1990 while (Base0 + Alignment <= Ranges[Index].BaseAddress + Ranges[Index].Length) {\r
1991 if ((BiggestScratchSize <= *ScratchSize) && (Ranges[Index].Type != DefaultType)) {\r
1992 Status = MtrrLibAppendVariableMtrr (\r
1993 VariableMtrr, VariableMtrrCapacity, VariableMtrrCount,\r
1994 Base0, Alignment, Ranges[Index].Type\r
1995 );\r
1996 if (RETURN_ERROR (Status)) {\r
1997 return Status;\r
1998 }\r
1999 }\r
2000 Base0 += Alignment;\r
2001 Alignment = MtrrLibBiggestAlignment (Base0, A0);\r
2002 }\r
2003\r
2004 //\r
2005 // Remove the above range from Ranges[Index]\r
2006 //\r
2007 Ranges[Index].Length -= Base0 - Ranges[Index].BaseAddress;\r
2008 Ranges[Index].BaseAddress = Base0;\r
2009 if (Ranges[Index].Length != 0) {\r
2010 break;\r
2011 } else {\r
2012 Index++;\r
2013 }\r
2014 }\r
2015\r
2016 if (Index == RangeCount) {\r
2017 break;\r
2018 }\r
2019\r
2020 //\r
2021 // Find continous ranges [Base0, Base1) which could be combined by MTRR.\r
2022 // Per SDM, the compatible types between[B0, B1) are:\r
2023 // UC, *\r
2024 // WB, WT\r
2025 // UC, WB, WT\r
2026 //\r
2027 CompatibleTypes = MtrrLibGetCompatibleTypes (&Ranges[Index], RangeCount - Index);\r
2028\r
2029 End = Index; // End points to last one that matches the CompatibleTypes.\r
2030 while (End + 1 < RangeCount) {\r
2031 if (((1 << Ranges[End + 1].Type) & CompatibleTypes) == 0) {\r
2032 break;\r
2033 }\r
2034 End++;\r
2035 }\r
2036 Alignment = MtrrLibBiggestAlignment (Base0, A0);\r
2037 Length = GetPowerOfTwo64 (Ranges[End].BaseAddress + Ranges[End].Length - Base0);\r
2038 Base1 = Base0 + MIN (Alignment, Length);\r
2039\r
2040 //\r
2041 // Base1 may not in Ranges[End]. Update End to the range Base1 belongs to.\r
2042 //\r
2043 End = Index;\r
2044 while (End + 1 < RangeCount) {\r
2045 if (Base1 <= Ranges[End + 1].BaseAddress) {\r
2046 break;\r
2047 }\r
2048 End++;\r
2049 }\r
2050\r
2051 Length = Ranges[End].Length;\r
2052 Ranges[End].Length = Base1 - Ranges[End].BaseAddress;\r
2053 ActualScratchSize = *ScratchSize;\r
2054 Status = MtrrLibCalculateMtrrs (\r
2055 DefaultType, A0,\r
2056 &Ranges[Index], End + 1 - Index,\r
2057 Scratch, &ActualScratchSize,\r
2058 VariableMtrr, VariableMtrrCapacity, VariableMtrrCount\r
2059 );\r
2060 if (Status == RETURN_BUFFER_TOO_SMALL) {\r
2061 BiggestScratchSize = MAX (BiggestScratchSize, ActualScratchSize);\r
2062 //\r
2063 // Ignore this error, because we need to calculate the biggest\r
2064 // scratch buffer size.\r
2065 //\r
2066 Status = RETURN_SUCCESS;\r
2067 }\r
2068 if (RETURN_ERROR (Status)) {\r
2069 return Status;\r
2070 }\r
2071\r
2072 if (Length != Ranges[End].Length) {\r
2073 Ranges[End].BaseAddress = Base1;\r
2074 Ranges[End].Length = Length - Ranges[End].Length;\r
2075 Index = End;\r
2076 } else {\r
2077 Index = End + 1;\r
2078 }\r
2079 }\r
2080\r
2081 if (*ScratchSize < BiggestScratchSize) {\r
2082 *ScratchSize = BiggestScratchSize;\r
2083 return RETURN_BUFFER_TOO_SMALL;\r
2084 }\r
2085 return RETURN_SUCCESS;\r
2086}\r
2087\r
2088/**\r
2089 Set the below-1MB memory attribute to fixed MTRR buffer.\r
2090 Modified flag array indicates which fixed MTRR is modified.\r
2091\r
2092 @param [in, out] FixedSettings Fixed MTRR buffer.\r
2093 @param [out] Modified Flag array indicating which MTRR is modified.\r
2094 @param [in] BaseAddress Base address.\r
2095 @param [in] Length Length.\r
2096 @param [in] Type Memory type.\r
2097\r
2098 @retval RETURN_SUCCESS The memory attribute is set successfully.\r
2099 @retval RETURN_UNSUPPORTED The requested range or cache type was invalid\r
2100 for the fixed MTRRs.\r
2101**/\r
2102RETURN_STATUS\r
2103MtrrLibSetBelow1MBMemoryAttribute (\r
2104 IN OUT MTRR_FIXED_SETTINGS *FixedSettings,\r
2105 OUT BOOLEAN *Modified,\r
2106 IN PHYSICAL_ADDRESS BaseAddress,\r
2107 IN UINT64 Length,\r
2108 IN MTRR_MEMORY_CACHE_TYPE Type\r
2109 )\r
2110{\r
2111 RETURN_STATUS Status;\r
2112 UINT32 MsrIndex;\r
2113 UINT64 ClearMask;\r
2114 UINT64 OrMask;\r
2115 UINT64 ClearMasks[ARRAY_SIZE (mMtrrLibFixedMtrrTable)];\r
2116 UINT64 OrMasks[ARRAY_SIZE (mMtrrLibFixedMtrrTable)];\r
2117 BOOLEAN LocalModified[ARRAY_SIZE (mMtrrLibFixedMtrrTable)];\r
2118\r
2119 ASSERT (BaseAddress < BASE_1MB);\r
2120\r
2121 SetMem (LocalModified, sizeof (LocalModified), FALSE);\r
2122\r
2123 //\r
2124 // (Value & ~0 | 0) still equals to (Value)\r
2125 //\r
2126 SetMem (ClearMasks, sizeof (ClearMasks), 0);\r
2127 SetMem (OrMasks, sizeof (OrMasks), 0);\r
2128\r
2129 MsrIndex = (UINT32)-1;\r
2130 while ((BaseAddress < BASE_1MB) && (Length != 0)) {\r
2131 Status = MtrrLibProgramFixedMtrr (Type, &BaseAddress, &Length, &MsrIndex, &ClearMask, &OrMask);\r
2132 if (RETURN_ERROR (Status)) {\r
2133 return Status;\r
2134 }\r
2135 ClearMasks[MsrIndex] = ClearMask;\r
2136 OrMasks[MsrIndex] = OrMask;\r
2137 Modified[MsrIndex] = TRUE;\r
2138 LocalModified[MsrIndex] = TRUE;\r
2139 }\r
2140\r
2141 for (MsrIndex = 0; MsrIndex < ARRAY_SIZE (mMtrrLibFixedMtrrTable); MsrIndex++) {\r
2142 if (LocalModified[MsrIndex]) {\r
2143 FixedSettings->Mtrr[MsrIndex] = (FixedSettings->Mtrr[MsrIndex] & ~ClearMasks[MsrIndex]) | OrMasks[MsrIndex];\r
2144 }\r
2145 }\r
2146 return RETURN_SUCCESS;\r
2147}\r
2148\r
2149/**\r
2150 This function attempts to set the attributes into MTRR setting buffer for multiple memory ranges.\r
2151\r
2152 @param[in, out] MtrrSetting MTRR setting buffer to be set.\r
2153 @param[in] Scratch A temporary scratch buffer that is used to perform the calculation.\r
2154 @param[in, out] ScratchSize Pointer to the size in bytes of the scratch buffer.\r
2155 It may be updated to the actual required size when the calculation\r
2156 needs more scratch buffer.\r
2157 @param[in] Ranges Pointer to an array of MTRR_MEMORY_RANGE.\r
2158 When range overlap happens, the last one takes higher priority.\r
2159 When the function returns, either all the attributes are set successfully,\r
2160 or none of them is set.\r
2161 @param[in] RangeCount Count of MTRR_MEMORY_RANGE.\r
2162\r
2163 @retval RETURN_SUCCESS The attributes were set for all the memory ranges.\r
2164 @retval RETURN_INVALID_PARAMETER Length in any range is zero.\r
2165 @retval RETURN_UNSUPPORTED The processor does not support one or more bytes of the\r
2166 memory resource range specified by BaseAddress and Length in any range.\r
2167 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support for the memory resource\r
2168 range specified by BaseAddress and Length in any range.\r
2169 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of\r
2170 the memory resource ranges.\r
2171 @retval RETURN_ACCESS_DENIED The attributes for the memory resource range specified by\r
2172 BaseAddress and Length cannot be modified.\r
2173 @retval RETURN_BUFFER_TOO_SMALL The scratch buffer is too small for MTRR calculation.\r
2174**/\r
2175RETURN_STATUS\r
2176EFIAPI\r
2177MtrrSetMemoryAttributesInMtrrSettings (\r
2178 IN OUT MTRR_SETTINGS *MtrrSetting,\r
2179 IN VOID *Scratch,\r
2180 IN OUT UINTN *ScratchSize,\r
2181 IN CONST MTRR_MEMORY_RANGE *Ranges,\r
2182 IN UINTN RangeCount\r
2183 )\r
2184{\r
2185 RETURN_STATUS Status;\r
2186 UINT32 Index;\r
2187 UINT64 BaseAddress;\r
2188 UINT64 Length;\r
2189 BOOLEAN Above1MbExist;\r
2190\r
2191 UINT64 MtrrValidBitsMask;\r
2192 UINT64 MtrrValidAddressMask;\r
2193 MTRR_MEMORY_CACHE_TYPE DefaultType;\r
2194 MTRR_VARIABLE_SETTINGS VariableSettings;\r
2195 MTRR_MEMORY_RANGE WorkingRanges[2 * ARRAY_SIZE (MtrrSetting->Variables.Mtrr) + 2];\r
2196 UINTN WorkingRangeCount;\r
2197 BOOLEAN Modified;\r
2198 MTRR_VARIABLE_SETTING VariableSetting;\r
2199 UINT32 OriginalVariableMtrrCount;\r
2200 UINT32 FirmwareVariableMtrrCount;\r
2201 UINT32 WorkingVariableMtrrCount;\r
2202 MTRR_MEMORY_RANGE OriginalVariableMtrr[ARRAY_SIZE (MtrrSetting->Variables.Mtrr)];\r
2203 MTRR_MEMORY_RANGE WorkingVariableMtrr[ARRAY_SIZE (MtrrSetting->Variables.Mtrr)];\r
2204 BOOLEAN VariableSettingModified[ARRAY_SIZE (MtrrSetting->Variables.Mtrr)];\r
2205\r
2206 BOOLEAN FixedSettingsModified[ARRAY_SIZE (mMtrrLibFixedMtrrTable)];\r
2207 MTRR_FIXED_SETTINGS WorkingFixedSettings;\r
2208\r
2209 MTRR_CONTEXT MtrrContext;\r
2210 BOOLEAN MtrrContextValid;\r
2211\r
2212 MtrrLibInitializeMtrrMask (&MtrrValidBitsMask, &MtrrValidAddressMask);\r
2213\r
2214 //\r
2215 // TRUE indicating the accordingly Variable setting needs modificaiton in OriginalVariableMtrr.\r
2216 //\r
2217 SetMem (VariableSettingModified, ARRAY_SIZE (VariableSettingModified), FALSE);\r
2218 //\r
2219 // TRUE indicating the accordingly Fixed setting needs modification in WorkingFixedSettings.\r
2220 //\r
2221 SetMem (FixedSettingsModified, ARRAY_SIZE (FixedSettingsModified), FALSE);\r
2222\r
2223 //\r
2224 // TRUE indicating the caller requests to set variable MTRRs.\r
2225 //\r
2226 Above1MbExist = FALSE;\r
2227 OriginalVariableMtrrCount = 0;\r
2228\r
2229 //\r
2230 // 1. Validate the parameters.\r
2231 //\r
2232 for (Index = 0; Index < RangeCount; Index++) {\r
2233 if (Ranges[Index].Length == 0) {\r
2234 return RETURN_INVALID_PARAMETER;\r
2235 }\r
2236 if (((Ranges[Index].BaseAddress & ~MtrrValidAddressMask) != 0) ||\r
2237 ((Ranges[Index].Length & ~MtrrValidAddressMask) != 0)\r
2238 ) {\r
2239 return RETURN_UNSUPPORTED;\r
2240 }\r
2241 if ((Ranges[Index].Type != CacheUncacheable) &&\r
2242 (Ranges[Index].Type != CacheWriteCombining) &&\r
2243 (Ranges[Index].Type != CacheWriteThrough) &&\r
2244 (Ranges[Index].Type != CacheWriteProtected) &&\r
2245 (Ranges[Index].Type != CacheWriteBack)) {\r
2246 return RETURN_INVALID_PARAMETER;\r
2247 }\r
2248 if (Ranges[Index].BaseAddress + Ranges[Index].Length > BASE_1MB) {\r
2249 Above1MbExist = TRUE;\r
2250 }\r
2251 }\r
2252\r
2253 //\r
2254 // 2. Apply the above-1MB memory attribute settings.\r
2255 //\r
2256 if (Above1MbExist) {\r
2257 //\r
2258 // 2.1. Read all variable MTRRs and convert to Ranges.\r
2259 //\r
2260 OriginalVariableMtrrCount = GetVariableMtrrCountWorker ();\r
2261 MtrrGetVariableMtrrWorker (MtrrSetting, OriginalVariableMtrrCount, &VariableSettings);\r
2262 MtrrLibGetRawVariableRanges (\r
2263 &VariableSettings, OriginalVariableMtrrCount,\r
2264 MtrrValidBitsMask, MtrrValidAddressMask, OriginalVariableMtrr\r
2265 );\r
2266\r
2267 DefaultType = MtrrGetDefaultMemoryTypeWorker (MtrrSetting);\r
2268 WorkingRangeCount = 1;\r
2269 WorkingRanges[0].BaseAddress = 0;\r
2270 WorkingRanges[0].Length = MtrrValidBitsMask + 1;\r
2271 WorkingRanges[0].Type = DefaultType;\r
2272\r
2273 Status = MtrrLibApplyVariableMtrrs (\r
2274 OriginalVariableMtrr, OriginalVariableMtrrCount,\r
2275 WorkingRanges, ARRAY_SIZE (WorkingRanges), &WorkingRangeCount);\r
2276 ASSERT_RETURN_ERROR (Status);\r
2277\r
2278 ASSERT (OriginalVariableMtrrCount >= PcdGet32 (PcdCpuNumberOfReservedVariableMtrrs));\r
2279 FirmwareVariableMtrrCount = OriginalVariableMtrrCount - PcdGet32 (PcdCpuNumberOfReservedVariableMtrrs);\r
2280 ASSERT (WorkingRangeCount <= 2 * FirmwareVariableMtrrCount + 1);\r
2281\r
2282 //\r
2283 // 2.2. Force [0, 1M) to UC, so that it doesn't impact subtraction algorithm.\r
2284 //\r
2285 Status = MtrrLibSetMemoryType (\r
2286 WorkingRanges, ARRAY_SIZE (WorkingRanges), &WorkingRangeCount,\r
2287 0, SIZE_1MB, CacheUncacheable\r
2288 );\r
2289 ASSERT (Status != RETURN_OUT_OF_RESOURCES);\r
2290\r
2291 //\r
2292 // 2.3. Apply the new memory attribute settings to Ranges.\r
2293 //\r
2294 Modified = FALSE;\r
2295 for (Index = 0; Index < RangeCount; Index++) {\r
2296 BaseAddress = Ranges[Index].BaseAddress;\r
2297 Length = Ranges[Index].Length;\r
2298 if (BaseAddress < BASE_1MB) {\r
2299 if (Length <= BASE_1MB - BaseAddress) {\r
2300 continue;\r
2301 }\r
2302 Length -= BASE_1MB - BaseAddress;\r
2303 BaseAddress = BASE_1MB;\r
2304 }\r
2305 Status = MtrrLibSetMemoryType (\r
2306 WorkingRanges, ARRAY_SIZE (WorkingRanges), &WorkingRangeCount,\r
2307 BaseAddress, Length, Ranges[Index].Type\r
2308 );\r
2309 if (Status == RETURN_ALREADY_STARTED) {\r
2310 Status = RETURN_SUCCESS;\r
2311 } else if (Status == RETURN_OUT_OF_RESOURCES) {\r
2312 return Status;\r
2313 } else {\r
2314 ASSERT_RETURN_ERROR (Status);\r
2315 Modified = TRUE;\r
2316 }\r
2317 }\r
2318\r
2319 if (Modified) {\r
2320 //\r
2321 // 2.4. Calculate the Variable MTRR settings based on the Ranges.\r
2322 // Buffer Too Small may be returned if the scratch buffer size is insufficient.\r
2323 //\r
2324 Status = MtrrLibSetMemoryRanges (\r
2325 DefaultType, LShiftU64 (1, (UINTN)HighBitSet64 (MtrrValidBitsMask)), WorkingRanges, WorkingRangeCount,\r
2326 Scratch, ScratchSize,\r
2327 WorkingVariableMtrr, FirmwareVariableMtrrCount + 1, &WorkingVariableMtrrCount\r
2328 );\r
2329 if (RETURN_ERROR (Status)) {\r
2330 return Status;\r
2331 }\r
2332\r
2333 //\r
2334 // 2.5. Remove the [0, 1MB) MTRR if it still exists (not merged with other range)\r
2335 //\r
2336 for (Index = 0; Index < WorkingVariableMtrrCount; Index++) {\r
2337 if (WorkingVariableMtrr[Index].BaseAddress == 0 && WorkingVariableMtrr[Index].Length == SIZE_1MB) {\r
2338 ASSERT (WorkingVariableMtrr[Index].Type == CacheUncacheable);\r
2339 WorkingVariableMtrrCount--;\r
2340 CopyMem (\r
2341 &WorkingVariableMtrr[Index], &WorkingVariableMtrr[Index + 1],\r
2342 (WorkingVariableMtrrCount - Index) * sizeof (WorkingVariableMtrr[0])\r
2343 );\r
2344 break;\r
2345 }\r
2346 }\r
2347\r
2348 if (WorkingVariableMtrrCount > FirmwareVariableMtrrCount) {\r
2349 return RETURN_OUT_OF_RESOURCES;\r
2350 }\r
2351\r
2352 //\r
2353 // 2.6. Merge the WorkingVariableMtrr to OriginalVariableMtrr\r
2354 // Make sure least modification is made to OriginalVariableMtrr.\r
2355 //\r
2356 MtrrLibMergeVariableMtrr (\r
2357 OriginalVariableMtrr, OriginalVariableMtrrCount,\r
2358 WorkingVariableMtrr, WorkingVariableMtrrCount,\r
2359 VariableSettingModified\r
2360 );\r
2361 }\r
2362 }\r
2363\r
2364 //\r
2365 // 3. Apply the below-1MB memory attribute settings.\r
2366 //\r
2367 ZeroMem (WorkingFixedSettings.Mtrr, sizeof (WorkingFixedSettings.Mtrr));\r
2368 for (Index = 0; Index < RangeCount; Index++) {\r
2369 if (Ranges[Index].BaseAddress >= BASE_1MB) {\r
2370 continue;\r
2371 }\r
2372\r
2373 Status = MtrrLibSetBelow1MBMemoryAttribute (\r
2374 &WorkingFixedSettings, FixedSettingsModified,\r
2375 Ranges[Index].BaseAddress, Ranges[Index].Length, Ranges[Index].Type\r
2376 );\r
2377 if (RETURN_ERROR (Status)) {\r
2378 return Status;\r
2379 }\r
2380 }\r
2381\r
2382 MtrrContextValid = FALSE;\r
2383 //\r
2384 // 4. Write fixed MTRRs that have been modified\r
2385 //\r
2386 for (Index = 0; Index < ARRAY_SIZE (FixedSettingsModified); Index++) {\r
2387 if (FixedSettingsModified[Index]) {\r
2388 if (MtrrSetting != NULL) {\r
2389 MtrrSetting->Fixed.Mtrr[Index] = WorkingFixedSettings.Mtrr[Index];\r
2390 } else {\r
2391 if (!MtrrContextValid) {\r
2392 MtrrLibPreMtrrChange (&MtrrContext);\r
2393 MtrrContextValid = TRUE;\r
2394 }\r
2395 AsmWriteMsr64 (\r
2396 mMtrrLibFixedMtrrTable[Index].Msr,\r
2397 WorkingFixedSettings.Mtrr[Index]\r
2398 );\r
2399 }\r
2400 }\r
2401 }\r
2402\r
2403 //\r
2404 // 5. Write variable MTRRs that have been modified\r
2405 //\r
2406 for (Index = 0; Index < OriginalVariableMtrrCount; Index++) {\r
2407 if (VariableSettingModified[Index]) {\r
2408 if (OriginalVariableMtrr[Index].Length != 0) {\r
2409 VariableSetting.Base = (OriginalVariableMtrr[Index].BaseAddress & MtrrValidAddressMask)\r
2410 | (UINT8)OriginalVariableMtrr[Index].Type;\r
2411 VariableSetting.Mask = ((~(OriginalVariableMtrr[Index].Length - 1)) & MtrrValidAddressMask) | BIT11;\r
2412 } else {\r
2413 VariableSetting.Base = 0;\r
2414 VariableSetting.Mask = 0;\r
2415 }\r
2416 if (MtrrSetting != NULL) {\r
2417 CopyMem (&MtrrSetting->Variables.Mtrr[Index], &VariableSetting, sizeof (VariableSetting));\r
2418 } else {\r
2419 if (!MtrrContextValid) {\r
2420 MtrrLibPreMtrrChange (&MtrrContext);\r
2421 MtrrContextValid = TRUE;\r
2422 }\r
2423 AsmWriteMsr64 (\r
2424 MSR_IA32_MTRR_PHYSBASE0 + (Index << 1),\r
2425 VariableSetting.Base\r
2426 );\r
2427 AsmWriteMsr64 (\r
2428 MSR_IA32_MTRR_PHYSMASK0 + (Index << 1),\r
2429 VariableSetting.Mask\r
2430 );\r
2431 }\r
2432 }\r
2433 }\r
2434\r
2435 if (MtrrSetting != NULL) {\r
2436 ((MSR_IA32_MTRR_DEF_TYPE_REGISTER *)&MtrrSetting->MtrrDefType)->Bits.E = 1;\r
2437 ((MSR_IA32_MTRR_DEF_TYPE_REGISTER *)&MtrrSetting->MtrrDefType)->Bits.FE = 1;\r
2438 } else {\r
2439 if (MtrrContextValid) {\r
2440 MtrrLibPostMtrrChange (&MtrrContext);\r
2441 }\r
2442 }\r
2443\r
2444 return RETURN_SUCCESS;\r
2445}\r
2446\r
2447/**\r
2448 This function attempts to set the attributes into MTRR setting buffer for a memory range.\r
2449\r
2450 @param[in, out] MtrrSetting MTRR setting buffer to be set.\r
2451 @param[in] BaseAddress The physical address that is the start address\r
2452 of a memory range.\r
2453 @param[in] Length The size in bytes of the memory range.\r
2454 @param[in] Attribute The bit mask of attributes to set for the\r
2455 memory range.\r
2456\r
2457 @retval RETURN_SUCCESS The attributes were set for the memory range.\r
2458 @retval RETURN_INVALID_PARAMETER Length is zero.\r
2459 @retval RETURN_UNSUPPORTED The processor does not support one or more bytes of the\r
2460 memory resource range specified by BaseAddress and Length.\r
2461 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support for the memory resource\r
2462 range specified by BaseAddress and Length.\r
2463 @retval RETURN_ACCESS_DENIED The attributes for the memory resource range specified by\r
2464 BaseAddress and Length cannot be modified.\r
2465 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of\r
2466 the memory resource range.\r
2467 @retval RETURN_BUFFER_TOO_SMALL The scratch buffer is too small for MTRR calculation.\r
2468**/\r
2469RETURN_STATUS\r
2470EFIAPI\r
2471MtrrSetMemoryAttributeInMtrrSettings (\r
2472 IN OUT MTRR_SETTINGS *MtrrSetting,\r
2473 IN PHYSICAL_ADDRESS BaseAddress,\r
2474 IN UINT64 Length,\r
2475 IN MTRR_MEMORY_CACHE_TYPE Attribute\r
2476 )\r
2477{\r
2478 RETURN_STATUS Status;\r
2479 UINT8 Scratch[SCRATCH_BUFFER_SIZE];\r
2480 UINTN ScratchSize;\r
2481 MTRR_MEMORY_RANGE Range;\r
2482\r
2483 if (!IsMtrrSupported ()) {\r
2484 return RETURN_UNSUPPORTED;\r
2485 }\r
2486\r
2487 Range.BaseAddress = BaseAddress;\r
2488 Range.Length = Length;\r
2489 Range.Type = Attribute;\r
2490 ScratchSize = sizeof (Scratch);\r
2491 Status = MtrrSetMemoryAttributesInMtrrSettings (MtrrSetting, Scratch, &ScratchSize, &Range, 1);\r
2492 DEBUG ((DEBUG_CACHE, "MtrrSetMemoryAttribute(MtrrSettings = %p) %a: [%016lx, %016lx) - %r\n",\r
2493 MtrrSetting,\r
2494 mMtrrMemoryCacheTypeShortName[Attribute], BaseAddress, BaseAddress + Length, Status));\r
2495\r
2496 if (!RETURN_ERROR (Status)) {\r
2497 MtrrDebugPrintAllMtrrsWorker (MtrrSetting);\r
2498 }\r
2499 return Status;\r
2500}\r
2501\r
2502/**\r
2503 This function attempts to set the attributes for a memory range.\r
2504\r
2505 @param[in] BaseAddress The physical address that is the start\r
2506 address of a memory range.\r
2507 @param[in] Length The size in bytes of the memory range.\r
2508 @param[in] Attributes The bit mask of attributes to set for the\r
2509 memory range.\r
2510\r
2511 @retval RETURN_SUCCESS The attributes were set for the memory\r
2512 range.\r
2513 @retval RETURN_INVALID_PARAMETER Length is zero.\r
2514 @retval RETURN_UNSUPPORTED The processor does not support one or\r
2515 more bytes of the memory resource range\r
2516 specified by BaseAddress and Length.\r
2517 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support\r
2518 for the memory resource range specified\r
2519 by BaseAddress and Length.\r
2520 @retval RETURN_ACCESS_DENIED The attributes for the memory resource\r
2521 range specified by BaseAddress and Length\r
2522 cannot be modified.\r
2523 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to\r
2524 modify the attributes of the memory\r
2525 resource range.\r
2526 @retval RETURN_BUFFER_TOO_SMALL The scratch buffer is too small for MTRR calculation.\r
2527**/\r
2528RETURN_STATUS\r
2529EFIAPI\r
2530MtrrSetMemoryAttribute (\r
2531 IN PHYSICAL_ADDRESS BaseAddress,\r
2532 IN UINT64 Length,\r
2533 IN MTRR_MEMORY_CACHE_TYPE Attribute\r
2534 )\r
2535{\r
2536 return MtrrSetMemoryAttributeInMtrrSettings (NULL, BaseAddress, Length, Attribute);\r
2537}\r
2538\r
2539/**\r
2540 Worker function setting variable MTRRs\r
2541\r
2542 @param[in] VariableSettings A buffer to hold variable MTRRs content.\r
2543\r
2544**/\r
2545VOID\r
2546MtrrSetVariableMtrrWorker (\r
2547 IN MTRR_VARIABLE_SETTINGS *VariableSettings\r
2548 )\r
2549{\r
2550 UINT32 Index;\r
2551 UINT32 VariableMtrrCount;\r
2552\r
2553 VariableMtrrCount = GetVariableMtrrCountWorker ();\r
2554 ASSERT (VariableMtrrCount <= ARRAY_SIZE (VariableSettings->Mtrr));\r
2555\r
2556 for (Index = 0; Index < VariableMtrrCount; Index++) {\r
2557 //\r
2558 // Mask MSR is always updated since caller might need to invalidate the MSR pair.\r
2559 // Base MSR is skipped when Mask.V is not set.\r
2560 //\r
2561 AsmWriteMsr64 (MSR_IA32_MTRR_PHYSMASK0 + (Index << 1), VariableSettings->Mtrr[Index].Mask);\r
2562 if (((MSR_IA32_MTRR_PHYSMASK_REGISTER *)&VariableSettings->Mtrr[Index].Mask)->Bits.V != 0) {\r
2563 AsmWriteMsr64 (MSR_IA32_MTRR_PHYSBASE0 + (Index << 1), VariableSettings->Mtrr[Index].Base);\r
2564 }\r
2565 }\r
2566}\r
2567\r
2568\r
2569/**\r
2570 This function sets variable MTRRs\r
2571\r
2572 @param[in] VariableSettings A buffer to hold variable MTRRs content.\r
2573\r
2574 @return The pointer of VariableSettings\r
2575\r
2576**/\r
2577MTRR_VARIABLE_SETTINGS*\r
2578EFIAPI\r
2579MtrrSetVariableMtrr (\r
2580 IN MTRR_VARIABLE_SETTINGS *VariableSettings\r
2581 )\r
2582{\r
2583 MTRR_CONTEXT MtrrContext;\r
2584\r
2585 if (!IsMtrrSupported ()) {\r
2586 return VariableSettings;\r
2587 }\r
2588\r
2589 MtrrLibPreMtrrChange (&MtrrContext);\r
2590 MtrrSetVariableMtrrWorker (VariableSettings);\r
2591 MtrrLibPostMtrrChange (&MtrrContext);\r
2592 MtrrDebugPrintAllMtrrs ();\r
2593\r
2594 return VariableSettings;\r
2595}\r
2596\r
2597/**\r
2598 Worker function setting fixed MTRRs\r
2599\r
2600 @param[in] FixedSettings A buffer to hold fixed MTRRs content.\r
2601\r
2602**/\r
2603VOID\r
2604MtrrSetFixedMtrrWorker (\r
2605 IN MTRR_FIXED_SETTINGS *FixedSettings\r
2606 )\r
2607{\r
2608 UINT32 Index;\r
2609\r
2610 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
2611 AsmWriteMsr64 (\r
2612 mMtrrLibFixedMtrrTable[Index].Msr,\r
2613 FixedSettings->Mtrr[Index]\r
2614 );\r
2615 }\r
2616}\r
2617\r
2618\r
2619/**\r
2620 This function sets fixed MTRRs\r
2621\r
2622 @param[in] FixedSettings A buffer to hold fixed MTRRs content.\r
2623\r
2624 @retval The pointer of FixedSettings\r
2625\r
2626**/\r
2627MTRR_FIXED_SETTINGS*\r
2628EFIAPI\r
2629MtrrSetFixedMtrr (\r
2630 IN MTRR_FIXED_SETTINGS *FixedSettings\r
2631 )\r
2632{\r
2633 MTRR_CONTEXT MtrrContext;\r
2634\r
2635 if (!IsMtrrSupported ()) {\r
2636 return FixedSettings;\r
2637 }\r
2638\r
2639 MtrrLibPreMtrrChange (&MtrrContext);\r
2640 MtrrSetFixedMtrrWorker (FixedSettings);\r
2641 MtrrLibPostMtrrChange (&MtrrContext);\r
2642 MtrrDebugPrintAllMtrrs ();\r
2643\r
2644 return FixedSettings;\r
2645}\r
2646\r
2647\r
2648/**\r
2649 This function gets the content in all MTRRs (variable and fixed)\r
2650\r
2651 @param[out] MtrrSetting A buffer to hold all MTRRs content.\r
2652\r
2653 @retval the pointer of MtrrSetting\r
2654\r
2655**/\r
2656MTRR_SETTINGS *\r
2657EFIAPI\r
2658MtrrGetAllMtrrs (\r
2659 OUT MTRR_SETTINGS *MtrrSetting\r
2660 )\r
2661{\r
2662 if (!IsMtrrSupported ()) {\r
2663 return MtrrSetting;\r
2664 }\r
2665\r
2666 //\r
2667 // Get fixed MTRRs\r
2668 //\r
2669 MtrrGetFixedMtrrWorker (&MtrrSetting->Fixed);\r
2670\r
2671 //\r
2672 // Get variable MTRRs\r
2673 //\r
2674 MtrrGetVariableMtrrWorker (\r
2675 NULL,\r
2676 GetVariableMtrrCountWorker (),\r
2677 &MtrrSetting->Variables\r
2678 );\r
2679\r
2680 //\r
2681 // Get MTRR_DEF_TYPE value\r
2682 //\r
2683 MtrrSetting->MtrrDefType = AsmReadMsr64 (MSR_IA32_MTRR_DEF_TYPE);\r
2684\r
2685 return MtrrSetting;\r
2686}\r
2687\r
2688\r
2689/**\r
2690 This function sets all MTRRs (variable and fixed)\r
2691\r
2692 @param[in] MtrrSetting A buffer holding all MTRRs content.\r
2693\r
2694 @retval The pointer of MtrrSetting\r
2695\r
2696**/\r
2697MTRR_SETTINGS *\r
2698EFIAPI\r
2699MtrrSetAllMtrrs (\r
2700 IN MTRR_SETTINGS *MtrrSetting\r
2701 )\r
2702{\r
2703 MTRR_CONTEXT MtrrContext;\r
2704\r
2705 if (!IsMtrrSupported ()) {\r
2706 return MtrrSetting;\r
2707 }\r
2708\r
2709 MtrrLibPreMtrrChange (&MtrrContext);\r
2710\r
2711 //\r
2712 // Set fixed MTRRs\r
2713 //\r
2714 MtrrSetFixedMtrrWorker (&MtrrSetting->Fixed);\r
2715\r
2716 //\r
2717 // Set variable MTRRs\r
2718 //\r
2719 MtrrSetVariableMtrrWorker (&MtrrSetting->Variables);\r
2720\r
2721 //\r
2722 // Set MTRR_DEF_TYPE value\r
2723 //\r
2724 AsmWriteMsr64 (MSR_IA32_MTRR_DEF_TYPE, MtrrSetting->MtrrDefType);\r
2725\r
2726 MtrrLibPostMtrrChangeEnableCache (&MtrrContext);\r
2727\r
2728 return MtrrSetting;\r
2729}\r
2730\r
2731\r
2732/**\r
2733 Checks if MTRR is supported.\r
2734\r
2735 @retval TRUE MTRR is supported.\r
2736 @retval FALSE MTRR is not supported.\r
2737\r
2738**/\r
2739BOOLEAN\r
2740EFIAPI\r
2741IsMtrrSupported (\r
2742 VOID\r
2743 )\r
2744{\r
2745 CPUID_VERSION_INFO_EDX Edx;\r
2746 MSR_IA32_MTRRCAP_REGISTER MtrrCap;\r
2747\r
2748 //\r
2749 // Check CPUID(1).EDX[12] for MTRR capability\r
2750 //\r
2751 AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &Edx.Uint32);\r
2752 if (Edx.Bits.MTRR == 0) {\r
2753 return FALSE;\r
2754 }\r
2755\r
2756 //\r
2757 // Check number of variable MTRRs and fixed MTRRs existence.\r
2758 // If number of variable MTRRs is zero, or fixed MTRRs do not\r
2759 // exist, return false.\r
2760 //\r
2761 MtrrCap.Uint64 = AsmReadMsr64 (MSR_IA32_MTRRCAP);\r
2762 if ((MtrrCap.Bits.VCNT == 0) || (MtrrCap.Bits.FIX == 0)) {\r
2763 return FALSE;\r
2764 }\r
2765 return TRUE;\r
2766}\r
2767\r
2768\r
2769/**\r
2770 Worker function prints all MTRRs for debugging.\r
2771\r
2772 If MtrrSetting is not NULL, print MTRR settings from input MTRR\r
2773 settings buffer.\r
2774 If MtrrSetting is NULL, print MTRR settings from MTRRs.\r
2775\r
2776 @param MtrrSetting A buffer holding all MTRRs content.\r
2777**/\r
2778VOID\r
2779MtrrDebugPrintAllMtrrsWorker (\r
2780 IN MTRR_SETTINGS *MtrrSetting\r
2781 )\r
2782{\r
2783 DEBUG_CODE (\r
2784 MTRR_SETTINGS LocalMtrrs;\r
2785 MTRR_SETTINGS *Mtrrs;\r
2786 UINTN Index;\r
2787 UINTN RangeCount;\r
2788 UINT64 MtrrValidBitsMask;\r
2789 UINT64 MtrrValidAddressMask;\r
2790 UINT32 VariableMtrrCount;\r
2791 MTRR_MEMORY_RANGE Ranges[\r
2792 ARRAY_SIZE (mMtrrLibFixedMtrrTable) * sizeof (UINT64) + 2 * ARRAY_SIZE (Mtrrs->Variables.Mtrr) + 1\r
2793 ];\r
2794 MTRR_MEMORY_RANGE RawVariableRanges[ARRAY_SIZE (Mtrrs->Variables.Mtrr)];\r
2795\r
2796 if (!IsMtrrSupported ()) {\r
2797 return;\r
2798 }\r
2799\r
2800 VariableMtrrCount = GetVariableMtrrCountWorker ();\r
2801\r
2802 if (MtrrSetting != NULL) {\r
2803 Mtrrs = MtrrSetting;\r
2804 } else {\r
2805 MtrrGetAllMtrrs (&LocalMtrrs);\r
2806 Mtrrs = &LocalMtrrs;\r
2807 }\r
2808\r
2809 //\r
2810 // Dump RAW MTRR contents\r
2811 //\r
2812 DEBUG((DEBUG_CACHE, "MTRR Settings\n"));\r
2813 DEBUG((DEBUG_CACHE, "=============\n"));\r
2814 DEBUG((DEBUG_CACHE, "MTRR Default Type: %016lx\n", Mtrrs->MtrrDefType));\r
2815 for (Index = 0; Index < ARRAY_SIZE (mMtrrLibFixedMtrrTable); Index++) {\r
2816 DEBUG((DEBUG_CACHE, "Fixed MTRR[%02d] : %016lx\n", Index, Mtrrs->Fixed.Mtrr[Index]));\r
2817 }\r
2818\r
2819 for (Index = 0; Index < VariableMtrrCount; Index++) {\r
2820 if (((MSR_IA32_MTRR_PHYSMASK_REGISTER *)&Mtrrs->Variables.Mtrr[Index].Mask)->Bits.V == 0) {\r
2821 //\r
2822 // If mask is not valid, then do not display range\r
2823 //\r
2824 continue;\r
2825 }\r
2826 DEBUG ((DEBUG_CACHE, "Variable MTRR[%02d]: Base=%016lx Mask=%016lx\n",\r
2827 Index,\r
2828 Mtrrs->Variables.Mtrr[Index].Base,\r
2829 Mtrrs->Variables.Mtrr[Index].Mask\r
2830 ));\r
2831 }\r
2832 DEBUG((DEBUG_CACHE, "\n"));\r
2833\r
2834 //\r
2835 // Dump MTRR setting in ranges\r
2836 //\r
2837 DEBUG((DEBUG_CACHE, "MTRR Ranges\n"));\r
2838 DEBUG((DEBUG_CACHE, "====================================\n"));\r
2839 MtrrLibInitializeMtrrMask (&MtrrValidBitsMask, &MtrrValidAddressMask);\r
2840 Ranges[0].BaseAddress = 0;\r
2841 Ranges[0].Length = MtrrValidBitsMask + 1;\r
2842 Ranges[0].Type = MtrrGetDefaultMemoryTypeWorker (Mtrrs);\r
2843 RangeCount = 1;\r
2844\r
2845 MtrrLibGetRawVariableRanges (\r
2846 &Mtrrs->Variables, VariableMtrrCount,\r
2847 MtrrValidBitsMask, MtrrValidAddressMask, RawVariableRanges\r
2848 );\r
2849 MtrrLibApplyVariableMtrrs (\r
2850 RawVariableRanges, VariableMtrrCount,\r
2851 Ranges, ARRAY_SIZE (Ranges), &RangeCount\r
2852 );\r
2853\r
2854 MtrrLibApplyFixedMtrrs (&Mtrrs->Fixed, Ranges, ARRAY_SIZE (Ranges), &RangeCount);\r
2855\r
2856 for (Index = 0; Index < RangeCount; Index++) {\r
2857 DEBUG ((DEBUG_CACHE, "%a:%016lx-%016lx\n",\r
2858 mMtrrMemoryCacheTypeShortName[Ranges[Index].Type],\r
2859 Ranges[Index].BaseAddress, Ranges[Index].BaseAddress + Ranges[Index].Length - 1\r
2860 ));\r
2861 }\r
2862 );\r
2863}\r
2864\r
2865/**\r
2866 This function prints all MTRRs for debugging.\r
2867**/\r
2868VOID\r
2869EFIAPI\r
2870MtrrDebugPrintAllMtrrs (\r
2871 VOID\r
2872 )\r
2873{\r
2874 MtrrDebugPrintAllMtrrsWorker (NULL);\r
2875}\r