UefiCpuPkg/CpuDxe: Fix multiple entries of RT_CODE in memory map
[mirror_edk2.git] / UefiCpuPkg / CpuDxe / CpuPageTable.c
index 76f44f9..9658ed7 100644 (file)
@@ -769,6 +769,20 @@ 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
@@ -790,7 +804,7 @@ RefreshGcdMemoryAttributesFromPaging (
   UINT64                              PageStartAddress;\r
   UINT64                              Attributes;\r
   UINT64                              Capabilities;\r
-  BOOLEAN                             DoUpdate;\r
+  UINT64                              NewAttributes;\r
   UINTN                               Index;\r
 \r
   //\r
@@ -802,17 +816,50 @@ RefreshGcdMemoryAttributesFromPaging (
 \r
   GetCurrentPagingContext (&PagingContext);\r
 \r
-  DoUpdate      = FALSE;\r
-  Capabilities  = 0;\r
-  Attributes    = 0;\r
-  BaseAddress   = 0;\r
-  PageLength    = 0;\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
@@ -826,7 +873,9 @@ RefreshGcdMemoryAttributesFromPaging (
       PageLength -= (MemorySpaceMap[Index].BaseAddress - BaseAddress);\r
     }\r
 \r
-    // Sync real page attributes to GCD\r
+    //\r
+    // Sync actual page attributes to GCD\r
+    //\r
     BaseAddress       = MemorySpaceMap[Index].BaseAddress;\r
     MemorySpaceLength = MemorySpaceMap[Index].Length;\r
     while (MemorySpaceLength > 0) {\r
@@ -842,23 +891,26 @@ RefreshGcdMemoryAttributesFromPaging (
         PageStartAddress  = (*PageEntry) & (UINT64)PageAttributeToMask(PageAttribute);\r
         PageLength        = PageAttributeToLength (PageAttribute) - (BaseAddress - PageStartAddress);\r
         Attributes        = GetAttributesFromPageEntry (PageEntry);\r
-\r
-        if (Attributes != (MemorySpaceMap[Index].Attributes & EFI_MEMORY_PAGETYPE_MASK)) {\r
-          DoUpdate = TRUE;\r
-          Attributes |= (MemorySpaceMap[Index].Attributes & ~EFI_MEMORY_PAGETYPE_MASK);\r
-          Capabilities = Attributes | MemorySpaceMap[Index].Capabilities;\r
-        } else {\r
-          DoUpdate = FALSE;\r
-        }\r
       }\r
 \r
       Length = MIN (PageLength, MemorySpaceLength);\r
-      if (DoUpdate) {\r
-        gDS->SetMemorySpaceCapabilities (BaseAddress, Length, Capabilities);\r
-        gDS->SetMemorySpaceAttributes (BaseAddress, Length, Attributes);\r
-        DEBUG ((DEBUG_INFO, "Update memory space attribute: [%02d] %016lx - %016lx (%08lx -> %08lx)\r\n",\r
-                             Index, BaseAddress, BaseAddress + Length - 1,\r
-                             MemorySpaceMap[Index].Attributes, Attributes));\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