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