]> git.proxmox.com Git - mirror_edk2.git/blobdiff - UefiCpuPkg/CpuDxe/CpuPageTable.c
UefiCpuPkg/CpuDxe: Fix multiple entries of RT_CODE in memory map
[mirror_edk2.git] / UefiCpuPkg / CpuDxe / CpuPageTable.c
index 2c61e7503e234eae95b2ec646ae926d297fc5ba8..9658ed74c557dbfcd574a1995b899d4a4d556f44 100644 (file)
@@ -23,6 +23,8 @@
 #include <Library/DebugLib.h>\r
 #include <Library/UefiBootServicesTableLib.h>\r
 #include <Protocol/MpService.h>\r
+\r
+#include "CpuDxe.h"\r
 #include "CpuPageTable.h"\r
 \r
 ///\r
@@ -440,8 +442,8 @@ ConvertPageEntryAttribute (
   *PageEntry = NewPageEntry;\r
   if (CurrentPageEntry != NewPageEntry) {\r
     *IsModified = TRUE;\r
-    DEBUG ((DEBUG_INFO, "ConvertPageEntryAttribute 0x%lx", CurrentPageEntry));\r
-    DEBUG ((DEBUG_INFO, "->0x%lx\n", NewPageEntry));\r
+    DEBUG ((DEBUG_VERBOSE, "ConvertPageEntryAttribute 0x%lx", CurrentPageEntry));\r
+    DEBUG ((DEBUG_VERBOSE, "->0x%lx\n", NewPageEntry));\r
   } else {\r
     *IsModified = FALSE;\r
   }\r
@@ -767,6 +769,159 @@ AssignMemoryPageAttributes (
   return Status;\r
 }\r
 \r
+/**\r
+ Check if Execute Disable feature is enabled or not.\r
+**/\r
+BOOLEAN\r
+IsExecuteDisableEnabled (\r
+  VOID\r
+  )\r
+{\r
+  MSR_CORE_IA32_EFER_REGISTER    MsrEfer;\r
+\r
+  MsrEfer.Uint64 = AsmReadMsr64 (MSR_IA32_EFER);\r
+  return (MsrEfer.Bits.NXE == 1);\r
+}\r
+\r
+/**\r
+  Update GCD memory space attributes according to current page table setup.\r
+**/\r
+VOID\r
+RefreshGcdMemoryAttributesFromPaging (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS                          Status;\r
+  UINTN                               NumberOfDescriptors;\r
+  EFI_GCD_MEMORY_SPACE_DESCRIPTOR     *MemorySpaceMap;\r
+  PAGE_TABLE_LIB_PAGING_CONTEXT       PagingContext;\r
+  PAGE_ATTRIBUTE                      PageAttribute;\r
+  UINT64                              *PageEntry;\r
+  UINT64                              PageLength;\r
+  UINT64                              MemorySpaceLength;\r
+  UINT64                              Length;\r
+  UINT64                              BaseAddress;\r
+  UINT64                              PageStartAddress;\r
+  UINT64                              Attributes;\r
+  UINT64                              Capabilities;\r
+  UINT64                              NewAttributes;\r
+  UINTN                               Index;\r
+\r
+  //\r
+  // Assuming that memory space map returned is sorted already; otherwise sort\r
+  // them in the order of lowest address to highest address.\r
+  //\r
+  Status = gDS->GetMemorySpaceMap (&NumberOfDescriptors, &MemorySpaceMap);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  GetCurrentPagingContext (&PagingContext);\r
+\r
+  Attributes      = 0;\r
+  NewAttributes   = 0;\r
+  BaseAddress     = 0;\r
+  PageLength      = 0;\r
+\r
+  if (IsExecuteDisableEnabled ()) {\r
+    Capabilities = EFI_MEMORY_RO | EFI_MEMORY_RP | EFI_MEMORY_XP;\r
+  } else {\r
+    Capabilities = EFI_MEMORY_RO | EFI_MEMORY_RP;\r
+  }\r
+\r
+  for (Index = 0; Index < NumberOfDescriptors; Index++) {\r
+    if (MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeNonExistent) {\r
+      continue;\r
+    }\r
+\r
+    //\r
+    // Sync the actual paging related capabilities back to GCD service first.\r
+    // As a side effect (good one), this can also help to avoid unnecessary\r
+    // memory map entries due to the different capabilities of the same type\r
+    // memory, such as multiple RT_CODE and RT_DATA entries in memory map,\r
+    // which could cause boot failure of some old Linux distro (before v4.3).\r
+    //\r
+    Status = gDS->SetMemorySpaceCapabilities (\r
+                    MemorySpaceMap[Index].BaseAddress,\r
+                    MemorySpaceMap[Index].Length,\r
+                    MemorySpaceMap[Index].Capabilities | Capabilities\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      //\r
+      // If we cannot udpate the capabilities, we cannot update its\r
+      // attributes either. So just simply skip current block of memory.\r
+      //\r
+      DEBUG ((\r
+        DEBUG_WARN,\r
+        "Failed to update capability: [%lu] %016lx - %016lx (%016lx -> %016lx)\r\n",\r
+        (UINT64)Index, MemorySpaceMap[Index].BaseAddress,\r
+        MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length - 1,\r
+        MemorySpaceMap[Index].Capabilities,\r
+        MemorySpaceMap[Index].Capabilities | Capabilities\r
+        ));\r
+      continue;\r
+    }\r
+\r
+    if (MemorySpaceMap[Index].BaseAddress >= (BaseAddress + PageLength)) {\r
+      //\r
+      // Current memory space starts at a new page. Resetting PageLength will\r
+      // trigger a retrieval of page attributes at new address.\r
+      //\r
+      PageLength = 0;\r
+    } else {\r
+      //\r
+      // In case current memory space is not adjacent to last one\r
+      //\r
+      PageLength -= (MemorySpaceMap[Index].BaseAddress - BaseAddress);\r
+    }\r
+\r
+    //\r
+    // Sync actual page attributes to GCD\r
+    //\r
+    BaseAddress       = MemorySpaceMap[Index].BaseAddress;\r
+    MemorySpaceLength = MemorySpaceMap[Index].Length;\r
+    while (MemorySpaceLength > 0) {\r
+      if (PageLength == 0) {\r
+        PageEntry = GetPageTableEntry (&PagingContext, BaseAddress, &PageAttribute);\r
+        if (PageEntry == NULL) {\r
+          break;\r
+        }\r
+\r
+        //\r
+        // Note current memory space might start in the middle of a page\r
+        //\r
+        PageStartAddress  = (*PageEntry) & (UINT64)PageAttributeToMask(PageAttribute);\r
+        PageLength        = PageAttributeToLength (PageAttribute) - (BaseAddress - PageStartAddress);\r
+        Attributes        = GetAttributesFromPageEntry (PageEntry);\r
+      }\r
+\r
+      Length = MIN (PageLength, MemorySpaceLength);\r
+      if (Attributes != (MemorySpaceMap[Index].Attributes &\r
+                         EFI_MEMORY_PAGETYPE_MASK)) {\r
+        NewAttributes = (MemorySpaceMap[Index].Attributes &\r
+                         ~EFI_MEMORY_PAGETYPE_MASK) | Attributes;\r
+        Status = gDS->SetMemorySpaceAttributes (\r
+                        BaseAddress,\r
+                        Length,\r
+                        NewAttributes\r
+                        );\r
+        ASSERT_EFI_ERROR (Status);\r
+        DEBUG ((\r
+          DEBUG_INFO,\r
+          "Updated memory space attribute: [%lu] %016lx - %016lx (%016lx -> %016lx)\r\n",\r
+          (UINT64)Index, BaseAddress, BaseAddress + Length - 1,\r
+          MemorySpaceMap[Index].Attributes,\r
+          NewAttributes\r
+          ));\r
+      }\r
+\r
+      PageLength        -= Length;\r
+      MemorySpaceLength -= Length;\r
+      BaseAddress       += Length;\r
+    }\r
+  }\r
+\r
+  FreePool (MemorySpaceMap);\r
+}\r
+\r
 /**\r
   Initialize the Page Table lib.\r
 **/\r