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
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
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
}\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
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
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
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
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
{\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