]> git.proxmox.com Git - mirror_edk2.git/blame - QuarkSocPkg/QuarkNorthCluster/Library/MtrrLib/MtrrLib.c
QuarkSocPkg MtrrLib: Enhance get mtrr mask logic.
[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
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
9b6bbcdb
MK
467 UINT64 OrMask;\r
468 UINT64 ClearMask;\r
469\r
9b6bbcdb
MK
470 OrMask = 0;\r
471 ClearMask = 0;\r
472\r
473 for (MsrNum = 0; MsrNum < MTRR_NUMBER_OF_FIXED_MTRR; MsrNum++) {\r
474 if ((*Base >= mMtrrLibFixedMtrrTable[MsrNum].BaseAddress) &&\r
475 (*Base <\r
476 (\r
477 mMtrrLibFixedMtrrTable[MsrNum].BaseAddress +\r
478 (8 * mMtrrLibFixedMtrrTable[MsrNum].Length)\r
479 )\r
480 )\r
481 ) {\r
482 break;\r
483 }\r
484 }\r
485\r
486 if (MsrNum == MTRR_NUMBER_OF_FIXED_MTRR) {\r
487 return RETURN_UNSUPPORTED;\r
488 }\r
489\r
490 //\r
491 // We found the fixed MTRR to be programmed\r
492 //\r
493 for (ByteShift = 0; ByteShift < 8; ByteShift++) {\r
494 if (*Base ==\r
495 (\r
496 mMtrrLibFixedMtrrTable[MsrNum].BaseAddress +\r
497 (ByteShift * mMtrrLibFixedMtrrTable[MsrNum].Length)\r
498 )\r
499 ) {\r
500 break;\r
501 }\r
502 }\r
503\r
504 if (ByteShift == 8) {\r
505 return RETURN_UNSUPPORTED;\r
506 }\r
507\r
508 for (\r
509 ;\r
510 ((ByteShift < 8) && (*Length >= mMtrrLibFixedMtrrTable[MsrNum].Length));\r
511 ByteShift++\r
512 ) {\r
513 OrMask |= LShiftU64 ((UINT64) MemoryCacheType, (UINT32) (ByteShift * 8));\r
514 ClearMask |= LShiftU64 ((UINT64) 0xFF, (UINT32) (ByteShift * 8));\r
515 *Length -= mMtrrLibFixedMtrrTable[MsrNum].Length;\r
516 *Base += mMtrrLibFixedMtrrTable[MsrNum].Length;\r
517 }\r
518\r
519 if (ByteShift < 8 && (*Length != 0)) {\r
520 return RETURN_UNSUPPORTED;\r
521 }\r
522\r
523 *ReturnMsrNum = MsrNum;\r
524 *ReturnClearMask = ClearMask;\r
525 *ReturnOrMask = OrMask;\r
526\r
527 return RETURN_SUCCESS;\r
528}\r
529\r
530\r
531/**\r
532 Worker function gets the attribute of variable MTRRs.\r
533\r
534 This function shadows the content of variable MTRRs into an\r
535 internal array: VariableMtrr.\r
536\r
537 @param[in] VariableSettings The variable MTRR values to shadow\r
538 @param[in] FirmwareVariableMtrrCount The number of variable MTRRs available to firmware\r
539 @param[in] MtrrValidBitsMask The mask for the valid bit of the MTRR\r
540 @param[in] MtrrValidAddressMask The valid address mask for MTRR\r
541 @param[out] VariableMtrr The array to shadow variable MTRRs content\r
542\r
543 @return The return value of this parameter indicates the\r
544 number of MTRRs which has been used.\r
545\r
546**/\r
547UINT32\r
548MtrrGetMemoryAttributeInVariableMtrrWorker (\r
549 IN MTRR_VARIABLE_SETTINGS *VariableSettings,\r
550 IN UINTN FirmwareVariableMtrrCount,\r
551 IN UINT64 MtrrValidBitsMask,\r
552 IN UINT64 MtrrValidAddressMask,\r
553 OUT VARIABLE_MTRR *VariableMtrr\r
554 )\r
555{\r
556 UINTN Index;\r
557 UINT32 UsedMtrr;\r
558\r
559 ZeroMem (VariableMtrr, sizeof (VARIABLE_MTRR) * MTRR_NUMBER_OF_VARIABLE_MTRR);\r
560 for (Index = 0, UsedMtrr = 0; Index < FirmwareVariableMtrrCount; Index++) {\r
561 if ((VariableSettings->Mtrr[Index].Mask & MTRR_LIB_CACHE_MTRR_ENABLED) != 0) {\r
562 VariableMtrr[Index].Msr = (UINT32)Index;\r
563 VariableMtrr[Index].BaseAddress = (VariableSettings->Mtrr[Index].Base & MtrrValidAddressMask);\r
564 VariableMtrr[Index].Length = ((~(VariableSettings->Mtrr[Index].Mask & MtrrValidAddressMask)) & MtrrValidBitsMask) + 1;\r
565 VariableMtrr[Index].Type = (VariableSettings->Mtrr[Index].Base & 0x0ff);\r
566 VariableMtrr[Index].Valid = TRUE;\r
567 VariableMtrr[Index].Used = TRUE;\r
568 UsedMtrr++;\r
569 }\r
570 }\r
571 return UsedMtrr;\r
572}\r
573\r
574\r
575/**\r
576 Gets the attribute of variable MTRRs.\r
577\r
578 This function shadows the content of variable MTRRs into an\r
579 internal array: VariableMtrr.\r
580\r
581 @param[in] MtrrValidBitsMask The mask for the valid bit of the MTRR\r
582 @param[in] MtrrValidAddressMask The valid address mask for MTRR\r
583 @param[out] VariableMtrr The array to shadow variable MTRRs content\r
584\r
74c6a103 585 @return The return value of this parameter indicates the\r
9b6bbcdb
MK
586 number of MTRRs which has been used.\r
587\r
588**/\r
589UINT32\r
590EFIAPI\r
591MtrrGetMemoryAttributeInVariableMtrr (\r
592 IN UINT64 MtrrValidBitsMask,\r
593 IN UINT64 MtrrValidAddressMask,\r
594 OUT VARIABLE_MTRR *VariableMtrr\r
595 )\r
596{\r
597 MTRR_VARIABLE_SETTINGS VariableSettings;\r
598\r
599 if (!IsMtrrSupported ()) {\r
600 return 0;\r
601 }\r
602\r
603 MtrrGetVariableMtrrWorker (\r
604 NULL,\r
605 GetVariableMtrrCountWorker (),\r
606 &VariableSettings\r
607 );\r
608\r
609 return MtrrGetMemoryAttributeInVariableMtrrWorker (\r
610 &VariableSettings,\r
611 GetFirmwareVariableMtrrCountWorker (),\r
612 MtrrValidBitsMask,\r
613 MtrrValidAddressMask,\r
614 VariableMtrr\r
615 );\r
616}\r
617\r
618\r
619/**\r
620 Checks overlap between given memory range and MTRRs.\r
621\r
622 @param[in] FirmwareVariableMtrrCount The number of variable MTRRs available\r
623 to firmware.\r
624 @param[in] Start The start address of memory range.\r
625 @param[in] End The end address of memory range.\r
626 @param[in] VariableMtrr The array to shadow variable MTRRs content\r
627\r
628 @retval TRUE Overlap exists.\r
629 @retval FALSE No overlap.\r
630\r
631**/\r
632BOOLEAN\r
633CheckMemoryAttributeOverlap (\r
634 IN UINTN FirmwareVariableMtrrCount,\r
635 IN PHYSICAL_ADDRESS Start,\r
636 IN PHYSICAL_ADDRESS End,\r
637 IN VARIABLE_MTRR *VariableMtrr\r
638 )\r
639{\r
640 UINT32 Index;\r
641\r
642 for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) {\r
643 if (\r
644 VariableMtrr[Index].Valid &&\r
645 !(\r
646 (Start > (VariableMtrr[Index].BaseAddress +\r
647 VariableMtrr[Index].Length - 1)\r
648 ) ||\r
649 (End < VariableMtrr[Index].BaseAddress)\r
650 )\r
651 ) {\r
652 return TRUE;\r
653 }\r
654 }\r
655\r
656 return FALSE;\r
657}\r
658\r
659\r
660/**\r
661 Marks a variable MTRR as non-valid.\r
662\r
663 @param[in] Index The index of the array VariableMtrr to be invalidated\r
664 @param[in] VariableMtrr The array to shadow variable MTRRs content\r
665 @param[out] UsedMtrr The number of MTRRs which has already been used\r
666\r
667**/\r
668VOID\r
669InvalidateShadowMtrr (\r
670 IN UINTN Index,\r
671 IN VARIABLE_MTRR *VariableMtrr,\r
672 OUT UINT32 *UsedMtrr\r
673 )\r
674{\r
675 VariableMtrr[Index].Valid = FALSE;\r
676 *UsedMtrr = *UsedMtrr - 1;\r
677}\r
678\r
679\r
680/**\r
681 Combines memory attributes.\r
682\r
683 If overlap exists between given memory range and MTRRs, try to combine them.\r
684\r
685 @param[in] FirmwareVariableMtrrCount The number of variable MTRRs\r
686 available to firmware.\r
687 @param[in] Attributes The memory type to set.\r
688 @param[in, out] Base The base address of memory range.\r
689 @param[in, out] Length The length of memory range.\r
690 @param[in] VariableMtrr The array to shadow variable MTRRs content\r
691 @param[in, out] UsedMtrr The number of MTRRs which has already been used\r
692 @param[out] OverwriteExistingMtrr Returns whether an existing MTRR was used\r
693\r
694 @retval EFI_SUCCESS Memory region successfully combined.\r
695 @retval EFI_ACCESS_DENIED Memory region cannot be combined.\r
696\r
697**/\r
698RETURN_STATUS\r
699CombineMemoryAttribute (\r
700 IN UINT32 FirmwareVariableMtrrCount,\r
701 IN UINT64 Attributes,\r
702 IN OUT UINT64 *Base,\r
703 IN OUT UINT64 *Length,\r
704 IN VARIABLE_MTRR *VariableMtrr,\r
705 IN OUT UINT32 *UsedMtrr,\r
706 OUT BOOLEAN *OverwriteExistingMtrr\r
707 )\r
708{\r
709 UINT32 Index;\r
710 UINT64 CombineStart;\r
711 UINT64 CombineEnd;\r
712 UINT64 MtrrEnd;\r
713 UINT64 EndAddress;\r
714 BOOLEAN CoveredByExistingMtrr;\r
715\r
716 *OverwriteExistingMtrr = FALSE;\r
717 CoveredByExistingMtrr = FALSE;\r
718 EndAddress = *Base +*Length - 1;\r
719\r
720 for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) {\r
721\r
722 MtrrEnd = VariableMtrr[Index].BaseAddress + VariableMtrr[Index].Length - 1;\r
723 if (\r
724 !VariableMtrr[Index].Valid ||\r
725 (\r
726 *Base > (MtrrEnd) ||\r
727 (EndAddress < VariableMtrr[Index].BaseAddress)\r
728 )\r
729 ) {\r
730 continue;\r
731 }\r
732\r
733 //\r
734 // Combine same attribute MTRR range\r
735 //\r
736 if (Attributes == VariableMtrr[Index].Type) {\r
737 //\r
738 // if the MTRR range contain the request range, set a flag, then continue to\r
739 // invalidate any MTRR of the same request range with higher priority cache type.\r
740 //\r
741 if (VariableMtrr[Index].BaseAddress <= *Base && MtrrEnd >= EndAddress) {\r
742 CoveredByExistingMtrr = TRUE;\r
743 continue;\r
744 }\r
745 //\r
746 // invalid this MTRR, and program the combine range\r
747 //\r
748 CombineStart =\r
749 (*Base) < VariableMtrr[Index].BaseAddress ?\r
750 (*Base) :\r
751 VariableMtrr[Index].BaseAddress;\r
752 CombineEnd = EndAddress > MtrrEnd ? EndAddress : MtrrEnd;\r
753\r
754 //\r
755 // Record the MTRR usage status in VariableMtrr array.\r
756 //\r
757 InvalidateShadowMtrr (Index, VariableMtrr, UsedMtrr);\r
758 *Base = CombineStart;\r
759 *Length = CombineEnd - CombineStart + 1;\r
760 EndAddress = CombineEnd;\r
761 *OverwriteExistingMtrr = TRUE;\r
762 continue;\r
763 } else {\r
764 //\r
765 // The cache type is different, but the range is convered by one MTRR\r
766 //\r
767 if (VariableMtrr[Index].BaseAddress == *Base && MtrrEnd == EndAddress) {\r
768 InvalidateShadowMtrr (Index, VariableMtrr, UsedMtrr);\r
769 continue;\r
770 }\r
771\r
772 }\r
773\r
774 if ((Attributes== MTRR_CACHE_WRITE_THROUGH &&\r
775 VariableMtrr[Index].Type == MTRR_CACHE_WRITE_BACK) ||\r
776 (Attributes == MTRR_CACHE_WRITE_BACK &&\r
777 VariableMtrr[Index].Type == MTRR_CACHE_WRITE_THROUGH) ||\r
778 (Attributes == MTRR_CACHE_UNCACHEABLE) ||\r
779 (VariableMtrr[Index].Type == MTRR_CACHE_UNCACHEABLE)\r
780 ) {\r
781 *OverwriteExistingMtrr = TRUE;\r
782 continue;\r
783 }\r
784 //\r
785 // Other type memory overlap is invalid\r
786 //\r
787 return RETURN_ACCESS_DENIED;\r
788 }\r
789\r
790 if (CoveredByExistingMtrr) {\r
791 *Length = 0;\r
792 }\r
793\r
794 return RETURN_SUCCESS;\r
795}\r
796\r
797\r
798/**\r
799 Calculates the maximum value which is a power of 2, but less the MemoryLength.\r
800\r
801 @param[in] MemoryLength The number to pass in.\r
802\r
803 @return The maximum value which is align to power of 2 and less the MemoryLength\r
804\r
805**/\r
806UINT64\r
807Power2MaxMemory (\r
808 IN UINT64 MemoryLength\r
809 )\r
810{\r
811 UINT64 Result;\r
812\r
813 if (RShiftU64 (MemoryLength, 32) != 0) {\r
814 Result = LShiftU64 (\r
815 (UINT64) GetPowerOfTwo32 (\r
816 (UINT32) RShiftU64 (MemoryLength, 32)\r
817 ),\r
818 32\r
819 );\r
820 } else {\r
821 Result = (UINT64) GetPowerOfTwo32 ((UINT32) MemoryLength);\r
822 }\r
823\r
824 return Result;\r
825}\r
826\r
827\r
828/**\r
829 Determines the MTRR numbers used to program a memory range.\r
830\r
831 This function first checks the alignment of the base address.\r
832 If the alignment of the base address <= Length, cover the memory range\r
833 (BaseAddress, alignment) by a MTRR, then BaseAddress += alignment and\r
834 Length -= alignment. Repeat the step until alignment > Length.\r
835\r
836 Then this function determines which direction of programming the variable\r
837 MTRRs for the remaining length will use fewer MTRRs.\r
838\r
839 @param[in] BaseAddress Length of Memory to program MTRR\r
840 @param[in] Length Length of Memory to program MTRR\r
841 @param[in] MtrrNumber Pointer to the number of necessary MTRRs\r
842\r
843 @retval TRUE Positive direction is better.\r
844 FALSE Negative direction is better.\r
845\r
846**/\r
847BOOLEAN\r
848GetMtrrNumberAndDirection (\r
849 IN UINT64 BaseAddress,\r
850 IN UINT64 Length,\r
851 IN UINTN *MtrrNumber\r
852 )\r
853{\r
854 UINT64 TempQword;\r
855 UINT64 Alignment;\r
856 UINT32 Positive;\r
857 UINT32 Subtractive;\r
858\r
859 *MtrrNumber = 0;\r
860\r
861 if (BaseAddress != 0) {\r
862 do {\r
863 //\r
864 // Calculate the alignment of the base address.\r
865 //\r
866 Alignment = LShiftU64 (1, (UINTN)LowBitSet64 (BaseAddress));\r
867\r
868 if (Alignment > Length) {\r
869 break;\r
870 }\r
871\r
872 (*MtrrNumber)++;\r
873 BaseAddress += Alignment;\r
874 Length -= Alignment;\r
875 } while (TRUE);\r
876\r
877 if (Length == 0) {\r
878 return TRUE;\r
879 }\r
880 }\r
881\r
882 TempQword = Length;\r
883 Positive = 0;\r
884 Subtractive = 0;\r
885\r
886 do {\r
887 TempQword -= Power2MaxMemory (TempQword);\r
888 Positive++;\r
889 } while (TempQword != 0);\r
890\r
891 TempQword = Power2MaxMemory (LShiftU64 (Length, 1)) - Length;\r
892 Subtractive++;\r
893 do {\r
894 TempQword -= Power2MaxMemory (TempQword);\r
895 Subtractive++;\r
896 } while (TempQword != 0);\r
897\r
898 if (Positive <= Subtractive) {\r
899 *MtrrNumber += Positive;\r
900 return TRUE;\r
901 } else {\r
902 *MtrrNumber += Subtractive;\r
903 return FALSE;\r
904 }\r
905}\r
906\r
907/**\r
908 Invalid variable MTRRs according to the value in the shadow array.\r
909\r
910 This function programs MTRRs according to the values specified\r
911 in the shadow array.\r
912\r
913 @param[in, out] VariableSettings Variable MTRR settings\r
914 @param[in] VariableMtrrCount Number of variable MTRRs\r
915 @param[in, out] VariableMtrr Shadow of variable MTRR contents\r
916\r
917**/\r
918VOID\r
919InvalidateMtrr (\r
920 IN OUT MTRR_VARIABLE_SETTINGS *VariableSettings,\r
921 IN UINTN VariableMtrrCount,\r
922 IN OUT VARIABLE_MTRR *VariableMtrr\r
923 )\r
924{\r
925 UINTN Index;\r
926\r
927 for (Index = 0; Index < VariableMtrrCount; Index++) {\r
928 if (!VariableMtrr[Index].Valid && VariableMtrr[Index].Used) {\r
929 VariableSettings->Mtrr[Index].Base = 0;\r
930 VariableSettings->Mtrr[Index].Mask = 0;\r
931 VariableMtrr[Index].Used = FALSE;\r
932 }\r
933 }\r
934}\r
935\r
936\r
937/**\r
938 Programs variable MTRRs\r
939\r
940 This function programs variable MTRRs\r
941\r
942 @param[in, out] VariableSettings Variable MTRR settings.\r
943 @param[in] MtrrNumber Index of MTRR to program.\r
944 @param[in] BaseAddress Base address of memory region.\r
945 @param[in] Length Length of memory region.\r
946 @param[in] MemoryCacheType Memory type to set.\r
947 @param[in] MtrrValidAddressMask The valid address mask for MTRR\r
948\r
949**/\r
950VOID\r
951ProgramVariableMtrr (\r
952 IN OUT MTRR_VARIABLE_SETTINGS *VariableSettings,\r
953 IN UINTN MtrrNumber,\r
954 IN PHYSICAL_ADDRESS BaseAddress,\r
955 IN UINT64 Length,\r
956 IN UINT64 MemoryCacheType,\r
957 IN UINT64 MtrrValidAddressMask\r
958 )\r
959{\r
960 UINT64 TempQword;\r
961\r
962 //\r
963 // MTRR Physical Base\r
964 //\r
965 TempQword = (BaseAddress & MtrrValidAddressMask) | MemoryCacheType;\r
966 VariableSettings->Mtrr[MtrrNumber].Base = TempQword;\r
967\r
968 //\r
969 // MTRR Physical Mask\r
970 //\r
971 TempQword = ~(Length - 1);\r
972 VariableSettings->Mtrr[MtrrNumber].Mask = (TempQword & MtrrValidAddressMask) | MTRR_LIB_CACHE_MTRR_ENABLED;\r
973}\r
974\r
975\r
976/**\r
977 Converts the Memory attribute value to MTRR_MEMORY_CACHE_TYPE.\r
978\r
979 If MtrrSetting is not NULL, gets the default memory attribute from input\r
980 MTRR settings buffer.\r
981 If MtrrSetting is NULL, gets the default memory attribute from MSR.\r
982\r
983 @param[in] MtrrSetting A buffer holding all MTRRs content.\r
984 @param[in] MtrrType MTRR memory type\r
985\r
986 @return The enum item in MTRR_MEMORY_CACHE_TYPE\r
987\r
988**/\r
989MTRR_MEMORY_CACHE_TYPE\r
990GetMemoryCacheTypeFromMtrrType (\r
991 IN MTRR_SETTINGS *MtrrSetting,\r
992 IN UINT64 MtrrType\r
993 )\r
994{\r
995 switch (MtrrType) {\r
996 case MTRR_CACHE_UNCACHEABLE:\r
997 return CacheUncacheable;\r
998 case MTRR_CACHE_WRITE_COMBINING:\r
999 return CacheWriteCombining;\r
1000 case MTRR_CACHE_WRITE_THROUGH:\r
1001 return CacheWriteThrough;\r
1002 case MTRR_CACHE_WRITE_PROTECTED:\r
1003 return CacheWriteProtected;\r
1004 case MTRR_CACHE_WRITE_BACK:\r
1005 return CacheWriteBack;\r
1006 default:\r
1007 //\r
1008 // MtrrType is MTRR_CACHE_INVALID_TYPE, that means\r
1009 // no MTRR covers the range\r
1010 //\r
1011 return MtrrGetDefaultMemoryTypeWorker (MtrrSetting);\r
1012 }\r
1013}\r
1014\r
1015/**\r
1016 Initializes the valid bits mask and valid address mask for MTRRs.\r
1017\r
1018 This function initializes the valid bits mask and valid address mask for MTRRs.\r
1019\r
1020 @param[out] MtrrValidBitsMask The mask for the valid bit of the MTRR\r
1021 @param[out] MtrrValidAddressMask The valid address mask for the MTRR\r
1022\r
1023**/\r
1024VOID\r
1025MtrrLibInitializeMtrrMask (\r
1026 OUT UINT64 *MtrrValidBitsMask,\r
1027 OUT UINT64 *MtrrValidAddressMask\r
1028 )\r
1029{\r
1030 UINT32 RegEax;\r
1031 UINT8 PhysicalAddressBits;\r
1032\r
1033 AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);\r
1034\r
1035 if (RegEax >= 0x80000008) {\r
1036 AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);\r
1037\r
1038 PhysicalAddressBits = (UINT8) RegEax;\r
9b6bbcdb 1039 } else {\r
055fa1c6 1040 PhysicalAddressBits = 36;\r
9b6bbcdb 1041 }\r
055fa1c6
ED
1042\r
1043 *MtrrValidBitsMask = LShiftU64 (1, PhysicalAddressBits) - 1;\r
1044 *MtrrValidAddressMask = *MtrrValidBitsMask & 0xfffffffffffff000ULL;\r
9b6bbcdb
MK
1045}\r
1046\r
1047\r
1048/**\r
1049 Determines the real attribute of a memory range.\r
1050\r
1051 This function is to arbitrate the real attribute of the memory when\r
1052 there are 2 MTRRs covers the same memory range. For further details,\r
1053 please refer the IA32 Software Developer's Manual, Volume 3,\r
1054 Section 10.11.4.1.\r
1055\r
1056 @param[in] MtrrType1 The first kind of Memory type\r
1057 @param[in] MtrrType2 The second kind of memory type\r
1058\r
1059**/\r
1060UINT64\r
1061MtrrPrecedence (\r
1062 IN UINT64 MtrrType1,\r
1063 IN UINT64 MtrrType2\r
1064 )\r
1065{\r
1066 UINT64 MtrrType;\r
1067\r
1068 MtrrType = MTRR_CACHE_INVALID_TYPE;\r
1069 switch (MtrrType1) {\r
1070 case MTRR_CACHE_UNCACHEABLE:\r
1071 MtrrType = MTRR_CACHE_UNCACHEABLE;\r
1072 break;\r
1073 case MTRR_CACHE_WRITE_COMBINING:\r
1074 if (\r
1075 MtrrType2==MTRR_CACHE_WRITE_COMBINING ||\r
1076 MtrrType2==MTRR_CACHE_UNCACHEABLE\r
1077 ) {\r
1078 MtrrType = MtrrType2;\r
1079 }\r
1080 break;\r
1081 case MTRR_CACHE_WRITE_THROUGH:\r
1082 if (\r
1083 MtrrType2==MTRR_CACHE_WRITE_THROUGH ||\r
1084 MtrrType2==MTRR_CACHE_WRITE_BACK\r
1085 ) {\r
1086 MtrrType = MTRR_CACHE_WRITE_THROUGH;\r
1087 } else if(MtrrType2==MTRR_CACHE_UNCACHEABLE) {\r
1088 MtrrType = MTRR_CACHE_UNCACHEABLE;\r
1089 }\r
1090 break;\r
1091 case MTRR_CACHE_WRITE_PROTECTED:\r
1092 if (MtrrType2 == MTRR_CACHE_WRITE_PROTECTED ||\r
1093 MtrrType2 == MTRR_CACHE_UNCACHEABLE) {\r
1094 MtrrType = MtrrType2;\r
1095 }\r
1096 break;\r
1097 case MTRR_CACHE_WRITE_BACK:\r
1098 if (\r
1099 MtrrType2== MTRR_CACHE_UNCACHEABLE ||\r
1100 MtrrType2==MTRR_CACHE_WRITE_THROUGH ||\r
1101 MtrrType2== MTRR_CACHE_WRITE_BACK\r
1102 ) {\r
1103 MtrrType = MtrrType2;\r
1104 }\r
1105 break;\r
1106 case MTRR_CACHE_INVALID_TYPE:\r
1107 MtrrType = MtrrType2;\r
1108 break;\r
1109 default:\r
1110 break;\r
1111 }\r
1112\r
1113 if (MtrrType2 == MTRR_CACHE_INVALID_TYPE) {\r
1114 MtrrType = MtrrType1;\r
1115 }\r
1116 return MtrrType;\r
1117}\r
1118\r
1119/**\r
1120 Worker function will get the memory cache type of the specific address.\r
1121\r
1122 If MtrrSetting is not NULL, gets the memory cache type from input\r
1123 MTRR settings buffer.\r
1124 If MtrrSetting is NULL, gets the memory cache type from MTRRs.\r
1125\r
1126 @param[in] MtrrSetting A buffer holding all MTRRs content.\r
1127 @param[in] Address The specific address\r
1128\r
1129 @return Memory cache type of the specific address\r
1130\r
1131**/\r
1132MTRR_MEMORY_CACHE_TYPE\r
1133MtrrGetMemoryAttributeByAddressWorker (\r
1134 IN MTRR_SETTINGS *MtrrSetting,\r
1135 IN PHYSICAL_ADDRESS Address\r
1136 )\r
1137{\r
1138 UINT64 TempQword;\r
1139 UINTN Index;\r
1140 UINTN SubIndex;\r
1141 UINT64 MtrrType;\r
1142 UINT64 TempMtrrType;\r
1143 MTRR_MEMORY_CACHE_TYPE CacheType;\r
1144 VARIABLE_MTRR VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];\r
1145 UINT64 MtrrValidBitsMask;\r
1146 UINT64 MtrrValidAddressMask;\r
1147 UINTN VariableMtrrCount;\r
1148 MTRR_VARIABLE_SETTINGS VariableSettings;\r
1149\r
1150 //\r
1151 // Check if MTRR is enabled, if not, return UC as attribute\r
1152 //\r
1153 if (MtrrSetting == NULL) {\r
1154 TempQword = MtrrRegisterRead (QUARK_NC_HOST_BRIDGE_IA32_MTRR_DEF_TYPE);\r
1155 } else {\r
1156 TempQword = MtrrSetting->MtrrDefType;\r
1157 }\r
1158 MtrrType = MTRR_CACHE_INVALID_TYPE;\r
1159\r
1160 if ((TempQword & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
1161 return CacheUncacheable;\r
1162 }\r
1163\r
1164 //\r
1165 // If address is less than 1M, then try to go through the fixed MTRR\r
1166 //\r
1167 if (Address < BASE_1MB) {\r
1168 if ((TempQword & MTRR_LIB_CACHE_FIXED_MTRR_ENABLED) != 0) {\r
1169 //\r
1170 // Go through the fixed MTRR\r
1171 //\r
1172 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
1173 if (Address >= mMtrrLibFixedMtrrTable[Index].BaseAddress &&\r
1174 Address < (\r
1175 mMtrrLibFixedMtrrTable[Index].BaseAddress +\r
1176 (mMtrrLibFixedMtrrTable[Index].Length * 8)\r
1177 )\r
1178 ) {\r
1179 SubIndex =\r
1180 ((UINTN)Address - mMtrrLibFixedMtrrTable[Index].BaseAddress) /\r
1181 mMtrrLibFixedMtrrTable[Index].Length;\r
1182 if (MtrrSetting == NULL) {\r
1183 TempQword = MtrrRegisterRead (mMtrrLibFixedMtrrTable[Index].Msr);\r
1184 } else {\r
1185 TempQword = MtrrSetting->Fixed.Mtrr[Index];\r
1186 }\r
1187 MtrrType = RShiftU64 (TempQword, SubIndex * 8) & 0xFF;\r
1188 return GetMemoryCacheTypeFromMtrrType (MtrrSetting, MtrrType);\r
1189 }\r
1190 }\r
1191 }\r
1192 }\r
1193 MtrrLibInitializeMtrrMask(&MtrrValidBitsMask, &MtrrValidAddressMask);\r
1194\r
1195 MtrrGetVariableMtrrWorker (\r
1196 MtrrSetting,\r
1197 GetVariableMtrrCountWorker (),\r
1198 &VariableSettings\r
1199 );\r
1200\r
1201 MtrrGetMemoryAttributeInVariableMtrrWorker (\r
1202 &VariableSettings,\r
1203 GetFirmwareVariableMtrrCountWorker (),\r
1204 MtrrValidBitsMask,\r
1205 MtrrValidAddressMask,\r
1206 VariableMtrr\r
1207 );\r
1208\r
1209 //\r
1210 // Go through the variable MTRR\r
1211 //\r
1212 VariableMtrrCount = GetVariableMtrrCountWorker ();\r
1213 ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);\r
1214\r
1215 for (Index = 0; Index < VariableMtrrCount; Index++) {\r
1216 if (VariableMtrr[Index].Valid) {\r
1217 if (Address >= VariableMtrr[Index].BaseAddress &&\r
1218 Address < VariableMtrr[Index].BaseAddress+VariableMtrr[Index].Length) {\r
1219 TempMtrrType = VariableMtrr[Index].Type;\r
1220 MtrrType = MtrrPrecedence (MtrrType, TempMtrrType);\r
1221 }\r
1222 }\r
1223 }\r
1224 CacheType = GetMemoryCacheTypeFromMtrrType (MtrrSetting, MtrrType);\r
1225\r
1226 return CacheType;\r
1227}\r
1228\r
1229\r
1230/**\r
1231 This function will get the memory cache type of the specific address.\r
1232\r
1233 This function is mainly for debug purpose.\r
1234\r
1235 @param[in] Address The specific address\r
1236\r
1237 @return Memory cache type of the specific address\r
1238\r
1239**/\r
1240MTRR_MEMORY_CACHE_TYPE\r
1241EFIAPI\r
1242MtrrGetMemoryAttribute (\r
1243 IN PHYSICAL_ADDRESS Address\r
1244 )\r
1245{\r
1246 if (!IsMtrrSupported ()) {\r
1247 return CacheUncacheable;\r
1248 }\r
1249\r
1250 return MtrrGetMemoryAttributeByAddressWorker (NULL, Address);\r
1251}\r
1252\r
1253/**\r
1254 Worker function prints all MTRRs for debugging.\r
1255\r
1256 If MtrrSetting is not NULL, print MTRR settings from from input MTRR\r
1257 settings buffer.\r
1258 If MtrrSetting is NULL, print MTRR settings from MTRRs.\r
1259\r
1260 @param MtrrSetting A buffer holding all MTRRs content.\r
1261**/\r
1262VOID\r
1263MtrrDebugPrintAllMtrrsWorker (\r
1264 IN MTRR_SETTINGS *MtrrSetting\r
1265 )\r
1266{\r
1267 DEBUG_CODE (\r
1268 MTRR_SETTINGS LocalMtrrs;\r
1269 MTRR_SETTINGS *Mtrrs;\r
1270 UINTN Index;\r
1271 UINTN Index1;\r
1272 UINTN VariableMtrrCount;\r
1273 UINT64 Base;\r
1274 UINT64 Limit;\r
1275 UINT64 MtrrBase;\r
1276 UINT64 MtrrLimit;\r
1277 UINT64 RangeBase;\r
1278 UINT64 RangeLimit;\r
1279 UINT64 NoRangeBase;\r
1280 UINT64 NoRangeLimit;\r
1281 UINT32 RegEax;\r
1282 UINTN MemoryType;\r
1283 UINTN PreviousMemoryType;\r
1284 BOOLEAN Found;\r
1285\r
1286 if (!IsMtrrSupported ()) {\r
1287 return;\r
1288 }\r
1289\r
1290 DEBUG((DEBUG_CACHE, "MTRR Settings\n"));\r
1291 DEBUG((DEBUG_CACHE, "=============\n"));\r
1292\r
1293 if (MtrrSetting != NULL) {\r
1294 Mtrrs = MtrrSetting;\r
1295 } else {\r
1296 MtrrGetAllMtrrs (&LocalMtrrs);\r
1297 Mtrrs = &LocalMtrrs;\r
1298 }\r
1299\r
1300 DEBUG((DEBUG_CACHE, "MTRR Default Type: %016lx\n", Mtrrs->MtrrDefType));\r
1301 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
1302 DEBUG((DEBUG_CACHE, "Fixed MTRR[%02d] : %016lx\n", Index, Mtrrs->Fixed.Mtrr[Index]));\r
1303 }\r
1304\r
1305 VariableMtrrCount = GetVariableMtrrCount ();\r
1306 for (Index = 0; Index < VariableMtrrCount; Index++) {\r
1307 DEBUG((DEBUG_CACHE, "Variable MTRR[%02d]: Base=%016lx Mask=%016lx\n",\r
1308 Index,\r
1309 Mtrrs->Variables.Mtrr[Index].Base,\r
1310 Mtrrs->Variables.Mtrr[Index].Mask\r
1311 ));\r
1312 }\r
1313 DEBUG((DEBUG_CACHE, "\n"));\r
1314 DEBUG((DEBUG_CACHE, "MTRR Ranges\n"));\r
1315 DEBUG((DEBUG_CACHE, "====================================\n"));\r
1316\r
1317 Base = 0;\r
1318 PreviousMemoryType = MTRR_CACHE_INVALID_TYPE;\r
1319 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
1320 Base = mMtrrLibFixedMtrrTable[Index].BaseAddress;\r
1321 for (Index1 = 0; Index1 < 8; Index1++) {\r
1322 MemoryType = (UINTN)(RShiftU64 (Mtrrs->Fixed.Mtrr[Index], Index1 * 8) & 0xff);\r
1323 if (MemoryType > CacheWriteBack) {\r
1324 MemoryType = MTRR_CACHE_INVALID_TYPE;\r
1325 }\r
1326 if (MemoryType != PreviousMemoryType) {\r
1327 if (PreviousMemoryType != MTRR_CACHE_INVALID_TYPE) {\r
1328 DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));\r
1329 }\r
1330 PreviousMemoryType = MemoryType;\r
1331 DEBUG((DEBUG_CACHE, "%a:%016lx-", mMtrrMemoryCacheTypeShortName[MemoryType], Base));\r
1332 }\r
1333 Base += mMtrrLibFixedMtrrTable[Index].Length;\r
1334 }\r
1335 }\r
1336 DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));\r
1337\r
1338 VariableMtrrCount = GetVariableMtrrCount ();\r
1339\r
1340 Limit = BIT36 - 1;\r
1341 AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);\r
1342 if (RegEax >= 0x80000008) {\r
1343 AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);\r
1344 Limit = LShiftU64 (1, RegEax & 0xff) - 1;\r
1345 }\r
1346 Base = BASE_1MB;\r
1347 PreviousMemoryType = MTRR_CACHE_INVALID_TYPE;\r
1348 do {\r
1349 MemoryType = MtrrGetMemoryAttributeByAddressWorker (Mtrrs, Base);\r
1350 if (MemoryType > CacheWriteBack) {\r
1351 MemoryType = MTRR_CACHE_INVALID_TYPE;\r
1352 }\r
1353\r
1354 if (MemoryType != PreviousMemoryType) {\r
1355 if (PreviousMemoryType != MTRR_CACHE_INVALID_TYPE) {\r
1356 DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));\r
1357 }\r
1358 PreviousMemoryType = MemoryType;\r
1359 DEBUG((DEBUG_CACHE, "%a:%016lx-", mMtrrMemoryCacheTypeShortName[MemoryType], Base));\r
1360 }\r
1361\r
1362 RangeBase = BASE_1MB;\r
1363 NoRangeBase = BASE_1MB;\r
1364 RangeLimit = Limit;\r
1365 NoRangeLimit = Limit;\r
1366\r
1367 for (Index = 0, Found = FALSE; Index < VariableMtrrCount; Index++) {\r
1368 if ((Mtrrs->Variables.Mtrr[Index].Mask & BIT11) == 0) {\r
1369 //\r
1370 // If mask is not valid, then do not display range\r
1371 //\r
1372 continue;\r
1373 }\r
1374 MtrrBase = (Mtrrs->Variables.Mtrr[Index].Base & (~(SIZE_4KB - 1)));\r
1375 MtrrLimit = MtrrBase + ((~(Mtrrs->Variables.Mtrr[Index].Mask & (~(SIZE_4KB - 1)))) & Limit);\r
1376\r
1377 if (Base >= MtrrBase && Base < MtrrLimit) {\r
1378 Found = TRUE;\r
1379 }\r
1380\r
1381 if (Base >= MtrrBase && MtrrBase > RangeBase) {\r
1382 RangeBase = MtrrBase;\r
1383 }\r
1384 if (Base > MtrrLimit && MtrrLimit > RangeBase) {\r
1385 RangeBase = MtrrLimit + 1;\r
1386 }\r
1387 if (Base < MtrrBase && MtrrBase < RangeLimit) {\r
1388 RangeLimit = MtrrBase - 1;\r
1389 }\r
1390 if (Base < MtrrLimit && MtrrLimit <= RangeLimit) {\r
1391 RangeLimit = MtrrLimit;\r
1392 }\r
1393\r
1394 if (Base > MtrrLimit && NoRangeBase < MtrrLimit) {\r
1395 NoRangeBase = MtrrLimit + 1;\r
1396 }\r
1397 if (Base < MtrrBase && NoRangeLimit > MtrrBase) {\r
1398 NoRangeLimit = MtrrBase - 1;\r
1399 }\r
1400 }\r
1401\r
1402 if (Found) {\r
1403 Base = RangeLimit + 1;\r
1404 } else {\r
1405 Base = NoRangeLimit + 1;\r
1406 }\r
1407 } while (Base < Limit);\r
1408 DEBUG((DEBUG_CACHE, "%016lx\n\n", Base - 1));\r
1409 );\r
1410}\r
1411\r
1412\r
1413/**\r
1414 This function prints all MTRRs for debugging.\r
1415**/\r
1416VOID\r
1417EFIAPI\r
1418MtrrDebugPrintAllMtrrs (\r
1419 VOID\r
1420 )\r
1421{\r
1422 MtrrDebugPrintAllMtrrsWorker (NULL);\r
1423}\r
1424\r
1425\r
1426/**\r
1427 Worker function attempts to set the attributes for a memory range.\r
1428\r
1429 If MtrrSettings is not NULL, set the attributes into the input MTRR\r
1430 settings buffer.\r
1431 If MtrrSettings is NULL, set the attributes into MTRRs registers.\r
1432\r
1433 @param[in, out] MtrrSetting A buffer holding all MTRRs content.\r
1434 @param[in] BaseAddress The physical address that is the start\r
1435 address of a memory region.\r
1436 @param[in] Length The size in bytes of the memory region.\r
1437 @param[in] Attribute The bit mask of attributes to set for the\r
1438 memory region.\r
1439\r
1440 @retval RETURN_SUCCESS The attributes were set for the memory\r
1441 region.\r
1442 @retval RETURN_INVALID_PARAMETER Length is zero.\r
1443 @retval RETURN_UNSUPPORTED The processor does not support one or\r
1444 more bytes of the memory resource range\r
1445 specified by BaseAddress and Length.\r
1446 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support\r
1447 for the memory resource range specified\r
1448 by BaseAddress and Length.\r
1449 @retval RETURN_ACCESS_DENIED The attributes for the memory resource\r
1450 range specified by BaseAddress and Length\r
1451 cannot be modified.\r
1452 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to\r
1453 modify the attributes of the memory\r
1454 resource range.\r
1455\r
1456**/\r
1457RETURN_STATUS\r
1458MtrrSetMemoryAttributeWorker (\r
1459 IN OUT MTRR_SETTINGS *MtrrSetting,\r
1460 IN PHYSICAL_ADDRESS BaseAddress,\r
1461 IN UINT64 Length,\r
1462 IN MTRR_MEMORY_CACHE_TYPE Attribute\r
1463 )\r
1464{\r
1465 UINT64 TempQword;\r
1466 RETURN_STATUS Status;\r
1467 UINT64 MemoryType;\r
1468 UINT64 Alignment;\r
1469 BOOLEAN OverLap;\r
1470 BOOLEAN Positive;\r
1471 UINT32 MsrNum;\r
1472 UINTN MtrrNumber;\r
1473 VARIABLE_MTRR VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];\r
1474 UINT32 UsedMtrr;\r
1475 UINT64 MtrrValidBitsMask;\r
1476 UINT64 MtrrValidAddressMask;\r
1477 BOOLEAN OverwriteExistingMtrr;\r
1478 UINT32 FirmwareVariableMtrrCount;\r
1479 MTRR_CONTEXT MtrrContext;\r
1480 BOOLEAN MtrrContextValid;\r
1481 BOOLEAN FixedSettingsValid[MTRR_NUMBER_OF_FIXED_MTRR];\r
1482 BOOLEAN FixedSettingsModified[MTRR_NUMBER_OF_FIXED_MTRR];\r
1483 MTRR_FIXED_SETTINGS WorkingFixedSettings;\r
1484 UINT32 VariableMtrrCount;\r
1485 MTRR_VARIABLE_SETTINGS OriginalVariableSettings;\r
1486 BOOLEAN ProgramVariableSettings;\r
1487 MTRR_VARIABLE_SETTINGS WorkingVariableSettings;\r
1488 UINT32 Index;\r
1489 UINT64 ClearMask;\r
1490 UINT64 OrMask;\r
1491 UINT64 NewValue;\r
1492 MTRR_VARIABLE_SETTINGS *VariableSettings;\r
1493\r
1494 MtrrContextValid = FALSE;\r
1495 VariableMtrrCount = 0;\r
1496 ZeroMem (&WorkingFixedSettings, sizeof (WorkingFixedSettings));\r
1497 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
1498 FixedSettingsValid[Index] = FALSE;\r
1499 FixedSettingsModified[Index] = FALSE;\r
1500 }\r
1501 ProgramVariableSettings = FALSE;\r
1502\r
1503 if (!IsMtrrSupported ()) {\r
1504 Status = RETURN_UNSUPPORTED;\r
1505 goto Done;\r
1506 }\r
1507\r
1508 MtrrLibInitializeMtrrMask (&MtrrValidBitsMask, &MtrrValidAddressMask);\r
1509\r
1510 TempQword = 0;\r
1511 MemoryType = (UINT64)Attribute;\r
1512 OverwriteExistingMtrr = FALSE;\r
1513\r
1514 //\r
1515 // Check for an invalid parameter\r
1516 //\r
1517 if (Length == 0) {\r
1518 Status = RETURN_INVALID_PARAMETER;\r
1519 goto Done;\r
1520 }\r
1521\r
1522 if (\r
1523 (BaseAddress & ~MtrrValidAddressMask) != 0 ||\r
1524 (Length & ~MtrrValidAddressMask) != 0\r
1525 ) {\r
1526 Status = RETURN_UNSUPPORTED;\r
1527 goto Done;\r
1528 }\r
1529\r
1530 //\r
1531 // Check if Fixed MTRR\r
1532 //\r
1533 Status = RETURN_SUCCESS;\r
1534 if (BaseAddress < BASE_1MB) {\r
1535 while ((BaseAddress < BASE_1MB) && (Length > 0) && Status == RETURN_SUCCESS) {\r
1536 Status = ProgramFixedMtrr (MemoryType, &BaseAddress, &Length, &MsrNum, &ClearMask, &OrMask);\r
1537 if (RETURN_ERROR (Status)) {\r
1538 goto Done;\r
1539 }\r
1540 if (MtrrSetting != NULL) {\r
1541 MtrrSetting->Fixed.Mtrr[MsrNum] = (MtrrSetting->Fixed.Mtrr[MsrNum] & ~ClearMask) | OrMask;\r
1542 MtrrSetting->MtrrDefType |= MTRR_LIB_CACHE_FIXED_MTRR_ENABLED;\r
1543 } else {\r
1544 if (!FixedSettingsValid[MsrNum]) {\r
1545 WorkingFixedSettings.Mtrr[MsrNum] = MtrrRegisterRead (mMtrrLibFixedMtrrTable[MsrNum].Msr);\r
1546 FixedSettingsValid[MsrNum] = TRUE;\r
1547 }\r
1548 NewValue = (WorkingFixedSettings.Mtrr[MsrNum] & ~ClearMask) | OrMask;\r
1549 if (WorkingFixedSettings.Mtrr[MsrNum] != NewValue) {\r
1550 WorkingFixedSettings.Mtrr[MsrNum] = NewValue;\r
1551 FixedSettingsModified[MsrNum] = TRUE;\r
1552 }\r
1553 }\r
1554 }\r
1555\r
1556 if (Length == 0) {\r
1557 //\r
1558 // A Length of 0 can only make sense for fixed MTTR ranges.\r
1559 // Since we just handled the fixed MTRRs, we can skip the\r
1560 // variable MTRR section.\r
1561 //\r
1562 goto Done;\r
1563 }\r
1564 }\r
1565\r
1566 //\r
1567 // Since memory ranges below 1MB will be overridden by the fixed MTRRs,\r
1568 // we can set the base to 0 to save variable MTRRs.\r
1569 //\r
1570 if (BaseAddress == BASE_1MB) {\r
1571 BaseAddress = 0;\r
1572 Length += SIZE_1MB;\r
1573 }\r
1574\r
1575 //\r
1576 // Read all variable MTRRs\r
1577 //\r
1578 VariableMtrrCount = GetVariableMtrrCountWorker ();\r
1579 FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCountWorker ();\r
1580 if (MtrrSetting != NULL) {\r
1581 VariableSettings = &MtrrSetting->Variables;\r
1582 } else {\r
1583 MtrrGetVariableMtrrWorker (NULL, VariableMtrrCount, &OriginalVariableSettings);\r
1584 CopyMem (&WorkingVariableSettings, &OriginalVariableSettings, sizeof (WorkingVariableSettings));\r
1585 ProgramVariableSettings = TRUE;\r
1586 VariableSettings = &WorkingVariableSettings;\r
1587 }\r
1588\r
1589 //\r
1590 // Check for overlap\r
1591 //\r
1592 UsedMtrr = MtrrGetMemoryAttributeInVariableMtrrWorker (\r
1593 VariableSettings,\r
1594 FirmwareVariableMtrrCount,\r
1595 MtrrValidBitsMask,\r
1596 MtrrValidAddressMask,\r
1597 VariableMtrr\r
1598 );\r
1599 OverLap = CheckMemoryAttributeOverlap (\r
1600 FirmwareVariableMtrrCount,\r
1601 BaseAddress,\r
1602 BaseAddress + Length - 1,\r
1603 VariableMtrr\r
1604 );\r
1605 if (OverLap) {\r
1606 Status = CombineMemoryAttribute (\r
1607 FirmwareVariableMtrrCount,\r
1608 MemoryType,\r
1609 &BaseAddress,\r
1610 &Length,\r
1611 VariableMtrr,\r
1612 &UsedMtrr,\r
1613 &OverwriteExistingMtrr\r
1614 );\r
1615 if (RETURN_ERROR (Status)) {\r
1616 goto Done;\r
1617 }\r
1618\r
1619 if (Length == 0) {\r
1620 //\r
1621 // Combined successfully, invalidate the now-unused MTRRs\r
1622 //\r
1623 InvalidateMtrr (VariableSettings, VariableMtrrCount, VariableMtrr);\r
1624 Status = RETURN_SUCCESS;\r
1625 goto Done;\r
1626 }\r
1627 }\r
1628\r
1629 //\r
1630 // The memory type is the same with the type specified by\r
1631 // MTRR_LIB_IA32_MTRR_DEF_TYPE.\r
1632 //\r
1633 if ((!OverwriteExistingMtrr) && (Attribute == MtrrGetDefaultMemoryType ())) {\r
1634 //\r
1635 // Invalidate the now-unused MTRRs\r
1636 //\r
1637 InvalidateMtrr (VariableSettings, VariableMtrrCount, VariableMtrr);\r
1638 goto Done;\r
1639 }\r
1640\r
1641 Positive = GetMtrrNumberAndDirection (BaseAddress, Length, &MtrrNumber);\r
1642\r
1643 if ((UsedMtrr + MtrrNumber) > FirmwareVariableMtrrCount) {\r
1644 Status = RETURN_OUT_OF_RESOURCES;\r
1645 goto Done;\r
1646 }\r
1647\r
1648 //\r
1649 // Invalidate the now-unused MTRRs\r
1650 //\r
1651 InvalidateMtrr (VariableSettings, VariableMtrrCount, VariableMtrr);\r
1652\r
1653 //\r
1654 // Find first unused MTRR\r
1655 //\r
1656 for (MsrNum = 0; MsrNum < VariableMtrrCount; MsrNum++) {\r
1657 if ((VariableSettings->Mtrr[MsrNum].Mask & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
1658 break;\r
1659 }\r
1660 }\r
1661\r
1662 if (BaseAddress != 0) {\r
1663 do {\r
1664 //\r
1665 // Calculate the alignment of the base address.\r
1666 //\r
1667 Alignment = LShiftU64 (1, (UINTN)LowBitSet64 (BaseAddress));\r
1668\r
1669 if (Alignment > Length) {\r
1670 break;\r
1671 }\r
1672\r
1673 //\r
1674 // Find unused MTRR\r
1675 //\r
1676 for (; MsrNum < VariableMtrrCount; MsrNum++) {\r
1677 if ((VariableSettings->Mtrr[MsrNum].Mask & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
1678 break;\r
1679 }\r
1680 }\r
1681\r
1682 ProgramVariableMtrr (\r
1683 VariableSettings,\r
1684 MsrNum,\r
1685 BaseAddress,\r
1686 Alignment,\r
1687 MemoryType,\r
1688 MtrrValidAddressMask\r
1689 );\r
1690 BaseAddress += Alignment;\r
1691 Length -= Alignment;\r
1692 } while (TRUE);\r
1693\r
1694 if (Length == 0) {\r
1695 goto Done;\r
1696 }\r
1697 }\r
1698\r
1699 TempQword = Length;\r
1700\r
1701 if (!Positive) {\r
1702 Length = Power2MaxMemory (LShiftU64 (TempQword, 1));\r
1703\r
1704 //\r
1705 // Find unused MTRR\r
1706 //\r
1707 for (; MsrNum < VariableMtrrCount; MsrNum++) {\r
1708 if ((VariableSettings->Mtrr[MsrNum].Mask & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
1709 break;\r
1710 }\r
1711 }\r
1712\r
1713 ProgramVariableMtrr (\r
1714 VariableSettings,\r
1715 MsrNum,\r
1716 BaseAddress,\r
1717 Length,\r
1718 MemoryType,\r
1719 MtrrValidAddressMask\r
1720 );\r
1721 BaseAddress += Length;\r
1722 TempQword = Length - TempQword;\r
1723 MemoryType = MTRR_CACHE_UNCACHEABLE;\r
1724 }\r
1725\r
1726 do {\r
1727 //\r
1728 // Find unused MTRR\r
1729 //\r
1730 for (; MsrNum < VariableMtrrCount; MsrNum++) {\r
1731 if ((VariableSettings->Mtrr[MsrNum].Mask & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
1732 break;\r
1733 }\r
1734 }\r
1735\r
1736 Length = Power2MaxMemory (TempQword);\r
1737 if (!Positive) {\r
1738 BaseAddress -= Length;\r
1739 }\r
1740\r
1741 ProgramVariableMtrr (\r
1742 VariableSettings,\r
1743 MsrNum,\r
1744 BaseAddress,\r
1745 Length,\r
1746 MemoryType,\r
1747 MtrrValidAddressMask\r
1748 );\r
1749\r
1750 if (Positive) {\r
1751 BaseAddress += Length;\r
1752 }\r
1753 TempQword -= Length;\r
1754\r
1755 } while (TempQword > 0);\r
1756\r
1757Done:\r
1758\r
1759 //\r
1760 // Write fixed MTRRs that have been modified\r
1761 //\r
1762 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
1763 if (FixedSettingsModified[Index]) {\r
1764 if (!MtrrContextValid) {\r
1765 PreMtrrChange (&MtrrContext);\r
1766 MtrrContextValid = TRUE;\r
1767 }\r
1768 MtrrRegisterWrite (\r
1769 mMtrrLibFixedMtrrTable[Index].Msr,\r
1770 WorkingFixedSettings.Mtrr[Index]\r
1771 );\r
1772 }\r
1773 }\r
1774\r
1775 //\r
1776 // Write variable MTRRs\r
1777 //\r
1778 if (ProgramVariableSettings) {\r
1779 for (Index = 0; Index < VariableMtrrCount; Index++) {\r
1780 if (WorkingVariableSettings.Mtrr[Index].Base != OriginalVariableSettings.Mtrr[Index].Base ||\r
1781 WorkingVariableSettings.Mtrr[Index].Mask != OriginalVariableSettings.Mtrr[Index].Mask ) {\r
1782 if (!MtrrContextValid) {\r
1783 PreMtrrChange (&MtrrContext);\r
1784 MtrrContextValid = TRUE;\r
1785 }\r
1786 MtrrRegisterWrite (\r
1787 QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSBASE0 + (Index << 1),\r
1788 WorkingVariableSettings.Mtrr[Index].Base\r
1789 );\r
1790 MtrrRegisterWrite (\r
1791 QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSBASE0 + (Index << 1) + 1,\r
1792 WorkingVariableSettings.Mtrr[Index].Mask\r
1793 );\r
1794 }\r
1795 }\r
1796 }\r
1797 if (MtrrContextValid) {\r
1798 PostMtrrChange (&MtrrContext);\r
1799 }\r
1800\r
1801 DEBUG((DEBUG_CACHE, " Status = %r\n", Status));\r
1802 if (!RETURN_ERROR (Status)) {\r
1803 if (MtrrSetting != NULL) {\r
1804 MtrrSetting->MtrrDefType |= MTRR_LIB_CACHE_MTRR_ENABLED;\r
1805 }\r
1806 MtrrDebugPrintAllMtrrsWorker (MtrrSetting);\r
1807 }\r
1808\r
1809 return Status;\r
1810}\r
1811\r
1812/**\r
1813 This function attempts to set the attributes for a memory range.\r
1814\r
1815 @param[in] BaseAddress The physical address that is the start\r
1816 address of a memory region.\r
1817 @param[in] Length The size in bytes of the memory region.\r
1818 @param[in] Attributes The bit mask of attributes to set for the\r
1819 memory region.\r
1820\r
1821 @retval RETURN_SUCCESS The attributes were set for the memory\r
1822 region.\r
1823 @retval RETURN_INVALID_PARAMETER Length is zero.\r
1824 @retval RETURN_UNSUPPORTED The processor does not support one or\r
1825 more bytes of the memory resource range\r
1826 specified by BaseAddress and Length.\r
1827 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support\r
1828 for the memory resource range specified\r
1829 by BaseAddress and Length.\r
1830 @retval RETURN_ACCESS_DENIED The attributes for the memory resource\r
1831 range specified by BaseAddress and Length\r
1832 cannot be modified.\r
1833 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to\r
1834 modify the attributes of the memory\r
1835 resource range.\r
1836\r
1837**/\r
1838RETURN_STATUS\r
1839EFIAPI\r
1840MtrrSetMemoryAttribute (\r
1841 IN PHYSICAL_ADDRESS BaseAddress,\r
1842 IN UINT64 Length,\r
1843 IN MTRR_MEMORY_CACHE_TYPE Attribute\r
1844 )\r
1845{\r
1846 DEBUG((DEBUG_CACHE, "MtrrSetMemoryAttribute() %a:%016lx-%016lx\n", mMtrrMemoryCacheTypeShortName[Attribute], BaseAddress, Length));\r
1847 return MtrrSetMemoryAttributeWorker (\r
1848 NULL,\r
1849 BaseAddress,\r
1850 Length,\r
1851 Attribute\r
1852 );\r
1853}\r
1854\r
1855/**\r
1856 This function attempts to set the attributes into MTRR setting buffer for a memory range.\r
1857\r
1858 @param[in, out] MtrrSetting MTRR setting buffer to be set.\r
1859 @param[in] BaseAddress The physical address that is the start address\r
1860 of a memory region.\r
1861 @param[in] Length The size in bytes of the memory region.\r
1862 @param[in] Attribute The bit mask of attributes to set for the\r
1863 memory region.\r
1864\r
1865 @retval RETURN_SUCCESS The attributes were set for the memory region.\r
1866 @retval RETURN_INVALID_PARAMETER Length is zero.\r
1867 @retval RETURN_UNSUPPORTED The processor does not support one or more bytes of the\r
1868 memory resource range specified by BaseAddress and Length.\r
1869 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support for the memory resource\r
1870 range specified by BaseAddress and Length.\r
1871 @retval RETURN_ACCESS_DENIED The attributes for the memory resource range specified by\r
1872 BaseAddress and Length cannot be modified.\r
1873 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of\r
1874 the memory resource range.\r
1875\r
1876**/\r
1877RETURN_STATUS\r
1878EFIAPI\r
1879MtrrSetMemoryAttributeInMtrrSettings (\r
1880 IN OUT MTRR_SETTINGS *MtrrSetting,\r
1881 IN PHYSICAL_ADDRESS BaseAddress,\r
1882 IN UINT64 Length,\r
1883 IN MTRR_MEMORY_CACHE_TYPE Attribute\r
1884 )\r
1885{\r
1886 DEBUG((DEBUG_CACHE, "MtrrSetMemoryAttributeMtrrSettings(%p) %a:%016lx-%016lx\n", MtrrSetting, mMtrrMemoryCacheTypeShortName[Attribute], BaseAddress, Length));\r
1887 return MtrrSetMemoryAttributeWorker (\r
1888 MtrrSetting,\r
1889 BaseAddress,\r
1890 Length,\r
1891 Attribute\r
1892 );\r
1893}\r
1894\r
1895/**\r
1896 Worker function setting variable MTRRs\r
1897\r
1898 @param[in] VariableSettings A buffer to hold variable MTRRs content.\r
1899\r
1900**/\r
1901VOID\r
1902MtrrSetVariableMtrrWorker (\r
1903 IN MTRR_VARIABLE_SETTINGS *VariableSettings\r
1904 )\r
1905{\r
1906 UINT32 Index;\r
1907 UINT32 VariableMtrrCount;\r
1908\r
1909 VariableMtrrCount = GetVariableMtrrCountWorker ();\r
1910 ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);\r
1911\r
1912 for (Index = 0; Index < VariableMtrrCount; Index++) {\r
1913 MtrrRegisterWrite (\r
1914 QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSBASE0 + (Index << 1),\r
1915 VariableSettings->Mtrr[Index].Base\r
1916 );\r
1917 MtrrRegisterWrite (\r
1918 QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSBASE0 + (Index << 1) + 1,\r
1919 VariableSettings->Mtrr[Index].Mask\r
1920 );\r
1921 }\r
1922}\r
1923\r
1924\r
1925/**\r
1926 This function sets variable MTRRs\r
1927\r
1928 @param[in] VariableSettings A buffer to hold variable MTRRs content.\r
1929\r
1930 @return The pointer of VariableSettings\r
1931\r
1932**/\r
1933MTRR_VARIABLE_SETTINGS*\r
1934EFIAPI\r
1935MtrrSetVariableMtrr (\r
1936 IN MTRR_VARIABLE_SETTINGS *VariableSettings\r
1937 )\r
1938{\r
1939 MTRR_CONTEXT MtrrContext;\r
1940\r
1941 if (!IsMtrrSupported ()) {\r
1942 return VariableSettings;\r
1943 }\r
1944\r
1945 PreMtrrChange (&MtrrContext);\r
1946 MtrrSetVariableMtrrWorker (VariableSettings);\r
1947 PostMtrrChange (&MtrrContext);\r
1948 MtrrDebugPrintAllMtrrs ();\r
1949\r
1950 return VariableSettings;\r
1951}\r
1952\r
1953/**\r
1954 Worker function setting fixed MTRRs\r
1955\r
1956 @param[in] FixedSettings A buffer to hold fixed MTRRs content.\r
1957\r
1958**/\r
1959VOID\r
1960MtrrSetFixedMtrrWorker (\r
1961 IN MTRR_FIXED_SETTINGS *FixedSettings\r
1962 )\r
1963{\r
1964 UINT32 Index;\r
1965\r
1966 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
1967 MtrrRegisterWrite (\r
1968 mMtrrLibFixedMtrrTable[Index].Msr,\r
1969 FixedSettings->Mtrr[Index]\r
1970 );\r
1971 }\r
1972}\r
1973\r
1974\r
1975/**\r
1976 This function sets fixed MTRRs\r
1977\r
1978 @param[in] FixedSettings A buffer to hold fixed MTRRs content.\r
1979\r
1980 @retval The pointer of FixedSettings\r
1981\r
1982**/\r
1983MTRR_FIXED_SETTINGS*\r
1984EFIAPI\r
1985MtrrSetFixedMtrr (\r
1986 IN MTRR_FIXED_SETTINGS *FixedSettings\r
1987 )\r
1988{\r
1989 MTRR_CONTEXT MtrrContext;\r
1990\r
1991 if (!IsMtrrSupported ()) {\r
1992 return FixedSettings;\r
1993 }\r
1994\r
1995 PreMtrrChange (&MtrrContext);\r
1996 MtrrSetFixedMtrrWorker (FixedSettings);\r
1997 PostMtrrChange (&MtrrContext);\r
1998 MtrrDebugPrintAllMtrrs ();\r
1999\r
2000 return FixedSettings;\r
2001}\r
2002\r
2003\r
2004/**\r
2005 This function gets the content in all MTRRs (variable and fixed)\r
2006\r
2007 @param[out] MtrrSetting A buffer to hold all MTRRs content.\r
2008\r
2009 @retval the pointer of MtrrSetting\r
2010\r
2011**/\r
2012MTRR_SETTINGS *\r
2013EFIAPI\r
2014MtrrGetAllMtrrs (\r
2015 OUT MTRR_SETTINGS *MtrrSetting\r
2016 )\r
2017{\r
2018 if (!IsMtrrSupported ()) {\r
2019 return MtrrSetting;\r
2020 }\r
2021\r
2022 //\r
2023 // Get fixed MTRRs\r
2024 //\r
2025 MtrrGetFixedMtrrWorker (&MtrrSetting->Fixed);\r
2026\r
2027 //\r
2028 // Get variable MTRRs\r
2029 //\r
2030 MtrrGetVariableMtrrWorker (\r
2031 NULL,\r
2032 GetVariableMtrrCountWorker (),\r
2033 &MtrrSetting->Variables\r
2034 );\r
2035\r
2036 //\r
2037 // Get MTRR_DEF_TYPE value\r
2038 //\r
2039 MtrrSetting->MtrrDefType = MtrrRegisterRead (QUARK_NC_HOST_BRIDGE_IA32_MTRR_DEF_TYPE);\r
2040\r
2041 return MtrrSetting;\r
2042}\r
2043\r
2044\r
2045/**\r
2046 This function sets all MTRRs (variable and fixed)\r
2047\r
2048 @param[in] MtrrSetting A buffer holding all MTRRs content.\r
2049\r
2050 @retval The pointer of MtrrSetting\r
2051\r
2052**/\r
2053MTRR_SETTINGS *\r
2054EFIAPI\r
2055MtrrSetAllMtrrs (\r
2056 IN MTRR_SETTINGS *MtrrSetting\r
2057 )\r
2058{\r
2059 MTRR_CONTEXT MtrrContext;\r
2060\r
2061 if (!IsMtrrSupported ()) {\r
2062 return MtrrSetting;\r
2063 }\r
2064\r
2065 PreMtrrChange (&MtrrContext);\r
2066\r
2067 //\r
2068 // Set fixed MTRRs\r
2069 //\r
2070 MtrrSetFixedMtrrWorker (&MtrrSetting->Fixed);\r
2071\r
2072 //\r
2073 // Set variable MTRRs\r
2074 //\r
2075 MtrrSetVariableMtrrWorker (&MtrrSetting->Variables);\r
2076\r
2077 //\r
2078 // Set MTRR_DEF_TYPE value\r
2079 //\r
2080 MtrrRegisterWrite (QUARK_NC_HOST_BRIDGE_IA32_MTRR_DEF_TYPE, MtrrSetting->MtrrDefType);\r
2081\r
2082 PostMtrrChangeEnableCache (&MtrrContext);\r
2083\r
2084 MtrrDebugPrintAllMtrrs ();\r
2085\r
2086 return MtrrSetting;\r
2087}\r
2088\r
2089\r
2090/**\r
2091 Checks if MTRR is supported.\r
2092\r
2093 @retval TRUE MTRR is supported.\r
2094 @retval FALSE MTRR is not supported.\r
2095\r
2096**/\r
2097BOOLEAN\r
2098EFIAPI\r
2099IsMtrrSupported (\r
2100 VOID\r
2101 )\r
2102{\r
2103 UINT32 RegEax;\r
2104\r
2105 //\r
2106 // Check CPUID(1).EAX[0..11] for Quark SoC\r
2107 //\r
2108 AsmCpuid (1, &RegEax, NULL, NULL, NULL);\r
2109 if ((RegEax & 0xfff) == QUARK_SOC_CPUID_FAMILY_MODEL_STEPPING) {\r
2110 return TRUE;\r
2111 }\r
2112\r
2113 return FALSE;\r
2114}\r