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