]> git.proxmox.com Git - mirror_edk2.git/blobdiff - UefiCpuPkg/Library/MtrrLib/MtrrLib.c
UefiCpuPkg/MtrrLib: Reduce hardware init when program variable MTRRs
[mirror_edk2.git] / UefiCpuPkg / Library / MtrrLib / MtrrLib.c
index 697dc4352f61dd1540035ebdd139ed97d0c9e16f..0e76e2f92ad54822c9a00e8b0443fee771eae4f0 100644 (file)
@@ -415,6 +415,9 @@ MtrrGetVariableMtrr (
   @param[in]      MemoryCacheType  The memory type to set.\r
   @param[in, out] Base             The base address of memory range.\r
   @param[in, out] Length           The length of memory range.\r
+  @param[out]     ReturnMsrNum     The index of the fixed MTRR MSR to program.\r
+  @param[out]     ReturnClearMask  The bits to clear in the fixed MTRR MSR.\r
+  @param[out]     ReturnOrMask     The bits to set in the fixed MTRR MSR.\r
 \r
   @retval RETURN_SUCCESS      The cache type was updated successfully\r
   @retval RETURN_UNSUPPORTED  The requested range or cache type was invalid\r
@@ -423,9 +426,12 @@ MtrrGetVariableMtrr (
 **/\r
 RETURN_STATUS\r
 ProgramFixedMtrr (\r
-  IN     UINT64     MemoryCacheType,\r
-  IN OUT UINT64     *Base,\r
-  IN OUT UINT64     *Length\r
+  IN     UINT64               MemoryCacheType,\r
+  IN OUT UINT64               *Base,\r
+  IN OUT UINT64               *Length,\r
+  OUT    UINT32               *ReturnMsrNum,\r
+  OUT    UINT64               *ReturnClearMask,\r
+  OUT    UINT64               *ReturnOrMask\r
   )\r
 {\r
   UINT32  MsrNum;\r
@@ -488,9 +494,10 @@ ProgramFixedMtrr (
     return RETURN_UNSUPPORTED;\r
   }\r
 \r
-  TempQword =\r
-    (AsmReadMsr64 (mMtrrLibFixedMtrrTable[MsrNum].Msr) & ~ClearMask) | OrMask;\r
-  AsmWriteMsr64 (mMtrrLibFixedMtrrTable[MsrNum].Msr, TempQword);\r
+  *ReturnMsrNum    = MsrNum;\r
+  *ReturnClearMask = ClearMask;\r
+  *ReturnOrMask    = OrMask;\r
+\r
   return RETURN_SUCCESS;\r
 }\r
 \r
@@ -876,30 +883,27 @@ GetMtrrNumberAndDirection (
   This function programs MTRRs according to the values specified\r
   in the shadow array.\r
 \r
+  @param[in, out]  VariableSettings   Variable MTRR settings\r
   @param[in]       VariableMtrrCount  Number of variable MTRRs\r
   @param[in, out]  VariableMtrr       Shadow of variable MTRR contents\r
 \r
 **/\r
 VOID\r
 InvalidateMtrr (\r
+  IN OUT MTRR_VARIABLE_SETTINGS  *VariableSettings,\r
   IN     UINTN                   VariableMtrrCount,\r
   IN OUT VARIABLE_MTRR           *VariableMtrr\r
   )\r
 {\r
   UINTN         Index;\r
-  MTRR_CONTEXT  MtrrContext;\r
 \r
-  PreMtrrChange (&MtrrContext);\r
-  Index = 0;\r
-  while (Index < VariableMtrrCount) {\r
+  for (Index = 0; Index < VariableMtrrCount; Index++) {\r
     if (!VariableMtrr[Index].Valid && VariableMtrr[Index].Used) {\r
-       AsmWriteMsr64 (VariableMtrr[Index].Msr, 0);\r
-       AsmWriteMsr64 (VariableMtrr[Index].Msr + 1, 0);\r
+       VariableSettings->Mtrr[Index].Base = 0;\r
+       VariableSettings->Mtrr[Index].Mask = 0;\r
        VariableMtrr[Index].Used = FALSE;\r
     }\r
-    Index ++;\r
   }\r
-  PostMtrrChange (&MtrrContext);\r
 }\r
 \r
 \r
@@ -908,6 +912,7 @@ InvalidateMtrr (
 \r
   This function programs variable MTRRs\r
 \r
+  @param[in, out]  VariableSettings      Variable MTRR settings.\r
   @param[in]       MtrrNumber            Index of MTRR to program.\r
   @param[in]       BaseAddress           Base address of memory region.\r
   @param[in]       Length                Length of memory region.\r
@@ -917,34 +922,27 @@ InvalidateMtrr (
 **/\r
 VOID\r
 ProgramVariableMtrr (\r
-  IN UINTN                    MtrrNumber,\r
-  IN PHYSICAL_ADDRESS         BaseAddress,\r
-  IN UINT64                   Length,\r
-  IN UINT64                   MemoryCacheType,\r
-  IN UINT64                   MtrrValidAddressMask\r
+  IN OUT MTRR_VARIABLE_SETTINGS  *VariableSettings,\r
+  IN     UINTN                   MtrrNumber,\r
+  IN     PHYSICAL_ADDRESS        BaseAddress,\r
+  IN     UINT64                  Length,\r
+  IN     UINT64                  MemoryCacheType,\r
+  IN     UINT64                  MtrrValidAddressMask\r
   )\r
 {\r
   UINT64        TempQword;\r
-  MTRR_CONTEXT  MtrrContext;\r
-\r
-  PreMtrrChange (&MtrrContext);\r
 \r
   //\r
   // MTRR Physical Base\r
   //\r
   TempQword = (BaseAddress & MtrrValidAddressMask) | MemoryCacheType;\r
-  AsmWriteMsr64 ((UINT32) MtrrNumber, TempQword);\r
+  VariableSettings->Mtrr[MtrrNumber].Base = TempQword;\r
 \r
   //\r
   // MTRR Physical Mask\r
   //\r
   TempQword = ~(Length - 1);\r
-  AsmWriteMsr64 (\r
-    (UINT32) (MtrrNumber + 1),\r
-    (TempQword & MtrrValidAddressMask) | MTRR_LIB_CACHE_MTRR_ENABLED\r
-    );\r
-\r
-  PostMtrrChange (&MtrrContext);\r
+  VariableSettings->Mtrr[MtrrNumber].Mask = (TempQword & MtrrValidAddressMask) | MTRR_LIB_CACHE_MTRR_ENABLED;\r
 }\r
 \r
 \r
@@ -1386,24 +1384,35 @@ MtrrSetMemoryAttribute (
   UINT64                    MtrrValidAddressMask;\r
   BOOLEAN                   OverwriteExistingMtrr;\r
   UINT32                    FirmwareVariableMtrrCount;\r
-  UINT32                    VariableMtrrEnd;\r
   MTRR_CONTEXT              MtrrContext;\r
+  BOOLEAN                   MtrrContextValid;\r
+  BOOLEAN                   FixedSettingsValid[MTRR_NUMBER_OF_FIXED_MTRR];\r
+  BOOLEAN                   FixedSettingsModified[MTRR_NUMBER_OF_FIXED_MTRR];\r
+  MTRR_FIXED_SETTINGS       WorkingFixedSettings;\r
   UINT32                    VariableMtrrCount;\r
   MTRR_VARIABLE_SETTINGS    OriginalVariableSettings;\r
+  BOOLEAN                   ProgramVariableSettings;\r
   MTRR_VARIABLE_SETTINGS    WorkingVariableSettings;\r
+  UINT32                    Index;\r
+  UINT64                    ClearMask;\r
+  UINT64                    OrMask;\r
+  UINT64                    NewValue;\r
   MTRR_VARIABLE_SETTINGS    *VariableSettings;\r
 \r
   DEBUG((DEBUG_CACHE, "MtrrSetMemoryAttribute() %a:%016lx-%016lx\n", mMtrrMemoryCacheTypeShortName[Attribute], BaseAddress, Length));\r
+  MtrrContextValid = FALSE;\r
+  for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
+    FixedSettingsValid[Index]    = FALSE;\r
+    FixedSettingsModified[Index] = FALSE;\r
+  }\r
+  ProgramVariableSettings = FALSE;\r
 \r
   if (!IsMtrrSupported ()) {\r
     Status = RETURN_UNSUPPORTED;\r
     goto Done;\r
   }\r
 \r
-  FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCountWorker ();\r
-  VariableMtrrEnd = MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (2 * GetVariableMtrrCount ()) - 1;\r
-\r
-  MtrrLibInitializeMtrrMask(&MtrrValidBitsMask, &MtrrValidAddressMask);\r
+  MtrrLibInitializeMtrrMask (&MtrrValidBitsMask, &MtrrValidAddressMask);\r
 \r
   TempQword = 0;\r
   MemoryType = (UINT64)Attribute;\r
@@ -1429,22 +1438,31 @@ MtrrSetMemoryAttribute (
   // Check if Fixed MTRR\r
   //\r
   Status = RETURN_SUCCESS;\r
-  while ((BaseAddress < BASE_1MB) && (Length > 0) && Status == RETURN_SUCCESS) {\r
-    PreMtrrChange (&MtrrContext);\r
-    Status = ProgramFixedMtrr (MemoryType, &BaseAddress, &Length);\r
-    PostMtrrChange (&MtrrContext);\r
-    if (RETURN_ERROR (Status)) {\r
-      goto Done;\r
+  if (BaseAddress < BASE_1MB) {\r
+    while ((BaseAddress < BASE_1MB) && (Length > 0) && Status == RETURN_SUCCESS) {\r
+      Status = ProgramFixedMtrr (MemoryType, &BaseAddress, &Length, &MsrNum, &ClearMask, &OrMask);\r
+      if (RETURN_ERROR (Status)) {\r
+        goto Done;\r
+      }\r
+      if (!FixedSettingsValid[MsrNum]) {\r
+        WorkingFixedSettings.Mtrr[MsrNum] = AsmReadMsr64 (mMtrrLibFixedMtrrTable[MsrNum].Msr);\r
+        FixedSettingsValid[MsrNum] = TRUE;\r
+      }\r
+      NewValue = (WorkingFixedSettings.Mtrr[MsrNum] & ~ClearMask) | OrMask;\r
+      if (WorkingFixedSettings.Mtrr[MsrNum] != NewValue) {\r
+        WorkingFixedSettings.Mtrr[MsrNum] = NewValue;\r
+        FixedSettingsModified[MsrNum] = TRUE;\r
+      }\r
     }\r
-  }\r
 \r
-  if (Length == 0) {\r
-    //\r
-    // A Length of 0 can only make sense for fixed MTTR ranges.\r
-    // Since we just handled the fixed MTRRs, we can skip the\r
-    // variable MTRR section.\r
-    //\r
-    goto Done;\r
+    if (Length == 0) {\r
+      //\r
+      // A Length of 0 can only make sense for fixed MTTR ranges.\r
+      // Since we just handled the fixed MTRRs, we can skip the\r
+      // variable MTRR section.\r
+      //\r
+      goto Done;\r
+    }\r
   }\r
 \r
   //\r
@@ -1460,8 +1478,10 @@ MtrrSetMemoryAttribute (
   // Read all variable MTRRs\r
   //\r
   VariableMtrrCount = GetVariableMtrrCountWorker ();\r
+  FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCountWorker ();\r
   MtrrGetVariableMtrrWorker (VariableMtrrCount, &OriginalVariableSettings);\r
   CopyMem (&WorkingVariableSettings, &OriginalVariableSettings, sizeof (WorkingVariableSettings));\r
+  ProgramVariableSettings = TRUE;\r
   VariableSettings = &WorkingVariableSettings;\r
 \r
   //\r
@@ -1480,7 +1500,6 @@ MtrrSetMemoryAttribute (
               BaseAddress + Length - 1,\r
               VariableMtrr\r
               );\r
-\r
   if (OverLap) {\r
     Status = CombineMemoryAttribute (\r
                FirmwareVariableMtrrCount,\r
@@ -1499,7 +1518,7 @@ MtrrSetMemoryAttribute (
       //\r
       // Combined successfully, invalidate the now-unused MTRRs\r
       //\r
-      InvalidateMtrr(VariableMtrrCount, VariableMtrr);\r
+      InvalidateMtrr (VariableSettings, VariableMtrrCount, VariableMtrr);\r
       Status = RETURN_SUCCESS;\r
       goto Done;\r
     }\r
@@ -1513,7 +1532,7 @@ MtrrSetMemoryAttribute (
     //\r
     // Invalidate the now-unused MTRRs\r
     //\r
-    InvalidateMtrr(VariableMtrrCount, VariableMtrr);\r
+    InvalidateMtrr (VariableSettings, VariableMtrrCount, VariableMtrr);\r
     goto Done;\r
   }\r
 \r
@@ -1527,16 +1546,13 @@ MtrrSetMemoryAttribute (
   //\r
   // Invalidate the now-unused MTRRs\r
   //\r
-  InvalidateMtrr(VariableMtrrCount, VariableMtrr);\r
+  InvalidateMtrr (VariableSettings, VariableMtrrCount, VariableMtrr);\r
 \r
   //\r
   // Find first unused MTRR\r
   //\r
-  for (MsrNum = MTRR_LIB_IA32_VARIABLE_MTRR_BASE;\r
-       MsrNum < VariableMtrrEnd;\r
-       MsrNum += 2\r
-      ) {\r
-    if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
+  for (MsrNum = 0; MsrNum < VariableMtrrCount; MsrNum++) {\r
+    if ((VariableSettings->Mtrr[MsrNum].Mask & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
       break;\r
     }\r
   }\r
@@ -1555,13 +1571,14 @@ MtrrSetMemoryAttribute (
       //\r
       // Find unused MTRR\r
       //\r
-      for (; MsrNum < VariableMtrrEnd; MsrNum += 2) {\r
-        if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
+      for (; MsrNum < VariableMtrrCount; MsrNum++) {\r
+        if ((VariableSettings->Mtrr[MsrNum].Mask & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
           break;\r
         }\r
       }\r
 \r
       ProgramVariableMtrr (\r
+        VariableSettings,\r
         MsrNum,\r
         BaseAddress,\r
         Alignment,\r
@@ -1585,13 +1602,14 @@ MtrrSetMemoryAttribute (
     //\r
     // Find unused MTRR\r
     //\r
-    for (; MsrNum < VariableMtrrEnd; MsrNum += 2) {\r
-      if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
+    for (; MsrNum < VariableMtrrCount; MsrNum++) {\r
+      if ((VariableSettings->Mtrr[MsrNum].Mask & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
         break;\r
       }\r
     }\r
 \r
     ProgramVariableMtrr (\r
+      VariableSettings,\r
       MsrNum,\r
       BaseAddress,\r
       Length,\r
@@ -1607,8 +1625,8 @@ MtrrSetMemoryAttribute (
     //\r
     // Find unused MTRR\r
     //\r
-    for (; MsrNum < VariableMtrrEnd; MsrNum += 2) {\r
-      if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
+    for (; MsrNum < VariableMtrrCount; MsrNum++) {\r
+      if ((VariableSettings->Mtrr[MsrNum].Mask & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
         break;\r
       }\r
     }\r
@@ -1619,6 +1637,7 @@ MtrrSetMemoryAttribute (
     }\r
 \r
     ProgramVariableMtrr (\r
+      VariableSettings,\r
       MsrNum,\r
       BaseAddress,\r
       Length,\r
@@ -1634,6 +1653,49 @@ MtrrSetMemoryAttribute (
   } while (TempQword > 0);\r
 \r
 Done:\r
+\r
+  //\r
+  // Write fixed MTRRs that have been modified\r
+  //\r
+  for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
+    if (FixedSettingsModified[Index]) {\r
+      if (!MtrrContextValid) {\r
+        PreMtrrChange (&MtrrContext);\r
+        MtrrContextValid = TRUE;\r
+      }\r
+      AsmWriteMsr64 (\r
+        mMtrrLibFixedMtrrTable[Index].Msr,\r
+        WorkingFixedSettings.Mtrr[Index]\r
+        );\r
+    }\r
+  }\r
+\r
+  //\r
+  // Write variable MTRRs\r
+  //\r
+  if (ProgramVariableSettings) {\r
+    for (Index = 0; Index < VariableMtrrCount; Index++) {\r
+      if (WorkingVariableSettings.Mtrr[Index].Base != OriginalVariableSettings.Mtrr[Index].Base ||\r
+          WorkingVariableSettings.Mtrr[Index].Mask != OriginalVariableSettings.Mtrr[Index].Mask    ) {\r
+        if (!MtrrContextValid) {\r
+          PreMtrrChange (&MtrrContext);\r
+          MtrrContextValid = TRUE;\r
+        }\r
+        AsmWriteMsr64 (\r
+          MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1),\r
+          WorkingVariableSettings.Mtrr[Index].Base\r
+          );\r
+        AsmWriteMsr64 (\r
+          MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1) + 1,\r
+          WorkingVariableSettings.Mtrr[Index].Mask\r
+          );\r
+      }\r
+    }\r
+  }\r
+  if (MtrrContextValid) {\r
+    PostMtrrChange (&MtrrContext);\r
+  }\r
+\r
   DEBUG((DEBUG_CACHE, "  Status = %r\n", Status));\r
   if (!RETURN_ERROR (Status)) {\r
     MtrrDebugPrintAllMtrrs ();\r