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