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