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