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