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