]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Core/Dxe/Gcd/Gcd.c
MdeModulePkg/Core: prevent re-acquire GCD memory lock
[mirror_edk2.git] / MdeModulePkg / Core / Dxe / Gcd / Gcd.c
index d9c65a8045e2906ceaf6ae6d6e33b3fe51fbaf4a..8bbdf7129f0f50a994ca56b3425c420d1889810b 100644 (file)
@@ -1691,10 +1691,10 @@ CoreGetMemorySpaceMap (
   OUT EFI_GCD_MEMORY_SPACE_DESCRIPTOR  **MemorySpaceMap\r
   )\r
 {\r
-  EFI_STATUS                       Status;\r
   LIST_ENTRY                       *Link;\r
   EFI_GCD_MAP_ENTRY                *Entry;\r
   EFI_GCD_MEMORY_SPACE_DESCRIPTOR  *Descriptor;\r
+  UINTN                            DescriptorCount;\r
 \r
   //\r
   // Make sure parameters are valid\r
@@ -1706,38 +1706,75 @@ CoreGetMemorySpaceMap (
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
-  CoreAcquireGcdMemoryLock ();\r
+  *NumberOfDescriptors  = 0;\r
+  *MemorySpaceMap       = NULL;\r
 \r
   //\r
-  // Count the number of descriptors\r
+  // Take the lock, for entering the loop with the lock held.\r
   //\r
-  *NumberOfDescriptors = CoreCountGcdMapEntry (&mGcdMemorySpaceMap);\r
+  CoreAcquireGcdMemoryLock ();\r
+  while (TRUE) {\r
+    //\r
+    // Count descriptors. It might be done more than once because the\r
+    // AllocatePool() called below has to be running outside the GCD lock.\r
+    //\r
+    DescriptorCount = CoreCountGcdMapEntry (&mGcdMemorySpaceMap);\r
+    if (DescriptorCount == *NumberOfDescriptors) {\r
+      //\r
+      // Fill in the MemorySpaceMap if no memory space map change.\r
+      //\r
+      Descriptor = *MemorySpaceMap;\r
+      Link = mGcdMemorySpaceMap.ForwardLink;\r
+      while (Link != &mGcdMemorySpaceMap) {\r
+        Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);\r
+        BuildMemoryDescriptor (Descriptor, Entry);\r
+        Descriptor++;\r
+        Link = Link->ForwardLink;\r
+      }\r
+      //\r
+      // We're done; exit the loop with the lock held.\r
+      //\r
+      break;\r
+    }\r
 \r
-  //\r
-  // Allocate the MemorySpaceMap\r
-  //\r
-  *MemorySpaceMap = AllocatePool (*NumberOfDescriptors * sizeof (EFI_GCD_MEMORY_SPACE_DESCRIPTOR));\r
-  if (*MemorySpaceMap == NULL) {\r
-    Status = EFI_OUT_OF_RESOURCES;\r
-    goto Done;\r
-  }\r
+    //\r
+    // Release the lock before memory allocation, because it might cause\r
+    // GCD lock conflict in one of calling path in AllocatPool().\r
+    //\r
+    CoreReleaseGcdMemoryLock ();\r
+\r
+    //\r
+    // Allocate memory to store the MemorySpaceMap. Note it might be already\r
+    // allocated if there's map descriptor change during memory allocation at\r
+    // last time.\r
+    //\r
+    if (*MemorySpaceMap != NULL) {\r
+      FreePool (*MemorySpaceMap);\r
+    }\r
 \r
+    *MemorySpaceMap = AllocatePool (DescriptorCount *\r
+                                    sizeof (EFI_GCD_MEMORY_SPACE_DESCRIPTOR));\r
+    if (*MemorySpaceMap == NULL) {\r
+      *NumberOfDescriptors = 0;\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+\r
+    //\r
+    // Save the descriptor count got before for another round of check to make\r
+    // sure we won't miss any, since we have code running outside the GCD lock.\r
+    //\r
+    *NumberOfDescriptors = DescriptorCount;\r
+    //\r
+    // Re-acquire the lock, for the next iteration.\r
+    //\r
+    CoreAcquireGcdMemoryLock ();\r
+  }\r
   //\r
-  // Fill in the MemorySpaceMap\r
+  // We exited the loop with the lock held, release it.\r
   //\r
-  Descriptor = *MemorySpaceMap;\r
-  Link = mGcdMemorySpaceMap.ForwardLink;\r
-  while (Link != &mGcdMemorySpaceMap) {\r
-    Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);\r
-    BuildMemoryDescriptor (Descriptor, Entry);\r
-    Descriptor++;\r
-    Link = Link->ForwardLink;\r
-  }\r
-  Status = EFI_SUCCESS;\r
-\r
-Done:\r
   CoreReleaseGcdMemoryLock ();\r
-  return Status;\r
+\r
+  return EFI_SUCCESS;\r
 }\r
 \r
 \r