]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/Library/MtrrLib/MtrrLib.c
UefiCpuPkg/MtrrLib: Add comments to recommend to use batch-set API
[mirror_edk2.git] / UefiCpuPkg / Library / MtrrLib / MtrrLib.c
CommitLineData
e50466da 1/** @file\r
2 MTRR setting library\r
3\r
3143144b 4 @par Note:\r
81f56049
JF
5 Most of services in this library instance are suggested to be invoked by BSP only,\r
6 except for MtrrSetAllMtrrs() which is used to sync BSP's MTRR setting to APs.\r
7\r
5a6c5af6 8 Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved.<BR>\r
01a1c0fc 9 This program and the accompanying materials\r
e50466da 10 are licensed and made available under the terms and conditions of the BSD License\r
11 which accompanies this distribution. The full text of the license may be found at\r
12 http://opensource.org/licenses/bsd-license.php\r
13\r
14 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
15 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
16\r
17**/\r
18\r
2bbd7e2f 19#include <Uefi.h>\r
3bb13d35
RN
20#include <Register/Cpuid.h>\r
21#include <Register/Msr.h>\r
22\r
e50466da 23#include <Library/MtrrLib.h>\r
24#include <Library/BaseLib.h>\r
25#include <Library/CpuLib.h>\r
26#include <Library/BaseMemoryLib.h>\r
27#include <Library/DebugLib.h>\r
28\r
eecad349
JF
29#define OR_SEED 0x0101010101010101ull\r
30#define CLEAR_SEED 0xFFFFFFFFFFFFFFFFull\r
2bbd7e2f
RN
31#define MAX_WEIGHT MAX_UINT8\r
32#define SCRATCH_BUFFER_SIZE (4 * SIZE_4KB)\r
8051302a 33#define MTRR_LIB_ASSERT_ALIGNED(B, L) ASSERT ((B & ~(L - 1)) == B);\r
2bbd7e2f 34\r
3143144b
RN
35#define M(x,y) ((x) * VertexCount + (y))\r
36#define O(x,y) ((y) * VertexCount + (x))\r
2bbd7e2f 37\r
c878cee4 38//\r
39// Context to save and restore when MTRRs are programmed\r
40//\r
41typedef struct {\r
42 UINTN Cr4;\r
43 BOOLEAN InterruptState;\r
44} MTRR_CONTEXT;\r
45\r
8051302a 46typedef struct {\r
2bbd7e2f
RN
47 UINT64 Address;\r
48 UINT64 Alignment;\r
8051302a 49 UINT64 Length;\r
57951033 50 MTRR_MEMORY_CACHE_TYPE Type : 7;\r
2bbd7e2f
RN
51\r
52 //\r
53 // Temprary use for calculating the best MTRR settings.\r
54 //\r
55 BOOLEAN Visited : 1;\r
56 UINT8 Weight;\r
57 UINT16 Previous;\r
58} MTRR_LIB_ADDRESS;\r
8051302a 59\r
e50466da 60//\r
61// This table defines the offset, base and length of the fixed MTRRs\r
62//\r
f877f300 63CONST FIXED_MTRR mMtrrLibFixedMtrrTable[] = {\r
e50466da 64 {\r
af838805 65 MSR_IA32_MTRR_FIX64K_00000,\r
e50466da 66 0,\r
67 SIZE_64KB\r
68 },\r
69 {\r
af838805 70 MSR_IA32_MTRR_FIX16K_80000,\r
e50466da 71 0x80000,\r
72 SIZE_16KB\r
73 },\r
74 {\r
af838805 75 MSR_IA32_MTRR_FIX16K_A0000,\r
e50466da 76 0xA0000,\r
77 SIZE_16KB\r
78 },\r
79 {\r
af838805 80 MSR_IA32_MTRR_FIX4K_C0000,\r
e50466da 81 0xC0000,\r
82 SIZE_4KB\r
83 },\r
84 {\r
af838805 85 MSR_IA32_MTRR_FIX4K_C8000,\r
e50466da 86 0xC8000,\r
87 SIZE_4KB\r
88 },\r
89 {\r
af838805 90 MSR_IA32_MTRR_FIX4K_D0000,\r
e50466da 91 0xD0000,\r
92 SIZE_4KB\r
93 },\r
94 {\r
af838805 95 MSR_IA32_MTRR_FIX4K_D8000,\r
e50466da 96 0xD8000,\r
97 SIZE_4KB\r
98 },\r
99 {\r
af838805 100 MSR_IA32_MTRR_FIX4K_E0000,\r
e50466da 101 0xE0000,\r
102 SIZE_4KB\r
103 },\r
104 {\r
af838805 105 MSR_IA32_MTRR_FIX4K_E8000,\r
e50466da 106 0xE8000,\r
107 SIZE_4KB\r
108 },\r
109 {\r
af838805 110 MSR_IA32_MTRR_FIX4K_F0000,\r
e50466da 111 0xF0000,\r
112 SIZE_4KB\r
113 },\r
114 {\r
af838805 115 MSR_IA32_MTRR_FIX4K_F8000,\r
e50466da 116 0xF8000,\r
117 SIZE_4KB\r
76b4cae3 118 }\r
e50466da 119};\r
120\r
f877f300 121//\r
122// Lookup table used to print MTRRs\r
123//\r
124GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 *mMtrrMemoryCacheTypeShortName[] = {\r
125 "UC", // CacheUncacheable\r
126 "WC", // CacheWriteCombining\r
127 "R*", // Invalid\r
128 "R*", // Invalid\r
129 "WT", // CacheWriteThrough\r
130 "WP", // CacheWriteProtected\r
131 "WB", // CacheWriteBack\r
132 "R*" // Invalid\r
133};\r
134\r
2bbd7e2f
RN
135\r
136/**\r
137 Worker function prints all MTRRs for debugging.\r
138\r
139 If MtrrSetting is not NULL, print MTRR settings from input MTRR\r
140 settings buffer.\r
141 If MtrrSetting is NULL, print MTRR settings from MTRRs.\r
142\r
143 @param MtrrSetting A buffer holding all MTRRs content.\r
144**/\r
145VOID\r
146MtrrDebugPrintAllMtrrsWorker (\r
147 IN MTRR_SETTINGS *MtrrSetting\r
148 );\r
149\r
31b3597e
MK
150/**\r
151 Worker function returns the variable MTRR count for the CPU.\r
152\r
153 @return Variable MTRR count\r
154\r
155**/\r
156UINT32\r
157GetVariableMtrrCountWorker (\r
158 VOID\r
159 )\r
160{\r
386f5785 161 MSR_IA32_MTRRCAP_REGISTER MtrrCap;\r
31b3597e 162\r
386f5785 163 MtrrCap.Uint64 = AsmReadMsr64 (MSR_IA32_MTRRCAP);\r
2bbd7e2f 164 ASSERT (MtrrCap.Bits.VCNT <= ARRAY_SIZE (((MTRR_VARIABLE_SETTINGS *) 0)->Mtrr));\r
386f5785 165 return MtrrCap.Bits.VCNT;\r
31b3597e
MK
166}\r
167\r
3b9be416
JY
168/**\r
169 Returns the variable MTRR count for the CPU.\r
170\r
171 @return Variable MTRR count\r
172\r
173**/\r
174UINT32\r
ed8dfd7b 175EFIAPI\r
3b9be416
JY
176GetVariableMtrrCount (\r
177 VOID\r
178 )\r
179{\r
947a573a 180 if (!IsMtrrSupported ()) {\r
181 return 0;\r
182 }\r
31b3597e 183 return GetVariableMtrrCountWorker ();\r
3b9be416
JY
184}\r
185\r
186/**\r
31b3597e 187 Worker function returns the firmware usable variable MTRR count for the CPU.\r
3b9be416
JY
188\r
189 @return Firmware usable variable MTRR count\r
190\r
191**/\r
192UINT32\r
31b3597e 193GetFirmwareVariableMtrrCountWorker (\r
3b9be416
JY
194 VOID\r
195 )\r
196{\r
947a573a 197 UINT32 VariableMtrrCount;\r
46309b11 198 UINT32 ReservedMtrrNumber;\r
947a573a 199\r
31b3597e 200 VariableMtrrCount = GetVariableMtrrCountWorker ();\r
46309b11
JF
201 ReservedMtrrNumber = PcdGet32 (PcdCpuNumberOfReservedVariableMtrrs);\r
202 if (VariableMtrrCount < ReservedMtrrNumber) {\r
947a573a 203 return 0;\r
204 }\r
205\r
46309b11 206 return VariableMtrrCount - ReservedMtrrNumber;\r
3b9be416 207}\r
e50466da 208\r
31b3597e
MK
209/**\r
210 Returns the firmware usable variable MTRR count for the CPU.\r
211\r
212 @return Firmware usable variable MTRR count\r
213\r
214**/\r
215UINT32\r
216EFIAPI\r
217GetFirmwareVariableMtrrCount (\r
218 VOID\r
219 )\r
220{\r
221 if (!IsMtrrSupported ()) {\r
222 return 0;\r
223 }\r
224 return GetFirmwareVariableMtrrCountWorker ();\r
225}\r
226\r
227/**\r
228 Worker function returns the default MTRR cache type for the system.\r
229\r
5abd5ed4
MK
230 If MtrrSetting is not NULL, returns the default MTRR cache type from input\r
231 MTRR settings buffer.\r
232 If MtrrSetting is NULL, returns the default MTRR cache type from MSR.\r
233\r
234 @param[in] MtrrSetting A buffer holding all MTRRs content.\r
235\r
31b3597e
MK
236 @return The default MTRR cache type.\r
237\r
238**/\r
239MTRR_MEMORY_CACHE_TYPE\r
240MtrrGetDefaultMemoryTypeWorker (\r
5abd5ed4 241 IN MTRR_SETTINGS *MtrrSetting\r
31b3597e
MK
242 )\r
243{\r
af838805
RN
244 MSR_IA32_MTRR_DEF_TYPE_REGISTER DefType;\r
245\r
5abd5ed4 246 if (MtrrSetting == NULL) {\r
af838805 247 DefType.Uint64 = AsmReadMsr64 (MSR_IA32_MTRR_DEF_TYPE);\r
5abd5ed4 248 } else {\r
af838805 249 DefType.Uint64 = MtrrSetting->MtrrDefType;\r
5abd5ed4 250 }\r
af838805
RN
251\r
252 return (MTRR_MEMORY_CACHE_TYPE) DefType.Bits.Type;\r
31b3597e
MK
253}\r
254\r
255\r
e50466da 256/**\r
257 Returns the default MTRR cache type for the system.\r
258\r
91ec7824 259 @return The default MTRR cache type.\r
e50466da 260\r
261**/\r
91ec7824 262MTRR_MEMORY_CACHE_TYPE\r
263EFIAPI\r
264MtrrGetDefaultMemoryType (\r
e50466da 265 VOID\r
91ec7824 266 )\r
e50466da 267{\r
91ec7824 268 if (!IsMtrrSupported ()) {\r
269 return CacheUncacheable;\r
270 }\r
5abd5ed4 271 return MtrrGetDefaultMemoryTypeWorker (NULL);\r
91ec7824 272}\r
e50466da 273\r
274/**\r
275 Preparation before programming MTRR.\r
276\r
277 This function will do some preparation for programming MTRRs:\r
278 disable cache, invalid cache and disable MTRR caching functionality\r
279\r
a5953380 280 @param[out] MtrrContext Pointer to context to save\r
e50466da 281\r
282**/\r
c878cee4 283VOID\r
b8f01599 284MtrrLibPreMtrrChange (\r
c878cee4 285 OUT MTRR_CONTEXT *MtrrContext\r
e50466da 286 )\r
287{\r
af838805 288 MSR_IA32_MTRR_DEF_TYPE_REGISTER DefType;\r
c878cee4 289 //\r
290 // Disable interrupts and save current interrupt state\r
291 //\r
292 MtrrContext->InterruptState = SaveAndDisableInterrupts();\r
76b4cae3 293\r
e50466da 294 //\r
295 // Enter no fill cache mode, CD=1(Bit30), NW=0 (Bit29)\r
296 //\r
58b23d90 297 AsmDisableCache ();\r
298\r
e50466da 299 //\r
58b23d90 300 // Save original CR4 value and clear PGE flag (Bit 7)\r
e50466da 301 //\r
c878cee4 302 MtrrContext->Cr4 = AsmReadCr4 ();\r
303 AsmWriteCr4 (MtrrContext->Cr4 & (~BIT7));\r
58b23d90 304\r
e50466da 305 //\r
306 // Flush all TLBs\r
307 //\r
308 CpuFlushTlb ();\r
58b23d90 309\r
e50466da 310 //\r
76b4cae3 311 // Disable MTRRs\r
e50466da 312 //\r
af838805
RN
313 DefType.Uint64 = AsmReadMsr64 (MSR_IA32_MTRR_DEF_TYPE);\r
314 DefType.Bits.E = 0;\r
315 AsmWriteMsr64 (MSR_IA32_MTRR_DEF_TYPE, DefType.Uint64);\r
e50466da 316}\r
317\r
e50466da 318/**\r
319 Cleaning up after programming MTRRs.\r
320\r
321 This function will do some clean up after programming MTRRs:\r
0779e5bf 322 Flush all TLBs, re-enable caching, restore CR4.\r
e50466da 323\r
a5953380 324 @param[in] MtrrContext Pointer to context to restore\r
e50466da 325\r
326**/\r
327VOID\r
b8f01599 328MtrrLibPostMtrrChangeEnableCache (\r
c878cee4 329 IN MTRR_CONTEXT *MtrrContext\r
e50466da 330 )\r
331{\r
e50466da 332 //\r
76b4cae3 333 // Flush all TLBs\r
e50466da 334 //\r
e50466da 335 CpuFlushTlb ();\r
336\r
337 //\r
338 // Enable Normal Mode caching CD=NW=0, CD(Bit30), NW(Bit29)\r
339 //\r
58b23d90 340 AsmEnableCache ();\r
e50466da 341\r
58b23d90 342 //\r
343 // Restore original CR4 value\r
344 //\r
c878cee4 345 AsmWriteCr4 (MtrrContext->Cr4);\r
76b4cae3 346\r
c878cee4 347 //\r
348 // Restore original interrupt state\r
349 //\r
350 SetInterruptState (MtrrContext->InterruptState);\r
e50466da 351}\r
352\r
0779e5bf 353/**\r
354 Cleaning up after programming MTRRs.\r
355\r
356 This function will do some clean up after programming MTRRs:\r
357 enable MTRR caching functionality, and enable cache\r
358\r
a5953380 359 @param[in] MtrrContext Pointer to context to restore\r
0779e5bf 360\r
361**/\r
362VOID\r
b8f01599 363MtrrLibPostMtrrChange (\r
c878cee4 364 IN MTRR_CONTEXT *MtrrContext\r
0779e5bf 365 )\r
366{\r
af838805 367 MSR_IA32_MTRR_DEF_TYPE_REGISTER DefType;\r
0779e5bf 368 //\r
369 // Enable Cache MTRR\r
370 //\r
af838805
RN
371 DefType.Uint64 = AsmReadMsr64 (MSR_IA32_MTRR_DEF_TYPE);\r
372 DefType.Bits.E = 1;\r
373 DefType.Bits.FE = 1;\r
374 AsmWriteMsr64 (MSR_IA32_MTRR_DEF_TYPE, DefType.Uint64);\r
0779e5bf 375\r
b8f01599 376 MtrrLibPostMtrrChangeEnableCache (MtrrContext);\r
0779e5bf 377}\r
378\r
85b7f65b
MK
379/**\r
380 Worker function gets the content in fixed MTRRs\r
381\r
382 @param[out] FixedSettings A buffer to hold fixed MTRRs content.\r
383\r
384 @retval The pointer of FixedSettings\r
385\r
386**/\r
387MTRR_FIXED_SETTINGS*\r
388MtrrGetFixedMtrrWorker (\r
389 OUT MTRR_FIXED_SETTINGS *FixedSettings\r
390 )\r
391{\r
392 UINT32 Index;\r
393\r
394 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
395 FixedSettings->Mtrr[Index] =\r
396 AsmReadMsr64 (mMtrrLibFixedMtrrTable[Index].Msr);\r
397 }\r
398\r
399 return FixedSettings;\r
400}\r
401\r
402\r
403/**\r
404 This function gets the content in fixed MTRRs\r
405\r
406 @param[out] FixedSettings A buffer to hold fixed MTRRs content.\r
407\r
408 @retval The pointer of FixedSettings\r
409\r
410**/\r
411MTRR_FIXED_SETTINGS*\r
412EFIAPI\r
413MtrrGetFixedMtrr (\r
414 OUT MTRR_FIXED_SETTINGS *FixedSettings\r
415 )\r
416{\r
417 if (!IsMtrrSupported ()) {\r
418 return FixedSettings;\r
419 }\r
420\r
421 return MtrrGetFixedMtrrWorker (FixedSettings);\r
422}\r
423\r
424\r
425/**\r
426 Worker function will get the raw value in variable MTRRs\r
427\r
5abd5ed4
MK
428 If MtrrSetting is not NULL, gets the variable MTRRs raw value from input\r
429 MTRR settings buffer.\r
430 If MtrrSetting is NULL, gets the variable MTRRs raw value from MTRRs.\r
431\r
432 @param[in] MtrrSetting A buffer holding all MTRRs content.\r
433 @param[in] VariableMtrrCount Number of variable MTRRs.\r
85b7f65b
MK
434 @param[out] VariableSettings A buffer to hold variable MTRRs content.\r
435\r
436 @return The VariableSettings input pointer\r
437\r
438**/\r
439MTRR_VARIABLE_SETTINGS*\r
440MtrrGetVariableMtrrWorker (\r
5abd5ed4 441 IN MTRR_SETTINGS *MtrrSetting,\r
acf431e6 442 IN UINT32 VariableMtrrCount,\r
85b7f65b
MK
443 OUT MTRR_VARIABLE_SETTINGS *VariableSettings\r
444 )\r
445{\r
446 UINT32 Index;\r
85b7f65b 447\r
2bbd7e2f 448 ASSERT (VariableMtrrCount <= ARRAY_SIZE (VariableSettings->Mtrr));\r
85b7f65b
MK
449\r
450 for (Index = 0; Index < VariableMtrrCount; Index++) {\r
5abd5ed4 451 if (MtrrSetting == NULL) {\r
9c8c4478
RN
452 VariableSettings->Mtrr[Index].Mask = AsmReadMsr64 (MSR_IA32_MTRR_PHYSMASK0 + (Index << 1));\r
453 //\r
454 // Skip to read the Base MSR when the Mask.V is not set.\r
455 //\r
456 if (((MSR_IA32_MTRR_PHYSMASK_REGISTER *)&VariableSettings->Mtrr[Index].Mask)->Bits.V != 0) {\r
457 VariableSettings->Mtrr[Index].Base = AsmReadMsr64 (MSR_IA32_MTRR_PHYSBASE0 + (Index << 1));\r
458 }\r
5abd5ed4
MK
459 } else {\r
460 VariableSettings->Mtrr[Index].Base = MtrrSetting->Variables.Mtrr[Index].Base;\r
461 VariableSettings->Mtrr[Index].Mask = MtrrSetting->Variables.Mtrr[Index].Mask;\r
462 }\r
85b7f65b
MK
463 }\r
464\r
465 return VariableSettings;\r
466}\r
467\r
468/**\r
469 This function will get the raw value in variable MTRRs\r
470\r
471 @param[out] VariableSettings A buffer to hold variable MTRRs content.\r
472\r
473 @return The VariableSettings input pointer\r
474\r
475**/\r
476MTRR_VARIABLE_SETTINGS*\r
477EFIAPI\r
478MtrrGetVariableMtrr (\r
479 OUT MTRR_VARIABLE_SETTINGS *VariableSettings\r
480 )\r
481{\r
482 if (!IsMtrrSupported ()) {\r
483 return VariableSettings;\r
484 }\r
485\r
486 return MtrrGetVariableMtrrWorker (\r
5abd5ed4 487 NULL,\r
acf431e6 488 GetVariableMtrrCountWorker (),\r
85b7f65b
MK
489 VariableSettings\r
490 );\r
491}\r
e50466da 492\r
493/**\r
494 Programs fixed MTRRs registers.\r
495\r
94240f1b 496 @param[in] Type The memory type to set.\r
76b4cae3
MK
497 @param[in, out] Base The base address of memory range.\r
498 @param[in, out] Length The length of memory range.\r
5fbb5ade 499 @param[in, out] LastMsrIndex On input, the last index of the fixed MTRR MSR to program.\r
0f354122 500 On return, the current index of the fixed MTRR MSR to program.\r
5fbb5ade
RN
501 @param[out] ClearMask The bits to clear in the fixed MTRR MSR.\r
502 @param[out] OrMask The bits to set in the fixed MTRR MSR.\r
e50466da 503\r
504 @retval RETURN_SUCCESS The cache type was updated successfully\r
505 @retval RETURN_UNSUPPORTED The requested range or cache type was invalid\r
506 for the fixed MTRRs.\r
507\r
508**/\r
509RETURN_STATUS\r
94240f1b
RN
510MtrrLibProgramFixedMtrr (\r
511 IN MTRR_MEMORY_CACHE_TYPE Type,\r
512 IN OUT UINT64 *Base,\r
513 IN OUT UINT64 *Length,\r
5fbb5ade
RN
514 IN OUT UINT32 *LastMsrIndex,\r
515 OUT UINT64 *ClearMask,\r
516 OUT UINT64 *OrMask\r
e50466da 517 )\r
518{\r
5fbb5ade 519 UINT32 MsrIndex;\r
eecad349
JF
520 UINT32 LeftByteShift;\r
521 UINT32 RightByteShift;\r
07e88920 522 UINT64 SubLength;\r
e50466da 523\r
eecad349
JF
524 //\r
525 // Find the fixed MTRR index to be programmed\r
526 //\r
5fbb5ade
RN
527 for (MsrIndex = *LastMsrIndex + 1; MsrIndex < ARRAY_SIZE (mMtrrLibFixedMtrrTable); MsrIndex++) {\r
528 if ((*Base >= mMtrrLibFixedMtrrTable[MsrIndex].BaseAddress) &&\r
e50466da 529 (*Base <\r
530 (\r
5fbb5ade
RN
531 mMtrrLibFixedMtrrTable[MsrIndex].BaseAddress +\r
532 (8 * mMtrrLibFixedMtrrTable[MsrIndex].Length)\r
e50466da 533 )\r
534 )\r
535 ) {\r
536 break;\r
537 }\r
538 }\r
539\r
5fbb5ade 540 ASSERT (MsrIndex != ARRAY_SIZE (mMtrrLibFixedMtrrTable));\r
e50466da 541\r
542 //\r
eecad349 543 // Find the begin offset in fixed MTRR and calculate byte offset of left shift\r
e50466da 544 //\r
5fbb5ade
RN
545 if ((((UINT32)*Base - mMtrrLibFixedMtrrTable[MsrIndex].BaseAddress) % mMtrrLibFixedMtrrTable[MsrIndex].Length) != 0) {\r
546 //\r
547 // Base address should be aligned to the begin of a certain Fixed MTRR range.\r
548 //\r
e50466da 549 return RETURN_UNSUPPORTED;\r
550 }\r
5fbb5ade
RN
551 LeftByteShift = ((UINT32)*Base - mMtrrLibFixedMtrrTable[MsrIndex].BaseAddress) / mMtrrLibFixedMtrrTable[MsrIndex].Length;\r
552 ASSERT (LeftByteShift < 8);\r
e50466da 553\r
eecad349
JF
554 //\r
555 // Find the end offset in fixed MTRR and calculate byte offset of right shift\r
556 //\r
5fbb5ade 557 SubLength = mMtrrLibFixedMtrrTable[MsrIndex].Length * (8 - LeftByteShift);\r
eecad349
JF
558 if (*Length >= SubLength) {\r
559 RightByteShift = 0;\r
07e88920 560 } else {\r
5fbb5ade
RN
561 if (((UINT32)(*Length) % mMtrrLibFixedMtrrTable[MsrIndex].Length) != 0) {\r
562 //\r
563 // Length should be aligned to the end of a certain Fixed MTRR range.\r
564 //\r
eecad349
JF
565 return RETURN_UNSUPPORTED;\r
566 }\r
5fbb5ade 567 RightByteShift = 8 - LeftByteShift - (UINT32)(*Length) / mMtrrLibFixedMtrrTable[MsrIndex].Length;\r
eecad349
JF
568 //\r
569 // Update SubLength by actual length\r
570 //\r
571 SubLength = *Length;\r
e50466da 572 }\r
573\r
5fbb5ade
RN
574 *ClearMask = CLEAR_SEED;\r
575 *OrMask = MultU64x32 (OR_SEED, (UINT32) Type);\r
eecad349
JF
576\r
577 if (LeftByteShift != 0) {\r
578 //\r
579 // Clear the low bits by LeftByteShift\r
580 //\r
5fbb5ade
RN
581 *ClearMask &= LShiftU64 (*ClearMask, LeftByteShift * 8);\r
582 *OrMask &= LShiftU64 (*OrMask, LeftByteShift * 8);\r
eecad349
JF
583 }\r
584\r
585 if (RightByteShift != 0) {\r
586 //\r
587 // Clear the high bits by RightByteShift\r
588 //\r
5fbb5ade
RN
589 *ClearMask &= RShiftU64 (*ClearMask, RightByteShift * 8);\r
590 *OrMask &= RShiftU64 (*OrMask, RightByteShift * 8);\r
e50466da 591 }\r
592\r
07e88920
JF
593 *Length -= SubLength;\r
594 *Base += SubLength;\r
595\r
5fbb5ade 596 *LastMsrIndex = MsrIndex;\r
fa25cf38 597\r
e50466da 598 return RETURN_SUCCESS;\r
599}\r
600\r
601\r
d0baed7d
MK
602/**\r
603 Worker function gets the attribute of variable MTRRs.\r
604\r
605 This function shadows the content of variable MTRRs into an\r
606 internal array: VariableMtrr.\r
607\r
10c361ad
RN
608 @param[in] VariableSettings The variable MTRR values to shadow\r
609 @param[in] VariableMtrrCount The number of variable MTRRs\r
610 @param[in] MtrrValidBitsMask The mask for the valid bit of the MTRR\r
611 @param[in] MtrrValidAddressMask The valid address mask for MTRR\r
612 @param[out] VariableMtrr The array to shadow variable MTRRs content\r
d0baed7d 613\r
10c361ad 614 @return Number of MTRRs which has been used.\r
d0baed7d
MK
615\r
616**/\r
617UINT32\r
618MtrrGetMemoryAttributeInVariableMtrrWorker (\r
619 IN MTRR_VARIABLE_SETTINGS *VariableSettings,\r
10c361ad 620 IN UINTN VariableMtrrCount,\r
d0baed7d
MK
621 IN UINT64 MtrrValidBitsMask,\r
622 IN UINT64 MtrrValidAddressMask,\r
623 OUT VARIABLE_MTRR *VariableMtrr\r
624 )\r
625{\r
626 UINTN Index;\r
627 UINT32 UsedMtrr;\r
628\r
2bbd7e2f 629 ZeroMem (VariableMtrr, sizeof (VARIABLE_MTRR) * ARRAY_SIZE (VariableSettings->Mtrr));\r
10c361ad 630 for (Index = 0, UsedMtrr = 0; Index < VariableMtrrCount; Index++) {\r
af838805 631 if (((MSR_IA32_MTRR_PHYSMASK_REGISTER *) &VariableSettings->Mtrr[Index].Mask)->Bits.V != 0) {\r
d0baed7d
MK
632 VariableMtrr[Index].Msr = (UINT32)Index;\r
633 VariableMtrr[Index].BaseAddress = (VariableSettings->Mtrr[Index].Base & MtrrValidAddressMask);\r
2bbd7e2f
RN
634 VariableMtrr[Index].Length =\r
635 ((~(VariableSettings->Mtrr[Index].Mask & MtrrValidAddressMask)) & MtrrValidBitsMask) + 1;\r
d0baed7d
MK
636 VariableMtrr[Index].Type = (VariableSettings->Mtrr[Index].Base & 0x0ff);\r
637 VariableMtrr[Index].Valid = TRUE;\r
638 VariableMtrr[Index].Used = TRUE;\r
639 UsedMtrr++;\r
640 }\r
641 }\r
642 return UsedMtrr;\r
643}\r
644\r
2bbd7e2f
RN
645/**\r
646 Convert variable MTRRs to a RAW MTRR_MEMORY_RANGE array.\r
647 One MTRR_MEMORY_RANGE element is created for each MTRR setting.\r
648 The routine doesn't remove the overlap or combine the near-by region.\r
649\r
650 @param[in] VariableSettings The variable MTRR values to shadow\r
651 @param[in] VariableMtrrCount The number of variable MTRRs\r
652 @param[in] MtrrValidBitsMask The mask for the valid bit of the MTRR\r
653 @param[in] MtrrValidAddressMask The valid address mask for MTRR\r
654 @param[out] VariableMtrr The array to shadow variable MTRRs content\r
655\r
656 @return Number of MTRRs which has been used.\r
657\r
658**/\r
659UINT32\r
660MtrrLibGetRawVariableRanges (\r
661 IN MTRR_VARIABLE_SETTINGS *VariableSettings,\r
662 IN UINTN VariableMtrrCount,\r
663 IN UINT64 MtrrValidBitsMask,\r
664 IN UINT64 MtrrValidAddressMask,\r
665 OUT MTRR_MEMORY_RANGE *VariableMtrr\r
666 )\r
667{\r
668 UINTN Index;\r
669 UINT32 UsedMtrr;\r
670\r
671 ZeroMem (VariableMtrr, sizeof (MTRR_MEMORY_RANGE) * ARRAY_SIZE (VariableSettings->Mtrr));\r
672 for (Index = 0, UsedMtrr = 0; Index < VariableMtrrCount; Index++) {\r
673 if (((MSR_IA32_MTRR_PHYSMASK_REGISTER *) &VariableSettings->Mtrr[Index].Mask)->Bits.V != 0) {\r
674 VariableMtrr[Index].BaseAddress = (VariableSettings->Mtrr[Index].Base & MtrrValidAddressMask);\r
675 VariableMtrr[Index].Length =\r
676 ((~(VariableSettings->Mtrr[Index].Mask & MtrrValidAddressMask)) & MtrrValidBitsMask) + 1;\r
677 VariableMtrr[Index].Type = (MTRR_MEMORY_CACHE_TYPE)(VariableSettings->Mtrr[Index].Base & 0x0ff);\r
678 UsedMtrr++;\r
679 }\r
680 }\r
681 return UsedMtrr;\r
682}\r
d0baed7d 683\r
e50466da 684/**\r
76b4cae3 685 Gets the attribute of variable MTRRs.\r
e50466da 686\r
3ba736f3
JY
687 This function shadows the content of variable MTRRs into an\r
688 internal array: VariableMtrr.\r
e50466da 689\r
76b4cae3
MK
690 @param[in] MtrrValidBitsMask The mask for the valid bit of the MTRR\r
691 @param[in] MtrrValidAddressMask The valid address mask for MTRR\r
692 @param[out] VariableMtrr The array to shadow variable MTRRs content\r
e50466da 693\r
438f1766 694 @return The return value of this parameter indicates the\r
3ba736f3 695 number of MTRRs which has been used.\r
e50466da 696\r
697**/\r
3ba736f3 698UINT32\r
e50466da 699EFIAPI\r
700MtrrGetMemoryAttributeInVariableMtrr (\r
701 IN UINT64 MtrrValidBitsMask,\r
702 IN UINT64 MtrrValidAddressMask,\r
703 OUT VARIABLE_MTRR *VariableMtrr\r
704 )\r
705{\r
d0baed7d 706 MTRR_VARIABLE_SETTINGS VariableSettings;\r
3b9be416 707\r
947a573a 708 if (!IsMtrrSupported ()) {\r
709 return 0;\r
710 }\r
711\r
d0baed7d 712 MtrrGetVariableMtrrWorker (\r
5abd5ed4 713 NULL,\r
d0baed7d
MK
714 GetVariableMtrrCountWorker (),\r
715 &VariableSettings\r
716 );\r
e50466da 717\r
d0baed7d
MK
718 return MtrrGetMemoryAttributeInVariableMtrrWorker (\r
719 &VariableSettings,\r
720 GetFirmwareVariableMtrrCountWorker (),\r
721 MtrrValidBitsMask,\r
722 MtrrValidAddressMask,\r
723 VariableMtrr\r
724 );\r
e50466da 725}\r
726\r
e50466da 727/**\r
1416ecb4
RN
728 Return the biggest alignment (lowest set bit) of address.\r
729 The function is equivalent to: 1 << LowBitSet64 (Address).\r
e50466da 730\r
8051302a
RN
731 @param Address The address to return the alignment.\r
732 @param Alignment0 The alignment to return when Address is 0.\r
e50466da 733\r
8051302a 734 @return The least alignment of the Address.\r
e50466da 735**/\r
8051302a 736UINT64\r
1416ecb4 737MtrrLibBiggestAlignment (\r
8051302a
RN
738 UINT64 Address,\r
739 UINT64 Alignment0\r
740)\r
e50466da 741{\r
8051302a
RN
742 if (Address == 0) {\r
743 return Alignment0;\r
e50466da 744 }\r
745\r
1416ecb4 746 return Address & ((~Address) + 1);\r
e50466da 747}\r
748\r
e50466da 749/**\r
8051302a 750 Return whether the left MTRR type precedes the right MTRR type.\r
76b4cae3 751\r
8051302a 752 The MTRR type precedence rules are:\r
10c361ad
RN
753 1. UC precedes any other type\r
754 2. WT precedes WB\r
755 For further details, please refer the IA32 Software Developer's Manual,\r
756 Volume 3, Section "MTRR Precedences".\r
e50466da 757\r
8051302a
RN
758 @param Left The left MTRR type.\r
759 @param Right The right MTRR type.\r
e50466da 760\r
8051302a
RN
761 @retval TRUE Left precedes Right.\r
762 @retval FALSE Left doesn't precede Right.\r
e50466da 763**/\r
8051302a
RN
764BOOLEAN\r
765MtrrLibTypeLeftPrecedeRight (\r
766 IN MTRR_MEMORY_CACHE_TYPE Left,\r
767 IN MTRR_MEMORY_CACHE_TYPE Right\r
768)\r
e50466da 769{\r
8051302a 770 return (BOOLEAN) (Left == CacheUncacheable || (Left == CacheWriteThrough && Right == CacheWriteBack));\r
e50466da 771}\r
772\r
e50466da 773/**\r
774 Initializes the valid bits mask and valid address mask for MTRRs.\r
775\r
776 This function initializes the valid bits mask and valid address mask for MTRRs.\r
777\r
76b4cae3
MK
778 @param[out] MtrrValidBitsMask The mask for the valid bit of the MTRR\r
779 @param[out] MtrrValidAddressMask The valid address mask for the MTRR\r
e50466da 780\r
781**/\r
e50466da 782VOID\r
783MtrrLibInitializeMtrrMask (\r
784 OUT UINT64 *MtrrValidBitsMask,\r
785 OUT UINT64 *MtrrValidAddressMask\r
786 )\r
787{\r
012f4054
RN
788 UINT32 MaxExtendedFunction;\r
789 CPUID_VIR_PHY_ADDRESS_SIZE_EAX VirPhyAddressSize;\r
e50466da 790\r
e50466da 791\r
012f4054 792 AsmCpuid (CPUID_EXTENDED_FUNCTION, &MaxExtendedFunction, NULL, NULL, NULL);\r
e50466da 793\r
012f4054
RN
794 if (MaxExtendedFunction >= CPUID_VIR_PHY_ADDRESS_SIZE) {\r
795 AsmCpuid (CPUID_VIR_PHY_ADDRESS_SIZE, &VirPhyAddressSize.Uint32, NULL, NULL, NULL);\r
e50466da 796 } else {\r
012f4054 797 VirPhyAddressSize.Bits.PhysicalAddressBits = 36;\r
e50466da 798 }\r
012f4054
RN
799\r
800 *MtrrValidBitsMask = LShiftU64 (1, VirPhyAddressSize.Bits.PhysicalAddressBits) - 1;\r
801 *MtrrValidAddressMask = *MtrrValidBitsMask & 0xfffffffffffff000ULL;\r
e50466da 802}\r
803\r
804\r
805/**\r
76b4cae3 806 Determines the real attribute of a memory range.\r
e50466da 807\r
808 This function is to arbitrate the real attribute of the memory when\r
10c361ad 809 there are 2 MTRRs covers the same memory range. For further details,\r
e50466da 810 please refer the IA32 Software Developer's Manual, Volume 3,\r
10c361ad 811 Section "MTRR Precedences".\r
e50466da 812\r
76b4cae3
MK
813 @param[in] MtrrType1 The first kind of Memory type\r
814 @param[in] MtrrType2 The second kind of memory type\r
e50466da 815\r
816**/\r
10c361ad 817MTRR_MEMORY_CACHE_TYPE\r
b8f01599 818MtrrLibPrecedence (\r
10c361ad
RN
819 IN MTRR_MEMORY_CACHE_TYPE MtrrType1,\r
820 IN MTRR_MEMORY_CACHE_TYPE MtrrType2\r
e50466da 821 )\r
822{\r
10c361ad
RN
823 if (MtrrType1 == MtrrType2) {\r
824 return MtrrType1;\r
e50466da 825 }\r
826\r
10c361ad
RN
827 ASSERT (\r
828 MtrrLibTypeLeftPrecedeRight (MtrrType1, MtrrType2) ||\r
829 MtrrLibTypeLeftPrecedeRight (MtrrType2, MtrrType1)\r
830 );\r
831\r
832 if (MtrrLibTypeLeftPrecedeRight (MtrrType1, MtrrType2)) {\r
833 return MtrrType1;\r
834 } else {\r
835 return MtrrType2;\r
e50466da 836 }\r
e50466da 837}\r
838\r
e50466da 839/**\r
5abd5ed4 840 Worker function will get the memory cache type of the specific address.\r
e50466da 841\r
5abd5ed4
MK
842 If MtrrSetting is not NULL, gets the memory cache type from input\r
843 MTRR settings buffer.\r
844 If MtrrSetting is NULL, gets the memory cache type from MTRRs.\r
e50466da 845\r
5abd5ed4 846 @param[in] MtrrSetting A buffer holding all MTRRs content.\r
85b7f65b
MK
847 @param[in] Address The specific address\r
848\r
849 @return Memory cache type of the specific address\r
e50466da 850\r
851**/\r
85b7f65b 852MTRR_MEMORY_CACHE_TYPE\r
5abd5ed4
MK
853MtrrGetMemoryAttributeByAddressWorker (\r
854 IN MTRR_SETTINGS *MtrrSetting,\r
85b7f65b 855 IN PHYSICAL_ADDRESS Address\r
e50466da 856 )\r
857{\r
10c361ad
RN
858 MSR_IA32_MTRR_DEF_TYPE_REGISTER DefType;\r
859 UINT64 FixedMtrr;\r
860 UINTN Index;\r
861 UINTN SubIndex;\r
862 MTRR_MEMORY_CACHE_TYPE MtrrType;\r
2bbd7e2f 863 MTRR_MEMORY_RANGE VariableMtrr[ARRAY_SIZE (MtrrSetting->Variables.Mtrr)];\r
10c361ad
RN
864 UINT64 MtrrValidBitsMask;\r
865 UINT64 MtrrValidAddressMask;\r
866 UINT32 VariableMtrrCount;\r
867 MTRR_VARIABLE_SETTINGS VariableSettings;\r
f877f300 868\r
e50466da 869 //\r
85b7f65b 870 // Check if MTRR is enabled, if not, return UC as attribute\r
e50466da 871 //\r
5abd5ed4 872 if (MtrrSetting == NULL) {\r
10c361ad 873 DefType.Uint64 = AsmReadMsr64 (MSR_IA32_MTRR_DEF_TYPE);\r
5abd5ed4 874 } else {\r
10c361ad 875 DefType.Uint64 = MtrrSetting->MtrrDefType;\r
5abd5ed4 876 }\r
e50466da 877\r
10c361ad 878 if (DefType.Bits.E == 0) {\r
85b7f65b 879 return CacheUncacheable;\r
e50466da 880 }\r
881\r
882 //\r
85b7f65b 883 // If address is less than 1M, then try to go through the fixed MTRR\r
e50466da 884 //\r
85b7f65b 885 if (Address < BASE_1MB) {\r
10c361ad 886 if (DefType.Bits.FE != 0) {\r
85b7f65b
MK
887 //\r
888 // Go through the fixed MTRR\r
889 //\r
890 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
10c361ad
RN
891 if (Address >= mMtrrLibFixedMtrrTable[Index].BaseAddress &&\r
892 Address < mMtrrLibFixedMtrrTable[Index].BaseAddress +\r
893 (mMtrrLibFixedMtrrTable[Index].Length * 8)) {\r
894 SubIndex =\r
895 ((UINTN) Address - mMtrrLibFixedMtrrTable[Index].BaseAddress) /\r
896 mMtrrLibFixedMtrrTable[Index].Length;\r
897 if (MtrrSetting == NULL) {\r
898 FixedMtrr = AsmReadMsr64 (mMtrrLibFixedMtrrTable[Index].Msr);\r
899 } else {\r
900 FixedMtrr = MtrrSetting->Fixed.Mtrr[Index];\r
901 }\r
902 return (MTRR_MEMORY_CACHE_TYPE) (RShiftU64 (FixedMtrr, SubIndex * 8) & 0xFF);\r
903 }\r
85b7f65b 904 }\r
e50466da 905 }\r
906 }\r
d0baed7d 907\r
10c361ad 908 VariableMtrrCount = GetVariableMtrrCountWorker ();\r
2bbd7e2f 909 ASSERT (VariableMtrrCount <= ARRAY_SIZE (MtrrSetting->Variables.Mtrr));\r
10c361ad 910 MtrrGetVariableMtrrWorker (MtrrSetting, VariableMtrrCount, &VariableSettings);\r
e50466da 911\r
10c361ad 912 MtrrLibInitializeMtrrMask (&MtrrValidBitsMask, &MtrrValidAddressMask);\r
2bbd7e2f 913 MtrrLibGetRawVariableRanges (\r
10c361ad
RN
914 &VariableSettings,\r
915 VariableMtrrCount,\r
916 MtrrValidBitsMask,\r
917 MtrrValidAddressMask,\r
918 VariableMtrr\r
919 );\r
d0baed7d 920\r
e50466da 921 //\r
85b7f65b 922 // Go through the variable MTRR\r
e50466da 923 //\r
10c361ad 924 MtrrType = CacheInvalid;\r
85b7f65b 925 for (Index = 0; Index < VariableMtrrCount; Index++) {\r
2bbd7e2f 926 if (VariableMtrr[Index].Length != 0) {\r
85b7f65b 927 if (Address >= VariableMtrr[Index].BaseAddress &&\r
10c361ad
RN
928 Address < VariableMtrr[Index].BaseAddress + VariableMtrr[Index].Length) {\r
929 if (MtrrType == CacheInvalid) {\r
930 MtrrType = (MTRR_MEMORY_CACHE_TYPE) VariableMtrr[Index].Type;\r
931 } else {\r
932 MtrrType = MtrrLibPrecedence (MtrrType, (MTRR_MEMORY_CACHE_TYPE) VariableMtrr[Index].Type);\r
933 }\r
85b7f65b
MK
934 }\r
935 }\r
e50466da 936 }\r
937\r
10c361ad
RN
938 //\r
939 // If there is no MTRR which covers the Address, use the default MTRR type.\r
940 //\r
941 if (MtrrType == CacheInvalid) {\r
942 MtrrType = (MTRR_MEMORY_CACHE_TYPE) DefType.Bits.Type;\r
943 }\r
944\r
945 return MtrrType;\r
85b7f65b
MK
946}\r
947\r
948\r
5abd5ed4
MK
949/**\r
950 This function will get the memory cache type of the specific address.\r
951\r
952 This function is mainly for debug purpose.\r
953\r
954 @param[in] Address The specific address\r
955\r
956 @return Memory cache type of the specific address\r
957\r
958**/\r
959MTRR_MEMORY_CACHE_TYPE\r
960EFIAPI\r
961MtrrGetMemoryAttribute (\r
962 IN PHYSICAL_ADDRESS Address\r
963 )\r
964{\r
965 if (!IsMtrrSupported ()) {\r
966 return CacheUncacheable;\r
967 }\r
968\r
969 return MtrrGetMemoryAttributeByAddressWorker (NULL, Address);\r
970}\r
971\r
8051302a
RN
972/**\r
973 Update the Ranges array to change the specified range identified by\r
974 BaseAddress and Length to Type.\r
975\r
976 @param Ranges Array holding memory type settings for all memory regions.\r
977 @param Capacity The maximum count of memory ranges the array can hold.\r
978 @param Count Return the new memory range count in the array.\r
979 @param BaseAddress The base address of the memory range to change type.\r
980 @param Length The length of the memory range to change type.\r
981 @param Type The new type of the specified memory range.\r
982\r
983 @retval RETURN_SUCCESS The type of the specified memory range is\r
984 changed successfully.\r
2bbd7e2f
RN
985 @retval RETURN_ALREADY_STARTED The type of the specified memory range equals\r
986 to the desired type.\r
8051302a
RN
987 @retval RETURN_OUT_OF_RESOURCES The new type set causes the count of memory\r
988 range exceeds capacity.\r
989**/\r
990RETURN_STATUS\r
991MtrrLibSetMemoryType (\r
2bbd7e2f
RN
992 IN MTRR_MEMORY_RANGE *Ranges,\r
993 IN UINTN Capacity,\r
994 IN OUT UINTN *Count,\r
8051302a
RN
995 IN UINT64 BaseAddress,\r
996 IN UINT64 Length,\r
997 IN MTRR_MEMORY_CACHE_TYPE Type\r
998 )\r
999{\r
2bbd7e2f 1000 UINTN Index;\r
8051302a
RN
1001 UINT64 Limit;\r
1002 UINT64 LengthLeft;\r
1003 UINT64 LengthRight;\r
2bbd7e2f
RN
1004 UINTN StartIndex;\r
1005 UINTN EndIndex;\r
1006 UINTN DeltaCount;\r
8051302a 1007\r
4ef6c385
RN
1008 LengthRight = 0;\r
1009 LengthLeft = 0;\r
8051302a
RN
1010 Limit = BaseAddress + Length;\r
1011 StartIndex = *Count;\r
1012 EndIndex = *Count;\r
1013 for (Index = 0; Index < *Count; Index++) {\r
1014 if ((StartIndex == *Count) &&\r
1015 (Ranges[Index].BaseAddress <= BaseAddress) &&\r
1016 (BaseAddress < Ranges[Index].BaseAddress + Ranges[Index].Length)) {\r
1017 StartIndex = Index;\r
1018 LengthLeft = BaseAddress - Ranges[Index].BaseAddress;\r
1019 }\r
1020\r
1021 if ((EndIndex == *Count) &&\r
1022 (Ranges[Index].BaseAddress < Limit) &&\r
1023 (Limit <= Ranges[Index].BaseAddress + Ranges[Index].Length)) {\r
1024 EndIndex = Index;\r
1025 LengthRight = Ranges[Index].BaseAddress + Ranges[Index].Length - Limit;\r
1026 break;\r
1027 }\r
1028 }\r
1029\r
1030 ASSERT (StartIndex != *Count && EndIndex != *Count);\r
1031 if (StartIndex == EndIndex && Ranges[StartIndex].Type == Type) {\r
2bbd7e2f 1032 return RETURN_ALREADY_STARTED;\r
8051302a
RN
1033 }\r
1034\r
1035 //\r
1036 // The type change may cause merging with previous range or next range.\r
1037 // Update the StartIndex, EndIndex, BaseAddress, Length so that following\r
1038 // logic doesn't need to consider merging.\r
1039 //\r
1040 if (StartIndex != 0) {\r
1041 if (LengthLeft == 0 && Ranges[StartIndex - 1].Type == Type) {\r
1042 StartIndex--;\r
1043 Length += Ranges[StartIndex].Length;\r
1044 BaseAddress -= Ranges[StartIndex].Length;\r
1045 }\r
1046 }\r
1047 if (EndIndex != (*Count) - 1) {\r
1048 if (LengthRight == 0 && Ranges[EndIndex + 1].Type == Type) {\r
1049 EndIndex++;\r
1050 Length += Ranges[EndIndex].Length;\r
1051 }\r
1052 }\r
1053\r
1054 //\r
1055 // |- 0 -|- 1 -|- 2 -|- 3 -| StartIndex EndIndex DeltaCount Count (Count = 4)\r
1056 // |++++++++++++++++++| 0 3 1=3-0-2 3\r
1057 // |+++++++| 0 1 -1=1-0-2 5\r
1058 // |+| 0 0 -2=0-0-2 6\r
1059 // |+++| 0 0 -1=0-0-2+1 5\r
1060 //\r
1061 //\r
1062 DeltaCount = EndIndex - StartIndex - 2;\r
1063 if (LengthLeft == 0) {\r
1064 DeltaCount++;\r
1065 }\r
1066 if (LengthRight == 0) {\r
1067 DeltaCount++;\r
1068 }\r
1069 if (*Count - DeltaCount > Capacity) {\r
1070 return RETURN_OUT_OF_RESOURCES;\r
1071 }\r
1072\r
1073 //\r
1074 // Reserve (-DeltaCount) space\r
1075 //\r
1076 CopyMem (&Ranges[EndIndex + 1 - DeltaCount], &Ranges[EndIndex + 1], (*Count - EndIndex - 1) * sizeof (Ranges[0]));\r
1077 *Count -= DeltaCount;\r
1078\r
1079 if (LengthLeft != 0) {\r
1080 Ranges[StartIndex].Length = LengthLeft;\r
1081 StartIndex++;\r
1082 }\r
1083 if (LengthRight != 0) {\r
1084 Ranges[EndIndex - DeltaCount].BaseAddress = BaseAddress + Length;\r
1085 Ranges[EndIndex - DeltaCount].Length = LengthRight;\r
1086 Ranges[EndIndex - DeltaCount].Type = Ranges[EndIndex].Type;\r
1087 }\r
1088 Ranges[StartIndex].BaseAddress = BaseAddress;\r
1089 Ranges[StartIndex].Length = Length;\r
1090 Ranges[StartIndex].Type = Type;\r
1091 return RETURN_SUCCESS;\r
1092}\r
1093\r
1094/**\r
2bbd7e2f 1095 Return the number of memory types in range [BaseAddress, BaseAddress + Length).\r
8051302a 1096\r
2bbd7e2f
RN
1097 @param Ranges Array holding memory type settings for all memory regions.\r
1098 @param RangeCount The count of memory ranges the array holds.\r
1099 @param BaseAddress Base address.\r
1100 @param Length Length.\r
1101 @param Types Return bit mask to indicate all memory types in the specified range.\r
8051302a 1102\r
2bbd7e2f 1103 @retval Number of memory types.\r
8051302a 1104**/\r
2bbd7e2f
RN
1105UINT8\r
1106MtrrLibGetNumberOfTypes (\r
1107 IN CONST MTRR_MEMORY_RANGE *Ranges,\r
1108 IN UINTN RangeCount,\r
1109 IN UINT64 BaseAddress,\r
1110 IN UINT64 Length,\r
1111 IN OUT UINT8 *Types OPTIONAL\r
1112 )\r
1113{\r
1114 UINTN Index;\r
1115 UINT8 TypeCount;\r
1116 UINT8 LocalTypes;\r
1117\r
1118 TypeCount = 0;\r
1119 LocalTypes = 0;\r
1120 for (Index = 0; Index < RangeCount; Index++) {\r
1121 if ((Ranges[Index].BaseAddress <= BaseAddress) &&\r
1122 (BaseAddress < Ranges[Index].BaseAddress + Ranges[Index].Length)\r
1123 ) {\r
1124 if ((LocalTypes & (1 << Ranges[Index].Type)) == 0) {\r
1125 LocalTypes |= (UINT8)(1 << Ranges[Index].Type);\r
1126 TypeCount++;\r
1127 }\r
1128\r
1129 if (BaseAddress + Length > Ranges[Index].BaseAddress + Ranges[Index].Length) {\r
1130 Length -= Ranges[Index].BaseAddress + Ranges[Index].Length - BaseAddress;\r
1131 BaseAddress = Ranges[Index].BaseAddress + Ranges[Index].Length;\r
1132 } else {\r
1133 break;\r
1134 }\r
1135 }\r
1136 }\r
1137\r
1138 if (Types != NULL) {\r
1139 *Types = LocalTypes;\r
1140 }\r
1141 return TypeCount;\r
1142}\r
8051302a
RN
1143\r
1144/**\r
3143144b
RN
1145 Calculate the least MTRR number from vertex Start to Stop and update\r
1146 the Previous of all vertices from Start to Stop is updated to reflect\r
2bbd7e2f
RN
1147 how the memory range is covered by MTRR.\r
1148\r
3143144b
RN
1149 @param VertexCount The count of vertices in the graph.\r
1150 @param Vertices Array holding all vertices.\r
1151 @param Weight 2-dimention array holding weights between vertices.\r
1152 @param Start Start vertex.\r
1153 @param Stop Stop vertex.\r
2bbd7e2f
RN
1154 @param IncludeOptional TRUE to count the optional weight.\r
1155**/\r
1156VOID\r
1157MtrrLibCalculateLeastMtrrs (\r
3143144b
RN
1158 IN UINT16 VertexCount,\r
1159 IN MTRR_LIB_ADDRESS *Vertices,\r
2bbd7e2f
RN
1160 IN OUT CONST UINT8 *Weight,\r
1161 IN UINT16 Start,\r
1162 IN UINT16 Stop,\r
1163 IN BOOLEAN IncludeOptional\r
1164 )\r
1165{\r
1166 UINT16 Index;\r
1167 UINT8 MinWeight;\r
1168 UINT16 MinI;\r
1169 UINT8 Mandatory;\r
1170 UINT8 Optional;\r
1171\r
1172 for (Index = Start; Index <= Stop; Index++) {\r
3143144b 1173 Vertices[Index].Visited = FALSE;\r
2bbd7e2f 1174 Mandatory = Weight[M(Start,Index)];\r
3143144b 1175 Vertices[Index].Weight = Mandatory;\r
2bbd7e2f
RN
1176 if (Mandatory != MAX_WEIGHT) {\r
1177 Optional = IncludeOptional ? Weight[O(Start, Index)] : 0;\r
3143144b
RN
1178 Vertices[Index].Weight += Optional;\r
1179 ASSERT (Vertices[Index].Weight >= Optional);\r
2bbd7e2f
RN
1180 }\r
1181 }\r
8051302a 1182\r
2bbd7e2f
RN
1183 MinI = Start;\r
1184 MinWeight = 0;\r
3143144b 1185 while (!Vertices[Stop].Visited) {\r
2bbd7e2f 1186 //\r
3143144b 1187 // Update the weight from the shortest vertex to other unvisited vertices\r
2bbd7e2f
RN
1188 //\r
1189 for (Index = Start + 1; Index <= Stop; Index++) {\r
3143144b 1190 if (!Vertices[Index].Visited) {\r
2bbd7e2f
RN
1191 Mandatory = Weight[M(MinI, Index)];\r
1192 if (Mandatory != MAX_WEIGHT) {\r
1193 Optional = IncludeOptional ? Weight[O(MinI, Index)] : 0;\r
3143144b
RN
1194 if (MinWeight + Mandatory + Optional <= Vertices[Index].Weight) {\r
1195 Vertices[Index].Weight = MinWeight + Mandatory + Optional;\r
1196 Vertices[Index].Previous = MinI; // Previous is Start based.\r
2bbd7e2f
RN
1197 }\r
1198 }\r
1199 }\r
1200 }\r
8051302a 1201\r
2bbd7e2f 1202 //\r
3143144b 1203 // Find the shortest vertex from Start\r
2bbd7e2f 1204 //\r
3143144b 1205 MinI = VertexCount;\r
2bbd7e2f
RN
1206 MinWeight = MAX_WEIGHT;\r
1207 for (Index = Start + 1; Index <= Stop; Index++) {\r
3143144b 1208 if (!Vertices[Index].Visited && MinWeight > Vertices[Index].Weight) {\r
2bbd7e2f 1209 MinI = Index;\r
3143144b 1210 MinWeight = Vertices[Index].Weight;\r
2bbd7e2f
RN
1211 }\r
1212 }\r
8051302a 1213\r
2bbd7e2f 1214 //\r
3143144b 1215 // Mark the shortest vertex from Start as visited\r
2bbd7e2f 1216 //\r
3143144b 1217 Vertices[MinI].Visited = TRUE;\r
2bbd7e2f
RN
1218 }\r
1219}\r
1220\r
1221/**\r
1222 Append the MTRR setting to MTRR setting array.\r
1223\r
1224 @param Mtrrs Array holding all MTRR settings.\r
1225 @param MtrrCapacity Capacity of the MTRR array.\r
1226 @param MtrrCount The count of MTRR settings in array.\r
1227 @param BaseAddress Base address.\r
1228 @param Length Length.\r
1229 @param Type Memory type.\r
1230\r
1231 @retval RETURN_SUCCESS MTRR setting is appended to array.\r
1232 @retval RETURN_OUT_OF_RESOURCES Array is full.\r
8051302a
RN
1233**/\r
1234RETURN_STATUS\r
2bbd7e2f
RN
1235MtrrLibAppendVariableMtrr (\r
1236 IN OUT MTRR_MEMORY_RANGE *Mtrrs,\r
1237 IN UINT32 MtrrCapacity,\r
1238 IN OUT UINT32 *MtrrCount,\r
1239 IN UINT64 BaseAddress,\r
1240 IN UINT64 Length,\r
1241 IN MTRR_MEMORY_CACHE_TYPE Type\r
1242 )\r
1243{\r
1244 if (*MtrrCount == MtrrCapacity) {\r
1245 return RETURN_OUT_OF_RESOURCES;\r
1246 }\r
1247\r
1248 Mtrrs[*MtrrCount].BaseAddress = BaseAddress;\r
1249 Mtrrs[*MtrrCount].Length = Length;\r
1250 Mtrrs[*MtrrCount].Type = Type;\r
1251 (*MtrrCount)++;\r
1252 return RETURN_SUCCESS;\r
1253}\r
1254\r
1255/**\r
1256 Return the memory type that has the least precedence.\r
1257\r
1258 @param TypeBits Bit mask of memory type.\r
1259\r
1260 @retval Memory type that has the least precedence.\r
1261**/\r
1262MTRR_MEMORY_CACHE_TYPE\r
1263MtrrLibLowestType (\r
1264 IN UINT8 TypeBits\r
8051302a
RN
1265)\r
1266{\r
2bbd7e2f 1267 INT8 Type;\r
8051302a 1268\r
2bbd7e2f
RN
1269 ASSERT (TypeBits != 0);\r
1270 for (Type = 7; (INT8)TypeBits > 0; Type--, TypeBits <<= 1);\r
1271 return (MTRR_MEMORY_CACHE_TYPE)Type;\r
1272}\r
8051302a 1273\r
2bbd7e2f
RN
1274/**\r
1275 Return TRUE when the Operand is exactly power of 2.\r
1276\r
1277 @retval TRUE Operand is exactly power of 2.\r
1278 @retval FALSE Operand is not power of 2.\r
1279**/\r
1280BOOLEAN\r
1281MtrrLibIsPowerOfTwo (\r
1282 IN UINT64 Operand\r
1283)\r
1284{\r
1285 ASSERT (Operand != 0);\r
1286 return (BOOLEAN) ((Operand & (Operand - 1)) == 0);\r
1287}\r
1288\r
1289/**\r
3143144b 1290 Calculate the subtractive path from vertex Start to Stop.\r
2bbd7e2f
RN
1291\r
1292 @param DefaultType Default memory type.\r
1293 @param A0 Alignment to use when base address is 0.\r
1294 @param Ranges Array holding memory type settings for all memory regions.\r
1295 @param RangeCount The count of memory ranges the array holds.\r
3143144b
RN
1296 @param VertexCount The count of vertices in the graph.\r
1297 @param Vertices Array holding all vertices.\r
1298 @param Weight 2-dimention array holding weights between vertices.\r
1299 @param Start Start vertex.\r
1300 @param Stop Stop vertex.\r
2bbd7e2f
RN
1301 @param Types Type bit mask of memory range from Start to Stop.\r
1302 @param TypeCount Number of different memory types from Start to Stop.\r
1303 @param Mtrrs Array holding all MTRR settings.\r
1304 @param MtrrCapacity Capacity of the MTRR array.\r
1305 @param MtrrCount The count of MTRR settings in array.\r
1306\r
1307 @retval RETURN_SUCCESS The subtractive path is calculated successfully.\r
1308 @retval RETURN_OUT_OF_RESOURCES The MTRR setting array is full.\r
1309\r
1310**/\r
1311RETURN_STATUS\r
1312MtrrLibCalculateSubtractivePath (\r
1313 IN MTRR_MEMORY_CACHE_TYPE DefaultType,\r
1314 IN UINT64 A0,\r
1315 IN CONST MTRR_MEMORY_RANGE *Ranges,\r
1316 IN UINTN RangeCount,\r
3143144b
RN
1317 IN UINT16 VertexCount,\r
1318 IN MTRR_LIB_ADDRESS *Vertices,\r
2bbd7e2f
RN
1319 IN OUT UINT8 *Weight,\r
1320 IN UINT16 Start,\r
1321 IN UINT16 Stop,\r
1322 IN UINT8 Types,\r
1323 IN UINT8 TypeCount,\r
1324 IN OUT MTRR_MEMORY_RANGE *Mtrrs, OPTIONAL\r
1325 IN UINT32 MtrrCapacity, OPTIONAL\r
1326 IN OUT UINT32 *MtrrCount OPTIONAL\r
1327 )\r
1328{\r
1329 RETURN_STATUS Status;\r
1330 UINT64 Base;\r
1331 UINT64 Length;\r
1332 UINT8 PrecedentTypes;\r
1333 UINTN Index;\r
1334 UINT64 HBase;\r
1335 UINT64 HLength;\r
1336 UINT64 SubLength;\r
1337 UINT16 SubStart;\r
1338 UINT16 SubStop;\r
1339 UINT16 Cur;\r
1340 UINT16 Pre;\r
1341 MTRR_MEMORY_CACHE_TYPE LowestType;\r
1342 MTRR_MEMORY_CACHE_TYPE LowestPrecedentType;\r
1343\r
3143144b
RN
1344 Base = Vertices[Start].Address;\r
1345 Length = Vertices[Stop].Address - Base;\r
2bbd7e2f
RN
1346\r
1347 LowestType = MtrrLibLowestType (Types);\r
1348\r
1349 //\r
1350 // Clear the lowest type (highest bit) to get the precedent types\r
1351 //\r
1352 PrecedentTypes = ~(1 << LowestType) & Types;\r
1353 LowestPrecedentType = MtrrLibLowestType (PrecedentTypes);\r
1354\r
1355 if (Mtrrs == NULL) {\r
1356 Weight[M(Start, Stop)] = ((LowestType == DefaultType) ? 0 : 1);\r
1357 Weight[O(Start, Stop)] = ((LowestType == DefaultType) ? 1 : 0);\r
1358 }\r
1359\r
1360 // Add all high level ranges\r
1361 HBase = MAX_UINT64;\r
1362 HLength = 0;\r
1363 for (Index = 0; Index < RangeCount; Index++) {\r
1364 if (Length == 0) {\r
1365 break;\r
1366 }\r
1367 if ((Base < Ranges[Index].BaseAddress) || (Ranges[Index].BaseAddress + Ranges[Index].Length <= Base)) {\r
1368 continue;\r
8051302a
RN
1369 }\r
1370\r
1371 //\r
2bbd7e2f 1372 // Base is in the Range[Index]\r
8051302a 1373 //\r
2bbd7e2f
RN
1374 if (Base + Length > Ranges[Index].BaseAddress + Ranges[Index].Length) {\r
1375 SubLength = Ranges[Index].BaseAddress + Ranges[Index].Length - Base;\r
1376 } else {\r
1377 SubLength = Length;\r
1378 }\r
1379 if (((1 << Ranges[Index].Type) & PrecedentTypes) != 0) {\r
1380 //\r
1381 // Meet a range whose types take precedence.\r
1382 // Update the [HBase, HBase + HLength) to include the range,\r
1383 // [HBase, HBase + HLength) may contain sub ranges with 2 different types, and both take precedence.\r
1384 //\r
1385 if (HBase == MAX_UINT64) {\r
1386 HBase = Base;\r
8051302a 1387 }\r
2bbd7e2f 1388 HLength += SubLength;\r
8051302a 1389 }\r
2bbd7e2f
RN
1390\r
1391 Base += SubLength;\r
1392 Length -= SubLength;\r
1393\r
1394 if (HLength == 0) {\r
1395 continue;\r
1396 }\r
1397\r
1398 if ((Ranges[Index].Type == LowestType) || (Length == 0)) { // meet low type or end\r
1399\r
1400 //\r
1401 // Add the MTRRs for each high priority type range\r
1402 // the range[HBase, HBase + HLength) contains only two types.\r
1403 // We might use positive or subtractive, depending on which way uses less MTRR\r
1404 //\r
1405 for (SubStart = Start; SubStart <= Stop; SubStart++) {\r
3143144b 1406 if (Vertices[SubStart].Address == HBase) {\r
2bbd7e2f
RN
1407 break;\r
1408 }\r
8051302a 1409 }\r
2bbd7e2f
RN
1410\r
1411 for (SubStop = SubStart; SubStop <= Stop; SubStop++) {\r
3143144b 1412 if (Vertices[SubStop].Address == HBase + HLength) {\r
2bbd7e2f
RN
1413 break;\r
1414 }\r
1415 }\r
3143144b
RN
1416 ASSERT (Vertices[SubStart].Address == HBase);\r
1417 ASSERT (Vertices[SubStop].Address == HBase + HLength);\r
2bbd7e2f
RN
1418\r
1419 if ((TypeCount == 2) || (SubStart == SubStop - 1)) {\r
1420 //\r
1421 // add subtractive MTRRs for [HBase, HBase + HLength)\r
1422 // [HBase, HBase + HLength) contains only one type.\r
1423 // while - loop is to split the range to MTRR - compliant aligned range.\r
1424 //\r
1425 if (Mtrrs == NULL) {\r
1426 Weight[M (Start, Stop)] += (UINT8)(SubStop - SubStart);\r
1427 } else {\r
1428 while (SubStart != SubStop) {\r
1429 Status = MtrrLibAppendVariableMtrr (\r
1430 Mtrrs, MtrrCapacity, MtrrCount,\r
57951033 1431 Vertices[SubStart].Address, Vertices[SubStart].Length, Vertices[SubStart].Type\r
2bbd7e2f
RN
1432 );\r
1433 if (RETURN_ERROR (Status)) {\r
1434 return Status;\r
1435 }\r
1436 SubStart++;\r
1437 }\r
1438 }\r
1439 } else {\r
1440 ASSERT (TypeCount == 3);\r
3143144b 1441 MtrrLibCalculateLeastMtrrs (VertexCount, Vertices, Weight, SubStart, SubStop, TRUE);\r
2bbd7e2f
RN
1442\r
1443 if (Mtrrs == NULL) {\r
3143144b 1444 Weight[M (Start, Stop)] += Vertices[SubStop].Weight;\r
2bbd7e2f
RN
1445 } else {\r
1446 // When we need to collect the optimal path from SubStart to SubStop\r
1447 while (SubStop != SubStart) {\r
1448 Cur = SubStop;\r
3143144b 1449 Pre = Vertices[Cur].Previous;\r
2bbd7e2f
RN
1450 SubStop = Pre;\r
1451\r
57951033 1452 if (Weight[M (Pre, Cur)] + Weight[O (Pre, Cur)] != 0) {\r
2bbd7e2f
RN
1453 Status = MtrrLibAppendVariableMtrr (\r
1454 Mtrrs, MtrrCapacity, MtrrCount,\r
57951033
RN
1455 Vertices[Pre].Address, Vertices[Cur].Address - Vertices[Pre].Address,\r
1456 (Pre != Cur - 1) ? LowestPrecedentType : Vertices[Pre].Type\r
2bbd7e2f
RN
1457 );\r
1458 if (RETURN_ERROR (Status)) {\r
1459 return Status;\r
1460 }\r
1461 }\r
1462 if (Pre != Cur - 1) {\r
1463 Status = MtrrLibCalculateSubtractivePath (\r
1464 DefaultType, A0,\r
1465 Ranges, RangeCount,\r
3143144b 1466 VertexCount, Vertices, Weight,\r
2bbd7e2f
RN
1467 Pre, Cur, PrecedentTypes, 2,\r
1468 Mtrrs, MtrrCapacity, MtrrCount\r
1469 );\r
1470 if (RETURN_ERROR (Status)) {\r
1471 return Status;\r
1472 }\r
1473 }\r
1474 }\r
1475 }\r
1476\r
1477 }\r
1478 //\r
1479 // Reset HBase, HLength\r
1480 //\r
1481 HBase = MAX_UINT64;\r
1482 HLength = 0;\r
8051302a 1483 }\r
8051302a 1484 }\r
2bbd7e2f 1485 return RETURN_SUCCESS;\r
8051302a
RN
1486}\r
1487\r
1488/**\r
2bbd7e2f
RN
1489 Calculate MTRR settings to cover the specified memory ranges.\r
1490\r
1491 @param DefaultType Default memory type.\r
1492 @param A0 Alignment to use when base address is 0.\r
1493 @param Ranges Memory range array holding the memory type\r
1494 settings for all memory address.\r
1495 @param RangeCount Count of memory ranges.\r
1496 @param Scratch A temporary scratch buffer that is used to perform the calculation.\r
1497 This is an optional parameter that may be NULL.\r
1498 @param ScratchSize Pointer to the size in bytes of the scratch buffer.\r
1499 It may be updated to the actual required size when the calculation\r
1500 needs more scratch buffer.\r
1501 @param Mtrrs Array holding all MTRR settings.\r
1502 @param MtrrCapacity Capacity of the MTRR array.\r
1503 @param MtrrCount The count of MTRR settings in array.\r
8051302a
RN
1504\r
1505 @retval RETURN_SUCCESS Variable MTRRs are allocated successfully.\r
1506 @retval RETURN_OUT_OF_RESOURCES Count of variable MTRRs exceeds capacity.\r
2bbd7e2f 1507 @retval RETURN_BUFFER_TOO_SMALL The scratch buffer is too small for MTRR calculation.\r
8051302a
RN
1508**/\r
1509RETURN_STATUS\r
2bbd7e2f
RN
1510MtrrLibCalculateMtrrs (\r
1511 IN MTRR_MEMORY_CACHE_TYPE DefaultType,\r
1512 IN UINT64 A0,\r
1513 IN CONST MTRR_MEMORY_RANGE *Ranges,\r
1514 IN UINTN RangeCount,\r
1515 IN VOID *Scratch,\r
1516 IN OUT UINTN *ScratchSize,\r
1517 IN OUT MTRR_MEMORY_RANGE *Mtrrs,\r
1518 IN UINT32 MtrrCapacity,\r
1519 IN OUT UINT32 *MtrrCount\r
1520 )\r
8051302a 1521{\r
2bbd7e2f
RN
1522 UINT64 Base0;\r
1523 UINT64 Base1;\r
1524 UINTN Index;\r
1525 UINT64 Base;\r
1526 UINT64 Length;\r
8051302a 1527 UINT64 Alignment;\r
2bbd7e2f 1528 UINT64 SubLength;\r
3143144b 1529 MTRR_LIB_ADDRESS *Vertices;\r
2bbd7e2f 1530 UINT8 *Weight;\r
3143144b
RN
1531 UINT32 VertexIndex;\r
1532 UINT32 VertexCount;\r
2bbd7e2f
RN
1533 UINTN RequiredScratchSize;\r
1534 UINT8 TypeCount;\r
1535 UINT16 Start;\r
1536 UINT16 Stop;\r
1537 UINT8 Type;\r
1538 RETURN_STATUS Status;\r
3ff1e898 1539\r
2bbd7e2f
RN
1540 Base0 = Ranges[0].BaseAddress;\r
1541 Base1 = Ranges[RangeCount - 1].BaseAddress + Ranges[RangeCount - 1].Length;\r
1542 MTRR_LIB_ASSERT_ALIGNED (Base0, Base1 - Base0);\r
8051302a 1543\r
2bbd7e2f 1544 //\r
3143144b 1545 // Count the number of vertices.\r
2bbd7e2f 1546 //\r
3143144b
RN
1547 Vertices = (MTRR_LIB_ADDRESS*)Scratch;\r
1548 for (VertexIndex = 0, Index = 0; Index < RangeCount; Index++) {\r
2bbd7e2f
RN
1549 Base = Ranges[Index].BaseAddress;\r
1550 Length = Ranges[Index].Length;\r
1551 while (Length != 0) {\r
1552 Alignment = MtrrLibBiggestAlignment (Base, A0);\r
1553 SubLength = Alignment;\r
1554 if (SubLength > Length) {\r
1555 SubLength = GetPowerOfTwo64 (Length);\r
1556 }\r
3143144b
RN
1557 if (VertexIndex < *ScratchSize / sizeof (*Vertices)) {\r
1558 Vertices[VertexIndex].Address = Base;\r
1559 Vertices[VertexIndex].Alignment = Alignment;\r
1560 Vertices[VertexIndex].Type = Ranges[Index].Type;\r
1561 Vertices[VertexIndex].Length = SubLength;\r
2bbd7e2f
RN
1562 }\r
1563 Base += SubLength;\r
1564 Length -= SubLength;\r
3143144b 1565 VertexIndex++;\r
2bbd7e2f 1566 }\r
8051302a 1567 }\r
2bbd7e2f 1568 //\r
3143144b 1569 // Vertices[VertexIndex] = Base1, so whole vertex count is (VertexIndex + 1).\r
2bbd7e2f 1570 //\r
3143144b 1571 VertexCount = VertexIndex + 1;\r
2bbd7e2f 1572 DEBUG ((\r
3143144b
RN
1573 DEBUG_CACHE, " Count of vertices (%016llx - %016llx) = %d\n",\r
1574 Ranges[0].BaseAddress, Ranges[RangeCount - 1].BaseAddress + Ranges[RangeCount - 1].Length, VertexCount\r
2bbd7e2f 1575 ));\r
3143144b 1576 ASSERT (VertexCount < MAX_UINT16);\r
8051302a 1577\r
3143144b 1578 RequiredScratchSize = VertexCount * sizeof (*Vertices) + VertexCount * VertexCount * sizeof (*Weight);\r
2bbd7e2f
RN
1579 if (*ScratchSize < RequiredScratchSize) {\r
1580 *ScratchSize = RequiredScratchSize;\r
1581 return RETURN_BUFFER_TOO_SMALL;\r
8051302a 1582 }\r
3143144b 1583 Vertices[VertexCount - 1].Address = Base1;\r
8051302a 1584\r
3143144b
RN
1585 Weight = (UINT8 *) &Vertices[VertexCount];\r
1586 for (VertexIndex = 0; VertexIndex < VertexCount; VertexIndex++) {\r
ffb4c72d
RN
1587 //\r
1588 // Set optional weight between vertices and self->self to 0\r
1589 //\r
3143144b 1590 SetMem (&Weight[M(VertexIndex, 0)], VertexIndex + 1, 0);\r
ffb4c72d 1591 //\r
3143144b 1592 // Set mandatory weight between vertices to MAX_WEIGHT\r
ffb4c72d 1593 //\r
3143144b 1594 SetMem (&Weight[M (VertexIndex, VertexIndex + 1)], VertexCount - VertexIndex - 1, MAX_WEIGHT);\r
ffb4c72d
RN
1595\r
1596 // Final result looks like:\r
1597 // 00 FF FF FF\r
1598 // 00 00 FF FF\r
1599 // 00 00 00 FF\r
1600 // 00 00 00 00\r
1601 }\r
1602\r
1603 //\r
1604 // Set mandatory weight and optional weight for adjacent vertices\r
1605 //\r
3143144b
RN
1606 for (VertexIndex = 0; VertexIndex < VertexCount - 1; VertexIndex++) {\r
1607 if (Vertices[VertexIndex].Type != DefaultType) {\r
1608 Weight[M (VertexIndex, VertexIndex + 1)] = 1;\r
1609 Weight[O (VertexIndex, VertexIndex + 1)] = 0;\r
ffb4c72d 1610 } else {\r
3143144b
RN
1611 Weight[M (VertexIndex, VertexIndex + 1)] = 0;\r
1612 Weight[O (VertexIndex, VertexIndex + 1)] = 1;\r
8051302a 1613 }\r
8051302a
RN
1614 }\r
1615\r
2bbd7e2f 1616 for (TypeCount = 2; TypeCount <= 3; TypeCount++) {\r
3143144b
RN
1617 for (Start = 0; Start < VertexCount; Start++) {\r
1618 for (Stop = Start + 2; Stop < VertexCount; Stop++) {\r
1619 ASSERT (Vertices[Stop].Address > Vertices[Start].Address);\r
1620 Length = Vertices[Stop].Address - Vertices[Start].Address;\r
1621 if (Length > Vertices[Start].Alignment) {\r
2bbd7e2f
RN
1622 //\r
1623 // Pickup a new Start when [Start, Stop) cannot be described by one MTRR.\r
1624 //\r
1625 break;\r
1626 }\r
1627 if ((Weight[M(Start, Stop)] == MAX_WEIGHT) && MtrrLibIsPowerOfTwo (Length)) {\r
1628 if (MtrrLibGetNumberOfTypes (\r
3143144b 1629 Ranges, RangeCount, Vertices[Start].Address, Vertices[Stop].Address - Vertices[Start].Address, &Type\r
2bbd7e2f
RN
1630 ) == TypeCount) {\r
1631 //\r
1632 // Update the Weight[Start, Stop] using subtractive path.\r
1633 //\r
1634 MtrrLibCalculateSubtractivePath (\r
1635 DefaultType, A0,\r
1636 Ranges, RangeCount,\r
3143144b 1637 (UINT16)VertexCount, Vertices, Weight,\r
2bbd7e2f
RN
1638 Start, Stop, Type, TypeCount,\r
1639 NULL, 0, NULL\r
1640 );\r
1641 } else if (TypeCount == 2) {\r
1642 //\r
1643 // Pick up a new Start when we expect 2-type range, but 3-type range is met.\r
1644 // Because no matter how Stop is increased, we always meet 3-type range.\r
1645 //\r
1646 break;\r
1647 }\r
1648 }\r
1649 }\r
1650 }\r
8051302a
RN
1651 }\r
1652\r
2bbd7e2f 1653 Status = RETURN_SUCCESS;\r
3143144b
RN
1654 MtrrLibCalculateLeastMtrrs ((UINT16) VertexCount, Vertices, Weight, 0, (UINT16) VertexCount - 1, FALSE);\r
1655 Stop = (UINT16) VertexCount - 1;\r
2bbd7e2f 1656 while (Stop != 0) {\r
3143144b 1657 Start = Vertices[Stop].Previous;\r
2bbd7e2f
RN
1658 TypeCount = MAX_UINT8;\r
1659 Type = 0;\r
1660 if (Weight[M(Start, Stop)] != 0) {\r
3143144b 1661 TypeCount = MtrrLibGetNumberOfTypes (Ranges, RangeCount, Vertices[Start].Address, Vertices[Stop].Address - Vertices[Start].Address, &Type);\r
2bbd7e2f
RN
1662 Status = MtrrLibAppendVariableMtrr (\r
1663 Mtrrs, MtrrCapacity, MtrrCount,\r
3143144b 1664 Vertices[Start].Address, Vertices[Stop].Address - Vertices[Start].Address,\r
2bbd7e2f
RN
1665 MtrrLibLowestType (Type)\r
1666 );\r
1667 if (RETURN_ERROR (Status)) {\r
1668 break;\r
8051302a
RN
1669 }\r
1670 }\r
1671\r
2bbd7e2f
RN
1672 if (Start != Stop - 1) {\r
1673 //\r
1674 // substractive path\r
1675 //\r
1676 if (TypeCount == MAX_UINT8) {\r
1677 TypeCount = MtrrLibGetNumberOfTypes (\r
3143144b 1678 Ranges, RangeCount, Vertices[Start].Address, Vertices[Stop].Address - Vertices[Start].Address, &Type\r
2bbd7e2f
RN
1679 );\r
1680 }\r
1681 Status = MtrrLibCalculateSubtractivePath (\r
1682 DefaultType, A0,\r
1683 Ranges, RangeCount,\r
3143144b 1684 (UINT16) VertexCount, Vertices, Weight, Start, Stop,\r
2bbd7e2f
RN
1685 Type, TypeCount,\r
1686 Mtrrs, MtrrCapacity, MtrrCount\r
1687 );\r
1688 if (RETURN_ERROR (Status)) {\r
1689 break;\r
1690 }\r
8051302a 1691 }\r
2bbd7e2f
RN
1692 Stop = Start;\r
1693 }\r
1694 return Status;\r
1695}\r
1696\r
8051302a 1697\r
2bbd7e2f 1698/**\r
57994d9c 1699 Apply the fixed MTRR settings to memory range array.\r
2bbd7e2f
RN
1700\r
1701 @param Fixed The fixed MTRR settings.\r
1702 @param Ranges Return the memory range array holding memory type\r
1703 settings for all memory address.\r
1704 @param RangeCapacity The capacity of memory range array.\r
1705 @param RangeCount Return the count of memory range.\r
1706\r
1707 @retval RETURN_SUCCESS The memory range array is returned successfully.\r
1708 @retval RETURN_OUT_OF_RESOURCES The count of memory ranges exceeds capacity.\r
1709**/\r
1710RETURN_STATUS\r
1711MtrrLibApplyFixedMtrrs (\r
1712 IN MTRR_FIXED_SETTINGS *Fixed,\r
1713 IN OUT MTRR_MEMORY_RANGE *Ranges,\r
1714 IN UINTN RangeCapacity,\r
1715 IN OUT UINTN *RangeCount\r
1716 )\r
1717{\r
1718 RETURN_STATUS Status;\r
1719 UINTN MsrIndex;\r
1720 UINTN Index;\r
1721 MTRR_MEMORY_CACHE_TYPE MemoryType;\r
1722 UINT64 Base;\r
1723\r
1724 Base = 0;\r
1725 for (MsrIndex = 0; MsrIndex < ARRAY_SIZE (mMtrrLibFixedMtrrTable); MsrIndex++) {\r
1726 ASSERT (Base == mMtrrLibFixedMtrrTable[MsrIndex].BaseAddress);\r
1727 for (Index = 0; Index < sizeof (UINT64); Index++) {\r
1728 MemoryType = (MTRR_MEMORY_CACHE_TYPE)((UINT8 *)(&Fixed->Mtrr[MsrIndex]))[Index];\r
1729 Status = MtrrLibSetMemoryType (\r
1730 Ranges, RangeCapacity, RangeCount, Base, mMtrrLibFixedMtrrTable[MsrIndex].Length, MemoryType\r
1731 );\r
1732 if (Status == RETURN_OUT_OF_RESOURCES) {\r
1733 return Status;\r
1734 }\r
1735 Base += mMtrrLibFixedMtrrTable[MsrIndex].Length;\r
1736 }\r
8051302a 1737 }\r
2bbd7e2f 1738 ASSERT (Base == BASE_1MB);\r
8051302a
RN
1739 return RETURN_SUCCESS;\r
1740}\r
1741\r
1742/**\r
2bbd7e2f 1743 Apply the variable MTRR settings to memory range array.\r
8051302a 1744\r
8051302a
RN
1745 @param VariableMtrr The variable MTRR array.\r
1746 @param VariableMtrrCount The count of variable MTRRs.\r
2bbd7e2f 1747 @param Ranges Return the memory range array with new MTRR settings applied.\r
8051302a
RN
1748 @param RangeCapacity The capacity of memory range array.\r
1749 @param RangeCount Return the count of memory range.\r
1750\r
1751 @retval RETURN_SUCCESS The memory range array is returned successfully.\r
1752 @retval RETURN_OUT_OF_RESOURCES The count of memory ranges exceeds capacity.\r
1753**/\r
1754RETURN_STATUS\r
2bbd7e2f
RN
1755MtrrLibApplyVariableMtrrs (\r
1756 IN CONST MTRR_MEMORY_RANGE *VariableMtrr,\r
1757 IN UINT32 VariableMtrrCount,\r
1758 IN OUT MTRR_MEMORY_RANGE *Ranges,\r
1759 IN UINTN RangeCapacity,\r
1760 IN OUT UINTN *RangeCount\r
1761 )\r
8051302a
RN
1762{\r
1763 RETURN_STATUS Status;\r
1764 UINTN Index;\r
1765\r
1766 //\r
1767 // WT > WB\r
1768 // UC > *\r
1769 // UC > * (except WB, UC) > WB\r
1770 //\r
1771\r
8051302a
RN
1772 //\r
1773 // 1. Set WB\r
1774 //\r
1775 for (Index = 0; Index < VariableMtrrCount; Index++) {\r
2bbd7e2f 1776 if ((VariableMtrr[Index].Length != 0) && (VariableMtrr[Index].Type == CacheWriteBack)) {\r
8051302a
RN
1777 Status = MtrrLibSetMemoryType (\r
1778 Ranges, RangeCapacity, RangeCount,\r
2bbd7e2f 1779 VariableMtrr[Index].BaseAddress, VariableMtrr[Index].Length, VariableMtrr[Index].Type\r
8051302a 1780 );\r
2bbd7e2f 1781 if (Status == RETURN_OUT_OF_RESOURCES) {\r
8051302a
RN
1782 return Status;\r
1783 }\r
1784 }\r
1785 }\r
1786\r
1787 //\r
1788 // 2. Set other types than WB or UC\r
1789 //\r
1790 for (Index = 0; Index < VariableMtrrCount; Index++) {\r
3143144b 1791 if ((VariableMtrr[Index].Length != 0) &&\r
2bbd7e2f 1792 (VariableMtrr[Index].Type != CacheWriteBack) && (VariableMtrr[Index].Type != CacheUncacheable)) {\r
8051302a 1793 Status = MtrrLibSetMemoryType (\r
2bbd7e2f
RN
1794 Ranges, RangeCapacity, RangeCount,\r
1795 VariableMtrr[Index].BaseAddress, VariableMtrr[Index].Length, VariableMtrr[Index].Type\r
1796 );\r
1797 if (Status == RETURN_OUT_OF_RESOURCES) {\r
8051302a
RN
1798 return Status;\r
1799 }\r
1800 }\r
1801 }\r
1802\r
1803 //\r
1804 // 3. Set UC\r
1805 //\r
1806 for (Index = 0; Index < VariableMtrrCount; Index++) {\r
2bbd7e2f 1807 if (VariableMtrr[Index].Length != 0 && VariableMtrr[Index].Type == CacheUncacheable) {\r
8051302a 1808 Status = MtrrLibSetMemoryType (\r
2bbd7e2f
RN
1809 Ranges, RangeCapacity, RangeCount,\r
1810 VariableMtrr[Index].BaseAddress, VariableMtrr[Index].Length, VariableMtrr[Index].Type\r
1811 );\r
1812 if (Status == RETURN_OUT_OF_RESOURCES) {\r
8051302a
RN
1813 return Status;\r
1814 }\r
1815 }\r
1816 }\r
1817 return RETURN_SUCCESS;\r
1818}\r
16c2d37e 1819\r
85b7f65b 1820/**\r
2bbd7e2f 1821 Return the memory type bit mask that's compatible to first type in the Ranges.\r
85b7f65b 1822\r
2bbd7e2f
RN
1823 @param Ranges Memory range array holding the memory type\r
1824 settings for all memory address.\r
1825 @param RangeCount Count of memory ranges.\r
b970ed68 1826\r
2bbd7e2f
RN
1827 @return Compatible memory type bit mask.\r
1828**/\r
1829UINT8\r
1830MtrrLibGetCompatibleTypes (\r
1831 IN CONST MTRR_MEMORY_RANGE *Ranges,\r
1832 IN UINTN RangeCount\r
1833 )\r
1834{\r
1835 ASSERT (RangeCount != 0);\r
1836\r
1837 switch (Ranges[0].Type) {\r
1838 case CacheWriteBack:\r
1839 case CacheWriteThrough:\r
1840 return (1 << CacheWriteBack) | (1 << CacheWriteThrough) | (1 << CacheUncacheable);\r
1841 break;\r
1842\r
1843 case CacheWriteCombining:\r
1844 case CacheWriteProtected:\r
1845 return (1 << Ranges[0].Type) | (1 << CacheUncacheable);\r
1846 break;\r
1847\r
1848 case CacheUncacheable:\r
1849 if (RangeCount == 1) {\r
1850 return (1 << CacheUncacheable);\r
1851 }\r
1852 return MtrrLibGetCompatibleTypes (&Ranges[1], RangeCount - 1);\r
1853 break;\r
85b7f65b 1854\r
2bbd7e2f
RN
1855 case CacheInvalid:\r
1856 default:\r
1857 ASSERT (FALSE);\r
1858 break;\r
1859 }\r
1860 return 0;\r
1861}\r
85b7f65b 1862\r
2bbd7e2f
RN
1863/**\r
1864 Overwrite the destination MTRR settings with the source MTRR settings.\r
1865 This routine is to make sure the modification to destination MTRR settings\r
1866 is as small as possible.\r
1867\r
1868 @param DstMtrrs Destination MTRR settings.\r
1869 @param DstMtrrCount Count of destination MTRR settings.\r
1870 @param SrcMtrrs Source MTRR settings.\r
1871 @param SrcMtrrCount Count of source MTRR settings.\r
1872 @param Modified Flag array to indicate which destination MTRR setting is modified.\r
85b7f65b 1873**/\r
2bbd7e2f
RN
1874VOID\r
1875MtrrLibMergeVariableMtrr (\r
1876 MTRR_MEMORY_RANGE *DstMtrrs,\r
1877 UINT32 DstMtrrCount,\r
1878 MTRR_MEMORY_RANGE *SrcMtrrs,\r
1879 UINT32 SrcMtrrCount,\r
1880 BOOLEAN *Modified\r
85b7f65b
MK
1881 )\r
1882{\r
2bbd7e2f
RN
1883 UINT32 DstIndex;\r
1884 UINT32 SrcIndex;\r
8051302a 1885\r
2bbd7e2f 1886 ASSERT (SrcMtrrCount <= DstMtrrCount);\r
8051302a 1887\r
2bbd7e2f
RN
1888 for (DstIndex = 0; DstIndex < DstMtrrCount; DstIndex++) {\r
1889 Modified[DstIndex] = FALSE;\r
85b7f65b 1890\r
2bbd7e2f
RN
1891 if (DstMtrrs[DstIndex].Length == 0) {\r
1892 continue;\r
1893 }\r
1894 for (SrcIndex = 0; SrcIndex < SrcMtrrCount; SrcIndex++) {\r
1895 if (DstMtrrs[DstIndex].BaseAddress == SrcMtrrs[SrcIndex].BaseAddress &&\r
1896 DstMtrrs[DstIndex].Length == SrcMtrrs[SrcIndex].Length &&\r
1897 DstMtrrs[DstIndex].Type == SrcMtrrs[SrcIndex].Type) {\r
1898 break;\r
1899 }\r
1900 }\r
85b7f65b 1901\r
2bbd7e2f
RN
1902 if (SrcIndex == SrcMtrrCount) {\r
1903 //\r
1904 // Remove the one from DstMtrrs which is not in SrcMtrrs\r
1905 //\r
1906 DstMtrrs[DstIndex].Length = 0;\r
1907 Modified[DstIndex] = TRUE;\r
1908 } else {\r
1909 //\r
1910 // Remove the one from SrcMtrrs which is also in DstMtrrs\r
1911 //\r
1912 SrcMtrrs[SrcIndex].Length = 0;\r
1913 }\r
85b7f65b
MK
1914 }\r
1915\r
2bbd7e2f
RN
1916 //\r
1917 // Now valid MTRR only exists in either DstMtrrs or SrcMtrrs.\r
1918 // Merge MTRRs from SrcMtrrs to DstMtrrs\r
1919 //\r
1920 DstIndex = 0;\r
1921 for (SrcIndex = 0; SrcIndex < SrcMtrrCount; SrcIndex++) {\r
1922 if (SrcMtrrs[SrcIndex].Length != 0) {\r
85b7f65b 1923\r
2bbd7e2f
RN
1924 //\r
1925 // Find the empty slot in DstMtrrs\r
1926 //\r
1927 while (DstIndex < DstMtrrCount) {\r
1928 if (DstMtrrs[DstIndex].Length == 0) {\r
1929 break;\r
1930 }\r
1931 DstIndex++;\r
1932 }\r
1933 ASSERT (DstIndex < DstMtrrCount);\r
1934 CopyMem (&DstMtrrs[DstIndex], &SrcMtrrs[SrcIndex], sizeof (SrcMtrrs[0]));\r
1935 Modified[DstIndex] = TRUE;\r
1936 }\r
85b7f65b 1937 }\r
2bbd7e2f
RN
1938}\r
1939\r
1940/**\r
1941 Calculate the variable MTRR settings for all memory ranges.\r
85b7f65b 1942\r
2bbd7e2f
RN
1943 @param DefaultType Default memory type.\r
1944 @param A0 Alignment to use when base address is 0.\r
1945 @param Ranges Memory range array holding the memory type\r
1946 settings for all memory address.\r
1947 @param RangeCount Count of memory ranges.\r
1948 @param Scratch Scratch buffer to be used in MTRR calculation.\r
1949 @param ScratchSize Pointer to the size of scratch buffer.\r
1950 @param VariableMtrr Array holding all MTRR settings.\r
1951 @param VariableMtrrCapacity Capacity of the MTRR array.\r
1952 @param VariableMtrrCount The count of MTRR settings in array.\r
1953\r
1954 @retval RETURN_SUCCESS Variable MTRRs are allocated successfully.\r
1955 @retval RETURN_OUT_OF_RESOURCES Count of variable MTRRs exceeds capacity.\r
1956 @retval RETURN_BUFFER_TOO_SMALL The scratch buffer is too small for MTRR calculation.\r
1957 The required scratch buffer size is returned through ScratchSize.\r
1958**/\r
1959RETURN_STATUS\r
1960MtrrLibSetMemoryRanges (\r
1961 IN MTRR_MEMORY_CACHE_TYPE DefaultType,\r
1962 IN UINT64 A0,\r
1963 IN MTRR_MEMORY_RANGE *Ranges,\r
1964 IN UINTN RangeCount,\r
1965 IN VOID *Scratch,\r
1966 IN OUT UINTN *ScratchSize,\r
1967 OUT MTRR_MEMORY_RANGE *VariableMtrr,\r
1968 IN UINT32 VariableMtrrCapacity,\r
1969 OUT UINT32 *VariableMtrrCount\r
1970 )\r
1971{\r
1972 RETURN_STATUS Status;\r
1973 UINT32 Index;\r
1974 UINT64 Base0;\r
1975 UINT64 Base1;\r
1976 UINT64 Alignment;\r
1977 UINT8 CompatibleTypes;\r
1978 UINT64 Length;\r
1979 UINT32 End;\r
1980 UINTN ActualScratchSize;\r
1981 UINTN BiggestScratchSize;\r
1982\r
1983 *VariableMtrrCount = 0;\r
3143144b 1984\r
85b7f65b 1985 //\r
2bbd7e2f
RN
1986 // Since the whole ranges need multiple calls of MtrrLibCalculateMtrrs().\r
1987 // Each call needs different scratch buffer size.\r
1988 // When the provided scratch buffer size is not sufficient in any call,\r
1989 // set the GetActualScratchSize to TRUE, and following calls will only\r
1990 // calculate the actual scratch size for the caller.\r
85b7f65b 1991 //\r
2bbd7e2f
RN
1992 BiggestScratchSize = 0;\r
1993\r
1994 for (Index = 0; Index < RangeCount;) {\r
1995 Base0 = Ranges[Index].BaseAddress;\r
1996\r
1997 //\r
1998 // Full step is optimal\r
1999 //\r
2000 while (Index < RangeCount) {\r
2001 ASSERT (Ranges[Index].BaseAddress == Base0);\r
2002 Alignment = MtrrLibBiggestAlignment (Base0, A0);\r
2003 while (Base0 + Alignment <= Ranges[Index].BaseAddress + Ranges[Index].Length) {\r
2004 if ((BiggestScratchSize <= *ScratchSize) && (Ranges[Index].Type != DefaultType)) {\r
2005 Status = MtrrLibAppendVariableMtrr (\r
2006 VariableMtrr, VariableMtrrCapacity, VariableMtrrCount,\r
2007 Base0, Alignment, Ranges[Index].Type\r
2008 );\r
2009 if (RETURN_ERROR (Status)) {\r
2010 return Status;\r
2011 }\r
2012 }\r
2013 Base0 += Alignment;\r
2014 Alignment = MtrrLibBiggestAlignment (Base0, A0);\r
fa25cf38 2015 }\r
2bbd7e2f
RN
2016\r
2017 //\r
2018 // Remove the above range from Ranges[Index]\r
2019 //\r
2020 Ranges[Index].Length -= Base0 - Ranges[Index].BaseAddress;\r
2021 Ranges[Index].BaseAddress = Base0;\r
2022 if (Ranges[Index].Length != 0) {\r
2023 break;\r
b970ed68 2024 } else {\r
2bbd7e2f 2025 Index++;\r
fa25cf38 2026 }\r
85b7f65b 2027 }\r
85b7f65b 2028\r
2bbd7e2f
RN
2029 if (Index == RangeCount) {\r
2030 break;\r
2031 }\r
2032\r
2033 //\r
2034 // Find continous ranges [Base0, Base1) which could be combined by MTRR.\r
2035 // Per SDM, the compatible types between[B0, B1) are:\r
2036 // UC, *\r
2037 // WB, WT\r
2038 // UC, WB, WT\r
2039 //\r
2040 CompatibleTypes = MtrrLibGetCompatibleTypes (&Ranges[Index], RangeCount - Index);\r
2041\r
2042 End = Index; // End points to last one that matches the CompatibleTypes.\r
2043 while (End + 1 < RangeCount) {\r
2044 if (((1 << Ranges[End + 1].Type) & CompatibleTypes) == 0) {\r
2045 break;\r
2046 }\r
2047 End++;\r
2048 }\r
2049 Alignment = MtrrLibBiggestAlignment (Base0, A0);\r
2050 Length = GetPowerOfTwo64 (Ranges[End].BaseAddress + Ranges[End].Length - Base0);\r
2051 Base1 = Base0 + MIN (Alignment, Length);\r
2052\r
2053 //\r
2054 // Base1 may not in Ranges[End]. Update End to the range Base1 belongs to.\r
2055 //\r
2056 End = Index;\r
2057 while (End + 1 < RangeCount) {\r
2058 if (Base1 <= Ranges[End + 1].BaseAddress) {\r
2059 break;\r
2060 }\r
2061 End++;\r
2062 }\r
2063\r
2064 Length = Ranges[End].Length;\r
2065 Ranges[End].Length = Base1 - Ranges[End].BaseAddress;\r
2066 ActualScratchSize = *ScratchSize;\r
2067 Status = MtrrLibCalculateMtrrs (\r
2068 DefaultType, A0,\r
2069 &Ranges[Index], End + 1 - Index,\r
2070 Scratch, &ActualScratchSize,\r
2071 VariableMtrr, VariableMtrrCapacity, VariableMtrrCount\r
2072 );\r
2073 if (Status == RETURN_BUFFER_TOO_SMALL) {\r
2074 BiggestScratchSize = MAX (BiggestScratchSize, ActualScratchSize);\r
fa25cf38 2075 //\r
2bbd7e2f
RN
2076 // Ignore this error, because we need to calculate the biggest\r
2077 // scratch buffer size.\r
fa25cf38 2078 //\r
2bbd7e2f
RN
2079 Status = RETURN_SUCCESS;\r
2080 }\r
2081 if (RETURN_ERROR (Status)) {\r
2082 return Status;\r
2083 }\r
2084\r
2085 if (Length != Ranges[End].Length) {\r
2086 Ranges[End].BaseAddress = Base1;\r
2087 Ranges[End].Length = Length - Ranges[End].Length;\r
2088 Index = End;\r
2089 } else {\r
2090 Index = End + 1;\r
fa25cf38 2091 }\r
85b7f65b
MK
2092 }\r
2093\r
2bbd7e2f
RN
2094 if (*ScratchSize < BiggestScratchSize) {\r
2095 *ScratchSize = BiggestScratchSize;\r
2096 return RETURN_BUFFER_TOO_SMALL;\r
2097 }\r
2098 return RETURN_SUCCESS;\r
2099}\r
85b7f65b 2100\r
2bbd7e2f
RN
2101/**\r
2102 Set the below-1MB memory attribute to fixed MTRR buffer.\r
2103 Modified flag array indicates which fixed MTRR is modified.\r
2104\r
2105 @param [in, out] FixedSettings Fixed MTRR buffer.\r
2106 @param [out] Modified Flag array indicating which MTRR is modified.\r
2107 @param [in] BaseAddress Base address.\r
2108 @param [in] Length Length.\r
2109 @param [in] Type Memory type.\r
2110\r
2111 @retval RETURN_SUCCESS The memory attribute is set successfully.\r
2112 @retval RETURN_UNSUPPORTED The requested range or cache type was invalid\r
2113 for the fixed MTRRs.\r
2114**/\r
2115RETURN_STATUS\r
2116MtrrLibSetBelow1MBMemoryAttribute (\r
2117 IN OUT MTRR_FIXED_SETTINGS *FixedSettings,\r
2118 OUT BOOLEAN *Modified,\r
2119 IN PHYSICAL_ADDRESS BaseAddress,\r
2120 IN UINT64 Length,\r
2121 IN MTRR_MEMORY_CACHE_TYPE Type\r
2122 )\r
2123{\r
2124 RETURN_STATUS Status;\r
2125 UINT32 MsrIndex;\r
2126 UINT64 ClearMask;\r
2127 UINT64 OrMask;\r
2128 UINT64 ClearMasks[ARRAY_SIZE (mMtrrLibFixedMtrrTable)];\r
2129 UINT64 OrMasks[ARRAY_SIZE (mMtrrLibFixedMtrrTable)];\r
86cabbcf 2130 BOOLEAN LocalModified[ARRAY_SIZE (mMtrrLibFixedMtrrTable)];\r
2bbd7e2f
RN
2131\r
2132 ASSERT (BaseAddress < BASE_1MB);\r
2133\r
86cabbcf
RN
2134 SetMem (LocalModified, sizeof (LocalModified), FALSE);\r
2135\r
2136 //\r
2137 // (Value & ~0 | 0) still equals to (Value)\r
2138 //\r
e00e0dd7
RN
2139 SetMem (ClearMasks, sizeof (ClearMasks), 0);\r
2140 SetMem (OrMasks, sizeof (OrMasks), 0);\r
86cabbcf 2141\r
2bbd7e2f
RN
2142 MsrIndex = (UINT32)-1;\r
2143 while ((BaseAddress < BASE_1MB) && (Length != 0)) {\r
2144 Status = MtrrLibProgramFixedMtrr (Type, &BaseAddress, &Length, &MsrIndex, &ClearMask, &OrMask);\r
2145 if (RETURN_ERROR (Status)) {\r
2146 return Status;\r
2147 }\r
86cabbcf
RN
2148 ClearMasks[MsrIndex] = ClearMask;\r
2149 OrMasks[MsrIndex] = OrMask;\r
2150 Modified[MsrIndex] = TRUE;\r
2151 LocalModified[MsrIndex] = TRUE;\r
e50466da 2152 }\r
8051302a 2153\r
2bbd7e2f 2154 for (MsrIndex = 0; MsrIndex < ARRAY_SIZE (mMtrrLibFixedMtrrTable); MsrIndex++) {\r
86cabbcf 2155 if (LocalModified[MsrIndex]) {\r
2bbd7e2f
RN
2156 FixedSettings->Mtrr[MsrIndex] = (FixedSettings->Mtrr[MsrIndex] & ~ClearMasks[MsrIndex]) | OrMasks[MsrIndex];\r
2157 }\r
2158 }\r
2159 return RETURN_SUCCESS;\r
2160}\r
2161\r
2162/**\r
2163 This function attempts to set the attributes into MTRR setting buffer for multiple memory ranges.\r
8051302a 2164\r
2bbd7e2f
RN
2165 @param[in, out] MtrrSetting MTRR setting buffer to be set.\r
2166 @param[in] Scratch A temporary scratch buffer that is used to perform the calculation.\r
2167 @param[in, out] ScratchSize Pointer to the size in bytes of the scratch buffer.\r
2168 It may be updated to the actual required size when the calculation\r
2169 needs more scratch buffer.\r
2170 @param[in] Ranges Pointer to an array of MTRR_MEMORY_RANGE.\r
2171 When range overlap happens, the last one takes higher priority.\r
2172 When the function returns, either all the attributes are set successfully,\r
2173 or none of them is set.\r
f6194f5a 2174 @param[in] RangeCount Count of MTRR_MEMORY_RANGE.\r
2bbd7e2f
RN
2175\r
2176 @retval RETURN_SUCCESS The attributes were set for all the memory ranges.\r
2177 @retval RETURN_INVALID_PARAMETER Length in any range is zero.\r
2178 @retval RETURN_UNSUPPORTED The processor does not support one or more bytes of the\r
2179 memory resource range specified by BaseAddress and Length in any range.\r
2180 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support for the memory resource\r
2181 range specified by BaseAddress and Length in any range.\r
2182 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of\r
2183 the memory resource ranges.\r
2184 @retval RETURN_ACCESS_DENIED The attributes for the memory resource range specified by\r
2185 BaseAddress and Length cannot be modified.\r
2186 @retval RETURN_BUFFER_TOO_SMALL The scratch buffer is too small for MTRR calculation.\r
2187**/\r
2188RETURN_STATUS\r
2189EFIAPI\r
2190MtrrSetMemoryAttributesInMtrrSettings (\r
2191 IN OUT MTRR_SETTINGS *MtrrSetting,\r
2192 IN VOID *Scratch,\r
2193 IN OUT UINTN *ScratchSize,\r
2194 IN CONST MTRR_MEMORY_RANGE *Ranges,\r
2195 IN UINTN RangeCount\r
2196 )\r
2197{\r
2198 RETURN_STATUS Status;\r
2199 UINT32 Index;\r
2200 UINT64 BaseAddress;\r
2201 UINT64 Length;\r
2202 BOOLEAN Above1MbExist;\r
2203\r
2204 UINT64 MtrrValidBitsMask;\r
2205 UINT64 MtrrValidAddressMask;\r
2206 MTRR_MEMORY_CACHE_TYPE DefaultType;\r
2207 MTRR_VARIABLE_SETTINGS VariableSettings;\r
2208 MTRR_MEMORY_RANGE WorkingRanges[2 * ARRAY_SIZE (MtrrSetting->Variables.Mtrr) + 2];\r
2209 UINTN WorkingRangeCount;\r
2210 BOOLEAN Modified;\r
2211 MTRR_VARIABLE_SETTING VariableSetting;\r
2212 UINT32 OriginalVariableMtrrCount;\r
2213 UINT32 FirmwareVariableMtrrCount;\r
2214 UINT32 WorkingVariableMtrrCount;\r
2215 MTRR_MEMORY_RANGE OriginalVariableMtrr[ARRAY_SIZE (MtrrSetting->Variables.Mtrr)];\r
2216 MTRR_MEMORY_RANGE WorkingVariableMtrr[ARRAY_SIZE (MtrrSetting->Variables.Mtrr)];\r
2217 BOOLEAN VariableSettingModified[ARRAY_SIZE (MtrrSetting->Variables.Mtrr)];\r
2218\r
2219 BOOLEAN FixedSettingsModified[ARRAY_SIZE (mMtrrLibFixedMtrrTable)];\r
2220 MTRR_FIXED_SETTINGS WorkingFixedSettings;\r
2221\r
2222 MTRR_CONTEXT MtrrContext;\r
2223 BOOLEAN MtrrContextValid;\r
2224\r
5a6c5af6 2225 Status = RETURN_SUCCESS;\r
2bbd7e2f 2226 MtrrLibInitializeMtrrMask (&MtrrValidBitsMask, &MtrrValidAddressMask);\r
e50466da 2227\r
2228 //\r
2bbd7e2f 2229 // TRUE indicating the accordingly Variable setting needs modificaiton in OriginalVariableMtrr.\r
e50466da 2230 //\r
2bbd7e2f 2231 SetMem (VariableSettingModified, ARRAY_SIZE (VariableSettingModified), FALSE);\r
8051302a 2232 //\r
2bbd7e2f 2233 // TRUE indicating the accordingly Fixed setting needs modification in WorkingFixedSettings.\r
8051302a 2234 //\r
2bbd7e2f
RN
2235 SetMem (FixedSettingsModified, ARRAY_SIZE (FixedSettingsModified), FALSE);\r
2236\r
2237 //\r
2238 // TRUE indicating the caller requests to set variable MTRRs.\r
2239 //\r
2240 Above1MbExist = FALSE;\r
2241 OriginalVariableMtrrCount = 0;\r
e50466da 2242\r
5a6c5af6
RN
2243 //\r
2244 // 0. Dump the requests.\r
2245 //\r
2246 DEBUG_CODE (\r
2247 DEBUG ((DEBUG_CACHE, "Mtrr: Set Mem Attribute to %a, ScratchSize = %x%a",\r
2248 (MtrrSetting == NULL) ? "Hardware" : "Buffer", *ScratchSize,\r
2249 (RangeCount <= 1) ? "," : "\n"\r
2250 ));\r
2251 for (Index = 0; Index < RangeCount; Index++) {\r
2252 DEBUG ((DEBUG_CACHE, " %a: [%016lx, %016lx)\n",\r
2253 mMtrrMemoryCacheTypeShortName[MIN (Ranges[Index].Type, CacheInvalid)],\r
2254 Ranges[Index].BaseAddress, Ranges[Index].BaseAddress + Ranges[Index].Length\r
2255 ));\r
2256 }\r
2257 );\r
2258\r
2bbd7e2f
RN
2259 //\r
2260 // 1. Validate the parameters.\r
2261 //\r
5a6c5af6
RN
2262 if (!IsMtrrSupported ()) {\r
2263 Status = RETURN_UNSUPPORTED;\r
2264 goto Exit;\r
2265 }\r
2266\r
8051302a 2267 for (Index = 0; Index < RangeCount; Index++) {\r
2bbd7e2f 2268 if (Ranges[Index].Length == 0) {\r
5a6c5af6
RN
2269 Status = RETURN_INVALID_PARAMETER;\r
2270 goto Exit;\r
2bbd7e2f
RN
2271 }\r
2272 if (((Ranges[Index].BaseAddress & ~MtrrValidAddressMask) != 0) ||\r
cee85c48
RN
2273 ((((Ranges[Index].BaseAddress + Ranges[Index].Length) & ~MtrrValidAddressMask) != 0) &&\r
2274 (Ranges[Index].BaseAddress + Ranges[Index].Length) != MtrrValidBitsMask + 1)\r
2bbd7e2f 2275 ) {\r
cee85c48
RN
2276 //\r
2277 // Either the BaseAddress or the Limit doesn't follow the alignment requirement.\r
2278 // Note: It's still valid if Limit doesn't follow the alignment requirement but equals to MAX Address.\r
2279 //\r
5a6c5af6
RN
2280 Status = RETURN_UNSUPPORTED;\r
2281 goto Exit;\r
2bbd7e2f
RN
2282 }\r
2283 if ((Ranges[Index].Type != CacheUncacheable) &&\r
2284 (Ranges[Index].Type != CacheWriteCombining) &&\r
2285 (Ranges[Index].Type != CacheWriteThrough) &&\r
2286 (Ranges[Index].Type != CacheWriteProtected) &&\r
2287 (Ranges[Index].Type != CacheWriteBack)) {\r
5a6c5af6
RN
2288 Status = RETURN_INVALID_PARAMETER;\r
2289 goto Exit;\r
2bbd7e2f
RN
2290 }\r
2291 if (Ranges[Index].BaseAddress + Ranges[Index].Length > BASE_1MB) {\r
2292 Above1MbExist = TRUE;\r
8051302a 2293 }\r
1a2ad6fc 2294 }\r
e50466da 2295\r
1a2ad6fc 2296 //\r
2bbd7e2f 2297 // 2. Apply the above-1MB memory attribute settings.\r
1a2ad6fc 2298 //\r
2bbd7e2f
RN
2299 if (Above1MbExist) {\r
2300 //\r
2301 // 2.1. Read all variable MTRRs and convert to Ranges.\r
2302 //\r
2303 OriginalVariableMtrrCount = GetVariableMtrrCountWorker ();\r
2304 MtrrGetVariableMtrrWorker (MtrrSetting, OriginalVariableMtrrCount, &VariableSettings);\r
2305 MtrrLibGetRawVariableRanges (\r
2306 &VariableSettings, OriginalVariableMtrrCount,\r
2307 MtrrValidBitsMask, MtrrValidAddressMask, OriginalVariableMtrr\r
2308 );\r
1a2ad6fc 2309\r
2bbd7e2f
RN
2310 DefaultType = MtrrGetDefaultMemoryTypeWorker (MtrrSetting);\r
2311 WorkingRangeCount = 1;\r
2312 WorkingRanges[0].BaseAddress = 0;\r
2313 WorkingRanges[0].Length = MtrrValidBitsMask + 1;\r
2314 WorkingRanges[0].Type = DefaultType;\r
1a2ad6fc 2315\r
2bbd7e2f
RN
2316 Status = MtrrLibApplyVariableMtrrs (\r
2317 OriginalVariableMtrr, OriginalVariableMtrrCount,\r
2318 WorkingRanges, ARRAY_SIZE (WorkingRanges), &WorkingRangeCount);\r
2319 ASSERT_RETURN_ERROR (Status);\r
1a2ad6fc 2320\r
2bbd7e2f
RN
2321 ASSERT (OriginalVariableMtrrCount >= PcdGet32 (PcdCpuNumberOfReservedVariableMtrrs));\r
2322 FirmwareVariableMtrrCount = OriginalVariableMtrrCount - PcdGet32 (PcdCpuNumberOfReservedVariableMtrrs);\r
2323 ASSERT (WorkingRangeCount <= 2 * FirmwareVariableMtrrCount + 1);\r
1a2ad6fc 2324\r
8051302a 2325 //\r
2bbd7e2f 2326 // 2.2. Force [0, 1M) to UC, so that it doesn't impact subtraction algorithm.\r
8051302a 2327 //\r
2bbd7e2f
RN
2328 Status = MtrrLibSetMemoryType (\r
2329 WorkingRanges, ARRAY_SIZE (WorkingRanges), &WorkingRangeCount,\r
2330 0, SIZE_1MB, CacheUncacheable\r
2331 );\r
2332 ASSERT (Status != RETURN_OUT_OF_RESOURCES);\r
8051302a 2333\r
2bbd7e2f
RN
2334 //\r
2335 // 2.3. Apply the new memory attribute settings to Ranges.\r
2336 //\r
2337 Modified = FALSE;\r
2338 for (Index = 0; Index < RangeCount; Index++) {\r
2339 BaseAddress = Ranges[Index].BaseAddress;\r
2340 Length = Ranges[Index].Length;\r
2341 if (BaseAddress < BASE_1MB) {\r
2342 if (Length <= BASE_1MB - BaseAddress) {\r
2343 continue;\r
1a2ad6fc 2344 }\r
2bbd7e2f
RN
2345 Length -= BASE_1MB - BaseAddress;\r
2346 BaseAddress = BASE_1MB;\r
1a2ad6fc 2347 }\r
2bbd7e2f
RN
2348 Status = MtrrLibSetMemoryType (\r
2349 WorkingRanges, ARRAY_SIZE (WorkingRanges), &WorkingRangeCount,\r
2350 BaseAddress, Length, Ranges[Index].Type\r
2351 );\r
2352 if (Status == RETURN_ALREADY_STARTED) {\r
2353 Status = RETURN_SUCCESS;\r
2354 } else if (Status == RETURN_OUT_OF_RESOURCES) {\r
5a6c5af6 2355 goto Exit;\r
8051302a 2356 } else {\r
2bbd7e2f
RN
2357 ASSERT_RETURN_ERROR (Status);\r
2358 Modified = TRUE;\r
8051302a 2359 }\r
1a2ad6fc 2360 }\r
1a2ad6fc 2361\r
2bbd7e2f
RN
2362 if (Modified) {\r
2363 //\r
2364 // 2.4. Calculate the Variable MTRR settings based on the Ranges.\r
2365 // Buffer Too Small may be returned if the scratch buffer size is insufficient.\r
2366 //\r
2367 Status = MtrrLibSetMemoryRanges (\r
2368 DefaultType, LShiftU64 (1, (UINTN)HighBitSet64 (MtrrValidBitsMask)), WorkingRanges, WorkingRangeCount,\r
2369 Scratch, ScratchSize,\r
2370 WorkingVariableMtrr, FirmwareVariableMtrrCount + 1, &WorkingVariableMtrrCount\r
2371 );\r
2372 if (RETURN_ERROR (Status)) {\r
5a6c5af6 2373 goto Exit;\r
2bbd7e2f 2374 }\r
e50466da 2375\r
2bbd7e2f
RN
2376 //\r
2377 // 2.5. Remove the [0, 1MB) MTRR if it still exists (not merged with other range)\r
2378 //\r
2379 for (Index = 0; Index < WorkingVariableMtrrCount; Index++) {\r
2380 if (WorkingVariableMtrr[Index].BaseAddress == 0 && WorkingVariableMtrr[Index].Length == SIZE_1MB) {\r
2381 ASSERT (WorkingVariableMtrr[Index].Type == CacheUncacheable);\r
2382 WorkingVariableMtrrCount--;\r
2383 CopyMem (\r
2384 &WorkingVariableMtrr[Index], &WorkingVariableMtrr[Index + 1],\r
2385 (WorkingVariableMtrrCount - Index) * sizeof (WorkingVariableMtrr[0])\r
2386 );\r
2387 break;\r
c9b44921 2388 }\r
85b7f65b 2389 }\r
2bbd7e2f
RN
2390\r
2391 if (WorkingVariableMtrrCount > FirmwareVariableMtrrCount) {\r
5a6c5af6
RN
2392 Status = RETURN_OUT_OF_RESOURCES;\r
2393 goto Exit;\r
2bbd7e2f
RN
2394 }\r
2395\r
2396 //\r
2397 // 2.6. Merge the WorkingVariableMtrr to OriginalVariableMtrr\r
2398 // Make sure least modification is made to OriginalVariableMtrr.\r
2399 //\r
2400 MtrrLibMergeVariableMtrr (\r
2401 OriginalVariableMtrr, OriginalVariableMtrrCount,\r
2402 WorkingVariableMtrr, WorkingVariableMtrrCount,\r
2403 VariableSettingModified\r
2404 );\r
85b7f65b 2405 }\r
e50466da 2406 }\r
2407\r
8051302a 2408 //\r
2bbd7e2f 2409 // 3. Apply the below-1MB memory attribute settings.\r
8051302a 2410 //\r
86cabbcf 2411 ZeroMem (WorkingFixedSettings.Mtrr, sizeof (WorkingFixedSettings.Mtrr));\r
2bbd7e2f
RN
2412 for (Index = 0; Index < RangeCount; Index++) {\r
2413 if (Ranges[Index].BaseAddress >= BASE_1MB) {\r
2414 continue;\r
85b7f65b 2415 }\r
85b7f65b 2416\r
2bbd7e2f
RN
2417 Status = MtrrLibSetBelow1MBMemoryAttribute (\r
2418 &WorkingFixedSettings, FixedSettingsModified,\r
2419 Ranges[Index].BaseAddress, Ranges[Index].Length, Ranges[Index].Type\r
2420 );\r
2421 if (RETURN_ERROR (Status)) {\r
5a6c5af6 2422 goto Exit;\r
2bbd7e2f 2423 }\r
8051302a 2424 }\r
fa25cf38 2425\r
8051302a 2426 MtrrContextValid = FALSE;\r
fa25cf38 2427 //\r
2bbd7e2f 2428 // 4. Write fixed MTRRs that have been modified\r
fa25cf38 2429 //\r
2bbd7e2f 2430 for (Index = 0; Index < ARRAY_SIZE (FixedSettingsModified); Index++) {\r
fa25cf38 2431 if (FixedSettingsModified[Index]) {\r
2bbd7e2f
RN
2432 if (MtrrSetting != NULL) {\r
2433 MtrrSetting->Fixed.Mtrr[Index] = WorkingFixedSettings.Mtrr[Index];\r
2434 } else {\r
2435 if (!MtrrContextValid) {\r
2436 MtrrLibPreMtrrChange (&MtrrContext);\r
2437 MtrrContextValid = TRUE;\r
2438 }\r
2439 AsmWriteMsr64 (\r
2440 mMtrrLibFixedMtrrTable[Index].Msr,\r
2441 WorkingFixedSettings.Mtrr[Index]\r
fa25cf38 2442 );\r
2bbd7e2f 2443 }\r
fa25cf38
MK
2444 }\r
2445 }\r
2446\r
b0fa5d29 2447 //\r
2bbd7e2f 2448 // 5. Write variable MTRRs that have been modified\r
b0fa5d29 2449 //\r
8051302a
RN
2450 for (Index = 0; Index < OriginalVariableMtrrCount; Index++) {\r
2451 if (VariableSettingModified[Index]) {\r
2bbd7e2f
RN
2452 if (OriginalVariableMtrr[Index].Length != 0) {\r
2453 VariableSetting.Base = (OriginalVariableMtrr[Index].BaseAddress & MtrrValidAddressMask)\r
2454 | (UINT8)OriginalVariableMtrr[Index].Type;\r
2455 VariableSetting.Mask = ((~(OriginalVariableMtrr[Index].Length - 1)) & MtrrValidAddressMask) | BIT11;\r
2456 } else {\r
2457 VariableSetting.Base = 0;\r
2458 VariableSetting.Mask = 0;\r
2459 }\r
2460 if (MtrrSetting != NULL) {\r
2461 CopyMem (&MtrrSetting->Variables.Mtrr[Index], &VariableSetting, sizeof (VariableSetting));\r
2462 } else {\r
2463 if (!MtrrContextValid) {\r
2464 MtrrLibPreMtrrChange (&MtrrContext);\r
2465 MtrrContextValid = TRUE;\r
2466 }\r
2467 AsmWriteMsr64 (\r
2468 MSR_IA32_MTRR_PHYSBASE0 + (Index << 1),\r
2469 VariableSetting.Base\r
2470 );\r
2471 AsmWriteMsr64 (\r
2472 MSR_IA32_MTRR_PHYSMASK0 + (Index << 1),\r
2473 VariableSetting.Mask\r
2474 );\r
b0fa5d29
MK
2475 }\r
2476 }\r
2477 }\r
2bbd7e2f
RN
2478\r
2479 if (MtrrSetting != NULL) {\r
2480 ((MSR_IA32_MTRR_DEF_TYPE_REGISTER *)&MtrrSetting->MtrrDefType)->Bits.E = 1;\r
2481 ((MSR_IA32_MTRR_DEF_TYPE_REGISTER *)&MtrrSetting->MtrrDefType)->Bits.FE = 1;\r
2482 } else {\r
2483 if (MtrrContextValid) {\r
2484 MtrrLibPostMtrrChange (&MtrrContext);\r
2485 }\r
fa25cf38
MK
2486 }\r
2487\r
5a6c5af6
RN
2488Exit:\r
2489 DEBUG ((DEBUG_CACHE, " Result = %r\n", Status));\r
2490 if (!RETURN_ERROR (Status)) {\r
2491 MtrrDebugPrintAllMtrrsWorker (MtrrSetting);\r
2492 }\r
2493 return Status;\r
31b3597e 2494}\r
b970ed68
MK
2495\r
2496/**\r
2bbd7e2f 2497 This function attempts to set the attributes into MTRR setting buffer for a memory range.\r
b970ed68 2498\r
2bbd7e2f
RN
2499 @param[in, out] MtrrSetting MTRR setting buffer to be set.\r
2500 @param[in] BaseAddress The physical address that is the start address\r
2501 of a memory range.\r
2502 @param[in] Length The size in bytes of the memory range.\r
2503 @param[in] Attribute The bit mask of attributes to set for the\r
2504 memory range.\r
b970ed68 2505\r
2bbd7e2f 2506 @retval RETURN_SUCCESS The attributes were set for the memory range.\r
b970ed68 2507 @retval RETURN_INVALID_PARAMETER Length is zero.\r
2bbd7e2f
RN
2508 @retval RETURN_UNSUPPORTED The processor does not support one or more bytes of the\r
2509 memory resource range specified by BaseAddress and Length.\r
2510 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support for the memory resource\r
2511 range specified by BaseAddress and Length.\r
2512 @retval RETURN_ACCESS_DENIED The attributes for the memory resource range specified by\r
2513 BaseAddress and Length cannot be modified.\r
2514 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of\r
2515 the memory resource range.\r
bc6a8b78
RN
2516 Multiple memory range attributes setting by calling this API multiple\r
2517 times may fail with status RETURN_OUT_OF_RESOURCES. It may not mean\r
2518 the number of CPU MTRRs are too small to set such memory attributes.\r
2519 Pass the multiple memory range attributes to one call of\r
2520 MtrrSetMemoryAttributesInMtrrSettings() may succeed.\r
8b2eb7b3
RN
2521 @retval RETURN_BUFFER_TOO_SMALL The fixed internal scratch buffer is too small for MTRR calculation.\r
2522 Caller should use MtrrSetMemoryAttributesInMtrrSettings() to specify\r
2523 external scratch buffer.\r
b970ed68
MK
2524**/\r
2525RETURN_STATUS\r
2526EFIAPI\r
2bbd7e2f
RN
2527MtrrSetMemoryAttributeInMtrrSettings (\r
2528 IN OUT MTRR_SETTINGS *MtrrSetting,\r
b970ed68
MK
2529 IN PHYSICAL_ADDRESS BaseAddress,\r
2530 IN UINT64 Length,\r
2531 IN MTRR_MEMORY_CACHE_TYPE Attribute\r
2532 )\r
2533{\r
2bbd7e2f
RN
2534 UINT8 Scratch[SCRATCH_BUFFER_SIZE];\r
2535 UINTN ScratchSize;\r
2536 MTRR_MEMORY_RANGE Range;\r
8051302a 2537\r
2bbd7e2f
RN
2538 Range.BaseAddress = BaseAddress;\r
2539 Range.Length = Length;\r
2540 Range.Type = Attribute;\r
2541 ScratchSize = sizeof (Scratch);\r
5a6c5af6 2542 return MtrrSetMemoryAttributesInMtrrSettings (MtrrSetting, Scratch, &ScratchSize, &Range, 1);\r
b970ed68
MK
2543}\r
2544\r
2545/**\r
2bbd7e2f 2546 This function attempts to set the attributes for a memory range.\r
b970ed68 2547\r
2bbd7e2f
RN
2548 @param[in] BaseAddress The physical address that is the start\r
2549 address of a memory range.\r
2550 @param[in] Length The size in bytes of the memory range.\r
2551 @param[in] Attributes The bit mask of attributes to set for the\r
2552 memory range.\r
b970ed68 2553\r
2bbd7e2f
RN
2554 @retval RETURN_SUCCESS The attributes were set for the memory\r
2555 range.\r
b970ed68 2556 @retval RETURN_INVALID_PARAMETER Length is zero.\r
2bbd7e2f
RN
2557 @retval RETURN_UNSUPPORTED The processor does not support one or\r
2558 more bytes of the memory resource range\r
2559 specified by BaseAddress and Length.\r
2560 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support\r
2561 for the memory resource range specified\r
2562 by BaseAddress and Length.\r
2563 @retval RETURN_ACCESS_DENIED The attributes for the memory resource\r
2564 range specified by BaseAddress and Length\r
2565 cannot be modified.\r
2566 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to\r
2567 modify the attributes of the memory\r
2568 resource range.\r
bc6a8b78
RN
2569 Multiple memory range attributes setting by calling this API multiple\r
2570 times may fail with status RETURN_OUT_OF_RESOURCES. It may not mean\r
2571 the number of CPU MTRRs are too small to set such memory attributes.\r
2572 Pass the multiple memory range attributes to one call of\r
2573 MtrrSetMemoryAttributesInMtrrSettings() may succeed.\r
8b2eb7b3
RN
2574 @retval RETURN_BUFFER_TOO_SMALL The fixed internal scratch buffer is too small for MTRR calculation.\r
2575 Caller should use MtrrSetMemoryAttributesInMtrrSettings() to specify\r
2576 external scratch buffer.\r
b970ed68
MK
2577**/\r
2578RETURN_STATUS\r
2579EFIAPI\r
2bbd7e2f 2580MtrrSetMemoryAttribute (\r
b970ed68
MK
2581 IN PHYSICAL_ADDRESS BaseAddress,\r
2582 IN UINT64 Length,\r
2583 IN MTRR_MEMORY_CACHE_TYPE Attribute\r
2584 )\r
2585{\r
2bbd7e2f 2586 return MtrrSetMemoryAttributeInMtrrSettings (NULL, BaseAddress, Length, Attribute);\r
b970ed68
MK
2587}\r
2588\r
e50466da 2589/**\r
2590 Worker function setting variable MTRRs\r
2591\r
76b4cae3 2592 @param[in] VariableSettings A buffer to hold variable MTRRs content.\r
e50466da 2593\r
2594**/\r
2595VOID\r
2596MtrrSetVariableMtrrWorker (\r
2597 IN MTRR_VARIABLE_SETTINGS *VariableSettings\r
2598 )\r
2599{\r
2600 UINT32 Index;\r
3b9be416 2601 UINT32 VariableMtrrCount;\r
e50466da 2602\r
acf431e6 2603 VariableMtrrCount = GetVariableMtrrCountWorker ();\r
2bbd7e2f 2604 ASSERT (VariableMtrrCount <= ARRAY_SIZE (VariableSettings->Mtrr));\r
5bdfa4e5 2605\r
3b9be416 2606 for (Index = 0; Index < VariableMtrrCount; Index++) {\r
9c8c4478
RN
2607 //\r
2608 // Mask MSR is always updated since caller might need to invalidate the MSR pair.\r
2609 // Base MSR is skipped when Mask.V is not set.\r
2610 //\r
2611 AsmWriteMsr64 (MSR_IA32_MTRR_PHYSMASK0 + (Index << 1), VariableSettings->Mtrr[Index].Mask);\r
2612 if (((MSR_IA32_MTRR_PHYSMASK_REGISTER *)&VariableSettings->Mtrr[Index].Mask)->Bits.V != 0) {\r
2613 AsmWriteMsr64 (MSR_IA32_MTRR_PHYSBASE0 + (Index << 1), VariableSettings->Mtrr[Index].Base);\r
2614 }\r
e50466da 2615 }\r
2616}\r
2617\r
2618\r
2619/**\r
2620 This function sets variable MTRRs\r
2621\r
76b4cae3 2622 @param[in] VariableSettings A buffer to hold variable MTRRs content.\r
e50466da 2623\r
2624 @return The pointer of VariableSettings\r
2625\r
2626**/\r
2627MTRR_VARIABLE_SETTINGS*\r
2628EFIAPI\r
2629MtrrSetVariableMtrr (\r
2630 IN MTRR_VARIABLE_SETTINGS *VariableSettings\r
2631 )\r
2632{\r
c878cee4 2633 MTRR_CONTEXT MtrrContext;\r
e50466da 2634\r
947a573a 2635 if (!IsMtrrSupported ()) {\r
2636 return VariableSettings;\r
2637 }\r
2638\r
b8f01599 2639 MtrrLibPreMtrrChange (&MtrrContext);\r
e50466da 2640 MtrrSetVariableMtrrWorker (VariableSettings);\r
b8f01599 2641 MtrrLibPostMtrrChange (&MtrrContext);\r
e518b80d
MK
2642 MtrrDebugPrintAllMtrrs ();\r
2643\r
e50466da 2644 return VariableSettings;\r
2645}\r
2646\r
e50466da 2647/**\r
2648 Worker function setting fixed MTRRs\r
2649\r
acf431e6 2650 @param[in] FixedSettings A buffer to hold fixed MTRRs content.\r
e50466da 2651\r
2652**/\r
2653VOID\r
2654MtrrSetFixedMtrrWorker (\r
2655 IN MTRR_FIXED_SETTINGS *FixedSettings\r
2656 )\r
2657{\r
2658 UINT32 Index;\r
2659\r
2660 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
2661 AsmWriteMsr64 (\r
f877f300 2662 mMtrrLibFixedMtrrTable[Index].Msr,\r
e50466da 2663 FixedSettings->Mtrr[Index]\r
2664 );\r
2665 }\r
2666}\r
2667\r
2668\r
2669/**\r
2670 This function sets fixed MTRRs\r
2671\r
acf431e6 2672 @param[in] FixedSettings A buffer to hold fixed MTRRs content.\r
e50466da 2673\r
2674 @retval The pointer of FixedSettings\r
2675\r
2676**/\r
2677MTRR_FIXED_SETTINGS*\r
2678EFIAPI\r
2679MtrrSetFixedMtrr (\r
2680 IN MTRR_FIXED_SETTINGS *FixedSettings\r
2681 )\r
2682{\r
c878cee4 2683 MTRR_CONTEXT MtrrContext;\r
e50466da 2684\r
947a573a 2685 if (!IsMtrrSupported ()) {\r
2686 return FixedSettings;\r
2687 }\r
2688\r
b8f01599 2689 MtrrLibPreMtrrChange (&MtrrContext);\r
e50466da 2690 MtrrSetFixedMtrrWorker (FixedSettings);\r
b8f01599 2691 MtrrLibPostMtrrChange (&MtrrContext);\r
e518b80d 2692 MtrrDebugPrintAllMtrrs ();\r
e50466da 2693\r
2694 return FixedSettings;\r
2695}\r
2696\r
2697\r
2698/**\r
2699 This function gets the content in all MTRRs (variable and fixed)\r
2700\r
acf431e6 2701 @param[out] MtrrSetting A buffer to hold all MTRRs content.\r
e50466da 2702\r
2703 @retval the pointer of MtrrSetting\r
2704\r
2705**/\r
2706MTRR_SETTINGS *\r
2707EFIAPI\r
2708MtrrGetAllMtrrs (\r
2709 OUT MTRR_SETTINGS *MtrrSetting\r
2710 )\r
2711{\r
947a573a 2712 if (!IsMtrrSupported ()) {\r
2713 return MtrrSetting;\r
2714 }\r
2715\r
e50466da 2716 //\r
2717 // Get fixed MTRRs\r
2718 //\r
acf431e6 2719 MtrrGetFixedMtrrWorker (&MtrrSetting->Fixed);\r
e50466da 2720\r
2721 //\r
2722 // Get variable MTRRs\r
2723 //\r
acf431e6 2724 MtrrGetVariableMtrrWorker (\r
5abd5ed4 2725 NULL,\r
acf431e6
MK
2726 GetVariableMtrrCountWorker (),\r
2727 &MtrrSetting->Variables\r
2728 );\r
e50466da 2729\r
2730 //\r
2731 // Get MTRR_DEF_TYPE value\r
2732 //\r
af838805 2733 MtrrSetting->MtrrDefType = AsmReadMsr64 (MSR_IA32_MTRR_DEF_TYPE);\r
e50466da 2734\r
2735 return MtrrSetting;\r
2736}\r
2737\r
2738\r
2739/**\r
2740 This function sets all MTRRs (variable and fixed)\r
2741\r
76b4cae3 2742 @param[in] MtrrSetting A buffer holding all MTRRs content.\r
e50466da 2743\r
2744 @retval The pointer of MtrrSetting\r
2745\r
2746**/\r
2747MTRR_SETTINGS *\r
2748EFIAPI\r
2749MtrrSetAllMtrrs (\r
2750 IN MTRR_SETTINGS *MtrrSetting\r
2751 )\r
2752{\r
c878cee4 2753 MTRR_CONTEXT MtrrContext;\r
e50466da 2754\r
947a573a 2755 if (!IsMtrrSupported ()) {\r
2756 return MtrrSetting;\r
2757 }\r
2758\r
b8f01599 2759 MtrrLibPreMtrrChange (&MtrrContext);\r
e50466da 2760\r
2761 //\r
2762 // Set fixed MTRRs\r
2763 //\r
2764 MtrrSetFixedMtrrWorker (&MtrrSetting->Fixed);\r
2765\r
2766 //\r
2767 // Set variable MTRRs\r
2768 //\r
2769 MtrrSetVariableMtrrWorker (&MtrrSetting->Variables);\r
2770\r
2771 //\r
2772 // Set MTRR_DEF_TYPE value\r
2773 //\r
af838805 2774 AsmWriteMsr64 (MSR_IA32_MTRR_DEF_TYPE, MtrrSetting->MtrrDefType);\r
e50466da 2775\r
b8f01599 2776 MtrrLibPostMtrrChangeEnableCache (&MtrrContext);\r
e50466da 2777\r
2778 return MtrrSetting;\r
2779}\r
2780\r
e518b80d 2781\r
947a573a 2782/**\r
2783 Checks if MTRR is supported.\r
2784\r
2785 @retval TRUE MTRR is supported.\r
2786 @retval FALSE MTRR is not supported.\r
2787\r
2788**/\r
2789BOOLEAN\r
2790EFIAPI\r
2791IsMtrrSupported (\r
2792 VOID\r
2793 )\r
2794{\r
3bb13d35
RN
2795 CPUID_VERSION_INFO_EDX Edx;\r
2796 MSR_IA32_MTRRCAP_REGISTER MtrrCap;\r
947a573a 2797\r
2798 //\r
2799 // Check CPUID(1).EDX[12] for MTRR capability\r
2800 //\r
3bb13d35
RN
2801 AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &Edx.Uint32);\r
2802 if (Edx.Bits.MTRR == 0) {\r
947a573a 2803 return FALSE;\r
2804 }\r
2805\r
2806 //\r
3bb13d35
RN
2807 // Check number of variable MTRRs and fixed MTRRs existence.\r
2808 // If number of variable MTRRs is zero, or fixed MTRRs do not\r
947a573a 2809 // exist, return false.\r
2810 //\r
3bb13d35
RN
2811 MtrrCap.Uint64 = AsmReadMsr64 (MSR_IA32_MTRRCAP);\r
2812 if ((MtrrCap.Bits.VCNT == 0) || (MtrrCap.Bits.FIX == 0)) {\r
947a573a 2813 return FALSE;\r
2814 }\r
947a573a 2815 return TRUE;\r
2816}\r
8051302a 2817\r
2bbd7e2f
RN
2818\r
2819/**\r
2820 Worker function prints all MTRRs for debugging.\r
2821\r
2822 If MtrrSetting is not NULL, print MTRR settings from input MTRR\r
2823 settings buffer.\r
2824 If MtrrSetting is NULL, print MTRR settings from MTRRs.\r
2825\r
2826 @param MtrrSetting A buffer holding all MTRRs content.\r
2827**/\r
2828VOID\r
2829MtrrDebugPrintAllMtrrsWorker (\r
2830 IN MTRR_SETTINGS *MtrrSetting\r
2831 )\r
2832{\r
2833 DEBUG_CODE (\r
2834 MTRR_SETTINGS LocalMtrrs;\r
2835 MTRR_SETTINGS *Mtrrs;\r
2836 UINTN Index;\r
2837 UINTN RangeCount;\r
2838 UINT64 MtrrValidBitsMask;\r
2839 UINT64 MtrrValidAddressMask;\r
1c29d038 2840 UINT32 VariableMtrrCount;\r
5a6c5af6 2841 BOOLEAN ContainVariableMtrr;\r
2bbd7e2f
RN
2842 MTRR_MEMORY_RANGE Ranges[\r
2843 ARRAY_SIZE (mMtrrLibFixedMtrrTable) * sizeof (UINT64) + 2 * ARRAY_SIZE (Mtrrs->Variables.Mtrr) + 1\r
2844 ];\r
2845 MTRR_MEMORY_RANGE RawVariableRanges[ARRAY_SIZE (Mtrrs->Variables.Mtrr)];\r
2846\r
2847 if (!IsMtrrSupported ()) {\r
2848 return;\r
2849 }\r
2850\r
1c29d038
RN
2851 VariableMtrrCount = GetVariableMtrrCountWorker ();\r
2852\r
2bbd7e2f
RN
2853 if (MtrrSetting != NULL) {\r
2854 Mtrrs = MtrrSetting;\r
2855 } else {\r
2856 MtrrGetAllMtrrs (&LocalMtrrs);\r
2857 Mtrrs = &LocalMtrrs;\r
2858 }\r
2859\r
2860 //\r
2861 // Dump RAW MTRR contents\r
2862 //\r
5a6c5af6
RN
2863 DEBUG ((DEBUG_CACHE, "MTRR Settings:\n"));\r
2864 DEBUG ((DEBUG_CACHE, "=============\n"));\r
2865 DEBUG ((DEBUG_CACHE, "MTRR Default Type: %016lx\n", Mtrrs->MtrrDefType));\r
2bbd7e2f 2866 for (Index = 0; Index < ARRAY_SIZE (mMtrrLibFixedMtrrTable); Index++) {\r
5a6c5af6 2867 DEBUG ((DEBUG_CACHE, "Fixed MTRR[%02d] : %016lx\n", Index, Mtrrs->Fixed.Mtrr[Index]));\r
2bbd7e2f 2868 }\r
5a6c5af6 2869 ContainVariableMtrr = FALSE;\r
1c29d038 2870 for (Index = 0; Index < VariableMtrrCount; Index++) {\r
9c8c4478 2871 if (((MSR_IA32_MTRR_PHYSMASK_REGISTER *)&Mtrrs->Variables.Mtrr[Index].Mask)->Bits.V == 0) {\r
2bbd7e2f
RN
2872 //\r
2873 // If mask is not valid, then do not display range\r
2874 //\r
2875 continue;\r
2876 }\r
5a6c5af6 2877 ContainVariableMtrr = TRUE;\r
2bbd7e2f
RN
2878 DEBUG ((DEBUG_CACHE, "Variable MTRR[%02d]: Base=%016lx Mask=%016lx\n",\r
2879 Index,\r
2880 Mtrrs->Variables.Mtrr[Index].Base,\r
2881 Mtrrs->Variables.Mtrr[Index].Mask\r
2882 ));\r
2883 }\r
5a6c5af6
RN
2884 if (!ContainVariableMtrr) {\r
2885 DEBUG ((DEBUG_CACHE, "Variable MTRR : None.\n"));\r
2886 }\r
2bbd7e2f
RN
2887 DEBUG((DEBUG_CACHE, "\n"));\r
2888\r
2889 //\r
2890 // Dump MTRR setting in ranges\r
2891 //\r
5a6c5af6 2892 DEBUG((DEBUG_CACHE, "Memory Ranges:\n"));\r
2bbd7e2f
RN
2893 DEBUG((DEBUG_CACHE, "====================================\n"));\r
2894 MtrrLibInitializeMtrrMask (&MtrrValidBitsMask, &MtrrValidAddressMask);\r
2895 Ranges[0].BaseAddress = 0;\r
2896 Ranges[0].Length = MtrrValidBitsMask + 1;\r
2897 Ranges[0].Type = MtrrGetDefaultMemoryTypeWorker (Mtrrs);\r
2898 RangeCount = 1;\r
2899\r
2900 MtrrLibGetRawVariableRanges (\r
1c29d038 2901 &Mtrrs->Variables, VariableMtrrCount,\r
2bbd7e2f
RN
2902 MtrrValidBitsMask, MtrrValidAddressMask, RawVariableRanges\r
2903 );\r
2904 MtrrLibApplyVariableMtrrs (\r
1c29d038 2905 RawVariableRanges, VariableMtrrCount,\r
2bbd7e2f
RN
2906 Ranges, ARRAY_SIZE (Ranges), &RangeCount\r
2907 );\r
2908\r
2909 MtrrLibApplyFixedMtrrs (&Mtrrs->Fixed, Ranges, ARRAY_SIZE (Ranges), &RangeCount);\r
2910\r
2911 for (Index = 0; Index < RangeCount; Index++) {\r
2912 DEBUG ((DEBUG_CACHE, "%a:%016lx-%016lx\n",\r
2913 mMtrrMemoryCacheTypeShortName[Ranges[Index].Type],\r
2914 Ranges[Index].BaseAddress, Ranges[Index].BaseAddress + Ranges[Index].Length - 1\r
2915 ));\r
2916 }\r
2917 );\r
2918}\r
2919\r
2920/**\r
2921 This function prints all MTRRs for debugging.\r
2922**/\r
2923VOID\r
2924EFIAPI\r
2925MtrrDebugPrintAllMtrrs (\r
2926 VOID\r
2927 )\r
2928{\r
2929 MtrrDebugPrintAllMtrrsWorker (NULL);\r
2930}\r