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