\r
#include <PiSmm.h>\r
\r
+#include <Protocol/SmmAccess2.h>\r
#include <Library/MemoryAllocationLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
#include <Library/BaseMemoryLib.h>\r
#include <Library/DebugLib.h>\r
#include "PiSmmCoreMemoryAllocationServices.h"\r
\r
+EFI_SMRAM_DESCRIPTOR *mSmramRanges = NULL;\r
+UINTN mSmramRangeCount = 0;\r
+\r
+/**\r
+ This function gets and 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
+\r
+**/\r
+VOID\r
+EFIAPI\r
+GetSmramRanges (\r
+ VOID\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
+\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
+ if (mSmramRanges == NULL) {\r
+ //\r
+ // SMRAM ranges is not got. Try to get them all.\r
+ //\r
+ GetSmramRanges();\r
+ }\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 = SmmFreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) Buffer, Pages);\r
+ if (BufferInSmram (Buffer)) {\r
+ //\r
+ // When Buffer is in SMRAM range, it should be allocated by SmmAllocatePages() service.\r
+ // So, SmmFreePages() service is used to free it.\r
+ //\r
+ Status = 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 = SmmFreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) Buffer, Pages);\r
+ if (BufferInSmram (Buffer)) {\r
+ //\r
+ // When Buffer is in SMRAM range, it should be allocated by SmmAllocatePages() service.\r
+ // So, SmmFreePages() service is used to free it.\r
+ //\r
+ Status = 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 = SmmFreePool (Buffer);\r
+ if (BufferInSmram (Buffer)) {\r
+ //\r
+ // When Buffer is in SMRAM range, it should be allocated by SmmAllocatePool() service.\r
+ // So, SmmFreePool() service is used to free it.\r
+ //\r
+ Status = 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
\r