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