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