UefiCpuPkg/CpuDxe: Fix out-of-sync issue in page attributes
[mirror_edk2.git] / UefiCpuPkg / CpuDxe / CpuPageTable.c
index 2c61e7503e234eae95b2ec646ae926d297fc5ba8..ae93f3f5534f446ae2f066922c50c83e61acb20f 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
@@ -767,6 +769,103 @@ AssignMemoryPageAttributes (
   return Status;\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
+  BOOLEAN                             DoUpdate;\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
+  BaseAddress = 0;\r
+  PageLength  = 0;\r
+  for (Index = 0; Index < NumberOfDescriptors; Index++) {\r
+    if (MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeNonExistent) {\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
+    // Sync real page attributes to GCD\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
+        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
+      }\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