QuarkSocPkg/QncSmmDispatcher: Fix context passed to SMI handlers
[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
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
585 @return The return value of this paramter indicates the\r
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
1039\r
1040 *MtrrValidBitsMask = LShiftU64 (1, PhysicalAddressBits) - 1;\r
1041 *MtrrValidAddressMask = *MtrrValidBitsMask & 0xfffffffffffff000ULL;\r
1042 } else {\r
1043 *MtrrValidBitsMask = MTRR_LIB_MSR_VALID_MASK;\r
1044 *MtrrValidAddressMask = MTRR_LIB_CACHE_VALID_ADDRESS;\r
1045 }\r
1046}\r
1047\r
1048\r
1049/**\r
1050 Determines the real attribute of a memory range.\r
1051\r
1052 This function is to arbitrate the real attribute of the memory when\r
1053 there are 2 MTRRs covers the same memory range. For further details,\r
1054 please refer the IA32 Software Developer's Manual, Volume 3,\r
1055 Section 10.11.4.1.\r
1056\r
1057 @param[in] MtrrType1 The first kind of Memory type\r
1058 @param[in] MtrrType2 The second kind of memory type\r
1059\r
1060**/\r
1061UINT64\r
1062MtrrPrecedence (\r
1063 IN UINT64 MtrrType1,\r
1064 IN UINT64 MtrrType2\r
1065 )\r
1066{\r
1067 UINT64 MtrrType;\r
1068\r
1069 MtrrType = MTRR_CACHE_INVALID_TYPE;\r
1070 switch (MtrrType1) {\r
1071 case MTRR_CACHE_UNCACHEABLE:\r
1072 MtrrType = MTRR_CACHE_UNCACHEABLE;\r
1073 break;\r
1074 case MTRR_CACHE_WRITE_COMBINING:\r
1075 if (\r
1076 MtrrType2==MTRR_CACHE_WRITE_COMBINING ||\r
1077 MtrrType2==MTRR_CACHE_UNCACHEABLE\r
1078 ) {\r
1079 MtrrType = MtrrType2;\r
1080 }\r
1081 break;\r
1082 case MTRR_CACHE_WRITE_THROUGH:\r
1083 if (\r
1084 MtrrType2==MTRR_CACHE_WRITE_THROUGH ||\r
1085 MtrrType2==MTRR_CACHE_WRITE_BACK\r
1086 ) {\r
1087 MtrrType = MTRR_CACHE_WRITE_THROUGH;\r
1088 } else if(MtrrType2==MTRR_CACHE_UNCACHEABLE) {\r
1089 MtrrType = MTRR_CACHE_UNCACHEABLE;\r
1090 }\r
1091 break;\r
1092 case MTRR_CACHE_WRITE_PROTECTED:\r
1093 if (MtrrType2 == MTRR_CACHE_WRITE_PROTECTED ||\r
1094 MtrrType2 == MTRR_CACHE_UNCACHEABLE) {\r
1095 MtrrType = MtrrType2;\r
1096 }\r
1097 break;\r
1098 case MTRR_CACHE_WRITE_BACK:\r
1099 if (\r
1100 MtrrType2== MTRR_CACHE_UNCACHEABLE ||\r
1101 MtrrType2==MTRR_CACHE_WRITE_THROUGH ||\r
1102 MtrrType2== MTRR_CACHE_WRITE_BACK\r
1103 ) {\r
1104 MtrrType = MtrrType2;\r
1105 }\r
1106 break;\r
1107 case MTRR_CACHE_INVALID_TYPE:\r
1108 MtrrType = MtrrType2;\r
1109 break;\r
1110 default:\r
1111 break;\r
1112 }\r
1113\r
1114 if (MtrrType2 == MTRR_CACHE_INVALID_TYPE) {\r
1115 MtrrType = MtrrType1;\r
1116 }\r
1117 return MtrrType;\r
1118}\r
1119\r
1120/**\r
1121 Worker function will get the memory cache type of the specific address.\r
1122\r
1123 If MtrrSetting is not NULL, gets the memory cache type from input\r
1124 MTRR settings buffer.\r
1125 If MtrrSetting is NULL, gets the memory cache type from MTRRs.\r
1126\r
1127 @param[in] MtrrSetting A buffer holding all MTRRs content.\r
1128 @param[in] Address The specific address\r
1129\r
1130 @return Memory cache type of the specific address\r
1131\r
1132**/\r
1133MTRR_MEMORY_CACHE_TYPE\r
1134MtrrGetMemoryAttributeByAddressWorker (\r
1135 IN MTRR_SETTINGS *MtrrSetting,\r
1136 IN PHYSICAL_ADDRESS Address\r
1137 )\r
1138{\r
1139 UINT64 TempQword;\r
1140 UINTN Index;\r
1141 UINTN SubIndex;\r
1142 UINT64 MtrrType;\r
1143 UINT64 TempMtrrType;\r
1144 MTRR_MEMORY_CACHE_TYPE CacheType;\r
1145 VARIABLE_MTRR VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];\r
1146 UINT64 MtrrValidBitsMask;\r
1147 UINT64 MtrrValidAddressMask;\r
1148 UINTN VariableMtrrCount;\r
1149 MTRR_VARIABLE_SETTINGS VariableSettings;\r
1150\r
1151 //\r
1152 // Check if MTRR is enabled, if not, return UC as attribute\r
1153 //\r
1154 if (MtrrSetting == NULL) {\r
1155 TempQword = MtrrRegisterRead (QUARK_NC_HOST_BRIDGE_IA32_MTRR_DEF_TYPE);\r
1156 } else {\r
1157 TempQword = MtrrSetting->MtrrDefType;\r
1158 }\r
1159 MtrrType = MTRR_CACHE_INVALID_TYPE;\r
1160\r
1161 if ((TempQword & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
1162 return CacheUncacheable;\r
1163 }\r
1164\r
1165 //\r
1166 // If address is less than 1M, then try to go through the fixed MTRR\r
1167 //\r
1168 if (Address < BASE_1MB) {\r
1169 if ((TempQword & MTRR_LIB_CACHE_FIXED_MTRR_ENABLED) != 0) {\r
1170 //\r
1171 // Go through the fixed MTRR\r
1172 //\r
1173 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
1174 if (Address >= mMtrrLibFixedMtrrTable[Index].BaseAddress &&\r
1175 Address < (\r
1176 mMtrrLibFixedMtrrTable[Index].BaseAddress +\r
1177 (mMtrrLibFixedMtrrTable[Index].Length * 8)\r
1178 )\r
1179 ) {\r
1180 SubIndex =\r
1181 ((UINTN)Address - mMtrrLibFixedMtrrTable[Index].BaseAddress) /\r
1182 mMtrrLibFixedMtrrTable[Index].Length;\r
1183 if (MtrrSetting == NULL) {\r
1184 TempQword = MtrrRegisterRead (mMtrrLibFixedMtrrTable[Index].Msr);\r
1185 } else {\r
1186 TempQword = MtrrSetting->Fixed.Mtrr[Index];\r
1187 }\r
1188 MtrrType = RShiftU64 (TempQword, SubIndex * 8) & 0xFF;\r
1189 return GetMemoryCacheTypeFromMtrrType (MtrrSetting, MtrrType);\r
1190 }\r
1191 }\r
1192 }\r
1193 }\r
1194 MtrrLibInitializeMtrrMask(&MtrrValidBitsMask, &MtrrValidAddressMask);\r
1195\r
1196 MtrrGetVariableMtrrWorker (\r
1197 MtrrSetting,\r
1198 GetVariableMtrrCountWorker (),\r
1199 &VariableSettings\r
1200 );\r
1201\r
1202 MtrrGetMemoryAttributeInVariableMtrrWorker (\r
1203 &VariableSettings,\r
1204 GetFirmwareVariableMtrrCountWorker (),\r
1205 MtrrValidBitsMask,\r
1206 MtrrValidAddressMask,\r
1207 VariableMtrr\r
1208 );\r
1209\r
1210 //\r
1211 // Go through the variable MTRR\r
1212 //\r
1213 VariableMtrrCount = GetVariableMtrrCountWorker ();\r
1214 ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);\r
1215\r
1216 for (Index = 0; Index < VariableMtrrCount; Index++) {\r
1217 if (VariableMtrr[Index].Valid) {\r
1218 if (Address >= VariableMtrr[Index].BaseAddress &&\r
1219 Address < VariableMtrr[Index].BaseAddress+VariableMtrr[Index].Length) {\r
1220 TempMtrrType = VariableMtrr[Index].Type;\r
1221 MtrrType = MtrrPrecedence (MtrrType, TempMtrrType);\r
1222 }\r
1223 }\r
1224 }\r
1225 CacheType = GetMemoryCacheTypeFromMtrrType (MtrrSetting, MtrrType);\r
1226\r
1227 return CacheType;\r
1228}\r
1229\r
1230\r
1231/**\r
1232 This function will get the memory cache type of the specific address.\r
1233\r
1234 This function is mainly for debug purpose.\r
1235\r
1236 @param[in] Address The specific address\r
1237\r
1238 @return Memory cache type of the specific address\r
1239\r
1240**/\r
1241MTRR_MEMORY_CACHE_TYPE\r
1242EFIAPI\r
1243MtrrGetMemoryAttribute (\r
1244 IN PHYSICAL_ADDRESS Address\r
1245 )\r
1246{\r
1247 if (!IsMtrrSupported ()) {\r
1248 return CacheUncacheable;\r
1249 }\r
1250\r
1251 return MtrrGetMemoryAttributeByAddressWorker (NULL, Address);\r
1252}\r
1253\r
1254/**\r
1255 Worker function prints all MTRRs for debugging.\r
1256\r
1257 If MtrrSetting is not NULL, print MTRR settings from from input MTRR\r
1258 settings buffer.\r
1259 If MtrrSetting is NULL, print MTRR settings from MTRRs.\r
1260\r
1261 @param MtrrSetting A buffer holding all MTRRs content.\r
1262**/\r
1263VOID\r
1264MtrrDebugPrintAllMtrrsWorker (\r
1265 IN MTRR_SETTINGS *MtrrSetting\r
1266 )\r
1267{\r
1268 DEBUG_CODE (\r
1269 MTRR_SETTINGS LocalMtrrs;\r
1270 MTRR_SETTINGS *Mtrrs;\r
1271 UINTN Index;\r
1272 UINTN Index1;\r
1273 UINTN VariableMtrrCount;\r
1274 UINT64 Base;\r
1275 UINT64 Limit;\r
1276 UINT64 MtrrBase;\r
1277 UINT64 MtrrLimit;\r
1278 UINT64 RangeBase;\r
1279 UINT64 RangeLimit;\r
1280 UINT64 NoRangeBase;\r
1281 UINT64 NoRangeLimit;\r
1282 UINT32 RegEax;\r
1283 UINTN MemoryType;\r
1284 UINTN PreviousMemoryType;\r
1285 BOOLEAN Found;\r
1286\r
1287 if (!IsMtrrSupported ()) {\r
1288 return;\r
1289 }\r
1290\r
1291 DEBUG((DEBUG_CACHE, "MTRR Settings\n"));\r
1292 DEBUG((DEBUG_CACHE, "=============\n"));\r
1293\r
1294 if (MtrrSetting != NULL) {\r
1295 Mtrrs = MtrrSetting;\r
1296 } else {\r
1297 MtrrGetAllMtrrs (&LocalMtrrs);\r
1298 Mtrrs = &LocalMtrrs;\r
1299 }\r
1300\r
1301 DEBUG((DEBUG_CACHE, "MTRR Default Type: %016lx\n", Mtrrs->MtrrDefType));\r
1302 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
1303 DEBUG((DEBUG_CACHE, "Fixed MTRR[%02d] : %016lx\n", Index, Mtrrs->Fixed.Mtrr[Index]));\r
1304 }\r
1305\r
1306 VariableMtrrCount = GetVariableMtrrCount ();\r
1307 for (Index = 0; Index < VariableMtrrCount; Index++) {\r
1308 DEBUG((DEBUG_CACHE, "Variable MTRR[%02d]: Base=%016lx Mask=%016lx\n",\r
1309 Index,\r
1310 Mtrrs->Variables.Mtrr[Index].Base,\r
1311 Mtrrs->Variables.Mtrr[Index].Mask\r
1312 ));\r
1313 }\r
1314 DEBUG((DEBUG_CACHE, "\n"));\r
1315 DEBUG((DEBUG_CACHE, "MTRR Ranges\n"));\r
1316 DEBUG((DEBUG_CACHE, "====================================\n"));\r
1317\r
1318 Base = 0;\r
1319 PreviousMemoryType = MTRR_CACHE_INVALID_TYPE;\r
1320 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
1321 Base = mMtrrLibFixedMtrrTable[Index].BaseAddress;\r
1322 for (Index1 = 0; Index1 < 8; Index1++) {\r
1323 MemoryType = (UINTN)(RShiftU64 (Mtrrs->Fixed.Mtrr[Index], Index1 * 8) & 0xff);\r
1324 if (MemoryType > CacheWriteBack) {\r
1325 MemoryType = MTRR_CACHE_INVALID_TYPE;\r
1326 }\r
1327 if (MemoryType != PreviousMemoryType) {\r
1328 if (PreviousMemoryType != MTRR_CACHE_INVALID_TYPE) {\r
1329 DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));\r
1330 }\r
1331 PreviousMemoryType = MemoryType;\r
1332 DEBUG((DEBUG_CACHE, "%a:%016lx-", mMtrrMemoryCacheTypeShortName[MemoryType], Base));\r
1333 }\r
1334 Base += mMtrrLibFixedMtrrTable[Index].Length;\r
1335 }\r
1336 }\r
1337 DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));\r
1338\r
1339 VariableMtrrCount = GetVariableMtrrCount ();\r
1340\r
1341 Limit = BIT36 - 1;\r
1342 AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);\r
1343 if (RegEax >= 0x80000008) {\r
1344 AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);\r
1345 Limit = LShiftU64 (1, RegEax & 0xff) - 1;\r
1346 }\r
1347 Base = BASE_1MB;\r
1348 PreviousMemoryType = MTRR_CACHE_INVALID_TYPE;\r
1349 do {\r
1350 MemoryType = MtrrGetMemoryAttributeByAddressWorker (Mtrrs, Base);\r
1351 if (MemoryType > CacheWriteBack) {\r
1352 MemoryType = MTRR_CACHE_INVALID_TYPE;\r
1353 }\r
1354\r
1355 if (MemoryType != PreviousMemoryType) {\r
1356 if (PreviousMemoryType != MTRR_CACHE_INVALID_TYPE) {\r
1357 DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));\r
1358 }\r
1359 PreviousMemoryType = MemoryType;\r
1360 DEBUG((DEBUG_CACHE, "%a:%016lx-", mMtrrMemoryCacheTypeShortName[MemoryType], Base));\r
1361 }\r
1362\r
1363 RangeBase = BASE_1MB;\r
1364 NoRangeBase = BASE_1MB;\r
1365 RangeLimit = Limit;\r
1366 NoRangeLimit = Limit;\r
1367\r
1368 for (Index = 0, Found = FALSE; Index < VariableMtrrCount; Index++) {\r
1369 if ((Mtrrs->Variables.Mtrr[Index].Mask & BIT11) == 0) {\r
1370 //\r
1371 // If mask is not valid, then do not display range\r
1372 //\r
1373 continue;\r
1374 }\r
1375 MtrrBase = (Mtrrs->Variables.Mtrr[Index].Base & (~(SIZE_4KB - 1)));\r
1376 MtrrLimit = MtrrBase + ((~(Mtrrs->Variables.Mtrr[Index].Mask & (~(SIZE_4KB - 1)))) & Limit);\r
1377\r
1378 if (Base >= MtrrBase && Base < MtrrLimit) {\r
1379 Found = TRUE;\r
1380 }\r
1381\r
1382 if (Base >= MtrrBase && MtrrBase > RangeBase) {\r
1383 RangeBase = MtrrBase;\r
1384 }\r
1385 if (Base > MtrrLimit && MtrrLimit > RangeBase) {\r
1386 RangeBase = MtrrLimit + 1;\r
1387 }\r
1388 if (Base < MtrrBase && MtrrBase < RangeLimit) {\r
1389 RangeLimit = MtrrBase - 1;\r
1390 }\r
1391 if (Base < MtrrLimit && MtrrLimit <= RangeLimit) {\r
1392 RangeLimit = MtrrLimit;\r
1393 }\r
1394\r
1395 if (Base > MtrrLimit && NoRangeBase < MtrrLimit) {\r
1396 NoRangeBase = MtrrLimit + 1;\r
1397 }\r
1398 if (Base < MtrrBase && NoRangeLimit > MtrrBase) {\r
1399 NoRangeLimit = MtrrBase - 1;\r
1400 }\r
1401 }\r
1402\r
1403 if (Found) {\r
1404 Base = RangeLimit + 1;\r
1405 } else {\r
1406 Base = NoRangeLimit + 1;\r
1407 }\r
1408 } while (Base < Limit);\r
1409 DEBUG((DEBUG_CACHE, "%016lx\n\n", Base - 1));\r
1410 );\r
1411}\r
1412\r
1413\r
1414/**\r
1415 This function prints all MTRRs for debugging.\r
1416**/\r
1417VOID\r
1418EFIAPI\r
1419MtrrDebugPrintAllMtrrs (\r
1420 VOID\r
1421 )\r
1422{\r
1423 MtrrDebugPrintAllMtrrsWorker (NULL);\r
1424}\r
1425\r
1426\r
1427/**\r
1428 Worker function attempts to set the attributes for a memory range.\r
1429\r
1430 If MtrrSettings is not NULL, set the attributes into the input MTRR\r
1431 settings buffer.\r
1432 If MtrrSettings is NULL, set the attributes into MTRRs registers.\r
1433\r
1434 @param[in, out] MtrrSetting A buffer holding all MTRRs content.\r
1435 @param[in] BaseAddress The physical address that is the start\r
1436 address of a memory region.\r
1437 @param[in] Length The size in bytes of the memory region.\r
1438 @param[in] Attribute The bit mask of attributes to set for the\r
1439 memory region.\r
1440\r
1441 @retval RETURN_SUCCESS The attributes were set for the memory\r
1442 region.\r
1443 @retval RETURN_INVALID_PARAMETER Length is zero.\r
1444 @retval RETURN_UNSUPPORTED The processor does not support one or\r
1445 more bytes of the memory resource range\r
1446 specified by BaseAddress and Length.\r
1447 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support\r
1448 for the memory resource range specified\r
1449 by BaseAddress and Length.\r
1450 @retval RETURN_ACCESS_DENIED The attributes for the memory resource\r
1451 range specified by BaseAddress and Length\r
1452 cannot be modified.\r
1453 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to\r
1454 modify the attributes of the memory\r
1455 resource range.\r
1456\r
1457**/\r
1458RETURN_STATUS\r
1459MtrrSetMemoryAttributeWorker (\r
1460 IN OUT MTRR_SETTINGS *MtrrSetting,\r
1461 IN PHYSICAL_ADDRESS BaseAddress,\r
1462 IN UINT64 Length,\r
1463 IN MTRR_MEMORY_CACHE_TYPE Attribute\r
1464 )\r
1465{\r
1466 UINT64 TempQword;\r
1467 RETURN_STATUS Status;\r
1468 UINT64 MemoryType;\r
1469 UINT64 Alignment;\r
1470 BOOLEAN OverLap;\r
1471 BOOLEAN Positive;\r
1472 UINT32 MsrNum;\r
1473 UINTN MtrrNumber;\r
1474 VARIABLE_MTRR VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];\r
1475 UINT32 UsedMtrr;\r
1476 UINT64 MtrrValidBitsMask;\r
1477 UINT64 MtrrValidAddressMask;\r
1478 BOOLEAN OverwriteExistingMtrr;\r
1479 UINT32 FirmwareVariableMtrrCount;\r
1480 MTRR_CONTEXT MtrrContext;\r
1481 BOOLEAN MtrrContextValid;\r
1482 BOOLEAN FixedSettingsValid[MTRR_NUMBER_OF_FIXED_MTRR];\r
1483 BOOLEAN FixedSettingsModified[MTRR_NUMBER_OF_FIXED_MTRR];\r
1484 MTRR_FIXED_SETTINGS WorkingFixedSettings;\r
1485 UINT32 VariableMtrrCount;\r
1486 MTRR_VARIABLE_SETTINGS OriginalVariableSettings;\r
1487 BOOLEAN ProgramVariableSettings;\r
1488 MTRR_VARIABLE_SETTINGS WorkingVariableSettings;\r
1489 UINT32 Index;\r
1490 UINT64 ClearMask;\r
1491 UINT64 OrMask;\r
1492 UINT64 NewValue;\r
1493 MTRR_VARIABLE_SETTINGS *VariableSettings;\r
1494\r
1495 MtrrContextValid = FALSE;\r
1496 VariableMtrrCount = 0;\r
1497 ZeroMem (&WorkingFixedSettings, sizeof (WorkingFixedSettings));\r
1498 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
1499 FixedSettingsValid[Index] = FALSE;\r
1500 FixedSettingsModified[Index] = FALSE;\r
1501 }\r
1502 ProgramVariableSettings = FALSE;\r
1503\r
1504 if (!IsMtrrSupported ()) {\r
1505 Status = RETURN_UNSUPPORTED;\r
1506 goto Done;\r
1507 }\r
1508\r
1509 MtrrLibInitializeMtrrMask (&MtrrValidBitsMask, &MtrrValidAddressMask);\r
1510\r
1511 TempQword = 0;\r
1512 MemoryType = (UINT64)Attribute;\r
1513 OverwriteExistingMtrr = FALSE;\r
1514\r
1515 //\r
1516 // Check for an invalid parameter\r
1517 //\r
1518 if (Length == 0) {\r
1519 Status = RETURN_INVALID_PARAMETER;\r
1520 goto Done;\r
1521 }\r
1522\r
1523 if (\r
1524 (BaseAddress & ~MtrrValidAddressMask) != 0 ||\r
1525 (Length & ~MtrrValidAddressMask) != 0\r
1526 ) {\r
1527 Status = RETURN_UNSUPPORTED;\r
1528 goto Done;\r
1529 }\r
1530\r
1531 //\r
1532 // Check if Fixed MTRR\r
1533 //\r
1534 Status = RETURN_SUCCESS;\r
1535 if (BaseAddress < BASE_1MB) {\r
1536 while ((BaseAddress < BASE_1MB) && (Length > 0) && Status == RETURN_SUCCESS) {\r
1537 Status = ProgramFixedMtrr (MemoryType, &BaseAddress, &Length, &MsrNum, &ClearMask, &OrMask);\r
1538 if (RETURN_ERROR (Status)) {\r
1539 goto Done;\r
1540 }\r
1541 if (MtrrSetting != NULL) {\r
1542 MtrrSetting->Fixed.Mtrr[MsrNum] = (MtrrSetting->Fixed.Mtrr[MsrNum] & ~ClearMask) | OrMask;\r
1543 MtrrSetting->MtrrDefType |= MTRR_LIB_CACHE_FIXED_MTRR_ENABLED;\r
1544 } else {\r
1545 if (!FixedSettingsValid[MsrNum]) {\r
1546 WorkingFixedSettings.Mtrr[MsrNum] = MtrrRegisterRead (mMtrrLibFixedMtrrTable[MsrNum].Msr);\r
1547 FixedSettingsValid[MsrNum] = TRUE;\r
1548 }\r
1549 NewValue = (WorkingFixedSettings.Mtrr[MsrNum] & ~ClearMask) | OrMask;\r
1550 if (WorkingFixedSettings.Mtrr[MsrNum] != NewValue) {\r
1551 WorkingFixedSettings.Mtrr[MsrNum] = NewValue;\r
1552 FixedSettingsModified[MsrNum] = TRUE;\r
1553 }\r
1554 }\r
1555 }\r
1556\r
1557 if (Length == 0) {\r
1558 //\r
1559 // A Length of 0 can only make sense for fixed MTTR ranges.\r
1560 // Since we just handled the fixed MTRRs, we can skip the\r
1561 // variable MTRR section.\r
1562 //\r
1563 goto Done;\r
1564 }\r
1565 }\r
1566\r
1567 //\r
1568 // Since memory ranges below 1MB will be overridden by the fixed MTRRs,\r
1569 // we can set the base to 0 to save variable MTRRs.\r
1570 //\r
1571 if (BaseAddress == BASE_1MB) {\r
1572 BaseAddress = 0;\r
1573 Length += SIZE_1MB;\r
1574 }\r
1575\r
1576 //\r
1577 // Read all variable MTRRs\r
1578 //\r
1579 VariableMtrrCount = GetVariableMtrrCountWorker ();\r
1580 FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCountWorker ();\r
1581 if (MtrrSetting != NULL) {\r
1582 VariableSettings = &MtrrSetting->Variables;\r
1583 } else {\r
1584 MtrrGetVariableMtrrWorker (NULL, VariableMtrrCount, &OriginalVariableSettings);\r
1585 CopyMem (&WorkingVariableSettings, &OriginalVariableSettings, sizeof (WorkingVariableSettings));\r
1586 ProgramVariableSettings = TRUE;\r
1587 VariableSettings = &WorkingVariableSettings;\r
1588 }\r
1589\r
1590 //\r
1591 // Check for overlap\r
1592 //\r
1593 UsedMtrr = MtrrGetMemoryAttributeInVariableMtrrWorker (\r
1594 VariableSettings,\r
1595 FirmwareVariableMtrrCount,\r
1596 MtrrValidBitsMask,\r
1597 MtrrValidAddressMask,\r
1598 VariableMtrr\r
1599 );\r
1600 OverLap = CheckMemoryAttributeOverlap (\r
1601 FirmwareVariableMtrrCount,\r
1602 BaseAddress,\r
1603 BaseAddress + Length - 1,\r
1604 VariableMtrr\r
1605 );\r
1606 if (OverLap) {\r
1607 Status = CombineMemoryAttribute (\r
1608 FirmwareVariableMtrrCount,\r
1609 MemoryType,\r
1610 &BaseAddress,\r
1611 &Length,\r
1612 VariableMtrr,\r
1613 &UsedMtrr,\r
1614 &OverwriteExistingMtrr\r
1615 );\r
1616 if (RETURN_ERROR (Status)) {\r
1617 goto Done;\r
1618 }\r
1619\r
1620 if (Length == 0) {\r
1621 //\r
1622 // Combined successfully, invalidate the now-unused MTRRs\r
1623 //\r
1624 InvalidateMtrr (VariableSettings, VariableMtrrCount, VariableMtrr);\r
1625 Status = RETURN_SUCCESS;\r
1626 goto Done;\r
1627 }\r
1628 }\r
1629\r
1630 //\r
1631 // The memory type is the same with the type specified by\r
1632 // MTRR_LIB_IA32_MTRR_DEF_TYPE.\r
1633 //\r
1634 if ((!OverwriteExistingMtrr) && (Attribute == MtrrGetDefaultMemoryType ())) {\r
1635 //\r
1636 // Invalidate the now-unused MTRRs\r
1637 //\r
1638 InvalidateMtrr (VariableSettings, VariableMtrrCount, VariableMtrr);\r
1639 goto Done;\r
1640 }\r
1641\r
1642 Positive = GetMtrrNumberAndDirection (BaseAddress, Length, &MtrrNumber);\r
1643\r
1644 if ((UsedMtrr + MtrrNumber) > FirmwareVariableMtrrCount) {\r
1645 Status = RETURN_OUT_OF_RESOURCES;\r
1646 goto Done;\r
1647 }\r
1648\r
1649 //\r
1650 // Invalidate the now-unused MTRRs\r
1651 //\r
1652 InvalidateMtrr (VariableSettings, VariableMtrrCount, VariableMtrr);\r
1653\r
1654 //\r
1655 // Find first unused MTRR\r
1656 //\r
1657 for (MsrNum = 0; MsrNum < VariableMtrrCount; MsrNum++) {\r
1658 if ((VariableSettings->Mtrr[MsrNum].Mask & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
1659 break;\r
1660 }\r
1661 }\r
1662\r
1663 if (BaseAddress != 0) {\r
1664 do {\r
1665 //\r
1666 // Calculate the alignment of the base address.\r
1667 //\r
1668 Alignment = LShiftU64 (1, (UINTN)LowBitSet64 (BaseAddress));\r
1669\r
1670 if (Alignment > Length) {\r
1671 break;\r
1672 }\r
1673\r
1674 //\r
1675 // Find unused MTRR\r
1676 //\r
1677 for (; MsrNum < VariableMtrrCount; MsrNum++) {\r
1678 if ((VariableSettings->Mtrr[MsrNum].Mask & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
1679 break;\r
1680 }\r
1681 }\r
1682\r
1683 ProgramVariableMtrr (\r
1684 VariableSettings,\r
1685 MsrNum,\r
1686 BaseAddress,\r
1687 Alignment,\r
1688 MemoryType,\r
1689 MtrrValidAddressMask\r
1690 );\r
1691 BaseAddress += Alignment;\r
1692 Length -= Alignment;\r
1693 } while (TRUE);\r
1694\r
1695 if (Length == 0) {\r
1696 goto Done;\r
1697 }\r
1698 }\r
1699\r
1700 TempQword = Length;\r
1701\r
1702 if (!Positive) {\r
1703 Length = Power2MaxMemory (LShiftU64 (TempQword, 1));\r
1704\r
1705 //\r
1706 // Find unused MTRR\r
1707 //\r
1708 for (; MsrNum < VariableMtrrCount; MsrNum++) {\r
1709 if ((VariableSettings->Mtrr[MsrNum].Mask & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
1710 break;\r
1711 }\r
1712 }\r
1713\r
1714 ProgramVariableMtrr (\r
1715 VariableSettings,\r
1716 MsrNum,\r
1717 BaseAddress,\r
1718 Length,\r
1719 MemoryType,\r
1720 MtrrValidAddressMask\r
1721 );\r
1722 BaseAddress += Length;\r
1723 TempQword = Length - TempQword;\r
1724 MemoryType = MTRR_CACHE_UNCACHEABLE;\r
1725 }\r
1726\r
1727 do {\r
1728 //\r
1729 // Find unused MTRR\r
1730 //\r
1731 for (; MsrNum < VariableMtrrCount; MsrNum++) {\r
1732 if ((VariableSettings->Mtrr[MsrNum].Mask & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
1733 break;\r
1734 }\r
1735 }\r
1736\r
1737 Length = Power2MaxMemory (TempQword);\r
1738 if (!Positive) {\r
1739 BaseAddress -= Length;\r
1740 }\r
1741\r
1742 ProgramVariableMtrr (\r
1743 VariableSettings,\r
1744 MsrNum,\r
1745 BaseAddress,\r
1746 Length,\r
1747 MemoryType,\r
1748 MtrrValidAddressMask\r
1749 );\r
1750\r
1751 if (Positive) {\r
1752 BaseAddress += Length;\r
1753 }\r
1754 TempQword -= Length;\r
1755\r
1756 } while (TempQword > 0);\r
1757\r
1758Done:\r
1759\r
1760 //\r
1761 // Write fixed MTRRs that have been modified\r
1762 //\r
1763 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
1764 if (FixedSettingsModified[Index]) {\r
1765 if (!MtrrContextValid) {\r
1766 PreMtrrChange (&MtrrContext);\r
1767 MtrrContextValid = TRUE;\r
1768 }\r
1769 MtrrRegisterWrite (\r
1770 mMtrrLibFixedMtrrTable[Index].Msr,\r
1771 WorkingFixedSettings.Mtrr[Index]\r
1772 );\r
1773 }\r
1774 }\r
1775\r
1776 //\r
1777 // Write variable MTRRs\r
1778 //\r
1779 if (ProgramVariableSettings) {\r
1780 for (Index = 0; Index < VariableMtrrCount; Index++) {\r
1781 if (WorkingVariableSettings.Mtrr[Index].Base != OriginalVariableSettings.Mtrr[Index].Base ||\r
1782 WorkingVariableSettings.Mtrr[Index].Mask != OriginalVariableSettings.Mtrr[Index].Mask ) {\r
1783 if (!MtrrContextValid) {\r
1784 PreMtrrChange (&MtrrContext);\r
1785 MtrrContextValid = TRUE;\r
1786 }\r
1787 MtrrRegisterWrite (\r
1788 QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSBASE0 + (Index << 1),\r
1789 WorkingVariableSettings.Mtrr[Index].Base\r
1790 );\r
1791 MtrrRegisterWrite (\r
1792 QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSBASE0 + (Index << 1) + 1,\r
1793 WorkingVariableSettings.Mtrr[Index].Mask\r
1794 );\r
1795 }\r
1796 }\r
1797 }\r
1798 if (MtrrContextValid) {\r
1799 PostMtrrChange (&MtrrContext);\r
1800 }\r
1801\r
1802 DEBUG((DEBUG_CACHE, " Status = %r\n", Status));\r
1803 if (!RETURN_ERROR (Status)) {\r
1804 if (MtrrSetting != NULL) {\r
1805 MtrrSetting->MtrrDefType |= MTRR_LIB_CACHE_MTRR_ENABLED;\r
1806 }\r
1807 MtrrDebugPrintAllMtrrsWorker (MtrrSetting);\r
1808 }\r
1809\r
1810 return Status;\r
1811}\r
1812\r
1813/**\r
1814 This function attempts to set the attributes for a memory range.\r
1815\r
1816 @param[in] BaseAddress The physical address that is the start\r
1817 address of a memory region.\r
1818 @param[in] Length The size in bytes of the memory region.\r
1819 @param[in] Attributes The bit mask of attributes to set for the\r
1820 memory region.\r
1821\r
1822 @retval RETURN_SUCCESS The attributes were set for the memory\r
1823 region.\r
1824 @retval RETURN_INVALID_PARAMETER Length is zero.\r
1825 @retval RETURN_UNSUPPORTED The processor does not support one or\r
1826 more bytes of the memory resource range\r
1827 specified by BaseAddress and Length.\r
1828 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support\r
1829 for the memory resource range specified\r
1830 by BaseAddress and Length.\r
1831 @retval RETURN_ACCESS_DENIED The attributes for the memory resource\r
1832 range specified by BaseAddress and Length\r
1833 cannot be modified.\r
1834 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to\r
1835 modify the attributes of the memory\r
1836 resource range.\r
1837\r
1838**/\r
1839RETURN_STATUS\r
1840EFIAPI\r
1841MtrrSetMemoryAttribute (\r
1842 IN PHYSICAL_ADDRESS BaseAddress,\r
1843 IN UINT64 Length,\r
1844 IN MTRR_MEMORY_CACHE_TYPE Attribute\r
1845 )\r
1846{\r
1847 DEBUG((DEBUG_CACHE, "MtrrSetMemoryAttribute() %a:%016lx-%016lx\n", mMtrrMemoryCacheTypeShortName[Attribute], BaseAddress, Length));\r
1848 return MtrrSetMemoryAttributeWorker (\r
1849 NULL,\r
1850 BaseAddress,\r
1851 Length,\r
1852 Attribute\r
1853 );\r
1854}\r
1855\r
1856/**\r
1857 This function attempts to set the attributes into MTRR setting buffer for a memory range.\r
1858\r
1859 @param[in, out] MtrrSetting MTRR setting buffer to be set.\r
1860 @param[in] BaseAddress The physical address that is the start address\r
1861 of a memory region.\r
1862 @param[in] Length The size in bytes of the memory region.\r
1863 @param[in] Attribute The bit mask of attributes to set for the\r
1864 memory region.\r
1865\r
1866 @retval RETURN_SUCCESS The attributes were set for the memory region.\r
1867 @retval RETURN_INVALID_PARAMETER Length is zero.\r
1868 @retval RETURN_UNSUPPORTED The processor does not support one or more bytes of the\r
1869 memory resource range specified by BaseAddress and Length.\r
1870 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support for the memory resource\r
1871 range specified by BaseAddress and Length.\r
1872 @retval RETURN_ACCESS_DENIED The attributes for the memory resource range specified by\r
1873 BaseAddress and Length cannot be modified.\r
1874 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of\r
1875 the memory resource range.\r
1876\r
1877**/\r
1878RETURN_STATUS\r
1879EFIAPI\r
1880MtrrSetMemoryAttributeInMtrrSettings (\r
1881 IN OUT MTRR_SETTINGS *MtrrSetting,\r
1882 IN PHYSICAL_ADDRESS BaseAddress,\r
1883 IN UINT64 Length,\r
1884 IN MTRR_MEMORY_CACHE_TYPE Attribute\r
1885 )\r
1886{\r
1887 DEBUG((DEBUG_CACHE, "MtrrSetMemoryAttributeMtrrSettings(%p) %a:%016lx-%016lx\n", MtrrSetting, mMtrrMemoryCacheTypeShortName[Attribute], BaseAddress, Length));\r
1888 return MtrrSetMemoryAttributeWorker (\r
1889 MtrrSetting,\r
1890 BaseAddress,\r
1891 Length,\r
1892 Attribute\r
1893 );\r
1894}\r
1895\r
1896/**\r
1897 Worker function setting variable MTRRs\r
1898\r
1899 @param[in] VariableSettings A buffer to hold variable MTRRs content.\r
1900\r
1901**/\r
1902VOID\r
1903MtrrSetVariableMtrrWorker (\r
1904 IN MTRR_VARIABLE_SETTINGS *VariableSettings\r
1905 )\r
1906{\r
1907 UINT32 Index;\r
1908 UINT32 VariableMtrrCount;\r
1909\r
1910 VariableMtrrCount = GetVariableMtrrCountWorker ();\r
1911 ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);\r
1912\r
1913 for (Index = 0; Index < VariableMtrrCount; Index++) {\r
1914 MtrrRegisterWrite (\r
1915 QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSBASE0 + (Index << 1),\r
1916 VariableSettings->Mtrr[Index].Base\r
1917 );\r
1918 MtrrRegisterWrite (\r
1919 QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSBASE0 + (Index << 1) + 1,\r
1920 VariableSettings->Mtrr[Index].Mask\r
1921 );\r
1922 }\r
1923}\r
1924\r
1925\r
1926/**\r
1927 This function sets variable MTRRs\r
1928\r
1929 @param[in] VariableSettings A buffer to hold variable MTRRs content.\r
1930\r
1931 @return The pointer of VariableSettings\r
1932\r
1933**/\r
1934MTRR_VARIABLE_SETTINGS*\r
1935EFIAPI\r
1936MtrrSetVariableMtrr (\r
1937 IN MTRR_VARIABLE_SETTINGS *VariableSettings\r
1938 )\r
1939{\r
1940 MTRR_CONTEXT MtrrContext;\r
1941\r
1942 if (!IsMtrrSupported ()) {\r
1943 return VariableSettings;\r
1944 }\r
1945\r
1946 PreMtrrChange (&MtrrContext);\r
1947 MtrrSetVariableMtrrWorker (VariableSettings);\r
1948 PostMtrrChange (&MtrrContext);\r
1949 MtrrDebugPrintAllMtrrs ();\r
1950\r
1951 return VariableSettings;\r
1952}\r
1953\r
1954/**\r
1955 Worker function setting fixed MTRRs\r
1956\r
1957 @param[in] FixedSettings A buffer to hold fixed MTRRs content.\r
1958\r
1959**/\r
1960VOID\r
1961MtrrSetFixedMtrrWorker (\r
1962 IN MTRR_FIXED_SETTINGS *FixedSettings\r
1963 )\r
1964{\r
1965 UINT32 Index;\r
1966\r
1967 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
1968 MtrrRegisterWrite (\r
1969 mMtrrLibFixedMtrrTable[Index].Msr,\r
1970 FixedSettings->Mtrr[Index]\r
1971 );\r
1972 }\r
1973}\r
1974\r
1975\r
1976/**\r
1977 This function sets fixed MTRRs\r
1978\r
1979 @param[in] FixedSettings A buffer to hold fixed MTRRs content.\r
1980\r
1981 @retval The pointer of FixedSettings\r
1982\r
1983**/\r
1984MTRR_FIXED_SETTINGS*\r
1985EFIAPI\r
1986MtrrSetFixedMtrr (\r
1987 IN MTRR_FIXED_SETTINGS *FixedSettings\r
1988 )\r
1989{\r
1990 MTRR_CONTEXT MtrrContext;\r
1991\r
1992 if (!IsMtrrSupported ()) {\r
1993 return FixedSettings;\r
1994 }\r
1995\r
1996 PreMtrrChange (&MtrrContext);\r
1997 MtrrSetFixedMtrrWorker (FixedSettings);\r
1998 PostMtrrChange (&MtrrContext);\r
1999 MtrrDebugPrintAllMtrrs ();\r
2000\r
2001 return FixedSettings;\r
2002}\r
2003\r
2004\r
2005/**\r
2006 This function gets the content in all MTRRs (variable and fixed)\r
2007\r
2008 @param[out] MtrrSetting A buffer to hold all MTRRs content.\r
2009\r
2010 @retval the pointer of MtrrSetting\r
2011\r
2012**/\r
2013MTRR_SETTINGS *\r
2014EFIAPI\r
2015MtrrGetAllMtrrs (\r
2016 OUT MTRR_SETTINGS *MtrrSetting\r
2017 )\r
2018{\r
2019 if (!IsMtrrSupported ()) {\r
2020 return MtrrSetting;\r
2021 }\r
2022\r
2023 //\r
2024 // Get fixed MTRRs\r
2025 //\r
2026 MtrrGetFixedMtrrWorker (&MtrrSetting->Fixed);\r
2027\r
2028 //\r
2029 // Get variable MTRRs\r
2030 //\r
2031 MtrrGetVariableMtrrWorker (\r
2032 NULL,\r
2033 GetVariableMtrrCountWorker (),\r
2034 &MtrrSetting->Variables\r
2035 );\r
2036\r
2037 //\r
2038 // Get MTRR_DEF_TYPE value\r
2039 //\r
2040 MtrrSetting->MtrrDefType = MtrrRegisterRead (QUARK_NC_HOST_BRIDGE_IA32_MTRR_DEF_TYPE);\r
2041\r
2042 return MtrrSetting;\r
2043}\r
2044\r
2045\r
2046/**\r
2047 This function sets all MTRRs (variable and fixed)\r
2048\r
2049 @param[in] MtrrSetting A buffer holding all MTRRs content.\r
2050\r
2051 @retval The pointer of MtrrSetting\r
2052\r
2053**/\r
2054MTRR_SETTINGS *\r
2055EFIAPI\r
2056MtrrSetAllMtrrs (\r
2057 IN MTRR_SETTINGS *MtrrSetting\r
2058 )\r
2059{\r
2060 MTRR_CONTEXT MtrrContext;\r
2061\r
2062 if (!IsMtrrSupported ()) {\r
2063 return MtrrSetting;\r
2064 }\r
2065\r
2066 PreMtrrChange (&MtrrContext);\r
2067\r
2068 //\r
2069 // Set fixed MTRRs\r
2070 //\r
2071 MtrrSetFixedMtrrWorker (&MtrrSetting->Fixed);\r
2072\r
2073 //\r
2074 // Set variable MTRRs\r
2075 //\r
2076 MtrrSetVariableMtrrWorker (&MtrrSetting->Variables);\r
2077\r
2078 //\r
2079 // Set MTRR_DEF_TYPE value\r
2080 //\r
2081 MtrrRegisterWrite (QUARK_NC_HOST_BRIDGE_IA32_MTRR_DEF_TYPE, MtrrSetting->MtrrDefType);\r
2082\r
2083 PostMtrrChangeEnableCache (&MtrrContext);\r
2084\r
2085 MtrrDebugPrintAllMtrrs ();\r
2086\r
2087 return MtrrSetting;\r
2088}\r
2089\r
2090\r
2091/**\r
2092 Checks if MTRR is supported.\r
2093\r
2094 @retval TRUE MTRR is supported.\r
2095 @retval FALSE MTRR is not supported.\r
2096\r
2097**/\r
2098BOOLEAN\r
2099EFIAPI\r
2100IsMtrrSupported (\r
2101 VOID\r
2102 )\r
2103{\r
2104 UINT32 RegEax;\r
2105\r
2106 //\r
2107 // Check CPUID(1).EAX[0..11] for Quark SoC\r
2108 //\r
2109 AsmCpuid (1, &RegEax, NULL, NULL, NULL);\r
2110 if ((RegEax & 0xfff) == QUARK_SOC_CPUID_FAMILY_MODEL_STEPPING) {\r
2111 return TRUE;\r
2112 }\r
2113\r
2114 return FALSE;\r
2115}\r