]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - UefiCpuPkg/Library/MtrrLib/MtrrLib.c
UefiCpuPkg/MtrrLib: Avoid running unnecessary code
[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 <Base.h>\r
20\r
21#include <Register/Cpuid.h>\r
22#include <Register/Msr.h>\r
23\r
24#include <Library/MtrrLib.h>\r
25#include <Library/BaseLib.h>\r
26#include <Library/CpuLib.h>\r
27#include <Library/BaseMemoryLib.h>\r
28#include <Library/DebugLib.h>\r
29\r
30#define OR_SEED 0x0101010101010101ull\r
31#define CLEAR_SEED 0xFFFFFFFFFFFFFFFFull\r
32\r
33#define MTRR_LIB_ASSERT_ALIGNED(B, L) ASSERT ((B & ~(L - 1)) == B);\r
34//\r
35// Context to save and restore when MTRRs are programmed\r
36//\r
37typedef struct {\r
38 UINTN Cr4;\r
39 BOOLEAN InterruptState;\r
40} MTRR_CONTEXT;\r
41\r
42typedef struct {\r
43 UINT64 BaseAddress;\r
44 UINT64 Length;\r
45 MTRR_MEMORY_CACHE_TYPE Type;\r
46} MEMORY_RANGE;\r
47\r
48//\r
49// This table defines the offset, base and length of the fixed MTRRs\r
50//\r
51CONST FIXED_MTRR mMtrrLibFixedMtrrTable[] = {\r
52 {\r
53 MSR_IA32_MTRR_FIX64K_00000,\r
54 0,\r
55 SIZE_64KB\r
56 },\r
57 {\r
58 MSR_IA32_MTRR_FIX16K_80000,\r
59 0x80000,\r
60 SIZE_16KB\r
61 },\r
62 {\r
63 MSR_IA32_MTRR_FIX16K_A0000,\r
64 0xA0000,\r
65 SIZE_16KB\r
66 },\r
67 {\r
68 MSR_IA32_MTRR_FIX4K_C0000,\r
69 0xC0000,\r
70 SIZE_4KB\r
71 },\r
72 {\r
73 MSR_IA32_MTRR_FIX4K_C8000,\r
74 0xC8000,\r
75 SIZE_4KB\r
76 },\r
77 {\r
78 MSR_IA32_MTRR_FIX4K_D0000,\r
79 0xD0000,\r
80 SIZE_4KB\r
81 },\r
82 {\r
83 MSR_IA32_MTRR_FIX4K_D8000,\r
84 0xD8000,\r
85 SIZE_4KB\r
86 },\r
87 {\r
88 MSR_IA32_MTRR_FIX4K_E0000,\r
89 0xE0000,\r
90 SIZE_4KB\r
91 },\r
92 {\r
93 MSR_IA32_MTRR_FIX4K_E8000,\r
94 0xE8000,\r
95 SIZE_4KB\r
96 },\r
97 {\r
98 MSR_IA32_MTRR_FIX4K_F0000,\r
99 0xF0000,\r
100 SIZE_4KB\r
101 },\r
102 {\r
103 MSR_IA32_MTRR_FIX4K_F8000,\r
104 0xF8000,\r
105 SIZE_4KB\r
106 }\r
107};\r
108\r
109//\r
110// Lookup table used to print MTRRs\r
111//\r
112GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 *mMtrrMemoryCacheTypeShortName[] = {\r
113 "UC", // CacheUncacheable\r
114 "WC", // CacheWriteCombining\r
115 "R*", // Invalid\r
116 "R*", // Invalid\r
117 "WT", // CacheWriteThrough\r
118 "WP", // CacheWriteProtected\r
119 "WB", // CacheWriteBack\r
120 "R*" // Invalid\r
121};\r
122\r
123/**\r
124 Worker function returns the variable MTRR count for the CPU.\r
125\r
126 @return Variable MTRR count\r
127\r
128**/\r
129UINT32\r
130GetVariableMtrrCountWorker (\r
131 VOID\r
132 )\r
133{\r
134 MSR_IA32_MTRRCAP_REGISTER MtrrCap;\r
135\r
136 MtrrCap.Uint64 = AsmReadMsr64 (MSR_IA32_MTRRCAP);\r
137 ASSERT (MtrrCap.Bits.VCNT <= MTRR_NUMBER_OF_VARIABLE_MTRR);\r
138 return MtrrCap.Bits.VCNT;\r
139}\r
140\r
141/**\r
142 Returns the variable MTRR count for the CPU.\r
143\r
144 @return Variable MTRR count\r
145\r
146**/\r
147UINT32\r
148EFIAPI\r
149GetVariableMtrrCount (\r
150 VOID\r
151 )\r
152{\r
153 if (!IsMtrrSupported ()) {\r
154 return 0;\r
155 }\r
156 return GetVariableMtrrCountWorker ();\r
157}\r
158\r
159/**\r
160 Worker function returns the firmware usable variable MTRR count for the CPU.\r
161\r
162 @return Firmware usable variable MTRR count\r
163\r
164**/\r
165UINT32\r
166GetFirmwareVariableMtrrCountWorker (\r
167 VOID\r
168 )\r
169{\r
170 UINT32 VariableMtrrCount;\r
171 UINT32 ReservedMtrrNumber;\r
172\r
173 VariableMtrrCount = GetVariableMtrrCountWorker ();\r
174 ReservedMtrrNumber = PcdGet32 (PcdCpuNumberOfReservedVariableMtrrs);\r
175 if (VariableMtrrCount < ReservedMtrrNumber) {\r
176 return 0;\r
177 }\r
178\r
179 return VariableMtrrCount - ReservedMtrrNumber;\r
180}\r
181\r
182/**\r
183 Returns the firmware usable variable MTRR count for the CPU.\r
184\r
185 @return Firmware usable variable MTRR count\r
186\r
187**/\r
188UINT32\r
189EFIAPI\r
190GetFirmwareVariableMtrrCount (\r
191 VOID\r
192 )\r
193{\r
194 if (!IsMtrrSupported ()) {\r
195 return 0;\r
196 }\r
197 return GetFirmwareVariableMtrrCountWorker ();\r
198}\r
199\r
200/**\r
201 Worker function returns the default MTRR cache type for the system.\r
202\r
203 If MtrrSetting is not NULL, returns the default MTRR cache type from input\r
204 MTRR settings buffer.\r
205 If MtrrSetting is NULL, returns the default MTRR cache type from MSR.\r
206\r
207 @param[in] MtrrSetting A buffer holding all MTRRs content.\r
208\r
209 @return The default MTRR cache type.\r
210\r
211**/\r
212MTRR_MEMORY_CACHE_TYPE\r
213MtrrGetDefaultMemoryTypeWorker (\r
214 IN MTRR_SETTINGS *MtrrSetting\r
215 )\r
216{\r
217 MSR_IA32_MTRR_DEF_TYPE_REGISTER DefType;\r
218\r
219 if (MtrrSetting == NULL) {\r
220 DefType.Uint64 = AsmReadMsr64 (MSR_IA32_MTRR_DEF_TYPE);\r
221 } else {\r
222 DefType.Uint64 = MtrrSetting->MtrrDefType;\r
223 }\r
224\r
225 return (MTRR_MEMORY_CACHE_TYPE) DefType.Bits.Type;\r
226}\r
227\r
228\r
229/**\r
230 Returns the default MTRR cache type for the system.\r
231\r
232 @return The default MTRR cache type.\r
233\r
234**/\r
235MTRR_MEMORY_CACHE_TYPE\r
236EFIAPI\r
237MtrrGetDefaultMemoryType (\r
238 VOID\r
239 )\r
240{\r
241 if (!IsMtrrSupported ()) {\r
242 return CacheUncacheable;\r
243 }\r
244 return MtrrGetDefaultMemoryTypeWorker (NULL);\r
245}\r
246\r
247/**\r
248 Preparation before programming MTRR.\r
249\r
250 This function will do some preparation for programming MTRRs:\r
251 disable cache, invalid cache and disable MTRR caching functionality\r
252\r
253 @param[out] MtrrContext Pointer to context to save\r
254\r
255**/\r
256VOID\r
257MtrrLibPreMtrrChange (\r
258 OUT MTRR_CONTEXT *MtrrContext\r
259 )\r
260{\r
261 MSR_IA32_MTRR_DEF_TYPE_REGISTER DefType;\r
262 //\r
263 // Disable interrupts and save current interrupt state\r
264 //\r
265 MtrrContext->InterruptState = SaveAndDisableInterrupts();\r
266\r
267 //\r
268 // Enter no fill cache mode, CD=1(Bit30), NW=0 (Bit29)\r
269 //\r
270 AsmDisableCache ();\r
271\r
272 //\r
273 // Save original CR4 value and clear PGE flag (Bit 7)\r
274 //\r
275 MtrrContext->Cr4 = AsmReadCr4 ();\r
276 AsmWriteCr4 (MtrrContext->Cr4 & (~BIT7));\r
277\r
278 //\r
279 // Flush all TLBs\r
280 //\r
281 CpuFlushTlb ();\r
282\r
283 //\r
284 // Disable MTRRs\r
285 //\r
286 DefType.Uint64 = AsmReadMsr64 (MSR_IA32_MTRR_DEF_TYPE);\r
287 DefType.Bits.E = 0;\r
288 AsmWriteMsr64 (MSR_IA32_MTRR_DEF_TYPE, DefType.Uint64);\r
289}\r
290\r
291/**\r
292 Cleaning up after programming MTRRs.\r
293\r
294 This function will do some clean up after programming MTRRs:\r
295 Flush all TLBs, re-enable caching, restore CR4.\r
296\r
297 @param[in] MtrrContext Pointer to context to restore\r
298\r
299**/\r
300VOID\r
301MtrrLibPostMtrrChangeEnableCache (\r
302 IN MTRR_CONTEXT *MtrrContext\r
303 )\r
304{\r
305 //\r
306 // Flush all TLBs\r
307 //\r
308 CpuFlushTlb ();\r
309\r
310 //\r
311 // Enable Normal Mode caching CD=NW=0, CD(Bit30), NW(Bit29)\r
312 //\r
313 AsmEnableCache ();\r
314\r
315 //\r
316 // Restore original CR4 value\r
317 //\r
318 AsmWriteCr4 (MtrrContext->Cr4);\r
319\r
320 //\r
321 // Restore original interrupt state\r
322 //\r
323 SetInterruptState (MtrrContext->InterruptState);\r
324}\r
325\r
326/**\r
327 Cleaning up after programming MTRRs.\r
328\r
329 This function will do some clean up after programming MTRRs:\r
330 enable MTRR caching functionality, and enable cache\r
331\r
332 @param[in] MtrrContext Pointer to context to restore\r
333\r
334**/\r
335VOID\r
336MtrrLibPostMtrrChange (\r
337 IN MTRR_CONTEXT *MtrrContext\r
338 )\r
339{\r
340 MSR_IA32_MTRR_DEF_TYPE_REGISTER DefType;\r
341 //\r
342 // Enable Cache MTRR\r
343 //\r
344 DefType.Uint64 = AsmReadMsr64 (MSR_IA32_MTRR_DEF_TYPE);\r
345 DefType.Bits.E = 1;\r
346 DefType.Bits.FE = 1;\r
347 AsmWriteMsr64 (MSR_IA32_MTRR_DEF_TYPE, DefType.Uint64);\r
348\r
349 MtrrLibPostMtrrChangeEnableCache (MtrrContext);\r
350}\r
351\r
352/**\r
353 Worker function gets the content in fixed MTRRs\r
354\r
355 @param[out] FixedSettings A buffer to hold fixed MTRRs content.\r
356\r
357 @retval The pointer of FixedSettings\r
358\r
359**/\r
360MTRR_FIXED_SETTINGS*\r
361MtrrGetFixedMtrrWorker (\r
362 OUT MTRR_FIXED_SETTINGS *FixedSettings\r
363 )\r
364{\r
365 UINT32 Index;\r
366\r
367 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
368 FixedSettings->Mtrr[Index] =\r
369 AsmReadMsr64 (mMtrrLibFixedMtrrTable[Index].Msr);\r
370 }\r
371\r
372 return FixedSettings;\r
373}\r
374\r
375\r
376/**\r
377 This function gets the content in fixed MTRRs\r
378\r
379 @param[out] FixedSettings A buffer to hold fixed MTRRs content.\r
380\r
381 @retval The pointer of FixedSettings\r
382\r
383**/\r
384MTRR_FIXED_SETTINGS*\r
385EFIAPI\r
386MtrrGetFixedMtrr (\r
387 OUT MTRR_FIXED_SETTINGS *FixedSettings\r
388 )\r
389{\r
390 if (!IsMtrrSupported ()) {\r
391 return FixedSettings;\r
392 }\r
393\r
394 return MtrrGetFixedMtrrWorker (FixedSettings);\r
395}\r
396\r
397\r
398/**\r
399 Worker function will get the raw value in variable MTRRs\r
400\r
401 If MtrrSetting is not NULL, gets the variable MTRRs raw value from input\r
402 MTRR settings buffer.\r
403 If MtrrSetting is NULL, gets the variable MTRRs raw value from MTRRs.\r
404\r
405 @param[in] MtrrSetting A buffer holding all MTRRs content.\r
406 @param[in] VariableMtrrCount Number of variable MTRRs.\r
407 @param[out] VariableSettings A buffer to hold variable MTRRs content.\r
408\r
409 @return The VariableSettings input pointer\r
410\r
411**/\r
412MTRR_VARIABLE_SETTINGS*\r
413MtrrGetVariableMtrrWorker (\r
414 IN MTRR_SETTINGS *MtrrSetting,\r
415 IN UINT32 VariableMtrrCount,\r
416 OUT MTRR_VARIABLE_SETTINGS *VariableSettings\r
417 )\r
418{\r
419 UINT32 Index;\r
420\r
421 ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);\r
422\r
423 for (Index = 0; Index < VariableMtrrCount; Index++) {\r
424 if (MtrrSetting == NULL) {\r
425 VariableSettings->Mtrr[Index].Base =\r
426 AsmReadMsr64 (MSR_IA32_MTRR_PHYSBASE0 + (Index << 1));\r
427 VariableSettings->Mtrr[Index].Mask =\r
428 AsmReadMsr64 (MSR_IA32_MTRR_PHYSMASK0 + (Index << 1));\r
429 } else {\r
430 VariableSettings->Mtrr[Index].Base = MtrrSetting->Variables.Mtrr[Index].Base;\r
431 VariableSettings->Mtrr[Index].Mask = MtrrSetting->Variables.Mtrr[Index].Mask;\r
432 }\r
433 }\r
434\r
435 return VariableSettings;\r
436}\r
437\r
438/**\r
439 This function will get the raw value in variable MTRRs\r
440\r
441 @param[out] VariableSettings A buffer to hold variable MTRRs content.\r
442\r
443 @return The VariableSettings input pointer\r
444\r
445**/\r
446MTRR_VARIABLE_SETTINGS*\r
447EFIAPI\r
448MtrrGetVariableMtrr (\r
449 OUT MTRR_VARIABLE_SETTINGS *VariableSettings\r
450 )\r
451{\r
452 if (!IsMtrrSupported ()) {\r
453 return VariableSettings;\r
454 }\r
455\r
456 return MtrrGetVariableMtrrWorker (\r
457 NULL,\r
458 GetVariableMtrrCountWorker (),\r
459 VariableSettings\r
460 );\r
461}\r
462\r
463/**\r
464 Programs fixed MTRRs registers.\r
465\r
466 @param[in] Type The memory type to set.\r
467 @param[in, out] Base The base address of memory range.\r
468 @param[in, out] Length The length of memory range.\r
469 @param[in, out] LastMsrNum On input, the last index of the fixed MTRR MSR to program.\r
470 On return, the current index of the fixed MTRR MSR to program.\r
471 @param[out] ReturnClearMask The bits to clear in the fixed MTRR MSR.\r
472 @param[out] ReturnOrMask The bits to set in the fixed MTRR MSR.\r
473\r
474 @retval RETURN_SUCCESS The cache type was updated successfully\r
475 @retval RETURN_UNSUPPORTED The requested range or cache type was invalid\r
476 for the fixed MTRRs.\r
477\r
478**/\r
479RETURN_STATUS\r
480MtrrLibProgramFixedMtrr (\r
481 IN MTRR_MEMORY_CACHE_TYPE Type,\r
482 IN OUT UINT64 *Base,\r
483 IN OUT UINT64 *Length,\r
484 IN OUT UINT32 *LastMsrNum,\r
485 OUT UINT64 *ReturnClearMask,\r
486 OUT UINT64 *ReturnOrMask\r
487 )\r
488{\r
489 UINT32 MsrNum;\r
490 UINT32 LeftByteShift;\r
491 UINT32 RightByteShift;\r
492 UINT64 OrMask;\r
493 UINT64 ClearMask;\r
494 UINT64 SubLength;\r
495\r
496 //\r
497 // Find the fixed MTRR index to be programmed\r
498 //\r
499 for (MsrNum = *LastMsrNum + 1; MsrNum < MTRR_NUMBER_OF_FIXED_MTRR; MsrNum++) {\r
500 if ((*Base >= mMtrrLibFixedMtrrTable[MsrNum].BaseAddress) &&\r
501 (*Base <\r
502 (\r
503 mMtrrLibFixedMtrrTable[MsrNum].BaseAddress +\r
504 (8 * mMtrrLibFixedMtrrTable[MsrNum].Length)\r
505 )\r
506 )\r
507 ) {\r
508 break;\r
509 }\r
510 }\r
511\r
512 if (MsrNum == MTRR_NUMBER_OF_FIXED_MTRR) {\r
513 return RETURN_UNSUPPORTED;\r
514 }\r
515\r
516 //\r
517 // Find the begin offset in fixed MTRR and calculate byte offset of left shift\r
518 //\r
519 LeftByteShift = ((UINT32)*Base - mMtrrLibFixedMtrrTable[MsrNum].BaseAddress)\r
520 / mMtrrLibFixedMtrrTable[MsrNum].Length;\r
521\r
522 if (LeftByteShift >= 8) {\r
523 return RETURN_UNSUPPORTED;\r
524 }\r
525\r
526 //\r
527 // Find the end offset in fixed MTRR and calculate byte offset of right shift\r
528 //\r
529 SubLength = mMtrrLibFixedMtrrTable[MsrNum].Length * (8 - LeftByteShift);\r
530 if (*Length >= SubLength) {\r
531 RightByteShift = 0;\r
532 } else {\r
533 RightByteShift = 8 - LeftByteShift -\r
534 (UINT32)(*Length) / mMtrrLibFixedMtrrTable[MsrNum].Length;\r
535 if ((LeftByteShift >= 8) ||\r
536 (((UINT32)(*Length) % mMtrrLibFixedMtrrTable[MsrNum].Length) != 0)\r
537 ) {\r
538 return RETURN_UNSUPPORTED;\r
539 }\r
540 //\r
541 // Update SubLength by actual length\r
542 //\r
543 SubLength = *Length;\r
544 }\r
545\r
546 ClearMask = CLEAR_SEED;\r
547 OrMask = MultU64x32 (OR_SEED, (UINT32) Type);\r
548\r
549 if (LeftByteShift != 0) {\r
550 //\r
551 // Clear the low bits by LeftByteShift\r
552 //\r
553 ClearMask &= LShiftU64 (ClearMask, LeftByteShift * 8);\r
554 OrMask &= LShiftU64 (OrMask, LeftByteShift * 8);\r
555 }\r
556\r
557 if (RightByteShift != 0) {\r
558 //\r
559 // Clear the high bits by RightByteShift\r
560 //\r
561 ClearMask &= RShiftU64 (ClearMask, RightByteShift * 8);\r
562 OrMask &= RShiftU64 (OrMask, RightByteShift * 8);\r
563 }\r
564\r
565 *Length -= SubLength;\r
566 *Base += SubLength;\r
567\r
568 *LastMsrNum = MsrNum;\r
569 *ReturnClearMask = ClearMask;\r
570 *ReturnOrMask = OrMask;\r
571\r
572 return RETURN_SUCCESS;\r
573}\r
574\r
575\r
576/**\r
577 Worker function gets the attribute of variable MTRRs.\r
578\r
579 This function shadows the content of variable MTRRs into an\r
580 internal array: VariableMtrr.\r
581\r
582 @param[in] VariableSettings The variable MTRR values to shadow\r
583 @param[in] VariableMtrrCount The number of variable MTRRs\r
584 @param[in] MtrrValidBitsMask The mask for the valid bit of the MTRR\r
585 @param[in] MtrrValidAddressMask The valid address mask for MTRR\r
586 @param[out] VariableMtrr The array to shadow variable MTRRs content\r
587\r
588 @return Number of MTRRs which has been used.\r
589\r
590**/\r
591UINT32\r
592MtrrGetMemoryAttributeInVariableMtrrWorker (\r
593 IN MTRR_VARIABLE_SETTINGS *VariableSettings,\r
594 IN UINTN VariableMtrrCount,\r
595 IN UINT64 MtrrValidBitsMask,\r
596 IN UINT64 MtrrValidAddressMask,\r
597 OUT VARIABLE_MTRR *VariableMtrr\r
598 )\r
599{\r
600 UINTN Index;\r
601 UINT32 UsedMtrr;\r
602\r
603 ZeroMem (VariableMtrr, sizeof (VARIABLE_MTRR) * MTRR_NUMBER_OF_VARIABLE_MTRR);\r
604 for (Index = 0, UsedMtrr = 0; Index < VariableMtrrCount; Index++) {\r
605 if (((MSR_IA32_MTRR_PHYSMASK_REGISTER *) &VariableSettings->Mtrr[Index].Mask)->Bits.V != 0) {\r
606 VariableMtrr[Index].Msr = (UINT32)Index;\r
607 VariableMtrr[Index].BaseAddress = (VariableSettings->Mtrr[Index].Base & MtrrValidAddressMask);\r
608 VariableMtrr[Index].Length = ((~(VariableSettings->Mtrr[Index].Mask & MtrrValidAddressMask)) & MtrrValidBitsMask) + 1;\r
609 VariableMtrr[Index].Type = (VariableSettings->Mtrr[Index].Base & 0x0ff);\r
610 VariableMtrr[Index].Valid = TRUE;\r
611 VariableMtrr[Index].Used = TRUE;\r
612 UsedMtrr++;\r
613 }\r
614 }\r
615 return UsedMtrr;\r
616}\r
617\r
618\r
619/**\r
620 Gets the attribute of variable MTRRs.\r
621\r
622 This function shadows the content of variable MTRRs into an\r
623 internal array: VariableMtrr.\r
624\r
625 @param[in] MtrrValidBitsMask The mask for the valid bit of the MTRR\r
626 @param[in] MtrrValidAddressMask The valid address mask for MTRR\r
627 @param[out] VariableMtrr The array to shadow variable MTRRs content\r
628\r
629 @return The return value of this parameter indicates the\r
630 number of MTRRs which has been used.\r
631\r
632**/\r
633UINT32\r
634EFIAPI\r
635MtrrGetMemoryAttributeInVariableMtrr (\r
636 IN UINT64 MtrrValidBitsMask,\r
637 IN UINT64 MtrrValidAddressMask,\r
638 OUT VARIABLE_MTRR *VariableMtrr\r
639 )\r
640{\r
641 MTRR_VARIABLE_SETTINGS VariableSettings;\r
642\r
643 if (!IsMtrrSupported ()) {\r
644 return 0;\r
645 }\r
646\r
647 MtrrGetVariableMtrrWorker (\r
648 NULL,\r
649 GetVariableMtrrCountWorker (),\r
650 &VariableSettings\r
651 );\r
652\r
653 return MtrrGetMemoryAttributeInVariableMtrrWorker (\r
654 &VariableSettings,\r
655 GetFirmwareVariableMtrrCountWorker (),\r
656 MtrrValidBitsMask,\r
657 MtrrValidAddressMask,\r
658 VariableMtrr\r
659 );\r
660}\r
661\r
662/**\r
663 Return the least alignment of address.\r
664\r
665 @param Address The address to return the alignment.\r
666 @param Alignment0 The alignment to return when Address is 0.\r
667\r
668 @return The least alignment of the Address.\r
669**/\r
670UINT64\r
671MtrrLibLeastAlignment (\r
672 UINT64 Address,\r
673 UINT64 Alignment0\r
674)\r
675{\r
676 if (Address == 0) {\r
677 return Alignment0;\r
678 }\r
679\r
680 return LShiftU64 (1, (UINTN) LowBitSet64 (Address));\r
681}\r
682\r
683/**\r
684 Return the number of required variable MTRRs to positively cover the\r
685 specified range.\r
686\r
687 @param BaseAddress Base address of the range.\r
688 @param Length Length of the range.\r
689 @param Alignment0 Alignment of 0.\r
690\r
691 @return The number of the required variable MTRRs.\r
692**/\r
693UINT32\r
694MtrrLibGetPositiveMtrrNumber (\r
695 IN UINT64 BaseAddress,\r
696 IN UINT64 Length,\r
697 IN UINT64 Alignment0\r
698)\r
699{\r
700 UINT64 SubLength;\r
701 UINT32 MtrrNumber;\r
702 BOOLEAN UseLeastAlignment;\r
703\r
704 UseLeastAlignment = TRUE;\r
705 SubLength = 0;\r
706\r
707 //\r
708 // Calculate the alignment of the base address.\r
709 //\r
710 for (MtrrNumber = 0; Length != 0; MtrrNumber++) {\r
711 if (UseLeastAlignment) {\r
712 SubLength = MtrrLibLeastAlignment (BaseAddress, Alignment0);\r
713\r
714 if (SubLength > Length) {\r
715 //\r
716 // Set a flag when remaining length is too small\r
717 // so that MtrrLibLeastAlignment() is not called in following loops.\r
718 //\r
719 UseLeastAlignment = FALSE;\r
720 }\r
721 }\r
722\r
723 if (!UseLeastAlignment) {\r
724 SubLength = GetPowerOfTwo64 (Length);\r
725 }\r
726\r
727 BaseAddress += SubLength;\r
728 Length -= SubLength;\r
729 }\r
730\r
731 return MtrrNumber;\r
732}\r
733\r
734/**\r
735 Return whether the left MTRR type precedes the right MTRR type.\r
736\r
737 The MTRR type precedence rules are:\r
738 1. UC precedes any other type\r
739 2. WT precedes WB\r
740 For further details, please refer the IA32 Software Developer's Manual,\r
741 Volume 3, Section "MTRR Precedences".\r
742\r
743 @param Left The left MTRR type.\r
744 @param Right The right MTRR type.\r
745\r
746 @retval TRUE Left precedes Right.\r
747 @retval FALSE Left doesn't precede Right.\r
748**/\r
749BOOLEAN\r
750MtrrLibTypeLeftPrecedeRight (\r
751 IN MTRR_MEMORY_CACHE_TYPE Left,\r
752 IN MTRR_MEMORY_CACHE_TYPE Right\r
753)\r
754{\r
755 return (BOOLEAN) (Left == CacheUncacheable || (Left == CacheWriteThrough && Right == CacheWriteBack));\r
756}\r
757\r
758\r
759/**\r
760 Return whether the type of the specified range can precede the specified type.\r
761\r
762 @param Ranges Memory range array holding memory type settings for all\r
763 the memory address.\r
764 @param RangeCount Count of memory ranges.\r
765 @param Type Type to check precedence.\r
766 @param SubBase Base address of the specified range.\r
767 @param SubLength Length of the specified range.\r
768\r
769 @retval TRUE The type of the specified range can precede the Type.\r
770 @retval FALSE The type of the specified range cannot precede the Type.\r
771 So the subtraction is not applicable.\r
772**/\r
773BOOLEAN\r
774MtrrLibSubstractable (\r
775 IN CONST MEMORY_RANGE *Ranges,\r
776 IN UINT32 RangeCount,\r
777 IN MTRR_MEMORY_CACHE_TYPE Type,\r
778 IN UINT64 SubBase,\r
779 IN UINT64 SubLength\r
780)\r
781{\r
782 UINT32 Index;\r
783 UINT64 Length;\r
784 // WT > WB\r
785 // UC > *\r
786 for (Index = 0; Index < RangeCount; Index++) {\r
787 if (Ranges[Index].BaseAddress <= SubBase && SubBase < Ranges[Index].BaseAddress + Ranges[Index].Length) {\r
788\r
789 if (Ranges[Index].BaseAddress + Ranges[Index].Length >= SubBase + SubLength) {\r
790 return MtrrLibTypeLeftPrecedeRight (Ranges[Index].Type, Type);\r
791\r
792 } else {\r
793 if (!MtrrLibTypeLeftPrecedeRight (Ranges[Index].Type, Type)) {\r
794 return FALSE;\r
795 }\r
796\r
797 Length = Ranges[Index].BaseAddress + Ranges[Index].Length - SubBase;\r
798 SubBase += Length;\r
799 SubLength -= Length;\r
800 }\r
801 }\r
802 }\r
803\r
804 ASSERT (FALSE);\r
805 return FALSE;\r
806}\r
807\r
808/**\r
809 Return the number of required variable MTRRs to cover the specified range.\r
810\r
811 The routine considers subtraction in the both side of the range to find out\r
812 the most optimal solution (which uses the least MTRRs).\r
813\r
814 @param Ranges Array holding memory type settings of all memory\r
815 address.\r
816 @param RangeCount Count of memory ranges.\r
817 @param VariableMtrr Array holding allocated variable MTRRs.\r
818 @param VariableMtrrCount Count of allocated variable MTRRs.\r
819 @param BaseAddress Base address of the specified range.\r
820 @param Length Length of the specified range.\r
821 @param Type MTRR type of the specified range.\r
822 @param Alignment0 Alignment of 0.\r
823 @param SubLeft Return the count of left subtraction.\r
824 @param SubRight Return the count of right subtraction.\r
825\r
826 @return Number of required variable MTRRs.\r
827**/\r
828UINT32\r
829MtrrLibGetMtrrNumber (\r
830 IN CONST MEMORY_RANGE *Ranges,\r
831 IN UINT32 RangeCount,\r
832 IN CONST VARIABLE_MTRR *VariableMtrr,\r
833 IN UINT32 VariableMtrrCount,\r
834 IN UINT64 BaseAddress,\r
835 IN UINT64 Length,\r
836 IN MTRR_MEMORY_CACHE_TYPE Type,\r
837 IN UINT64 Alignment0,\r
838 OUT UINT32 *SubLeft, // subtractive from BaseAddress to get more aligned address, to save MTRR\r
839 OUT UINT32 *SubRight // subtractive from BaseAddress + Length, to save MTRR\r
840 )\r
841{\r
842 UINT64 Alignment;\r
843 UINT32 LeastLeftMtrrNumber;\r
844 UINT32 MiddleMtrrNumber;\r
845 UINT32 LeastRightMtrrNumber;\r
846 UINT32 CurrentMtrrNumber;\r
847 UINT32 SubtractiveCount;\r
848 UINT32 SubtractiveMtrrNumber;\r
849 UINT32 LeastSubtractiveMtrrNumber;\r
850 UINT64 SubtractiveBaseAddress;\r
851 UINT64 SubtractiveLength;\r
852 UINT64 BaseAlignment;\r
853 UINT32 Index;\r
854\r
855 *SubLeft = 0;\r
856 *SubRight = 0;\r
857 LeastSubtractiveMtrrNumber = 0;\r
858 BaseAlignment = 0;\r
859\r
860 //\r
861 // Get the optimal left subtraction solution.\r
862 //\r
863 if (BaseAddress != 0) {\r
864 SubtractiveBaseAddress = 0;\r
865 SubtractiveLength = 0;\r
866 //\r
867 // Get the MTRR number needed without left subtraction.\r
868 //\r
869 LeastLeftMtrrNumber = MtrrLibGetPositiveMtrrNumber (BaseAddress, Length, Alignment0);\r
870\r
871 //\r
872 // Left subtraction bit by bit, to find the optimal left subtraction solution.\r
873 //\r
874 for (SubtractiveMtrrNumber = 0, SubtractiveCount = 1; BaseAddress != 0; SubtractiveCount++) {\r
875 Alignment = MtrrLibLeastAlignment (BaseAddress, Alignment0);\r
876\r
877 //\r
878 // Check whether the memory type of [BaseAddress - Alignment, BaseAddress) can override Type.\r
879 // IA32 Manual defines the following override rules:\r
880 // WT > WB\r
881 // UC > * (any)\r
882 //\r
883 if (!MtrrLibSubstractable (Ranges, RangeCount, Type, BaseAddress - Alignment, Alignment)) {\r
884 break;\r
885 }\r
886\r
887 for (Index = 0; Index < VariableMtrrCount; Index++) {\r
888 if ((VariableMtrr[Index].BaseAddress == BaseAddress - Alignment) &&\r
889 (VariableMtrr[Index].Length == Alignment)) {\r
890 break;\r
891 }\r
892 }\r
893 if (Index == VariableMtrrCount) {\r
894 //\r
895 // Increment SubtractiveMtrrNumber when [BaseAddress - Alignment, BaseAddress) is not be planed as a MTRR\r
896 //\r
897 SubtractiveMtrrNumber++;\r
898 }\r
899\r
900 BaseAddress -= Alignment;\r
901 Length += Alignment;\r
902\r
903 CurrentMtrrNumber = SubtractiveMtrrNumber + MtrrLibGetPositiveMtrrNumber (BaseAddress, Length, Alignment0);\r
904 if (CurrentMtrrNumber <= LeastLeftMtrrNumber) {\r
905 LeastLeftMtrrNumber = CurrentMtrrNumber;\r
906 LeastSubtractiveMtrrNumber = SubtractiveMtrrNumber;\r
907 *SubLeft = SubtractiveCount;\r
908 SubtractiveBaseAddress = BaseAddress;\r
909 SubtractiveLength = Length;\r
910 }\r
911 }\r
912\r
913 //\r
914 // If left subtraction is better, subtract BaseAddress to left, and enlarge Length\r
915 //\r
916 if (*SubLeft != 0) {\r
917 BaseAddress = SubtractiveBaseAddress;\r
918 Length = SubtractiveLength;\r
919 }\r
920 }\r
921\r
922 //\r
923 // Increment BaseAddress greedily until (BaseAddress + Alignment) exceeds (BaseAddress + Length)\r
924 //\r
925 MiddleMtrrNumber = 0;\r
926 while (Length != 0) {\r
927 BaseAlignment = MtrrLibLeastAlignment (BaseAddress, Alignment0);\r
928 if (BaseAlignment > Length) {\r
929 break;\r
930 }\r
931 BaseAddress += BaseAlignment;\r
932 Length -= BaseAlignment;\r
933 MiddleMtrrNumber++;\r
934 }\r
935\r
936\r
937 if (Length == 0) {\r
938 return LeastSubtractiveMtrrNumber + MiddleMtrrNumber;\r
939 }\r
940\r
941\r
942 //\r
943 // Get the optimal right subtraction solution.\r
944 //\r
945\r
946 //\r
947 // Get the MTRR number needed without right subtraction.\r
948 //\r
949 LeastRightMtrrNumber = MtrrLibGetPositiveMtrrNumber (BaseAddress, Length, Alignment0);\r
950\r
951 for (SubtractiveCount = 1; Length < BaseAlignment; SubtractiveCount++) {\r
952 Alignment = MtrrLibLeastAlignment (BaseAddress + Length, Alignment0);\r
953 if (!MtrrLibSubstractable (Ranges, RangeCount, Type, BaseAddress + Length, Alignment)) {\r
954 break;\r
955 }\r
956\r
957 Length += Alignment;\r
958\r
959 //\r
960 // SubtractiveCount = Number of MTRRs used for subtraction\r
961 //\r
962 CurrentMtrrNumber = SubtractiveCount + MtrrLibGetPositiveMtrrNumber (BaseAddress, Length, Alignment0);\r
963 if (CurrentMtrrNumber <= LeastRightMtrrNumber) {\r
964 LeastRightMtrrNumber = CurrentMtrrNumber;\r
965 *SubRight = SubtractiveCount;\r
966 SubtractiveLength = Length;\r
967 }\r
968 }\r
969\r
970 return LeastSubtractiveMtrrNumber + MiddleMtrrNumber + LeastRightMtrrNumber;\r
971}\r
972\r
973/**\r
974 Initializes the valid bits mask and valid address mask for MTRRs.\r
975\r
976 This function initializes the valid bits mask and valid address mask for MTRRs.\r
977\r
978 @param[out] MtrrValidBitsMask The mask for the valid bit of the MTRR\r
979 @param[out] MtrrValidAddressMask The valid address mask for the MTRR\r
980\r
981**/\r
982VOID\r
983MtrrLibInitializeMtrrMask (\r
984 OUT UINT64 *MtrrValidBitsMask,\r
985 OUT UINT64 *MtrrValidAddressMask\r
986 )\r
987{\r
988 UINT32 MaxExtendedFunction;\r
989 CPUID_VIR_PHY_ADDRESS_SIZE_EAX VirPhyAddressSize;\r
990\r
991\r
992 AsmCpuid (CPUID_EXTENDED_FUNCTION, &MaxExtendedFunction, NULL, NULL, NULL);\r
993\r
994 if (MaxExtendedFunction >= CPUID_VIR_PHY_ADDRESS_SIZE) {\r
995 AsmCpuid (CPUID_VIR_PHY_ADDRESS_SIZE, &VirPhyAddressSize.Uint32, NULL, NULL, NULL);\r
996 } else {\r
997 VirPhyAddressSize.Bits.PhysicalAddressBits = 36;\r
998 }\r
999\r
1000 *MtrrValidBitsMask = LShiftU64 (1, VirPhyAddressSize.Bits.PhysicalAddressBits) - 1;\r
1001 *MtrrValidAddressMask = *MtrrValidBitsMask & 0xfffffffffffff000ULL;\r
1002}\r
1003\r
1004\r
1005/**\r
1006 Determines the real attribute of a memory range.\r
1007\r
1008 This function is to arbitrate the real attribute of the memory when\r
1009 there are 2 MTRRs covers the same memory range. For further details,\r
1010 please refer the IA32 Software Developer's Manual, Volume 3,\r
1011 Section "MTRR Precedences".\r
1012\r
1013 @param[in] MtrrType1 The first kind of Memory type\r
1014 @param[in] MtrrType2 The second kind of memory type\r
1015\r
1016**/\r
1017MTRR_MEMORY_CACHE_TYPE\r
1018MtrrLibPrecedence (\r
1019 IN MTRR_MEMORY_CACHE_TYPE MtrrType1,\r
1020 IN MTRR_MEMORY_CACHE_TYPE MtrrType2\r
1021 )\r
1022{\r
1023 if (MtrrType1 == MtrrType2) {\r
1024 return MtrrType1;\r
1025 }\r
1026\r
1027 ASSERT (\r
1028 MtrrLibTypeLeftPrecedeRight (MtrrType1, MtrrType2) ||\r
1029 MtrrLibTypeLeftPrecedeRight (MtrrType2, MtrrType1)\r
1030 );\r
1031\r
1032 if (MtrrLibTypeLeftPrecedeRight (MtrrType1, MtrrType2)) {\r
1033 return MtrrType1;\r
1034 } else {\r
1035 return MtrrType2;\r
1036 }\r
1037}\r
1038\r
1039/**\r
1040 Worker function will get the memory cache type of the specific address.\r
1041\r
1042 If MtrrSetting is not NULL, gets the memory cache type from input\r
1043 MTRR settings buffer.\r
1044 If MtrrSetting is NULL, gets the memory cache type from MTRRs.\r
1045\r
1046 @param[in] MtrrSetting A buffer holding all MTRRs content.\r
1047 @param[in] Address The specific address\r
1048\r
1049 @return Memory cache type of the specific address\r
1050\r
1051**/\r
1052MTRR_MEMORY_CACHE_TYPE\r
1053MtrrGetMemoryAttributeByAddressWorker (\r
1054 IN MTRR_SETTINGS *MtrrSetting,\r
1055 IN PHYSICAL_ADDRESS Address\r
1056 )\r
1057{\r
1058 MSR_IA32_MTRR_DEF_TYPE_REGISTER DefType;\r
1059 UINT64 FixedMtrr;\r
1060 UINTN Index;\r
1061 UINTN SubIndex;\r
1062 MTRR_MEMORY_CACHE_TYPE MtrrType;\r
1063 VARIABLE_MTRR VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];\r
1064 UINT64 MtrrValidBitsMask;\r
1065 UINT64 MtrrValidAddressMask;\r
1066 UINT32 VariableMtrrCount;\r
1067 MTRR_VARIABLE_SETTINGS VariableSettings;\r
1068\r
1069 //\r
1070 // Check if MTRR is enabled, if not, return UC as attribute\r
1071 //\r
1072 if (MtrrSetting == NULL) {\r
1073 DefType.Uint64 = AsmReadMsr64 (MSR_IA32_MTRR_DEF_TYPE);\r
1074 } else {\r
1075 DefType.Uint64 = MtrrSetting->MtrrDefType;\r
1076 }\r
1077\r
1078 if (DefType.Bits.E == 0) {\r
1079 return CacheUncacheable;\r
1080 }\r
1081\r
1082 //\r
1083 // If address is less than 1M, then try to go through the fixed MTRR\r
1084 //\r
1085 if (Address < BASE_1MB) {\r
1086 if (DefType.Bits.FE != 0) {\r
1087 //\r
1088 // Go through the fixed MTRR\r
1089 //\r
1090 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
1091 if (Address >= mMtrrLibFixedMtrrTable[Index].BaseAddress &&\r
1092 Address < mMtrrLibFixedMtrrTable[Index].BaseAddress +\r
1093 (mMtrrLibFixedMtrrTable[Index].Length * 8)) {\r
1094 SubIndex =\r
1095 ((UINTN) Address - mMtrrLibFixedMtrrTable[Index].BaseAddress) /\r
1096 mMtrrLibFixedMtrrTable[Index].Length;\r
1097 if (MtrrSetting == NULL) {\r
1098 FixedMtrr = AsmReadMsr64 (mMtrrLibFixedMtrrTable[Index].Msr);\r
1099 } else {\r
1100 FixedMtrr = MtrrSetting->Fixed.Mtrr[Index];\r
1101 }\r
1102 return (MTRR_MEMORY_CACHE_TYPE) (RShiftU64 (FixedMtrr, SubIndex * 8) & 0xFF);\r
1103 }\r
1104 }\r
1105 }\r
1106 }\r
1107\r
1108 VariableMtrrCount = GetVariableMtrrCountWorker ();\r
1109 ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);\r
1110 MtrrGetVariableMtrrWorker (MtrrSetting, VariableMtrrCount, &VariableSettings);\r
1111\r
1112 MtrrLibInitializeMtrrMask (&MtrrValidBitsMask, &MtrrValidAddressMask);\r
1113 MtrrGetMemoryAttributeInVariableMtrrWorker (\r
1114 &VariableSettings,\r
1115 VariableMtrrCount,\r
1116 MtrrValidBitsMask,\r
1117 MtrrValidAddressMask,\r
1118 VariableMtrr\r
1119 );\r
1120\r
1121 //\r
1122 // Go through the variable MTRR\r
1123 //\r
1124 MtrrType = CacheInvalid;\r
1125 for (Index = 0; Index < VariableMtrrCount; Index++) {\r
1126 if (VariableMtrr[Index].Valid) {\r
1127 if (Address >= VariableMtrr[Index].BaseAddress &&\r
1128 Address < VariableMtrr[Index].BaseAddress + VariableMtrr[Index].Length) {\r
1129 if (MtrrType == CacheInvalid) {\r
1130 MtrrType = (MTRR_MEMORY_CACHE_TYPE) VariableMtrr[Index].Type;\r
1131 } else {\r
1132 MtrrType = MtrrLibPrecedence (MtrrType, (MTRR_MEMORY_CACHE_TYPE) VariableMtrr[Index].Type);\r
1133 }\r
1134 }\r
1135 }\r
1136 }\r
1137\r
1138 //\r
1139 // If there is no MTRR which covers the Address, use the default MTRR type.\r
1140 //\r
1141 if (MtrrType == CacheInvalid) {\r
1142 MtrrType = (MTRR_MEMORY_CACHE_TYPE) DefType.Bits.Type;\r
1143 }\r
1144\r
1145 return MtrrType;\r
1146}\r
1147\r
1148\r
1149/**\r
1150 This function will get the memory cache type of the specific address.\r
1151\r
1152 This function is mainly for debug purpose.\r
1153\r
1154 @param[in] Address The specific address\r
1155\r
1156 @return Memory cache type of the specific address\r
1157\r
1158**/\r
1159MTRR_MEMORY_CACHE_TYPE\r
1160EFIAPI\r
1161MtrrGetMemoryAttribute (\r
1162 IN PHYSICAL_ADDRESS Address\r
1163 )\r
1164{\r
1165 if (!IsMtrrSupported ()) {\r
1166 return CacheUncacheable;\r
1167 }\r
1168\r
1169 return MtrrGetMemoryAttributeByAddressWorker (NULL, Address);\r
1170}\r
1171\r
1172/**\r
1173 Worker function prints all MTRRs for debugging.\r
1174\r
1175 If MtrrSetting is not NULL, print MTRR settings from input MTRR\r
1176 settings buffer.\r
1177 If MtrrSetting is NULL, print MTRR settings from MTRRs.\r
1178\r
1179 @param MtrrSetting A buffer holding all MTRRs content.\r
1180**/\r
1181VOID\r
1182MtrrDebugPrintAllMtrrsWorker (\r
1183 IN MTRR_SETTINGS *MtrrSetting\r
1184 )\r
1185{\r
1186 DEBUG_CODE (\r
1187 MTRR_SETTINGS LocalMtrrs;\r
1188 MTRR_SETTINGS *Mtrrs;\r
1189 UINTN Index;\r
1190 UINTN Index1;\r
1191 UINTN VariableMtrrCount;\r
1192 UINT64 Base;\r
1193 UINT64 Limit;\r
1194 UINT64 MtrrBase;\r
1195 UINT64 MtrrLimit;\r
1196 UINT64 RangeBase;\r
1197 UINT64 RangeLimit;\r
1198 UINT64 NoRangeBase;\r
1199 UINT64 NoRangeLimit;\r
1200 UINT32 RegEax;\r
1201 UINTN MemoryType;\r
1202 UINTN PreviousMemoryType;\r
1203 BOOLEAN Found;\r
1204\r
1205 if (!IsMtrrSupported ()) {\r
1206 return;\r
1207 }\r
1208\r
1209 DEBUG((DEBUG_CACHE, "MTRR Settings\n"));\r
1210 DEBUG((DEBUG_CACHE, "=============\n"));\r
1211\r
1212 if (MtrrSetting != NULL) {\r
1213 Mtrrs = MtrrSetting;\r
1214 } else {\r
1215 MtrrGetAllMtrrs (&LocalMtrrs);\r
1216 Mtrrs = &LocalMtrrs;\r
1217 }\r
1218\r
1219 DEBUG((DEBUG_CACHE, "MTRR Default Type: %016lx\n", Mtrrs->MtrrDefType));\r
1220 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
1221 DEBUG((DEBUG_CACHE, "Fixed MTRR[%02d] : %016lx\n", Index, Mtrrs->Fixed.Mtrr[Index]));\r
1222 }\r
1223\r
1224 VariableMtrrCount = GetVariableMtrrCount ();\r
1225 for (Index = 0; Index < VariableMtrrCount; Index++) {\r
1226 DEBUG((DEBUG_CACHE, "Variable MTRR[%02d]: Base=%016lx Mask=%016lx\n",\r
1227 Index,\r
1228 Mtrrs->Variables.Mtrr[Index].Base,\r
1229 Mtrrs->Variables.Mtrr[Index].Mask\r
1230 ));\r
1231 }\r
1232 DEBUG((DEBUG_CACHE, "\n"));\r
1233 DEBUG((DEBUG_CACHE, "MTRR Ranges\n"));\r
1234 DEBUG((DEBUG_CACHE, "====================================\n"));\r
1235\r
1236 Base = 0;\r
1237 PreviousMemoryType = MTRR_CACHE_INVALID_TYPE;\r
1238 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
1239 Base = mMtrrLibFixedMtrrTable[Index].BaseAddress;\r
1240 for (Index1 = 0; Index1 < 8; Index1++) {\r
1241 MemoryType = (UINTN)(RShiftU64 (Mtrrs->Fixed.Mtrr[Index], Index1 * 8) & 0xff);\r
1242 if (MemoryType > CacheWriteBack) {\r
1243 MemoryType = MTRR_CACHE_INVALID_TYPE;\r
1244 }\r
1245 if (MemoryType != PreviousMemoryType) {\r
1246 if (PreviousMemoryType != MTRR_CACHE_INVALID_TYPE) {\r
1247 DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));\r
1248 }\r
1249 PreviousMemoryType = MemoryType;\r
1250 DEBUG((DEBUG_CACHE, "%a:%016lx-", mMtrrMemoryCacheTypeShortName[MemoryType], Base));\r
1251 }\r
1252 Base += mMtrrLibFixedMtrrTable[Index].Length;\r
1253 }\r
1254 }\r
1255 DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));\r
1256\r
1257 VariableMtrrCount = GetVariableMtrrCount ();\r
1258\r
1259 Limit = BIT36 - 1;\r
1260 AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);\r
1261 if (RegEax >= 0x80000008) {\r
1262 AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);\r
1263 Limit = LShiftU64 (1, RegEax & 0xff) - 1;\r
1264 }\r
1265 Base = BASE_1MB;\r
1266 PreviousMemoryType = MTRR_CACHE_INVALID_TYPE;\r
1267 do {\r
1268 MemoryType = MtrrGetMemoryAttributeByAddressWorker (Mtrrs, Base);\r
1269 if (MemoryType > CacheWriteBack) {\r
1270 MemoryType = MTRR_CACHE_INVALID_TYPE;\r
1271 }\r
1272\r
1273 if (MemoryType != PreviousMemoryType) {\r
1274 if (PreviousMemoryType != MTRR_CACHE_INVALID_TYPE) {\r
1275 DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));\r
1276 }\r
1277 PreviousMemoryType = MemoryType;\r
1278 DEBUG((DEBUG_CACHE, "%a:%016lx-", mMtrrMemoryCacheTypeShortName[MemoryType], Base));\r
1279 }\r
1280\r
1281 RangeBase = BASE_1MB;\r
1282 NoRangeBase = BASE_1MB;\r
1283 RangeLimit = Limit;\r
1284 NoRangeLimit = Limit;\r
1285\r
1286 for (Index = 0, Found = FALSE; Index < VariableMtrrCount; Index++) {\r
1287 if ((Mtrrs->Variables.Mtrr[Index].Mask & BIT11) == 0) {\r
1288 //\r
1289 // If mask is not valid, then do not display range\r
1290 //\r
1291 continue;\r
1292 }\r
1293 MtrrBase = (Mtrrs->Variables.Mtrr[Index].Base & (~(SIZE_4KB - 1)));\r
1294 MtrrLimit = MtrrBase + ((~(Mtrrs->Variables.Mtrr[Index].Mask & (~(SIZE_4KB - 1)))) & Limit);\r
1295\r
1296 if (Base >= MtrrBase && Base < MtrrLimit) {\r
1297 Found = TRUE;\r
1298 }\r
1299\r
1300 if (Base >= MtrrBase && MtrrBase > RangeBase) {\r
1301 RangeBase = MtrrBase;\r
1302 }\r
1303 if (Base > MtrrLimit && MtrrLimit > RangeBase) {\r
1304 RangeBase = MtrrLimit + 1;\r
1305 }\r
1306 if (Base < MtrrBase && MtrrBase < RangeLimit) {\r
1307 RangeLimit = MtrrBase - 1;\r
1308 }\r
1309 if (Base < MtrrLimit && MtrrLimit <= RangeLimit) {\r
1310 RangeLimit = MtrrLimit;\r
1311 }\r
1312\r
1313 if (Base > MtrrLimit && NoRangeBase < MtrrLimit) {\r
1314 NoRangeBase = MtrrLimit + 1;\r
1315 }\r
1316 if (Base < MtrrBase && NoRangeLimit > MtrrBase) {\r
1317 NoRangeLimit = MtrrBase - 1;\r
1318 }\r
1319 }\r
1320\r
1321 if (Found) {\r
1322 Base = RangeLimit + 1;\r
1323 } else {\r
1324 Base = NoRangeLimit + 1;\r
1325 }\r
1326 } while (Base < Limit);\r
1327 DEBUG((DEBUG_CACHE, "%016lx\n\n", Base - 1));\r
1328 );\r
1329}\r
1330\r
1331\r
1332/**\r
1333 This function prints all MTRRs for debugging.\r
1334**/\r
1335VOID\r
1336EFIAPI\r
1337MtrrDebugPrintAllMtrrs (\r
1338 VOID\r
1339 )\r
1340{\r
1341 MtrrDebugPrintAllMtrrsWorker (NULL);\r
1342}\r
1343\r
1344/**\r
1345 Update the Ranges array to change the specified range identified by\r
1346 BaseAddress and Length to Type.\r
1347\r
1348 @param Ranges Array holding memory type settings for all memory regions.\r
1349 @param Capacity The maximum count of memory ranges the array can hold.\r
1350 @param Count Return the new memory range count in the array.\r
1351 @param BaseAddress The base address of the memory range to change type.\r
1352 @param Length The length of the memory range to change type.\r
1353 @param Type The new type of the specified memory range.\r
1354\r
1355 @retval RETURN_SUCCESS The type of the specified memory range is\r
1356 changed successfully.\r
1357 @retval RETURN_OUT_OF_RESOURCES The new type set causes the count of memory\r
1358 range exceeds capacity.\r
1359**/\r
1360RETURN_STATUS\r
1361MtrrLibSetMemoryType (\r
1362 IN MEMORY_RANGE *Ranges,\r
1363 IN UINT32 Capacity,\r
1364 IN OUT UINT32 *Count,\r
1365 IN UINT64 BaseAddress,\r
1366 IN UINT64 Length,\r
1367 IN MTRR_MEMORY_CACHE_TYPE Type\r
1368 )\r
1369{\r
1370 UINT32 Index;\r
1371 UINT64 Limit;\r
1372 UINT64 LengthLeft;\r
1373 UINT64 LengthRight;\r
1374 UINT32 StartIndex;\r
1375 UINT32 EndIndex;\r
1376 UINT32 DeltaCount;\r
1377\r
1378 LengthRight = 0;\r
1379 LengthLeft = 0;\r
1380 Limit = BaseAddress + Length;\r
1381 StartIndex = *Count;\r
1382 EndIndex = *Count;\r
1383 for (Index = 0; Index < *Count; Index++) {\r
1384 if ((StartIndex == *Count) &&\r
1385 (Ranges[Index].BaseAddress <= BaseAddress) &&\r
1386 (BaseAddress < Ranges[Index].BaseAddress + Ranges[Index].Length)) {\r
1387 StartIndex = Index;\r
1388 LengthLeft = BaseAddress - Ranges[Index].BaseAddress;\r
1389 }\r
1390\r
1391 if ((EndIndex == *Count) &&\r
1392 (Ranges[Index].BaseAddress < Limit) &&\r
1393 (Limit <= Ranges[Index].BaseAddress + Ranges[Index].Length)) {\r
1394 EndIndex = Index;\r
1395 LengthRight = Ranges[Index].BaseAddress + Ranges[Index].Length - Limit;\r
1396 break;\r
1397 }\r
1398 }\r
1399\r
1400 ASSERT (StartIndex != *Count && EndIndex != *Count);\r
1401 if (StartIndex == EndIndex && Ranges[StartIndex].Type == Type) {\r
1402 return RETURN_SUCCESS;\r
1403 }\r
1404\r
1405 //\r
1406 // The type change may cause merging with previous range or next range.\r
1407 // Update the StartIndex, EndIndex, BaseAddress, Length so that following\r
1408 // logic doesn't need to consider merging.\r
1409 //\r
1410 if (StartIndex != 0) {\r
1411 if (LengthLeft == 0 && Ranges[StartIndex - 1].Type == Type) {\r
1412 StartIndex--;\r
1413 Length += Ranges[StartIndex].Length;\r
1414 BaseAddress -= Ranges[StartIndex].Length;\r
1415 }\r
1416 }\r
1417 if (EndIndex != (*Count) - 1) {\r
1418 if (LengthRight == 0 && Ranges[EndIndex + 1].Type == Type) {\r
1419 EndIndex++;\r
1420 Length += Ranges[EndIndex].Length;\r
1421 }\r
1422 }\r
1423\r
1424 //\r
1425 // |- 0 -|- 1 -|- 2 -|- 3 -| StartIndex EndIndex DeltaCount Count (Count = 4)\r
1426 // |++++++++++++++++++| 0 3 1=3-0-2 3\r
1427 // |+++++++| 0 1 -1=1-0-2 5\r
1428 // |+| 0 0 -2=0-0-2 6\r
1429 // |+++| 0 0 -1=0-0-2+1 5\r
1430 //\r
1431 //\r
1432 DeltaCount = EndIndex - StartIndex - 2;\r
1433 if (LengthLeft == 0) {\r
1434 DeltaCount++;\r
1435 }\r
1436 if (LengthRight == 0) {\r
1437 DeltaCount++;\r
1438 }\r
1439 if (*Count - DeltaCount > Capacity) {\r
1440 return RETURN_OUT_OF_RESOURCES;\r
1441 }\r
1442\r
1443 //\r
1444 // Reserve (-DeltaCount) space\r
1445 //\r
1446 CopyMem (&Ranges[EndIndex + 1 - DeltaCount], &Ranges[EndIndex + 1], (*Count - EndIndex - 1) * sizeof (Ranges[0]));\r
1447 *Count -= DeltaCount;\r
1448\r
1449 if (LengthLeft != 0) {\r
1450 Ranges[StartIndex].Length = LengthLeft;\r
1451 StartIndex++;\r
1452 }\r
1453 if (LengthRight != 0) {\r
1454 Ranges[EndIndex - DeltaCount].BaseAddress = BaseAddress + Length;\r
1455 Ranges[EndIndex - DeltaCount].Length = LengthRight;\r
1456 Ranges[EndIndex - DeltaCount].Type = Ranges[EndIndex].Type;\r
1457 }\r
1458 Ranges[StartIndex].BaseAddress = BaseAddress;\r
1459 Ranges[StartIndex].Length = Length;\r
1460 Ranges[StartIndex].Type = Type;\r
1461 return RETURN_SUCCESS;\r
1462}\r
1463\r
1464/**\r
1465 Allocate one or more variable MTRR to cover the range identified by\r
1466 BaseAddress and Length.\r
1467\r
1468 @param Ranges Memory range array holding the memory type\r
1469 settings for all memory address.\r
1470 @param RangeCount Count of memory ranges.\r
1471 @param VariableMtrr Variable MTRR array.\r
1472 @param VariableMtrrCapacity Capacity of variable MTRR array.\r
1473 @param VariableMtrrCount Count of variable MTRR.\r
1474 @param BaseAddress Base address of the memory range.\r
1475 @param Length Length of the memory range.\r
1476 @param Type MTRR type of the memory range.\r
1477 @param Alignment0 Alignment of 0.\r
1478\r
1479 @retval RETURN_SUCCESS Variable MTRRs are allocated successfully.\r
1480 @retval RETURN_OUT_OF_RESOURCES Count of variable MTRRs exceeds capacity.\r
1481**/\r
1482RETURN_STATUS\r
1483MtrrLibSetMemoryAttributeInVariableMtrr (\r
1484 IN CONST MEMORY_RANGE *Ranges,\r
1485 IN UINT32 RangeCount,\r
1486 IN OUT VARIABLE_MTRR *VariableMtrr,\r
1487 IN UINT32 VariableMtrrCapacity,\r
1488 IN OUT UINT32 *VariableMtrrCount,\r
1489 IN UINT64 BaseAddress,\r
1490 IN UINT64 Length,\r
1491 IN MTRR_MEMORY_CACHE_TYPE Type,\r
1492 IN UINT64 Alignment0\r
1493 );\r
1494\r
1495/**\r
1496 Allocate one or more variable MTRR to cover the range identified by\r
1497 BaseAddress and Length.\r
1498\r
1499 The routine recursively calls MtrrLibSetMemoryAttributeInVariableMtrr()\r
1500 to allocate variable MTRRs when the range contains several sub-ranges\r
1501 with different attributes.\r
1502\r
1503 @param Ranges Memory range array holding the memory type\r
1504 settings for all memory address.\r
1505 @param RangeCount Count of memory ranges.\r
1506 @param VariableMtrr Variable MTRR array.\r
1507 @param VariableMtrrCapacity Capacity of variable MTRR array.\r
1508 @param VariableMtrrCount Count of variable MTRR.\r
1509 @param BaseAddress Base address of the memory range.\r
1510 @param Length Length of the memory range.\r
1511 @param Type MTRR type of the range.\r
1512 If it's CacheInvalid, the memory range may\r
1513 contains several sub-ranges with different\r
1514 attributes.\r
1515 @param Alignment0 Alignment of 0.\r
1516\r
1517 @retval RETURN_SUCCESS Variable MTRRs are allocated successfully.\r
1518 @retval RETURN_OUT_OF_RESOURCES Count of variable MTRRs exceeds capacity.\r
1519**/\r
1520RETURN_STATUS\r
1521MtrrLibAddVariableMtrr (\r
1522 IN CONST MEMORY_RANGE *Ranges,\r
1523 IN UINT32 RangeCount,\r
1524 IN OUT VARIABLE_MTRR *VariableMtrr,\r
1525 IN UINT32 VariableMtrrCapacity,\r
1526 IN OUT UINT32 *VariableMtrrCount,\r
1527 IN PHYSICAL_ADDRESS BaseAddress,\r
1528 IN UINT64 Length,\r
1529 IN MTRR_MEMORY_CACHE_TYPE Type,\r
1530 IN UINT64 Alignment0\r
1531)\r
1532{\r
1533 RETURN_STATUS Status;\r
1534 UINT32 Index;\r
1535 UINT64 SubLength;\r
1536\r
1537 MTRR_LIB_ASSERT_ALIGNED (BaseAddress, Length);\r
1538 if (Type == CacheInvalid) {\r
1539 ASSERT (Ranges != NULL);\r
1540 for (Index = 0; Index < RangeCount; Index++) {\r
1541 if (Ranges[Index].BaseAddress <= BaseAddress && BaseAddress < Ranges[Index].BaseAddress + Ranges[Index].Length) {\r
1542\r
1543 //\r
1544 // Because the Length may not be aligned to BaseAddress, below code calls\r
1545 // MtrrLibSetMemoryAttributeInVariableMtrr() instead of itself.\r
1546 // MtrrLibSetMemoryAttributeInVariableMtrr() splits the range to several\r
1547 // aligned ranges.\r
1548 //\r
1549 if (Ranges[Index].BaseAddress + Ranges[Index].Length >= BaseAddress + Length) {\r
1550 return MtrrLibSetMemoryAttributeInVariableMtrr (\r
1551 Ranges, RangeCount, VariableMtrr, VariableMtrrCapacity, VariableMtrrCount,\r
1552 BaseAddress, Length, Ranges[Index].Type, Alignment0\r
1553 );\r
1554 } else {\r
1555 SubLength = Ranges[Index].BaseAddress + Ranges[Index].Length - BaseAddress;\r
1556 Status = MtrrLibSetMemoryAttributeInVariableMtrr (\r
1557 Ranges, RangeCount, VariableMtrr, VariableMtrrCapacity, VariableMtrrCount,\r
1558 BaseAddress, SubLength, Ranges[Index].Type, Alignment0\r
1559 );\r
1560 if (RETURN_ERROR (Status)) {\r
1561 return Status;\r
1562 }\r
1563 BaseAddress += SubLength;\r
1564 Length -= SubLength;\r
1565 }\r
1566 }\r
1567 }\r
1568\r
1569 //\r
1570 // Because memory ranges cover all the memory addresses, it's impossible to be here.\r
1571 //\r
1572 ASSERT (FALSE);\r
1573 return RETURN_DEVICE_ERROR;\r
1574 } else {\r
1575 for (Index = 0; Index < *VariableMtrrCount; Index++) {\r
1576 if (VariableMtrr[Index].BaseAddress == BaseAddress && VariableMtrr[Index].Length == Length) {\r
1577 ASSERT (VariableMtrr[Index].Type == Type);\r
1578 break;\r
1579 }\r
1580 }\r
1581 if (Index == *VariableMtrrCount) {\r
1582 if (*VariableMtrrCount == VariableMtrrCapacity) {\r
1583 return RETURN_OUT_OF_RESOURCES;\r
1584 }\r
1585 VariableMtrr[Index].BaseAddress = BaseAddress;\r
1586 VariableMtrr[Index].Length = Length;\r
1587 VariableMtrr[Index].Type = Type;\r
1588 VariableMtrr[Index].Valid = TRUE;\r
1589 VariableMtrr[Index].Used = TRUE;\r
1590 (*VariableMtrrCount)++;\r
1591 }\r
1592 return RETURN_SUCCESS;\r
1593 }\r
1594}\r
1595\r
1596/**\r
1597 Allocate one or more variable MTRR to cover the range identified by\r
1598 BaseAddress and Length.\r
1599\r
1600 @param Ranges Memory range array holding the memory type\r
1601 settings for all memory address.\r
1602 @param RangeCount Count of memory ranges.\r
1603 @param VariableMtrr Variable MTRR array.\r
1604 @param VariableMtrrCapacity Capacity of variable MTRR array.\r
1605 @param VariableMtrrCount Count of variable MTRR.\r
1606 @param BaseAddress Base address of the memory range.\r
1607 @param Length Length of the memory range.\r
1608 @param Type MTRR type of the memory range.\r
1609 @param Alignment0 Alignment of 0.\r
1610\r
1611 @retval RETURN_SUCCESS Variable MTRRs are allocated successfully.\r
1612 @retval RETURN_OUT_OF_RESOURCES Count of variable MTRRs exceeds capacity.\r
1613**/\r
1614RETURN_STATUS\r
1615MtrrLibSetMemoryAttributeInVariableMtrr (\r
1616 IN CONST MEMORY_RANGE *Ranges,\r
1617 IN UINT32 RangeCount,\r
1618 IN OUT VARIABLE_MTRR *VariableMtrr,\r
1619 IN UINT32 VariableMtrrCapacity,\r
1620 IN OUT UINT32 *VariableMtrrCount,\r
1621 IN UINT64 BaseAddress,\r
1622 IN UINT64 Length,\r
1623 IN MTRR_MEMORY_CACHE_TYPE Type,\r
1624 IN UINT64 Alignment0\r
1625)\r
1626{\r
1627 UINT64 Alignment;\r
1628 UINT32 MtrrNumber;\r
1629 UINT32 SubtractiveLeft;\r
1630 UINT32 SubtractiveRight;\r
1631 BOOLEAN UseLeastAlignment;\r
1632\r
1633 Alignment = 0;\r
1634\r
1635 MtrrNumber = MtrrLibGetMtrrNumber (Ranges, RangeCount, VariableMtrr, *VariableMtrrCount,\r
1636 BaseAddress, Length, Type, Alignment0, &SubtractiveLeft, &SubtractiveRight);\r
1637\r
1638 if (MtrrNumber + *VariableMtrrCount > VariableMtrrCapacity) {\r
1639 return RETURN_OUT_OF_RESOURCES;\r
1640 }\r
1641\r
1642 while (SubtractiveLeft-- != 0) {\r
1643 Alignment = MtrrLibLeastAlignment (BaseAddress, Alignment0);\r
1644 ASSERT (Alignment <= Length);\r
1645\r
1646 MtrrLibAddVariableMtrr (Ranges, RangeCount, VariableMtrr, VariableMtrrCapacity, VariableMtrrCount,\r
1647 BaseAddress - Alignment, Alignment, CacheInvalid, Alignment0);\r
1648 BaseAddress -= Alignment;\r
1649 Length += Alignment;\r
1650 }\r
1651\r
1652 while (Length != 0) {\r
1653 Alignment = MtrrLibLeastAlignment (BaseAddress, Alignment0);\r
1654 if (Alignment > Length) {\r
1655 break;\r
1656 }\r
1657 MtrrLibAddVariableMtrr (NULL, 0, VariableMtrr, VariableMtrrCapacity, VariableMtrrCount,\r
1658 BaseAddress, Alignment, Type, Alignment0);\r
1659 BaseAddress += Alignment;\r
1660 Length -= Alignment;\r
1661 }\r
1662\r
1663 while (SubtractiveRight-- != 0) {\r
1664 Alignment = MtrrLibLeastAlignment (BaseAddress + Length, Alignment0);\r
1665 MtrrLibAddVariableMtrr (Ranges, RangeCount, VariableMtrr, VariableMtrrCapacity, VariableMtrrCount,\r
1666 BaseAddress + Length, Alignment, CacheInvalid, Alignment0);\r
1667 Length += Alignment;\r
1668 }\r
1669\r
1670 UseLeastAlignment = TRUE;\r
1671 while (Length != 0) {\r
1672 if (UseLeastAlignment) {\r
1673 Alignment = MtrrLibLeastAlignment (BaseAddress, Alignment0);\r
1674 if (Alignment > Length) {\r
1675 UseLeastAlignment = FALSE;\r
1676 }\r
1677 }\r
1678\r
1679 if (!UseLeastAlignment) {\r
1680 Alignment = GetPowerOfTwo64 (Length);\r
1681 }\r
1682\r
1683 MtrrLibAddVariableMtrr (NULL, 0, VariableMtrr, VariableMtrrCapacity, VariableMtrrCount,\r
1684 BaseAddress, Alignment, Type, Alignment0);\r
1685 BaseAddress += Alignment;\r
1686 Length -= Alignment;\r
1687 }\r
1688 return RETURN_SUCCESS;\r
1689}\r
1690\r
1691/**\r
1692 Return an array of memory ranges holding memory type settings for all memory\r
1693 address.\r
1694\r
1695 @param DefaultType The default memory type.\r
1696 @param TotalLength The total length of the memory.\r
1697 @param VariableMtrr The variable MTRR array.\r
1698 @param VariableMtrrCount The count of variable MTRRs.\r
1699 @param Ranges Return the memory range array holding memory type\r
1700 settings for all memory address.\r
1701 @param RangeCapacity The capacity of memory range array.\r
1702 @param RangeCount Return the count of memory range.\r
1703\r
1704 @retval RETURN_SUCCESS The memory range array is returned successfully.\r
1705 @retval RETURN_OUT_OF_RESOURCES The count of memory ranges exceeds capacity.\r
1706**/\r
1707RETURN_STATUS\r
1708MtrrLibGetMemoryTypes (\r
1709 IN MTRR_MEMORY_CACHE_TYPE DefaultType,\r
1710 IN UINT64 TotalLength,\r
1711 IN CONST VARIABLE_MTRR *VariableMtrr,\r
1712 IN UINT32 VariableMtrrCount,\r
1713 OUT MEMORY_RANGE *Ranges,\r
1714 IN UINT32 RangeCapacity,\r
1715 OUT UINT32 *RangeCount\r
1716)\r
1717{\r
1718 RETURN_STATUS Status;\r
1719 UINTN Index;\r
1720\r
1721 //\r
1722 // WT > WB\r
1723 // UC > *\r
1724 // UC > * (except WB, UC) > WB\r
1725 //\r
1726\r
1727 //\r
1728 // 0. Set whole range as DefaultType\r
1729 //\r
1730 *RangeCount = 1;\r
1731 Ranges[0].BaseAddress = 0;\r
1732 Ranges[0].Length = TotalLength;\r
1733 Ranges[0].Type = DefaultType;\r
1734\r
1735 //\r
1736 // 1. Set WB\r
1737 //\r
1738 for (Index = 0; Index < VariableMtrrCount; Index++) {\r
1739 if (VariableMtrr[Index].Valid && VariableMtrr[Index].Type == CacheWriteBack) {\r
1740 Status = MtrrLibSetMemoryType (\r
1741 Ranges, RangeCapacity, RangeCount,\r
1742 VariableMtrr[Index].BaseAddress, VariableMtrr[Index].Length, (MTRR_MEMORY_CACHE_TYPE) VariableMtrr[Index].Type\r
1743 );\r
1744 if (RETURN_ERROR (Status)) {\r
1745 return Status;\r
1746 }\r
1747 }\r
1748 }\r
1749\r
1750 //\r
1751 // 2. Set other types than WB or UC\r
1752 //\r
1753 for (Index = 0; Index < VariableMtrrCount; Index++) {\r
1754 if (VariableMtrr[Index].Valid && VariableMtrr[Index].Type != CacheWriteBack && VariableMtrr[Index].Type != CacheUncacheable) {\r
1755 Status = MtrrLibSetMemoryType (\r
1756 Ranges, RangeCapacity, RangeCount,\r
1757 VariableMtrr[Index].BaseAddress, VariableMtrr[Index].Length, (MTRR_MEMORY_CACHE_TYPE) VariableMtrr[Index].Type\r
1758 );\r
1759 if (RETURN_ERROR (Status)) {\r
1760 return Status;\r
1761 }\r
1762 }\r
1763 }\r
1764\r
1765 //\r
1766 // 3. Set UC\r
1767 //\r
1768 for (Index = 0; Index < VariableMtrrCount; Index++) {\r
1769 if (VariableMtrr[Index].Valid && VariableMtrr[Index].Type == CacheUncacheable) {\r
1770 Status = MtrrLibSetMemoryType (\r
1771 Ranges, RangeCapacity, RangeCount,\r
1772 VariableMtrr[Index].BaseAddress, VariableMtrr[Index].Length, (MTRR_MEMORY_CACHE_TYPE) VariableMtrr[Index].Type\r
1773 );\r
1774 if (RETURN_ERROR (Status)) {\r
1775 return Status;\r
1776 }\r
1777 }\r
1778 }\r
1779 return RETURN_SUCCESS;\r
1780}\r
1781\r
1782/**\r
1783 Worker function attempts to set the attributes for a memory range.\r
1784\r
1785 If MtrrSetting is not NULL, set the attributes into the input MTRR\r
1786 settings buffer.\r
1787 If MtrrSetting is NULL, set the attributes into MTRRs registers.\r
1788\r
1789 @param[in, out] MtrrSetting A buffer holding all MTRRs content.\r
1790 @param[in] BaseAddress The physical address that is the start\r
1791 address of a memory range.\r
1792 @param[in] Length The size in bytes of the memory range.\r
1793 @param[in] Type The MTRR type to set for the memory range.\r
1794\r
1795 @retval RETURN_SUCCESS The attributes were set for the memory\r
1796 range.\r
1797 @retval RETURN_INVALID_PARAMETER Length is zero.\r
1798 @retval RETURN_UNSUPPORTED The processor does not support one or\r
1799 more bytes of the memory resource range\r
1800 specified by BaseAddress and Length.\r
1801 @retval RETURN_UNSUPPORTED The MTRR type is not support for the\r
1802 memory resource range specified\r
1803 by BaseAddress and Length.\r
1804 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to\r
1805 modify the attributes of the memory\r
1806 resource range.\r
1807\r
1808**/\r
1809RETURN_STATUS\r
1810MtrrSetMemoryAttributeWorker (\r
1811 IN OUT MTRR_SETTINGS *MtrrSetting,\r
1812 IN PHYSICAL_ADDRESS BaseAddress,\r
1813 IN UINT64 Length,\r
1814 IN MTRR_MEMORY_CACHE_TYPE Type\r
1815 )\r
1816{\r
1817 RETURN_STATUS Status;\r
1818 UINT32 Index;\r
1819 UINT32 WorkingIndex;\r
1820 //\r
1821 // N variable MTRRs can maximumly separate (2N + 1) Ranges, plus 1 range for [0, 1M).\r
1822 //\r
1823 MEMORY_RANGE Ranges[MTRR_NUMBER_OF_VARIABLE_MTRR * 2 + 2];\r
1824 UINT32 RangeCount;\r
1825 UINT64 MtrrValidBitsMask;\r
1826 UINT64 MtrrValidAddressMask;\r
1827 UINT64 Alignment0;\r
1828 MTRR_CONTEXT MtrrContext;\r
1829 BOOLEAN MtrrContextValid;\r
1830\r
1831 MTRR_MEMORY_CACHE_TYPE DefaultType;\r
1832\r
1833 UINT32 MsrIndex;\r
1834 UINT64 ClearMask;\r
1835 UINT64 OrMask;\r
1836 UINT64 NewValue;\r
1837 BOOLEAN FixedSettingsValid[MTRR_NUMBER_OF_FIXED_MTRR];\r
1838 BOOLEAN FixedSettingsModified[MTRR_NUMBER_OF_FIXED_MTRR];\r
1839 MTRR_FIXED_SETTINGS WorkingFixedSettings;\r
1840\r
1841 UINT32 FirmwareVariableMtrrCount;\r
1842 MTRR_VARIABLE_SETTINGS *VariableSettings;\r
1843 MTRR_VARIABLE_SETTINGS OriginalVariableSettings;\r
1844 UINT32 OriginalVariableMtrrCount;\r
1845 VARIABLE_MTRR OriginalVariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];\r
1846 UINT32 WorkingVariableMtrrCount;\r
1847 VARIABLE_MTRR WorkingVariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];\r
1848 BOOLEAN VariableSettingModified[MTRR_NUMBER_OF_VARIABLE_MTRR];\r
1849 UINTN FreeVariableMtrrCount;\r
1850\r
1851 if (Length == 0) {\r
1852 return RETURN_INVALID_PARAMETER;\r
1853 }\r
1854\r
1855 MtrrLibInitializeMtrrMask (&MtrrValidBitsMask, &MtrrValidAddressMask);\r
1856 if (((BaseAddress & ~MtrrValidAddressMask) != 0) || (Length & ~MtrrValidAddressMask) != 0) {\r
1857 return RETURN_UNSUPPORTED;\r
1858 }\r
1859 OriginalVariableMtrrCount = 0;\r
1860 VariableSettings = NULL;\r
1861\r
1862 ZeroMem (&WorkingFixedSettings, sizeof (WorkingFixedSettings));\r
1863 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
1864 FixedSettingsValid[Index] = FALSE;\r
1865 FixedSettingsModified[Index] = FALSE;\r
1866 }\r
1867\r
1868 //\r
1869 // Check if Fixed MTRR\r
1870 //\r
1871 if (BaseAddress < BASE_1MB) {\r
1872 MsrIndex = (UINT32)-1;\r
1873 while ((BaseAddress < BASE_1MB) && (Length != 0)) {\r
1874 Status = MtrrLibProgramFixedMtrr (Type, &BaseAddress, &Length, &MsrIndex, &ClearMask, &OrMask);\r
1875 if (RETURN_ERROR (Status)) {\r
1876 return Status;\r
1877 }\r
1878 if (MtrrSetting != NULL) {\r
1879 MtrrSetting->Fixed.Mtrr[MsrIndex] = (MtrrSetting->Fixed.Mtrr[MsrIndex] & ~ClearMask) | OrMask;\r
1880 ((MSR_IA32_MTRR_DEF_TYPE_REGISTER *) &MtrrSetting->MtrrDefType)->Bits.FE = 1;\r
1881 } else {\r
1882 if (!FixedSettingsValid[MsrIndex]) {\r
1883 WorkingFixedSettings.Mtrr[MsrIndex] = AsmReadMsr64 (mMtrrLibFixedMtrrTable[MsrIndex].Msr);\r
1884 FixedSettingsValid[MsrIndex] = TRUE;\r
1885 }\r
1886 NewValue = (WorkingFixedSettings.Mtrr[MsrIndex] & ~ClearMask) | OrMask;\r
1887 if (WorkingFixedSettings.Mtrr[MsrIndex] != NewValue) {\r
1888 WorkingFixedSettings.Mtrr[MsrIndex] = NewValue;\r
1889 FixedSettingsModified[MsrIndex] = TRUE;\r
1890 }\r
1891 }\r
1892 }\r
1893\r
1894 if (Length == 0) {\r
1895 //\r
1896 // A Length of 0 can only make sense for fixed MTTR ranges.\r
1897 // Since we just handled the fixed MTRRs, we can skip the\r
1898 // variable MTRR section.\r
1899 //\r
1900 goto Done;\r
1901 }\r
1902 }\r
1903\r
1904 //\r
1905 // Read the default MTRR type\r
1906 //\r
1907 DefaultType = MtrrGetDefaultMemoryTypeWorker (MtrrSetting);\r
1908\r
1909 //\r
1910 // Read all variable MTRRs and convert to Ranges.\r
1911 //\r
1912 OriginalVariableMtrrCount = GetVariableMtrrCountWorker ();\r
1913 if (MtrrSetting == NULL) {\r
1914 ZeroMem (&OriginalVariableSettings, sizeof (OriginalVariableSettings));\r
1915 MtrrGetVariableMtrrWorker (NULL, OriginalVariableMtrrCount, &OriginalVariableSettings);\r
1916 VariableSettings = &OriginalVariableSettings;\r
1917 } else {\r
1918 VariableSettings = &MtrrSetting->Variables;\r
1919 }\r
1920 MtrrGetMemoryAttributeInVariableMtrrWorker (VariableSettings, OriginalVariableMtrrCount, MtrrValidBitsMask, MtrrValidAddressMask, OriginalVariableMtrr);\r
1921\r
1922 Status = MtrrLibGetMemoryTypes (\r
1923 DefaultType, MtrrValidBitsMask + 1, OriginalVariableMtrr, OriginalVariableMtrrCount,\r
1924 Ranges, 2 * OriginalVariableMtrrCount + 1, &RangeCount\r
1925 );\r
1926 ASSERT (Status == RETURN_SUCCESS);\r
1927\r
1928 FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCountWorker ();\r
1929 ASSERT (RangeCount <= 2 * FirmwareVariableMtrrCount + 1);\r
1930\r
1931 //\r
1932 // Force [0, 1M) to UC, so that it doesn't impact left subtraction algorithm.\r
1933 //\r
1934 Status = MtrrLibSetMemoryType (Ranges, 2 * FirmwareVariableMtrrCount + 2, &RangeCount, 0, SIZE_1MB, CacheUncacheable);\r
1935 ASSERT (Status == RETURN_SUCCESS);\r
1936 //\r
1937 // Apply Type to [BaseAddress, BaseAddress + Length)\r
1938 //\r
1939 Status = MtrrLibSetMemoryType (Ranges, 2 * FirmwareVariableMtrrCount + 2, &RangeCount, BaseAddress, Length, Type);\r
1940 if (RETURN_ERROR (Status)) {\r
1941 return Status;\r
1942 }\r
1943\r
1944 Alignment0 = LShiftU64 (1, (UINTN) HighBitSet64 (MtrrValidBitsMask));\r
1945 WorkingVariableMtrrCount = 0;\r
1946 ZeroMem (&WorkingVariableMtrr, sizeof (WorkingVariableMtrr));\r
1947 for (Index = 0; Index < RangeCount; Index++) {\r
1948 if (Ranges[Index].Type != DefaultType) {\r
1949 //\r
1950 // Maximum allowed MTRR count is (FirmwareVariableMtrrCount + 1)\r
1951 // Because potentially the range [0, 1MB) is not merged, but can be ignored because fixed MTRR covers that\r
1952 //\r
1953 Status = MtrrLibSetMemoryAttributeInVariableMtrr (\r
1954 Ranges, RangeCount,\r
1955 WorkingVariableMtrr, FirmwareVariableMtrrCount + 1, &WorkingVariableMtrrCount,\r
1956 Ranges[Index].BaseAddress, Ranges[Index].Length,\r
1957 Ranges[Index].Type, Alignment0\r
1958 );\r
1959 if (RETURN_ERROR (Status)) {\r
1960 return Status;\r
1961 }\r
1962 }\r
1963 }\r
1964\r
1965 //\r
1966 // Remove the [0, 1MB) MTRR if it still exists (not merged with other range)\r
1967 //\r
1968 if (WorkingVariableMtrr[0].BaseAddress == 0 && WorkingVariableMtrr[0].Length == SIZE_1MB) {\r
1969 ASSERT (WorkingVariableMtrr[0].Type == CacheUncacheable);\r
1970 WorkingVariableMtrrCount--;\r
1971 CopyMem (&WorkingVariableMtrr[0], &WorkingVariableMtrr[1], WorkingVariableMtrrCount * sizeof (VARIABLE_MTRR));\r
1972 }\r
1973\r
1974 if (WorkingVariableMtrrCount > FirmwareVariableMtrrCount) {\r
1975 return RETURN_OUT_OF_RESOURCES;\r
1976 }\r
1977\r
1978 for (Index = 0; Index < OriginalVariableMtrrCount; Index++) {\r
1979 VariableSettingModified[Index] = FALSE;\r
1980\r
1981 if (!OriginalVariableMtrr[Index].Valid) {\r
1982 continue;\r
1983 }\r
1984 for (WorkingIndex = 0; WorkingIndex < WorkingVariableMtrrCount; WorkingIndex++) {\r
1985 if (OriginalVariableMtrr[Index].BaseAddress == WorkingVariableMtrr[WorkingIndex].BaseAddress &&\r
1986 OriginalVariableMtrr[Index].Length == WorkingVariableMtrr[WorkingIndex].Length &&\r
1987 OriginalVariableMtrr[Index].Type == WorkingVariableMtrr[WorkingIndex].Type) {\r
1988 break;\r
1989 }\r
1990 }\r
1991\r
1992 if (WorkingIndex == WorkingVariableMtrrCount) {\r
1993 //\r
1994 // Remove the one from OriginalVariableMtrr which is not in WorkingVariableMtrr\r
1995 //\r
1996 OriginalVariableMtrr[Index].Valid = FALSE;\r
1997 VariableSettingModified[Index] = TRUE;\r
1998 } else {\r
1999 //\r
2000 // Remove the one from WorkingVariableMtrr which is also in OriginalVariableMtrr\r
2001 //\r
2002 WorkingVariableMtrr[WorkingIndex].Valid = FALSE;\r
2003 }\r
2004 //\r
2005 // The above two operations cause that valid MTRR only exists in either OriginalVariableMtrr or WorkingVariableMtrr.\r
2006 //\r
2007 }\r
2008\r
2009 //\r
2010 // Merge remaining MTRRs from WorkingVariableMtrr to OriginalVariableMtrr\r
2011 //\r
2012 for (FreeVariableMtrrCount = 0, WorkingIndex = 0, Index = 0; Index < OriginalVariableMtrrCount; Index++) {\r
2013 if (!OriginalVariableMtrr[Index].Valid) {\r
2014 for (; WorkingIndex < WorkingVariableMtrrCount; WorkingIndex++) {\r
2015 if (WorkingVariableMtrr[WorkingIndex].Valid) {\r
2016 break;\r
2017 }\r
2018 }\r
2019 if (WorkingIndex == WorkingVariableMtrrCount) {\r
2020 FreeVariableMtrrCount++;\r
2021 } else {\r
2022 CopyMem (&OriginalVariableMtrr[Index], &WorkingVariableMtrr[WorkingIndex], sizeof (VARIABLE_MTRR));\r
2023 VariableSettingModified[Index] = TRUE;\r
2024 WorkingIndex++;\r
2025 }\r
2026 }\r
2027 }\r
2028 ASSERT (OriginalVariableMtrrCount - FreeVariableMtrrCount <= FirmwareVariableMtrrCount);\r
2029\r
2030 //\r
2031 // Move MTRRs after the FirmwareVariableMtrrCount position to beginning\r
2032 //\r
2033 if (FirmwareVariableMtrrCount < OriginalVariableMtrrCount) {\r
2034 WorkingIndex = FirmwareVariableMtrrCount;\r
2035 for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) {\r
2036 if (!OriginalVariableMtrr[Index].Valid) {\r
2037 //\r
2038 // Found an empty MTRR in WorkingIndex position\r
2039 //\r
2040 for (; WorkingIndex < OriginalVariableMtrrCount; WorkingIndex++) {\r
2041 if (OriginalVariableMtrr[WorkingIndex].Valid) {\r
2042 break;\r
2043 }\r
2044 }\r
2045\r
2046 if (WorkingIndex != OriginalVariableMtrrCount) {\r
2047 CopyMem (&OriginalVariableMtrr[Index], &OriginalVariableMtrr[WorkingIndex], sizeof (VARIABLE_MTRR));\r
2048 VariableSettingModified[Index] = TRUE;\r
2049 VariableSettingModified[WorkingIndex] = TRUE;\r
2050 OriginalVariableMtrr[WorkingIndex].Valid = FALSE;\r
2051 }\r
2052 }\r
2053 }\r
2054 }\r
2055\r
2056 //\r
2057 // Convert OriginalVariableMtrr to VariableSettings\r
2058 // NOTE: MTRR from FirmwareVariableMtrr to OriginalVariableMtrr need to update as well.\r
2059 //\r
2060 for (Index = 0; Index < OriginalVariableMtrrCount; Index++) {\r
2061 if (VariableSettingModified[Index]) {\r
2062 if (OriginalVariableMtrr[Index].Valid) {\r
2063 VariableSettings->Mtrr[Index].Base = (OriginalVariableMtrr[Index].BaseAddress & MtrrValidAddressMask) | (UINT8) OriginalVariableMtrr[Index].Type;\r
2064 VariableSettings->Mtrr[Index].Mask = ((~(OriginalVariableMtrr[Index].Length - 1)) & MtrrValidAddressMask) | BIT11;\r
2065 } else {\r
2066 VariableSettings->Mtrr[Index].Base = 0;\r
2067 VariableSettings->Mtrr[Index].Mask = 0;\r
2068 }\r
2069 }\r
2070 }\r
2071\r
2072Done:\r
2073 if (MtrrSetting != NULL) {\r
2074 ((MSR_IA32_MTRR_DEF_TYPE_REGISTER *) &MtrrSetting->MtrrDefType)->Bits.E = 1;\r
2075 return RETURN_SUCCESS;\r
2076 }\r
2077\r
2078 MtrrContextValid = FALSE;\r
2079 //\r
2080 // Write fixed MTRRs that have been modified\r
2081 //\r
2082 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
2083 if (FixedSettingsModified[Index]) {\r
2084 if (!MtrrContextValid) {\r
2085 MtrrLibPreMtrrChange (&MtrrContext);\r
2086 MtrrContextValid = TRUE;\r
2087 }\r
2088 AsmWriteMsr64 (\r
2089 mMtrrLibFixedMtrrTable[Index].Msr,\r
2090 WorkingFixedSettings.Mtrr[Index]\r
2091 );\r
2092 }\r
2093 }\r
2094\r
2095 //\r
2096 // Write variable MTRRs\r
2097 // When only fixed MTRRs were changed, below loop doesn't run\r
2098 // because OriginalVariableMtrrCount equals to 0.\r
2099 //\r
2100 for (Index = 0; Index < OriginalVariableMtrrCount; Index++) {\r
2101 if (VariableSettingModified[Index]) {\r
2102 if (!MtrrContextValid) {\r
2103 MtrrLibPreMtrrChange (&MtrrContext);\r
2104 MtrrContextValid = TRUE;\r
2105 }\r
2106 AsmWriteMsr64 (\r
2107 MSR_IA32_MTRR_PHYSBASE0 + (Index << 1),\r
2108 VariableSettings->Mtrr[Index].Base\r
2109 );\r
2110 AsmWriteMsr64 (\r
2111 MSR_IA32_MTRR_PHYSMASK0 + (Index << 1),\r
2112 VariableSettings->Mtrr[Index].Mask\r
2113 );\r
2114 }\r
2115 }\r
2116 if (MtrrContextValid) {\r
2117 MtrrLibPostMtrrChange (&MtrrContext);\r
2118 }\r
2119\r
2120 return RETURN_SUCCESS;\r
2121}\r
2122\r
2123/**\r
2124 This function attempts to set the attributes for a memory range.\r
2125\r
2126 @param[in] BaseAddress The physical address that is the start\r
2127 address of a memory range.\r
2128 @param[in] Length The size in bytes of the memory range.\r
2129 @param[in] Attributes The bit mask of attributes to set for the\r
2130 memory range.\r
2131\r
2132 @retval RETURN_SUCCESS The attributes were set for the memory\r
2133 range.\r
2134 @retval RETURN_INVALID_PARAMETER Length is zero.\r
2135 @retval RETURN_UNSUPPORTED The processor does not support one or\r
2136 more bytes of the memory resource range\r
2137 specified by BaseAddress and Length.\r
2138 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support\r
2139 for the memory resource range specified\r
2140 by BaseAddress and Length.\r
2141 @retval RETURN_ACCESS_DENIED The attributes for the memory resource\r
2142 range specified by BaseAddress and Length\r
2143 cannot be modified.\r
2144 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to\r
2145 modify the attributes of the memory\r
2146 resource range.\r
2147\r
2148**/\r
2149RETURN_STATUS\r
2150EFIAPI\r
2151MtrrSetMemoryAttribute (\r
2152 IN PHYSICAL_ADDRESS BaseAddress,\r
2153 IN UINT64 Length,\r
2154 IN MTRR_MEMORY_CACHE_TYPE Attribute\r
2155 )\r
2156{\r
2157 RETURN_STATUS Status;\r
2158\r
2159 if (!IsMtrrSupported ()) {\r
2160 return RETURN_UNSUPPORTED;\r
2161 }\r
2162\r
2163 Status = MtrrSetMemoryAttributeWorker (NULL, BaseAddress, Length, Attribute);\r
2164 DEBUG ((DEBUG_CACHE, "MtrrSetMemoryAttribute() %a: [%016lx, %016lx) - %r\n",\r
2165 mMtrrMemoryCacheTypeShortName[Attribute], BaseAddress, BaseAddress + Length, Status));\r
2166\r
2167 if (!RETURN_ERROR (Status)) {\r
2168 MtrrDebugPrintAllMtrrsWorker (NULL);\r
2169 }\r
2170 return Status;\r
2171}\r
2172\r
2173/**\r
2174 This function attempts to set the attributes into MTRR setting buffer for a memory range.\r
2175\r
2176 @param[in, out] MtrrSetting MTRR setting buffer to be set.\r
2177 @param[in] BaseAddress The physical address that is the start address\r
2178 of a memory range.\r
2179 @param[in] Length The size in bytes of the memory range.\r
2180 @param[in] Attribute The bit mask of attributes to set for the\r
2181 memory range.\r
2182\r
2183 @retval RETURN_SUCCESS The attributes were set for the memory range.\r
2184 @retval RETURN_INVALID_PARAMETER Length is zero.\r
2185 @retval RETURN_UNSUPPORTED The processor does not support one or more bytes of the\r
2186 memory resource range specified by BaseAddress and Length.\r
2187 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support for the memory resource\r
2188 range specified by BaseAddress and Length.\r
2189 @retval RETURN_ACCESS_DENIED The attributes for the memory resource range specified by\r
2190 BaseAddress and Length cannot be modified.\r
2191 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of\r
2192 the memory resource range.\r
2193\r
2194**/\r
2195RETURN_STATUS\r
2196EFIAPI\r
2197MtrrSetMemoryAttributeInMtrrSettings (\r
2198 IN OUT MTRR_SETTINGS *MtrrSetting,\r
2199 IN PHYSICAL_ADDRESS BaseAddress,\r
2200 IN UINT64 Length,\r
2201 IN MTRR_MEMORY_CACHE_TYPE Attribute\r
2202 )\r
2203{\r
2204 RETURN_STATUS Status;\r
2205 Status = MtrrSetMemoryAttributeWorker (MtrrSetting, BaseAddress, Length, Attribute);\r
2206 DEBUG((DEBUG_CACHE, "MtrrSetMemoryAttributeMtrrSettings(%p) %a: [%016lx, %016lx) - %r\n",\r
2207 MtrrSetting, mMtrrMemoryCacheTypeShortName[Attribute], BaseAddress, BaseAddress + Length, Status));\r
2208\r
2209 if (!RETURN_ERROR (Status)) {\r
2210 MtrrDebugPrintAllMtrrsWorker (MtrrSetting);\r
2211 }\r
2212\r
2213 return Status;\r
2214}\r
2215\r
2216/**\r
2217 Worker function setting variable MTRRs\r
2218\r
2219 @param[in] VariableSettings A buffer to hold variable MTRRs content.\r
2220\r
2221**/\r
2222VOID\r
2223MtrrSetVariableMtrrWorker (\r
2224 IN MTRR_VARIABLE_SETTINGS *VariableSettings\r
2225 )\r
2226{\r
2227 UINT32 Index;\r
2228 UINT32 VariableMtrrCount;\r
2229\r
2230 VariableMtrrCount = GetVariableMtrrCountWorker ();\r
2231 ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);\r
2232\r
2233 for (Index = 0; Index < VariableMtrrCount; Index++) {\r
2234 AsmWriteMsr64 (\r
2235 MSR_IA32_MTRR_PHYSBASE0 + (Index << 1),\r
2236 VariableSettings->Mtrr[Index].Base\r
2237 );\r
2238 AsmWriteMsr64 (\r
2239 MSR_IA32_MTRR_PHYSMASK0 + (Index << 1),\r
2240 VariableSettings->Mtrr[Index].Mask\r
2241 );\r
2242 }\r
2243}\r
2244\r
2245\r
2246/**\r
2247 This function sets variable MTRRs\r
2248\r
2249 @param[in] VariableSettings A buffer to hold variable MTRRs content.\r
2250\r
2251 @return The pointer of VariableSettings\r
2252\r
2253**/\r
2254MTRR_VARIABLE_SETTINGS*\r
2255EFIAPI\r
2256MtrrSetVariableMtrr (\r
2257 IN MTRR_VARIABLE_SETTINGS *VariableSettings\r
2258 )\r
2259{\r
2260 MTRR_CONTEXT MtrrContext;\r
2261\r
2262 if (!IsMtrrSupported ()) {\r
2263 return VariableSettings;\r
2264 }\r
2265\r
2266 MtrrLibPreMtrrChange (&MtrrContext);\r
2267 MtrrSetVariableMtrrWorker (VariableSettings);\r
2268 MtrrLibPostMtrrChange (&MtrrContext);\r
2269 MtrrDebugPrintAllMtrrs ();\r
2270\r
2271 return VariableSettings;\r
2272}\r
2273\r
2274/**\r
2275 Worker function setting fixed MTRRs\r
2276\r
2277 @param[in] FixedSettings A buffer to hold fixed MTRRs content.\r
2278\r
2279**/\r
2280VOID\r
2281MtrrSetFixedMtrrWorker (\r
2282 IN MTRR_FIXED_SETTINGS *FixedSettings\r
2283 )\r
2284{\r
2285 UINT32 Index;\r
2286\r
2287 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
2288 AsmWriteMsr64 (\r
2289 mMtrrLibFixedMtrrTable[Index].Msr,\r
2290 FixedSettings->Mtrr[Index]\r
2291 );\r
2292 }\r
2293}\r
2294\r
2295\r
2296/**\r
2297 This function sets fixed MTRRs\r
2298\r
2299 @param[in] FixedSettings A buffer to hold fixed MTRRs content.\r
2300\r
2301 @retval The pointer of FixedSettings\r
2302\r
2303**/\r
2304MTRR_FIXED_SETTINGS*\r
2305EFIAPI\r
2306MtrrSetFixedMtrr (\r
2307 IN MTRR_FIXED_SETTINGS *FixedSettings\r
2308 )\r
2309{\r
2310 MTRR_CONTEXT MtrrContext;\r
2311\r
2312 if (!IsMtrrSupported ()) {\r
2313 return FixedSettings;\r
2314 }\r
2315\r
2316 MtrrLibPreMtrrChange (&MtrrContext);\r
2317 MtrrSetFixedMtrrWorker (FixedSettings);\r
2318 MtrrLibPostMtrrChange (&MtrrContext);\r
2319 MtrrDebugPrintAllMtrrs ();\r
2320\r
2321 return FixedSettings;\r
2322}\r
2323\r
2324\r
2325/**\r
2326 This function gets the content in all MTRRs (variable and fixed)\r
2327\r
2328 @param[out] MtrrSetting A buffer to hold all MTRRs content.\r
2329\r
2330 @retval the pointer of MtrrSetting\r
2331\r
2332**/\r
2333MTRR_SETTINGS *\r
2334EFIAPI\r
2335MtrrGetAllMtrrs (\r
2336 OUT MTRR_SETTINGS *MtrrSetting\r
2337 )\r
2338{\r
2339 if (!IsMtrrSupported ()) {\r
2340 return MtrrSetting;\r
2341 }\r
2342\r
2343 //\r
2344 // Get fixed MTRRs\r
2345 //\r
2346 MtrrGetFixedMtrrWorker (&MtrrSetting->Fixed);\r
2347\r
2348 //\r
2349 // Get variable MTRRs\r
2350 //\r
2351 MtrrGetVariableMtrrWorker (\r
2352 NULL,\r
2353 GetVariableMtrrCountWorker (),\r
2354 &MtrrSetting->Variables\r
2355 );\r
2356\r
2357 //\r
2358 // Get MTRR_DEF_TYPE value\r
2359 //\r
2360 MtrrSetting->MtrrDefType = AsmReadMsr64 (MSR_IA32_MTRR_DEF_TYPE);\r
2361\r
2362 return MtrrSetting;\r
2363}\r
2364\r
2365\r
2366/**\r
2367 This function sets all MTRRs (variable and fixed)\r
2368\r
2369 @param[in] MtrrSetting A buffer holding all MTRRs content.\r
2370\r
2371 @retval The pointer of MtrrSetting\r
2372\r
2373**/\r
2374MTRR_SETTINGS *\r
2375EFIAPI\r
2376MtrrSetAllMtrrs (\r
2377 IN MTRR_SETTINGS *MtrrSetting\r
2378 )\r
2379{\r
2380 MTRR_CONTEXT MtrrContext;\r
2381\r
2382 if (!IsMtrrSupported ()) {\r
2383 return MtrrSetting;\r
2384 }\r
2385\r
2386 MtrrLibPreMtrrChange (&MtrrContext);\r
2387\r
2388 //\r
2389 // Set fixed MTRRs\r
2390 //\r
2391 MtrrSetFixedMtrrWorker (&MtrrSetting->Fixed);\r
2392\r
2393 //\r
2394 // Set variable MTRRs\r
2395 //\r
2396 MtrrSetVariableMtrrWorker (&MtrrSetting->Variables);\r
2397\r
2398 //\r
2399 // Set MTRR_DEF_TYPE value\r
2400 //\r
2401 AsmWriteMsr64 (MSR_IA32_MTRR_DEF_TYPE, MtrrSetting->MtrrDefType);\r
2402\r
2403 MtrrLibPostMtrrChangeEnableCache (&MtrrContext);\r
2404\r
2405 return MtrrSetting;\r
2406}\r
2407\r
2408\r
2409/**\r
2410 Checks if MTRR is supported.\r
2411\r
2412 @retval TRUE MTRR is supported.\r
2413 @retval FALSE MTRR is not supported.\r
2414\r
2415**/\r
2416BOOLEAN\r
2417EFIAPI\r
2418IsMtrrSupported (\r
2419 VOID\r
2420 )\r
2421{\r
2422 CPUID_VERSION_INFO_EDX Edx;\r
2423 MSR_IA32_MTRRCAP_REGISTER MtrrCap;\r
2424\r
2425 //\r
2426 // Check CPUID(1).EDX[12] for MTRR capability\r
2427 //\r
2428 AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &Edx.Uint32);\r
2429 if (Edx.Bits.MTRR == 0) {\r
2430 return FALSE;\r
2431 }\r
2432\r
2433 //\r
2434 // Check number of variable MTRRs and fixed MTRRs existence.\r
2435 // If number of variable MTRRs is zero, or fixed MTRRs do not\r
2436 // exist, return false.\r
2437 //\r
2438 MtrrCap.Uint64 = AsmReadMsr64 (MSR_IA32_MTRRCAP);\r
2439 if ((MtrrCap.Bits.VCNT == 0) || (MtrrCap.Bits.FIX == 0)) {\r
2440 return FALSE;\r
2441 }\r
2442 return TRUE;\r
2443}\r
2444\r