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