]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdePkg/Library/SmmMemoryAllocationLib/MemoryAllocationLib.c
MdePkg:Fix typo 'caculate' in MdePkg.
[mirror_edk2.git] / MdePkg / Library / SmmMemoryAllocationLib / MemoryAllocationLib.c
index f8ab33a44ac28536f0d8181e29ac04f0e1832d77..ab27ac65832c62df67ebea93092b0519c4aacb90 100644 (file)
@@ -11,7 +11,7 @@
   In addition, allocation for the Reserved memory types are not supported and \r
   will always return NULL.\r
 \r
-  Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
+  Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>\r
   This program and the accompanying materials                          \r
   are licensed and made available under the terms and conditions of the BSD License         \r
   which accompanies this distribution.  The full text of the license may be found at        \r
 \r
 #include <PiSmm.h>\r
 \r
+#include <Protocol/SmmAccess2.h>\r
 #include <Library/MemoryAllocationLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
 #include <Library/SmmServicesTableLib.h>\r
 #include <Library/BaseMemoryLib.h>\r
 #include <Library/DebugLib.h>\r
 \r
+EFI_SMRAM_DESCRIPTOR  *mSmramRanges;\r
+UINTN                 mSmramRangeCount;\r
+\r
+/**\r
+  The constructor function caches SMRAM ranges that are present in the system.\r
+    \r
+  It will ASSERT() if SMM Access2 Protocol doesn't exist.\r
+  It will ASSERT() if SMRAM ranges can't be got.\r
+  It will ASSERT() if Resource can't be allocated for cache SMRAM range. \r
+  It will always return EFI_SUCCESS.\r
+\r
+  @param  ImageHandle   The firmware allocated handle for the EFI image.\r
+  @param  SystemTable   A pointer to the EFI System Table.\r
+\r
+  @retval EFI_SUCCESS   The constructor always returns EFI_SUCCESS.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmMemoryAllocationLibConstructor (\r
+  IN EFI_HANDLE        ImageHandle,\r
+  IN EFI_SYSTEM_TABLE  *SystemTable\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  EFI_SMM_ACCESS2_PROTOCOL  *SmmAccess;\r
+  UINTN                     Size;\r
+\r
+  //\r
+  // Locate SMM Access2 Protocol\r
+  //\r
+  Status = gBS->LocateProtocol (\r
+                  &gEfiSmmAccess2ProtocolGuid, \r
+                  NULL, \r
+                  (VOID **)&SmmAccess\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  //\r
+  // Get SMRAM range information\r
+  //\r
+  Size = 0;\r
+  Status = SmmAccess->GetCapabilities (SmmAccess, &Size, NULL);\r
+  ASSERT (Status == EFI_BUFFER_TOO_SMALL);\r
+\r
+  mSmramRanges = (EFI_SMRAM_DESCRIPTOR *) AllocatePool (Size);\r
+  ASSERT (mSmramRanges != NULL);\r
+\r
+  Status = SmmAccess->GetCapabilities (SmmAccess, &Size, mSmramRanges);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  mSmramRangeCount = Size / sizeof (EFI_SMRAM_DESCRIPTOR);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  If SMM driver exits with an error, it must call this routine \r
+  to free the allocated resource before the exiting.\r
+\r
+  @param[in]  ImageHandle   The firmware allocated handle for the EFI image.\r
+  @param[in]  SystemTable   A pointer to the EFI System Table.\r
+\r
+  @retval     EFI_SUCCESS   The deconstructor always returns EFI_SUCCESS.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmMemoryAllocationLibDestructor (\r
+  IN EFI_HANDLE        ImageHandle,\r
+  IN EFI_SYSTEM_TABLE  *SystemTable\r
+  )\r
+{\r
+  FreePool (mSmramRanges);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Check whether the start address of buffer is within any of the SMRAM ranges.\r
+\r
+  @param[in]  Buffer   The pointer to the buffer to be checked.\r
+\r
+  @retval     TURE     The buffer is in SMRAM ranges.\r
+  @retval     FALSE    The buffer is out of SMRAM ranges.\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+BufferInSmram (\r
+  IN VOID *Buffer\r
+  )\r
+{\r
+  UINTN  Index;\r
+\r
+  for (Index = 0; Index < mSmramRangeCount; Index ++) {\r
+    if (((EFI_PHYSICAL_ADDRESS) (UINTN) Buffer >= mSmramRanges[Index].CpuStart) && \r
+        ((EFI_PHYSICAL_ADDRESS) (UINTN) Buffer < (mSmramRanges[Index].CpuStart + mSmramRanges[Index].PhysicalSize))) {\r
+      return TRUE;\r
+    }\r
+  }\r
+\r
+  return FALSE;\r
+}\r
+\r
 /**\r
   Allocates one or more 4KB pages of a certain memory type.\r
 \r
@@ -156,7 +261,19 @@ FreePages (
   EFI_STATUS  Status;\r
 \r
   ASSERT (Pages != 0);\r
-  Status = gSmst->SmmFreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) Buffer, Pages);\r
+  if (BufferInSmram (Buffer)) {\r
+    //\r
+    // When Buffer is in SMRAM range, it should be allocated by gSmst->SmmAllocatePages() service.\r
+    // So, gSmst->SmmFreePages() service is used to free it.\r
+    //\r
+    Status = gSmst->SmmFreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) Buffer, Pages);\r
+  } else {\r
+    //\r
+    // When Buffer is out of SMRAM range, it should be allocated by gBS->AllocatePages() service.\r
+    // So, gBS->FreePages() service is used to free it.\r
+    //\r
+    Status = gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) Buffer, Pages);\r
+  }\r
   ASSERT_EFI_ERROR (Status);\r
 }\r
 \r
@@ -168,6 +285,7 @@ FreePages (
   If Pages is 0, then NULL is returned. If there is not enough memory at the \r
   specified alignment remaining to satisfy the request, then NULL is returned.\r
   If Alignment is not a power of two and Alignment is not zero, then ASSERT().\r
+  If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT().\r
 \r
   @param  MemoryType            The type of memory to allocate.\r
   @param  Pages                 The number of 4 KB pages to allocate.\r
@@ -202,7 +320,7 @@ InternalAllocateAlignedPages (
   }\r
   if (Alignment > EFI_PAGE_SIZE) {\r
     //\r
-    // Caculate the total number of pages since alignment is larger than page size.\r
+    // Calculate the total number of pages since alignment is larger than page size.\r
     //\r
     AlignmentMask  = Alignment - 1;\r
     RealPages      = Pages + EFI_SIZE_TO_PAGES (Alignment);\r
@@ -255,6 +373,7 @@ InternalAllocateAlignedPages (
   specified alignment remaining to satisfy the request, then NULL is returned.\r
   \r
   If Alignment is not a power of two and Alignment is not zero, then ASSERT().\r
+  If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT().\r
 \r
   @param  Pages                 The number of 4 KB pages to allocate.\r
   @param  Alignment             The requested alignment of the allocation.  \r
@@ -283,6 +402,7 @@ AllocateAlignedPages (
   specified alignment remaining to satisfy the request, then NULL is returned.\r
   \r
   If Alignment is not a power of two and Alignment is not zero, then ASSERT().\r
+  If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT().\r
 \r
   @param  Pages                 The number of 4 KB pages to allocate.\r
   @param  Alignment             The requested alignment of the allocation.  \r
@@ -311,6 +431,7 @@ AllocateAlignedRuntimePages (
   specified alignment remaining to satisfy the request, then NULL is returned.\r
   \r
   If Alignment is not a power of two and Alignment is not zero, then ASSERT().\r
+  If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT().\r
 \r
   @param  Pages                 The number of 4 KB pages to allocate.\r
   @param  Alignment             The requested alignment of the allocation.  \r
@@ -357,7 +478,19 @@ FreeAlignedPages (
   EFI_STATUS  Status;\r
 \r
   ASSERT (Pages != 0);\r
-  Status = gSmst->SmmFreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) Buffer, Pages);\r
+  if (BufferInSmram (Buffer)) {\r
+    //\r
+    // When Buffer is in SMRAM range, it should be allocated by gSmst->SmmAllocatePages() service.\r
+    // So, gSmst->SmmFreePages() service is used to free it.\r
+    //\r
+    Status = gSmst->SmmFreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) Buffer, Pages);\r
+  } else {\r
+    //\r
+    // When Buffer is out of SMRAM range, it should be allocated by gBS->AllocatePages() service.\r
+    // So, gBS->FreePages() service is used to free it.\r
+    //\r
+    Status = gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) Buffer, Pages);\r
+  }\r
   ASSERT_EFI_ERROR (Status);\r
 }\r
 \r
@@ -831,6 +964,18 @@ FreePool (
 {\r
   EFI_STATUS    Status;\r
 \r
-  Status = gSmst->SmmFreePool (Buffer);\r
+  if (BufferInSmram (Buffer)) {\r
+    //\r
+    // When Buffer is in SMRAM range, it should be allocated by gSmst->SmmAllocatePool() service.\r
+    // So, gSmst->SmmFreePool() service is used to free it.\r
+    //\r
+    Status = gSmst->SmmFreePool (Buffer);\r
+  } else {\r
+    //\r
+    // When Buffer is out of SMRAM range, it should be allocated by gBS->AllocatePool() service.\r
+    // So, gBS->FreePool() service is used to free it.\r
+    //\r
+    Status = gBS->FreePool (Buffer);\r
+  }\r
   ASSERT_EFI_ERROR (Status);\r
 }\r