+/** @file\r
+ Support routines for SMRAM profile.\r
+\r
+ Copyright (c) 2014, 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
+ http://opensource.org/licenses/bsd-license.php.\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "PiSmmCore.h"\r
+\r
+#define IS_SMRAM_PROFILE_ENABLED ((PcdGet8 (PcdMemoryProfilePropertyMask) & BIT1) != 0)\r
+\r
+typedef struct {\r
+ UINT32 Signature;\r
+ MEMORY_PROFILE_CONTEXT Context;\r
+ LIST_ENTRY *DriverInfoList;\r
+} MEMORY_PROFILE_CONTEXT_DATA;\r
+\r
+typedef struct {\r
+ UINT32 Signature;\r
+ MEMORY_PROFILE_DRIVER_INFO DriverInfo;\r
+ LIST_ENTRY *AllocInfoList;\r
+ LIST_ENTRY Link;\r
+} MEMORY_PROFILE_DRIVER_INFO_DATA;\r
+\r
+typedef struct {\r
+ UINT32 Signature;\r
+ MEMORY_PROFILE_ALLOC_INFO AllocInfo;\r
+ LIST_ENTRY Link;\r
+} MEMORY_PROFILE_ALLOC_INFO_DATA;\r
+\r
+//\r
+// When free memory less than 4 pages, dump it.\r
+//\r
+#define SMRAM_INFO_DUMP_PAGE_THRESHOLD 4\r
+\r
+GLOBAL_REMOVE_IF_UNREFERENCED MEMORY_PROFILE_FREE_MEMORY mSmramFreeMemory = {\r
+ {\r
+ MEMORY_PROFILE_FREE_MEMORY_SIGNATURE,\r
+ sizeof (MEMORY_PROFILE_FREE_MEMORY),\r
+ MEMORY_PROFILE_FREE_MEMORY_REVISION\r
+ },\r
+ 0,\r
+ 0\r
+};\r
+\r
+GLOBAL_REMOVE_IF_UNREFERENCED LIST_ENTRY mImageQueue = INITIALIZE_LIST_HEAD_VARIABLE (mImageQueue);\r
+GLOBAL_REMOVE_IF_UNREFERENCED MEMORY_PROFILE_CONTEXT_DATA mSmramProfileContext = {\r
+ MEMORY_PROFILE_CONTEXT_SIGNATURE,\r
+ {\r
+ {\r
+ MEMORY_PROFILE_CONTEXT_SIGNATURE,\r
+ sizeof (MEMORY_PROFILE_CONTEXT),\r
+ MEMORY_PROFILE_CONTEXT_REVISION\r
+ },\r
+ 0,\r
+ 0,\r
+ {0},\r
+ {0},\r
+ 0,\r
+ 0,\r
+ 0\r
+ },\r
+ &mImageQueue,\r
+};\r
+GLOBAL_REMOVE_IF_UNREFERENCED MEMORY_PROFILE_CONTEXT_DATA *mSmramProfileContextPtr;\r
+\r
+BOOLEAN mSmramReadyToLock;\r
+BOOLEAN mSmramProfileRecordingStatus = FALSE;\r
+\r
+/**\r
+ Return SMRAM profile context.\r
+\r
+ @return SMRAM profile context.\r
+\r
+**/\r
+MEMORY_PROFILE_CONTEXT_DATA *\r
+GetSmramProfileContext (\r
+ VOID\r
+ )\r
+{\r
+ return mSmramProfileContextPtr;\r
+}\r
+\r
+/**\r
+ Retrieves the magic value from the PE/COFF header.\r
+\r
+ @param Hdr The buffer in which to return the PE32, PE32+, or TE header.\r
+\r
+ @return EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC - Image is PE32\r
+ @return EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC - Image is PE32+\r
+\r
+**/\r
+UINT16\r
+InternalPeCoffGetPeHeaderMagicValue (\r
+ IN EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr\r
+ )\r
+{\r
+ //\r
+ // NOTE: Some versions of Linux ELILO for Itanium have an incorrect magic value\r
+ // in the PE/COFF Header. If the MachineType is Itanium(IA64) and the\r
+ // Magic value in the OptionalHeader is EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC\r
+ // then override the returned value to EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC\r
+ //\r
+ if (Hdr.Pe32->FileHeader.Machine == IMAGE_FILE_MACHINE_IA64 && Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
+ return EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
+ }\r
+ //\r
+ // Return the magic value from the PC/COFF Optional Header\r
+ //\r
+ return Hdr.Pe32->OptionalHeader.Magic;\r
+}\r
+\r
+/**\r
+ Retrieves and returns the Subsystem of a PE/COFF image that has been loaded into system memory.\r
+ If Pe32Data is NULL, then ASSERT().\r
+\r
+ @param Pe32Data The pointer to the PE/COFF image that is loaded in system memory.\r
+\r
+ @return The Subsystem of the PE/COFF image.\r
+\r
+**/\r
+UINT16\r
+InternalPeCoffGetSubsystem (\r
+ IN VOID *Pe32Data\r
+ )\r
+{\r
+ EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;\r
+ EFI_IMAGE_DOS_HEADER *DosHdr;\r
+ UINT16 Magic;\r
+\r
+ ASSERT (Pe32Data != NULL);\r
+\r
+ DosHdr = (EFI_IMAGE_DOS_HEADER *) Pe32Data;\r
+ if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {\r
+ //\r
+ // DOS image header is present, so read the PE header after the DOS image header.\r
+ //\r
+ Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *) ((UINTN) Pe32Data + (UINTN) ((DosHdr->e_lfanew) & 0x0ffff));\r
+ } else {\r
+ //\r
+ // DOS image header is not present, so PE header is at the image base.\r
+ //\r
+ Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *) Pe32Data;\r
+ }\r
+\r
+ if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {\r
+ return Hdr.Te->Subsystem;\r
+ } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {\r
+ Magic = InternalPeCoffGetPeHeaderMagicValue (Hdr);\r
+ if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
+ return Hdr.Pe32->OptionalHeader.Subsystem;\r
+ } else if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {\r
+ return Hdr.Pe32Plus->OptionalHeader.Subsystem;\r
+ }\r
+ }\r
+\r
+ return 0x0000;\r
+}\r
+\r
+/**\r
+ Retrieves and returns a pointer to the entry point to a PE/COFF image that has been loaded\r
+ into system memory with the PE/COFF Loader Library functions.\r
+\r
+ Retrieves the entry point to the PE/COFF image specified by Pe32Data and returns this entry\r
+ point in EntryPoint. If the entry point could not be retrieved from the PE/COFF image, then\r
+ return RETURN_INVALID_PARAMETER. Otherwise return RETURN_SUCCESS.\r
+ If Pe32Data is NULL, then ASSERT().\r
+ If EntryPoint is NULL, then ASSERT().\r
+\r
+ @param Pe32Data The pointer to the PE/COFF image that is loaded in system memory.\r
+ @param EntryPoint The pointer to entry point to the PE/COFF image to return.\r
+\r
+ @retval RETURN_SUCCESS EntryPoint was returned.\r
+ @retval RETURN_INVALID_PARAMETER The entry point could not be found in the PE/COFF image.\r
+\r
+**/\r
+RETURN_STATUS\r
+InternalPeCoffGetEntryPoint (\r
+ IN VOID *Pe32Data,\r
+ OUT VOID **EntryPoint\r
+ )\r
+{\r
+ EFI_IMAGE_DOS_HEADER *DosHdr;\r
+ EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;\r
+\r
+ ASSERT (Pe32Data != NULL);\r
+ ASSERT (EntryPoint != NULL);\r
+\r
+ DosHdr = (EFI_IMAGE_DOS_HEADER *) Pe32Data;\r
+ if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {\r
+ //\r
+ // DOS image header is present, so read the PE header after the DOS image header.\r
+ //\r
+ Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *) ((UINTN) Pe32Data + (UINTN) ((DosHdr->e_lfanew) & 0x0ffff));\r
+ } else {\r
+ //\r
+ // DOS image header is not present, so PE header is at the image base.\r
+ //\r
+ Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *) Pe32Data;\r
+ }\r
+\r
+ //\r
+ // Calculate the entry point relative to the start of the image.\r
+ // AddressOfEntryPoint is common for PE32 & PE32+\r
+ //\r
+ if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {\r
+ *EntryPoint = (VOID *) ((UINTN) Pe32Data + (UINTN) (Hdr.Te->AddressOfEntryPoint & 0x0ffffffff) + sizeof (EFI_TE_IMAGE_HEADER) - Hdr.Te->StrippedSize);\r
+ return RETURN_SUCCESS;\r
+ } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {\r
+ *EntryPoint = (VOID *) ((UINTN) Pe32Data + (UINTN) (Hdr.Pe32->OptionalHeader.AddressOfEntryPoint & 0x0ffffffff));\r
+ return RETURN_SUCCESS;\r
+ }\r
+\r
+ return RETURN_UNSUPPORTED;\r
+}\r
+\r
+/**\r
+ Build driver info.\r
+\r
+ @param ContextData Memory profile context.\r
+ @param FileName File name of the image.\r
+ @param ImageBase Image base address.\r
+ @param ImageSize Image size.\r
+ @param EntryPoint Entry point of the image.\r
+ @param ImageSubsystem Image subsystem of the image.\r
+\r
+ @param FileType File type of the image.\r
+\r
+ @return Pointer to memory profile driver info.\r
+\r
+**/\r
+MEMORY_PROFILE_DRIVER_INFO_DATA *\r
+BuildDriverInfo (\r
+ IN MEMORY_PROFILE_CONTEXT_DATA *ContextData,\r
+ IN EFI_GUID *FileName,\r
+ IN PHYSICAL_ADDRESS ImageBase,\r
+ IN UINT64 ImageSize,\r
+ IN PHYSICAL_ADDRESS EntryPoint,\r
+ IN UINT16 ImageSubsystem,\r
+ IN EFI_FV_FILETYPE FileType\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ MEMORY_PROFILE_DRIVER_INFO *DriverInfo;\r
+ MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;\r
+ VOID *EntryPointInImage;\r
+\r
+ //\r
+ // Use SmmInternalAllocatePool() that will not update profile for this AllocatePool action.\r
+ //\r
+ Status = SmmInternalAllocatePool (\r
+ EfiRuntimeServicesData,\r
+ sizeof (*DriverInfoData) + sizeof (LIST_ENTRY),\r
+ (VOID **) &DriverInfoData\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return NULL;\r
+ }\r
+\r
+ ZeroMem (DriverInfoData, sizeof (*DriverInfoData));\r
+\r
+ DriverInfo = &DriverInfoData->DriverInfo;\r
+ DriverInfoData->Signature = MEMORY_PROFILE_DRIVER_INFO_SIGNATURE;\r
+ DriverInfo->Header.Signature = MEMORY_PROFILE_DRIVER_INFO_SIGNATURE;\r
+ DriverInfo->Header.Length = sizeof (MEMORY_PROFILE_DRIVER_INFO);\r
+ DriverInfo->Header.Revision = MEMORY_PROFILE_DRIVER_INFO_REVISION;\r
+ if (FileName != NULL) {\r
+ CopyMem (&DriverInfo->FileName, FileName, sizeof (EFI_GUID));\r
+ }\r
+ DriverInfo->ImageBase = ImageBase;\r
+ DriverInfo->ImageSize = ImageSize;\r
+ DriverInfo->EntryPoint = EntryPoint;\r
+ DriverInfo->ImageSubsystem = ImageSubsystem;\r
+ if ((EntryPoint != 0) && ((EntryPoint < ImageBase) || (EntryPoint >= (ImageBase + ImageSize)))) {\r
+ //\r
+ // If the EntryPoint is not in the range of image buffer, it should come from emulation environment.\r
+ // So patch ImageBuffer here to align the EntryPoint.\r
+ //\r
+ Status = InternalPeCoffGetEntryPoint ((VOID *) (UINTN) ImageBase, &EntryPointInImage);\r
+ ASSERT_EFI_ERROR (Status);\r
+ DriverInfo->ImageBase = ImageBase + EntryPoint - (PHYSICAL_ADDRESS) (UINTN) EntryPointInImage;\r
+ }\r
+ DriverInfo->FileType = FileType;\r
+ DriverInfoData->AllocInfoList = (LIST_ENTRY *) (DriverInfoData + 1);\r
+ InitializeListHead (DriverInfoData->AllocInfoList);\r
+ DriverInfo->CurrentUsage = 0;\r
+ DriverInfo->PeakUsage = 0;\r
+ DriverInfo->AllocRecordCount = 0;\r
+\r
+ InsertTailList (ContextData->DriverInfoList, &DriverInfoData->Link);\r
+ ContextData->Context.ImageCount ++;\r
+ ContextData->Context.TotalImageSize += DriverInfo->ImageSize;\r
+\r
+ return DriverInfoData;\r
+}\r
+\r
+/**\r
+ Register image to DXE.\r
+\r
+ @param FileName File name of the image.\r
+ @param ImageBase Image base address.\r
+ @param ImageSize Image size.\r
+ @param FileType File type of the image.\r
+\r
+**/\r
+VOID\r
+RegisterImageToDxe (\r
+ IN EFI_GUID *FileName,\r
+ IN PHYSICAL_ADDRESS ImageBase,\r
+ IN UINT64 ImageSize,\r
+ IN EFI_FV_FILETYPE FileType\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EDKII_MEMORY_PROFILE_PROTOCOL *ProfileProtocol;\r
+ MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FilePath;\r
+ UINT8 TempBuffer[sizeof (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH) + sizeof (EFI_DEVICE_PATH_PROTOCOL)];\r
+\r
+ if (IS_SMRAM_PROFILE_ENABLED) {\r
+\r
+ FilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)TempBuffer;\r
+ Status = gBS->LocateProtocol (&gEdkiiMemoryProfileGuid, NULL, (VOID **) &ProfileProtocol);\r
+ if (!EFI_ERROR (Status)) {\r
+ EfiInitializeFwVolDevicepathNode (FilePath, FileName);\r
+ SetDevicePathEndNode (FilePath + 1);\r
+\r
+ Status = ProfileProtocol->RegisterImage (\r
+ ProfileProtocol,\r
+ (EFI_DEVICE_PATH_PROTOCOL *) FilePath,\r
+ ImageBase,\r
+ ImageSize,\r
+ FileType\r
+ );\r
+ }\r
+ }\r
+}\r
+\r
+/**\r
+ Unregister image from DXE.\r
+\r
+ @param FileName File name of the image.\r
+ @param ImageBase Image base address.\r
+ @param ImageSize Image size.\r
+\r
+**/\r
+VOID\r
+UnregisterImageFromDxe (\r
+ IN EFI_GUID *FileName,\r
+ IN PHYSICAL_ADDRESS ImageBase,\r
+ IN UINT64 ImageSize\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EDKII_MEMORY_PROFILE_PROTOCOL *ProfileProtocol;\r
+ MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FilePath;\r
+ UINT8 TempBuffer[sizeof (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH) + sizeof (EFI_DEVICE_PATH_PROTOCOL)];\r
+\r
+ if (IS_SMRAM_PROFILE_ENABLED) {\r
+\r
+ FilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)TempBuffer;\r
+ Status = gBS->LocateProtocol (&gEdkiiMemoryProfileGuid, NULL, (VOID *) &ProfileProtocol);\r
+ if (!EFI_ERROR (Status)) {\r
+ EfiInitializeFwVolDevicepathNode (FilePath, FileName);\r
+ SetDevicePathEndNode (FilePath + 1);\r
+\r
+ Status = ProfileProtocol->UnregisterImage (\r
+ ProfileProtocol,\r
+ (EFI_DEVICE_PATH_PROTOCOL *) FilePath,\r
+ ImageBase,\r
+ ImageSize\r
+ );\r
+ }\r
+ }\r
+}\r
+\r
+/**\r
+ Register SMM Core to SMRAM profile.\r
+\r
+ @param ContextData SMRAM profile context.\r
+\r
+ @retval TRUE Register success.\r
+ @retval FALSE Register fail.\r
+\r
+**/\r
+BOOLEAN\r
+RegisterSmmCore (\r
+ IN MEMORY_PROFILE_CONTEXT_DATA *ContextData\r
+ )\r
+{\r
+ MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;\r
+ PHYSICAL_ADDRESS ImageBase;\r
+\r
+ ASSERT (ContextData != NULL);\r
+\r
+ RegisterImageToDxe (\r
+ &gEfiCallerIdGuid,\r
+ gSmmCorePrivate->PiSmmCoreImageBase,\r
+ gSmmCorePrivate->PiSmmCoreImageSize,\r
+ EFI_FV_FILETYPE_SMM_CORE\r
+ );\r
+\r
+ ImageBase = gSmmCorePrivate->PiSmmCoreImageBase;\r
+ DriverInfoData = BuildDriverInfo (\r
+ ContextData,\r
+ &gEfiCallerIdGuid,\r
+ ImageBase,\r
+ gSmmCorePrivate->PiSmmCoreImageSize,\r
+ gSmmCorePrivate->PiSmmCoreEntryPoint,\r
+ InternalPeCoffGetSubsystem ((VOID *) (UINTN) ImageBase),\r
+ EFI_FV_FILETYPE_SMM_CORE\r
+ );\r
+ if (DriverInfoData == NULL) {\r
+ return FALSE;\r
+ }\r
+\r
+ return TRUE;\r
+}\r
+\r
+/**\r
+ Initialize SMRAM profile.\r
+\r
+**/\r
+VOID\r
+SmramProfileInit (\r
+ VOID\r
+ )\r
+{\r
+ MEMORY_PROFILE_CONTEXT_DATA *SmramProfileContext;\r
+\r
+ if (!IS_SMRAM_PROFILE_ENABLED) {\r
+ return;\r
+ }\r
+\r
+ SmramProfileContext = GetSmramProfileContext ();\r
+ if (SmramProfileContext != NULL) {\r
+ return;\r
+ }\r
+\r
+ mSmramProfileRecordingStatus = TRUE;\r
+ mSmramProfileContextPtr = &mSmramProfileContext;\r
+\r
+ RegisterSmmCore (&mSmramProfileContext);\r
+\r
+ DEBUG ((EFI_D_INFO, "SmramProfileInit SmramProfileContext - 0x%x\n", &mSmramProfileContext));\r
+}\r
+\r
+/**\r
+ Register SMM image to SMRAM profile.\r
+\r
+ @param DriverEntry SMM image info.\r
+ @param RegisterToDxe Register image to DXE.\r
+\r
+ @retval TRUE Register success.\r
+ @retval FALSE Register fail.\r
+\r
+**/\r
+BOOLEAN\r
+RegisterSmramProfileImage (\r
+ IN EFI_SMM_DRIVER_ENTRY *DriverEntry,\r
+ IN BOOLEAN RegisterToDxe\r
+ )\r
+{\r
+ MEMORY_PROFILE_CONTEXT_DATA *ContextData;\r
+ MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;\r
+\r
+ if (!IS_SMRAM_PROFILE_ENABLED) {\r
+ return FALSE;\r
+ }\r
+\r
+ if (RegisterToDxe) {\r
+ RegisterImageToDxe (\r
+ &DriverEntry->FileName,\r
+ DriverEntry->ImageBuffer,\r
+ EFI_PAGES_TO_SIZE (DriverEntry->NumberOfPage),\r
+ EFI_FV_FILETYPE_SMM\r
+ );\r
+ }\r
+\r
+ ContextData = GetSmramProfileContext ();\r
+ if (ContextData == NULL) {\r
+ return FALSE;\r
+ }\r
+\r
+ DriverInfoData = BuildDriverInfo (\r
+ ContextData,\r
+ &DriverEntry->FileName,\r
+ DriverEntry->ImageBuffer,\r
+ EFI_PAGES_TO_SIZE (DriverEntry->NumberOfPage),\r
+ DriverEntry->ImageEntryPoint,\r
+ InternalPeCoffGetSubsystem ((VOID *) (UINTN) DriverEntry->ImageBuffer),\r
+ EFI_FV_FILETYPE_SMM\r
+ );\r
+ if (DriverInfoData == NULL) {\r
+ return FALSE;\r
+ }\r
+\r
+ return TRUE;\r
+}\r
+\r
+/**\r
+ Search image from memory profile.\r
+\r
+ @param ContextData Memory profile context.\r
+ @param FileName Image file name.\r
+ @param Address Image Address.\r
+\r
+ @return Pointer to memory profile driver info.\r
+\r
+**/\r
+MEMORY_PROFILE_DRIVER_INFO_DATA *\r
+GetMemoryProfileDriverInfoByFileNameAndAddress (\r
+ IN MEMORY_PROFILE_CONTEXT_DATA *ContextData,\r
+ IN EFI_GUID *FileName,\r
+ IN PHYSICAL_ADDRESS Address\r
+ )\r
+{\r
+ MEMORY_PROFILE_DRIVER_INFO *DriverInfo;\r
+ MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;\r
+ LIST_ENTRY *DriverLink;\r
+ LIST_ENTRY *DriverInfoList;\r
+\r
+ DriverInfoList = ContextData->DriverInfoList;\r
+\r
+ for (DriverLink = DriverInfoList->ForwardLink;\r
+ DriverLink != DriverInfoList;\r
+ DriverLink = DriverLink->ForwardLink) {\r
+ DriverInfoData = CR (\r
+ DriverLink,\r
+ MEMORY_PROFILE_DRIVER_INFO_DATA,\r
+ Link,\r
+ MEMORY_PROFILE_DRIVER_INFO_SIGNATURE\r
+ );\r
+ DriverInfo = &DriverInfoData->DriverInfo;\r
+ if ((CompareGuid (&DriverInfo->FileName, FileName)) &&\r
+ (Address >= DriverInfo->ImageBase) &&\r
+ (Address < (DriverInfo->ImageBase + DriverInfo->ImageSize))) {\r
+ return DriverInfoData;\r
+ }\r
+ }\r
+\r
+ return NULL;\r
+}\r
+\r
+/**\r
+ Search dummy image from SMRAM profile.\r
+\r
+ @param ContextData Memory profile context.\r
+\r
+ @return Pointer to memory profile driver info.\r
+\r
+**/\r
+MEMORY_PROFILE_DRIVER_INFO_DATA *\r
+FindDummyImage (\r
+ IN MEMORY_PROFILE_CONTEXT_DATA *ContextData\r
+ )\r
+{\r
+ MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;\r
+ LIST_ENTRY *DriverLink;\r
+ LIST_ENTRY *DriverInfoList;\r
+\r
+ DriverInfoList = ContextData->DriverInfoList;\r
+\r
+ for (DriverLink = DriverInfoList->ForwardLink;\r
+ DriverLink != DriverInfoList;\r
+ DriverLink = DriverLink->ForwardLink) {\r
+ DriverInfoData = CR (\r
+ DriverLink,\r
+ MEMORY_PROFILE_DRIVER_INFO_DATA,\r
+ Link,\r
+ MEMORY_PROFILE_DRIVER_INFO_SIGNATURE\r
+ );\r
+ if (CompareGuid (&gZeroGuid, &DriverInfoData->DriverInfo.FileName)) {\r
+ return DriverInfoData;\r
+ }\r
+ }\r
+\r
+ return BuildDriverInfo (ContextData, &gZeroGuid, 0, 0, 0, 0, 0);\r
+}\r
+\r
+/**\r
+ Search image from memory profile.\r
+ It will return image, if (Address >= ImageBuffer) AND (Address < ImageBuffer + ImageSize)\r
+\r
+ @param ContextData Memory profile context.\r
+ @param Address Image or Function address.\r
+\r
+ @return Pointer to memory profile driver info.\r
+\r
+**/\r
+MEMORY_PROFILE_DRIVER_INFO_DATA *\r
+GetMemoryProfileDriverInfoFromAddress (\r
+ IN MEMORY_PROFILE_CONTEXT_DATA *ContextData,\r
+ IN PHYSICAL_ADDRESS Address\r
+ )\r
+{\r
+ MEMORY_PROFILE_DRIVER_INFO *DriverInfo;\r
+ MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;\r
+ LIST_ENTRY *DriverLink;\r
+ LIST_ENTRY *DriverInfoList;\r
+\r
+ DriverInfoList = ContextData->DriverInfoList;\r
+\r
+ for (DriverLink = DriverInfoList->ForwardLink;\r
+ DriverLink != DriverInfoList;\r
+ DriverLink = DriverLink->ForwardLink) {\r
+ DriverInfoData = CR (\r
+ DriverLink,\r
+ MEMORY_PROFILE_DRIVER_INFO_DATA,\r
+ Link,\r
+ MEMORY_PROFILE_DRIVER_INFO_SIGNATURE\r
+ );\r
+ DriverInfo = &DriverInfoData->DriverInfo;\r
+ if ((Address >= DriverInfo->ImageBase) &&\r
+ (Address < (DriverInfo->ImageBase + DriverInfo->ImageSize))) {\r
+ return DriverInfoData;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Should never come here.\r
+ //\r
+ return FindDummyImage (ContextData);\r
+}\r
+\r
+/**\r
+ Unregister image from SMRAM profile.\r
+\r
+ @param DriverEntry SMM image info.\r
+ @param UnregisterFromDxe Unregister image from DXE.\r
+\r
+ @retval TRUE Unregister success.\r
+ @retval FALSE Unregister fail.\r
+\r
+**/\r
+BOOLEAN\r
+UnregisterSmramProfileImage (\r
+ IN EFI_SMM_DRIVER_ENTRY *DriverEntry,\r
+ IN BOOLEAN UnregisterFromDxe\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ MEMORY_PROFILE_CONTEXT_DATA *ContextData;\r
+ MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;\r
+ EFI_GUID *FileName;\r
+ PHYSICAL_ADDRESS ImageAddress;\r
+ VOID *EntryPointInImage;\r
+\r
+ if (!IS_SMRAM_PROFILE_ENABLED) {\r
+ return FALSE;\r
+ }\r
+\r
+ if (UnregisterFromDxe) {\r
+ UnregisterImageFromDxe (\r
+ &DriverEntry->FileName,\r
+ DriverEntry->ImageBuffer,\r
+ EFI_PAGES_TO_SIZE (DriverEntry->NumberOfPage)\r
+ );\r
+ }\r
+\r
+ ContextData = GetSmramProfileContext ();\r
+ if (ContextData == NULL) {\r
+ return FALSE;\r
+ }\r
+\r
+ DriverInfoData = NULL;\r
+ FileName = &DriverEntry->FileName;\r
+ ImageAddress = DriverEntry->ImageBuffer;\r
+ if ((DriverEntry->ImageEntryPoint < ImageAddress) || (DriverEntry->ImageEntryPoint >= (ImageAddress + EFI_PAGES_TO_SIZE (DriverEntry->NumberOfPage)))) {\r
+ //\r
+ // If the EntryPoint is not in the range of image buffer, it should come from emulation environment.\r
+ // So patch ImageAddress here to align the EntryPoint.\r
+ //\r
+ Status = InternalPeCoffGetEntryPoint ((VOID *) (UINTN) ImageAddress, &EntryPointInImage);\r
+ ASSERT_EFI_ERROR (Status);\r
+ ImageAddress = ImageAddress + (UINTN) DriverEntry->ImageEntryPoint - (UINTN) EntryPointInImage;\r
+ }\r
+ if (FileName != NULL) {\r
+ DriverInfoData = GetMemoryProfileDriverInfoByFileNameAndAddress (ContextData, FileName, ImageAddress);\r
+ }\r
+ if (DriverInfoData == NULL) {\r
+ DriverInfoData = GetMemoryProfileDriverInfoFromAddress (ContextData, ImageAddress);\r
+ }\r
+ if (DriverInfoData == NULL) {\r
+ return FALSE;\r
+ }\r
+\r
+ ContextData->Context.TotalImageSize -= DriverInfoData->DriverInfo.ImageSize;\r
+\r
+ DriverInfoData->DriverInfo.ImageBase = 0;\r
+ DriverInfoData->DriverInfo.ImageSize = 0;\r
+\r
+ if (DriverInfoData->DriverInfo.PeakUsage == 0) {\r
+ ContextData->Context.ImageCount --;\r
+ RemoveEntryList (&DriverInfoData->Link);\r
+ //\r
+ // Use SmmInternalFreePool() that will not update profile for this FreePool action.\r
+ //\r
+ SmmInternalFreePool (DriverInfoData);\r
+ }\r
+\r
+ return TRUE;\r
+}\r
+\r
+/**\r
+ Return if this memory type needs to be recorded into memory profile.\r
+ If BIOS memory type (0 ~ EfiMaxMemoryType), it checks bit (1 << MemoryType).\r
+ If OS memory type (0x80000000 ~ 0xFFFFFFFF), it checks bit63 - 0x8000000000000000.\r
+\r
+ @param MemoryType Memory type.\r
+\r
+ @retval TRUE This memory type need to be recorded.\r
+ @retval FALSE This memory type need not to be recorded.\r
+\r
+**/\r
+BOOLEAN\r
+SmmCoreNeedRecordProfile (\r
+ IN EFI_MEMORY_TYPE MemoryType\r
+ )\r
+{\r
+ UINT64 TestBit;\r
+\r
+ if ((UINT32) MemoryType >= 0x80000000) {\r
+ TestBit = BIT63;\r
+ } else {\r
+ TestBit = LShiftU64 (1, MemoryType);\r
+ }\r
+\r
+ if ((PcdGet64 (PcdMemoryProfileMemoryType) & TestBit) != 0) {\r
+ return TRUE;\r
+ } else {\r
+ return FALSE;\r
+ }\r
+}\r
+\r
+/**\r
+ Convert EFI memory type to profile memory index. The rule is:\r
+ If BIOS memory type (0 ~ EfiMaxMemoryType), ProfileMemoryIndex = MemoryType.\r
+ If OS memory type (0x80000000 ~ 0xFFFFFFFF), ProfileMemoryIndex = EfiMaxMemoryType.\r
+\r
+ @param MemoryType Memory type.\r
+\r
+ @return EFI memory type as profile memory index.\r
+\r
+**/\r
+EFI_MEMORY_TYPE\r
+GetProfileMemoryIndex (\r
+ IN EFI_MEMORY_TYPE MemoryType\r
+ )\r
+{\r
+ if ((UINT32) MemoryType >= 0x80000000) {\r
+ return EfiMaxMemoryType;\r
+ } else {\r
+ return MemoryType;\r
+ }\r
+}\r
+\r
+/**\r
+ Update SMRAM profile FreeMemoryPages information\r
+\r
+ @param ContextData Memory profile context.\r
+\r
+**/\r
+VOID\r
+SmramProfileUpdateFreePages (\r
+ IN MEMORY_PROFILE_CONTEXT_DATA *ContextData\r
+ )\r
+{\r
+ LIST_ENTRY *Node;\r
+ FREE_PAGE_LIST *Pages;\r
+ LIST_ENTRY *FreePageList;\r
+ UINTN NumberOfPages;\r
+\r
+ NumberOfPages = 0;\r
+ FreePageList = &mSmmMemoryMap;\r
+ for (Node = FreePageList->BackLink;\r
+ Node != FreePageList;\r
+ Node = Node->BackLink) {\r
+ Pages = BASE_CR (Node, FREE_PAGE_LIST, Link);\r
+ NumberOfPages += Pages->NumberOfPages;\r
+ }\r
+\r
+ mSmramFreeMemory.TotalFreeMemoryPages = NumberOfPages;\r
+\r
+ if (NumberOfPages <= SMRAM_INFO_DUMP_PAGE_THRESHOLD) {\r
+ DumpSmramInfo ();\r
+ }\r
+}\r
+\r
+/**\r
+ Update SMRAM profile Allocate information.\r
+\r
+ @param CallerAddress Address of caller who call Allocate.\r
+ @param Action This Allocate action.\r
+ @param MemoryType Memory type.\r
+ @param Size Buffer size.\r
+ @param Buffer Buffer address.\r
+\r
+ @retval TRUE Profile udpate success.\r
+ @retval FALSE Profile update fail.\r
+\r
+**/\r
+BOOLEAN\r
+SmmCoreUpdateProfileAllocate (\r
+ IN PHYSICAL_ADDRESS CallerAddress,\r
+ IN MEMORY_PROFILE_ACTION Action,\r
+ IN EFI_MEMORY_TYPE MemoryType,\r
+ IN UINTN Size,\r
+ IN VOID *Buffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ MEMORY_PROFILE_CONTEXT *Context;\r
+ MEMORY_PROFILE_DRIVER_INFO *DriverInfo;\r
+ MEMORY_PROFILE_ALLOC_INFO *AllocInfo;\r
+ MEMORY_PROFILE_CONTEXT_DATA *ContextData;\r
+ MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;\r
+ MEMORY_PROFILE_ALLOC_INFO_DATA *AllocInfoData;\r
+ EFI_MEMORY_TYPE ProfileMemoryIndex;\r
+\r
+ ContextData = GetSmramProfileContext ();\r
+ if (ContextData == NULL) {\r
+ return FALSE;\r
+ }\r
+\r
+ DriverInfoData = GetMemoryProfileDriverInfoFromAddress (ContextData, CallerAddress);\r
+ ASSERT (DriverInfoData != NULL);\r
+\r
+ //\r
+ // Use SmmInternalAllocatePool() that will not update profile for this AllocatePool action.\r
+ //\r
+ Status = SmmInternalAllocatePool (\r
+ EfiRuntimeServicesData,\r
+ sizeof (*AllocInfoData),\r
+ (VOID **) &AllocInfoData\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return FALSE;\r
+ }\r
+ AllocInfo = &AllocInfoData->AllocInfo;\r
+ AllocInfoData->Signature = MEMORY_PROFILE_ALLOC_INFO_SIGNATURE;\r
+ AllocInfo->Header.Signature = MEMORY_PROFILE_ALLOC_INFO_SIGNATURE;\r
+ AllocInfo->Header.Length = sizeof (MEMORY_PROFILE_ALLOC_INFO);\r
+ AllocInfo->Header.Revision = MEMORY_PROFILE_ALLOC_INFO_REVISION;\r
+ AllocInfo->CallerAddress = CallerAddress;\r
+ AllocInfo->SequenceId = ContextData->Context.SequenceCount;\r
+ AllocInfo->Action = Action;\r
+ AllocInfo->MemoryType = MemoryType;\r
+ AllocInfo->Buffer = (PHYSICAL_ADDRESS) (UINTN) Buffer;\r
+ AllocInfo->Size = Size;\r
+\r
+ InsertTailList (DriverInfoData->AllocInfoList, &AllocInfoData->Link);\r
+\r
+ ProfileMemoryIndex = GetProfileMemoryIndex (MemoryType);\r
+\r
+ DriverInfo = &DriverInfoData->DriverInfo;\r
+ DriverInfo->CurrentUsage += Size;\r
+ if (DriverInfo->PeakUsage < DriverInfo->CurrentUsage) {\r
+ DriverInfo->PeakUsage = DriverInfo->CurrentUsage;\r
+ }\r
+ DriverInfo->CurrentUsageByType[ProfileMemoryIndex] += Size;\r
+ if (DriverInfo->PeakUsageByType[ProfileMemoryIndex] < DriverInfo->CurrentUsageByType[ProfileMemoryIndex]) {\r
+ DriverInfo->PeakUsageByType[ProfileMemoryIndex] = DriverInfo->CurrentUsageByType[ProfileMemoryIndex];\r
+ }\r
+ DriverInfo->AllocRecordCount ++;\r
+\r
+ Context = &ContextData->Context;\r
+ Context->CurrentTotalUsage += Size;\r
+ if (Context->PeakTotalUsage < Context->CurrentTotalUsage) {\r
+ Context->PeakTotalUsage = Context->CurrentTotalUsage;\r
+ }\r
+ Context->CurrentTotalUsageByType[ProfileMemoryIndex] += Size;\r
+ if (Context->PeakTotalUsageByType[ProfileMemoryIndex] < Context->CurrentTotalUsageByType[ProfileMemoryIndex]) {\r
+ Context->PeakTotalUsageByType[ProfileMemoryIndex] = Context->CurrentTotalUsageByType[ProfileMemoryIndex];\r
+ }\r
+ Context->SequenceCount ++;\r
+\r
+ SmramProfileUpdateFreePages (ContextData);\r
+ return TRUE;\r
+}\r
+\r
+/**\r
+ Get memory profile alloc info from memory profile\r
+\r
+ @param DriverInfoData Driver info\r
+ @param Action This Free action\r
+ @param Size Buffer size\r
+ @param Buffer Buffer address\r
+\r
+ @return Pointer to memory profile alloc info.\r
+**/\r
+MEMORY_PROFILE_ALLOC_INFO_DATA *\r
+GetMemoryProfileAllocInfoFromAddress (\r
+ IN MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData,\r
+ IN MEMORY_PROFILE_ACTION Action,\r
+ IN UINTN Size,\r
+ IN VOID *Buffer\r
+ )\r
+{\r
+ LIST_ENTRY *AllocInfoList;\r
+ LIST_ENTRY *AllocLink;\r
+ MEMORY_PROFILE_ALLOC_INFO *AllocInfo;\r
+ MEMORY_PROFILE_ALLOC_INFO_DATA *AllocInfoData;\r
+\r
+ AllocInfoList = DriverInfoData->AllocInfoList;\r
+\r
+ for (AllocLink = AllocInfoList->ForwardLink;\r
+ AllocLink != AllocInfoList;\r
+ AllocLink = AllocLink->ForwardLink) {\r
+ AllocInfoData = CR (\r
+ AllocLink,\r
+ MEMORY_PROFILE_ALLOC_INFO_DATA,\r
+ Link,\r
+ MEMORY_PROFILE_ALLOC_INFO_SIGNATURE\r
+ );\r
+ AllocInfo = &AllocInfoData->AllocInfo;\r
+ if (AllocInfo->Action != Action) {\r
+ continue;\r
+ }\r
+ switch (Action) {\r
+ case MemoryProfileActionAllocatePages:\r
+ if ((AllocInfo->Buffer <= (PHYSICAL_ADDRESS) (UINTN) Buffer) &&\r
+ ((AllocInfo->Buffer + AllocInfo->Size) >= ((PHYSICAL_ADDRESS) (UINTN) Buffer + Size))) {\r
+ return AllocInfoData;\r
+ }\r
+ break;\r
+ case MemoryProfileActionAllocatePool:\r
+ if (AllocInfo->Buffer == (PHYSICAL_ADDRESS) (UINTN) Buffer) {\r
+ return AllocInfoData;\r
+ }\r
+ break;\r
+ default:\r
+ ASSERT (FALSE);\r
+ break;\r
+ }\r
+ }\r
+\r
+ return NULL;\r
+}\r
+\r
+/**\r
+ Update SMRAM profile Free information.\r
+\r
+ @param CallerAddress Address of caller who call Free.\r
+ @param Action This Free action.\r
+ @param Size Buffer size.\r
+ @param Buffer Buffer address.\r
+\r
+ @retval TRUE Profile udpate success.\r
+ @retval FALSE Profile update fail.\r
+\r
+**/\r
+BOOLEAN\r
+SmmCoreUpdateProfileFree (\r
+ IN PHYSICAL_ADDRESS CallerAddress,\r
+ IN MEMORY_PROFILE_ACTION Action,\r
+ IN UINTN Size,\r
+ IN VOID *Buffer\r
+ )\r
+{\r
+ MEMORY_PROFILE_CONTEXT *Context;\r
+ MEMORY_PROFILE_DRIVER_INFO *DriverInfo;\r
+ MEMORY_PROFILE_ALLOC_INFO *AllocInfo;\r
+ MEMORY_PROFILE_CONTEXT_DATA *ContextData;\r
+ MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;\r
+ LIST_ENTRY *DriverLink;\r
+ LIST_ENTRY *DriverInfoList;\r
+ MEMORY_PROFILE_DRIVER_INFO_DATA *ThisDriverInfoData;\r
+ MEMORY_PROFILE_ALLOC_INFO_DATA *AllocInfoData;\r
+ EFI_MEMORY_TYPE ProfileMemoryIndex;\r
+\r
+ ContextData = GetSmramProfileContext ();\r
+ if (ContextData == NULL) {\r
+ return FALSE;\r
+ }\r
+\r
+ DriverInfoData = GetMemoryProfileDriverInfoFromAddress (ContextData, CallerAddress);\r
+ ASSERT (DriverInfoData != NULL);\r
+\r
+ switch (Action) {\r
+ case MemoryProfileActionFreePages:\r
+ AllocInfoData = GetMemoryProfileAllocInfoFromAddress (DriverInfoData, MemoryProfileActionAllocatePages, Size, Buffer);\r
+ break;\r
+ case MemoryProfileActionFreePool:\r
+ AllocInfoData = GetMemoryProfileAllocInfoFromAddress (DriverInfoData, MemoryProfileActionAllocatePool, 0, Buffer);\r
+ break;\r
+ default:\r
+ ASSERT (FALSE);\r
+ AllocInfoData = NULL;\r
+ break;\r
+ }\r
+ if (AllocInfoData == NULL) {\r
+ //\r
+ // Legal case, because driver A might free memory allocated by driver B, by some protocol.\r
+ //\r
+ DriverInfoList = ContextData->DriverInfoList;\r
+\r
+ for (DriverLink = DriverInfoList->ForwardLink;\r
+ DriverLink != DriverInfoList;\r
+ DriverLink = DriverLink->ForwardLink) {\r
+ ThisDriverInfoData = CR (\r
+ DriverLink,\r
+ MEMORY_PROFILE_DRIVER_INFO_DATA,\r
+ Link,\r
+ MEMORY_PROFILE_DRIVER_INFO_SIGNATURE\r
+ );\r
+ switch (Action) {\r
+ case MemoryProfileActionFreePages:\r
+ AllocInfoData = GetMemoryProfileAllocInfoFromAddress (ThisDriverInfoData, MemoryProfileActionAllocatePages, Size, Buffer);\r
+ break;\r
+ case MemoryProfileActionFreePool:\r
+ AllocInfoData = GetMemoryProfileAllocInfoFromAddress (ThisDriverInfoData, MemoryProfileActionAllocatePool, 0, Buffer);\r
+ break;\r
+ default:\r
+ ASSERT (FALSE);\r
+ AllocInfoData = NULL;\r
+ break;\r
+ }\r
+ if (AllocInfoData != NULL) {\r
+ DriverInfoData = ThisDriverInfoData;\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (AllocInfoData == NULL) {\r
+ //\r
+ // No matched allocate operation is found for this free operation.\r
+ // It is because the specified memory type allocate operation has been\r
+ // filtered by CoreNeedRecordProfile(), but free operations have no\r
+ // memory type information, they can not be filtered by CoreNeedRecordProfile().\r
+ // Then, they will be filtered here.\r
+ //\r
+ return FALSE;\r
+ }\r
+ }\r
+\r
+ Context = &ContextData->Context;\r
+ DriverInfo = &DriverInfoData->DriverInfo;\r
+ AllocInfo = &AllocInfoData->AllocInfo;\r
+\r
+ ProfileMemoryIndex = GetProfileMemoryIndex (AllocInfo->MemoryType);\r
+\r
+ Context->CurrentTotalUsage -= AllocInfo->Size;\r
+ Context->CurrentTotalUsageByType[ProfileMemoryIndex] -= AllocInfo->Size;\r
+\r
+ DriverInfo->CurrentUsage -= AllocInfo->Size;\r
+ DriverInfo->CurrentUsageByType[ProfileMemoryIndex] -= AllocInfo->Size;\r
+ DriverInfo->AllocRecordCount --;\r
+\r
+ RemoveEntryList (&AllocInfoData->Link);\r
+\r
+ if (Action == MemoryProfileActionFreePages) {\r
+ if (AllocInfo->Buffer != (PHYSICAL_ADDRESS) (UINTN) Buffer) {\r
+ SmmCoreUpdateProfileAllocate (\r
+ AllocInfo->CallerAddress,\r
+ MemoryProfileActionAllocatePages,\r
+ AllocInfo->MemoryType,\r
+ (UINTN) ((PHYSICAL_ADDRESS) (UINTN) Buffer - AllocInfo->Buffer),\r
+ (VOID *) (UINTN) AllocInfo->Buffer\r
+ );\r
+ }\r
+ if (AllocInfo->Buffer + AllocInfo->Size != ((PHYSICAL_ADDRESS) (UINTN) Buffer + Size)) {\r
+ SmmCoreUpdateProfileAllocate (\r
+ AllocInfo->CallerAddress,\r
+ MemoryProfileActionAllocatePages,\r
+ AllocInfo->MemoryType,\r
+ (UINTN) ((AllocInfo->Buffer + AllocInfo->Size) - ((PHYSICAL_ADDRESS) (UINTN) Buffer + Size)),\r
+ (VOID *) ((UINTN) Buffer + Size)\r
+ );\r
+ }\r
+ }\r
+\r
+ //\r
+ // Use SmmInternalFreePool() that will not update profile for this FreePool action.\r
+ //\r
+ SmmInternalFreePool (AllocInfoData);\r
+\r
+ return TRUE;\r
+}\r
+\r
+/**\r
+ Update SMRAM profile information.\r
+\r
+ @param CallerAddress Address of caller who call Allocate or Free.\r
+ @param Action This Allocate or Free action.\r
+ @param MemoryType Memory type.\r
+ @param Size Buffer size.\r
+ @param Buffer Buffer address.\r
+\r
+ @retval TRUE Profile udpate success.\r
+ @retval FALSE Profile update fail.\r
+\r
+**/\r
+BOOLEAN\r
+SmmCoreUpdateProfile (\r
+ IN PHYSICAL_ADDRESS CallerAddress,\r
+ IN MEMORY_PROFILE_ACTION Action,\r
+ IN EFI_MEMORY_TYPE MemoryType, // Valid for AllocatePages/AllocatePool\r
+ IN UINTN Size, // Valid for AllocatePages/FreePages/AllocatePool\r
+ IN VOID *Buffer\r
+ )\r
+{\r
+ MEMORY_PROFILE_CONTEXT_DATA *ContextData;\r
+\r
+ if (!IS_SMRAM_PROFILE_ENABLED) {\r
+ return FALSE;\r
+ }\r
+\r
+ if (!mSmramProfileRecordingStatus) {\r
+ return FALSE;\r
+ }\r
+\r
+ //\r
+ // Free operations have no memory type information, so skip the check.\r
+ //\r
+ if ((Action == MemoryProfileActionAllocatePages) || (Action == MemoryProfileActionAllocatePool)) {\r
+ //\r
+ // Only record limited MemoryType.\r
+ //\r
+ if (!SmmCoreNeedRecordProfile (MemoryType)) {\r
+ return FALSE;\r
+ }\r
+ }\r
+\r
+ ContextData = GetSmramProfileContext ();\r
+ if (ContextData == NULL) {\r
+ return FALSE;\r
+ }\r
+\r
+ switch (Action) {\r
+ case MemoryProfileActionAllocatePages:\r
+ SmmCoreUpdateProfileAllocate (CallerAddress, Action, MemoryType, Size, Buffer);\r
+ break;\r
+ case MemoryProfileActionFreePages:\r
+ SmmCoreUpdateProfileFree (CallerAddress, Action, Size, Buffer);\r
+ break;\r
+ case MemoryProfileActionAllocatePool:\r
+ SmmCoreUpdateProfileAllocate (CallerAddress, Action, MemoryType, Size, Buffer);\r
+ break;\r
+ case MemoryProfileActionFreePool:\r
+ SmmCoreUpdateProfileFree (CallerAddress, Action, 0, Buffer);\r
+ break;\r
+ default:\r
+ ASSERT (FALSE);\r
+ break;\r
+ }\r
+\r
+ return TRUE;\r
+}\r
+\r
+/**\r
+ SMRAM profile ready to lock callback function.\r
+\r
+**/\r
+VOID\r
+SmramProfileReadyToLock (\r
+ VOID\r
+ )\r
+{\r
+ if (!IS_SMRAM_PROFILE_ENABLED) {\r
+ return;\r
+ }\r
+\r
+ DEBUG ((EFI_D_INFO, "SmramProfileReadyToLock\n"));\r
+ mSmramReadyToLock = TRUE;\r
+}\r
+\r
+////////////////////\r
+\r
+/**\r
+ This function check if the address is in SMRAM.\r
+\r
+ @param Buffer the buffer address to be checked.\r
+ @param Length the buffer length to be checked.\r
+\r
+ @retval TRUE this address is in SMRAM.\r
+ @retval FALSE this address is NOT in SMRAM.\r
+\r
+**/\r
+BOOLEAN\r
+InternalIsAddressInSmram (\r
+ IN PHYSICAL_ADDRESS Buffer,\r
+ IN UINT64 Length\r
+ )\r
+{\r
+ UINTN Index;\r
+\r
+ for (Index = 0; Index < mFullSmramRangeCount; Index ++) {\r
+ if (((Buffer >= mFullSmramRanges[Index].CpuStart) && (Buffer < mFullSmramRanges[Index].CpuStart + mFullSmramRanges[Index].PhysicalSize)) ||\r
+ ((mFullSmramRanges[Index].CpuStart >= Buffer) && (mFullSmramRanges[Index].CpuStart < Buffer + Length))) {\r
+ return TRUE;\r
+ }\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+/**\r
+ This function check if the address refered by Buffer and Length is valid.\r
+\r
+ @param Buffer the buffer address to be checked.\r
+ @param Length the buffer length to be checked.\r
+\r
+ @retval TRUE this address is valid.\r
+ @retval FALSE this address is NOT valid.\r
+**/\r
+BOOLEAN\r
+InternalIsAddressValid (\r
+ IN UINTN Buffer,\r
+ IN UINTN Length\r
+ )\r
+{\r
+ if (Buffer > (MAX_ADDRESS - Length)) {\r
+ //\r
+ // Overflow happen\r
+ //\r
+ return FALSE;\r
+ }\r
+ if (InternalIsAddressInSmram ((PHYSICAL_ADDRESS) Buffer, (UINT64)Length)) {\r
+ return FALSE;\r
+ }\r
+ return TRUE;\r
+}\r
+\r
+/**\r
+ Get SMRAM profile data size.\r
+\r
+ @return SMRAM profile data size.\r
+\r
+**/\r
+UINTN\r
+SmramProfileGetDataSize (\r
+ VOID\r
+ )\r
+{\r
+ MEMORY_PROFILE_CONTEXT_DATA *ContextData;\r
+ MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;\r
+ LIST_ENTRY *DriverInfoList;\r
+ LIST_ENTRY *DriverLink;\r
+ UINTN TotalSize;\r
+ LIST_ENTRY *Node;\r
+ LIST_ENTRY *FreePageList;\r
+ LIST_ENTRY *FreePoolList;\r
+ FREE_POOL_HEADER *Pool;\r
+ UINTN PoolListIndex;\r
+ UINTN Index;\r
+\r
+ ContextData = GetSmramProfileContext ();\r
+ if (ContextData == NULL) {\r
+ return 0;\r
+ }\r
+\r
+ TotalSize = sizeof (MEMORY_PROFILE_CONTEXT);\r
+ TotalSize += sizeof (MEMORY_PROFILE_DRIVER_INFO) * (UINTN) ContextData->Context.ImageCount;\r
+\r
+ DriverInfoList = ContextData->DriverInfoList;\r
+ for (DriverLink = DriverInfoList->ForwardLink;\r
+ DriverLink != DriverInfoList;\r
+ DriverLink = DriverLink->ForwardLink) {\r
+ DriverInfoData = CR (\r
+ DriverLink,\r
+ MEMORY_PROFILE_DRIVER_INFO_DATA,\r
+ Link,\r
+ MEMORY_PROFILE_DRIVER_INFO_SIGNATURE\r
+ );\r
+ TotalSize += sizeof (MEMORY_PROFILE_ALLOC_INFO) * (UINTN) DriverInfoData->DriverInfo.AllocRecordCount;\r
+ }\r
+\r
+\r
+ Index = 0;\r
+ FreePageList = &mSmmMemoryMap;\r
+ for (Node = FreePageList->BackLink;\r
+ Node != FreePageList;\r
+ Node = Node->BackLink) {\r
+ Index++;\r
+ }\r
+ for (PoolListIndex = 0; PoolListIndex < MAX_POOL_INDEX; PoolListIndex++) {\r
+ FreePoolList = &mSmmPoolLists[PoolListIndex];\r
+ for (Node = FreePoolList->BackLink;\r
+ Node != FreePoolList;\r
+ Node = Node->BackLink) {\r
+ Pool = BASE_CR (Node, FREE_POOL_HEADER, Link);\r
+ if (Pool->Header.Available) {\r
+ Index++;\r
+ }\r
+ }\r
+ }\r
+\r
+\r
+ TotalSize += (sizeof (MEMORY_PROFILE_FREE_MEMORY) + Index * sizeof (MEMORY_PROFILE_DESCRIPTOR));\r
+ TotalSize += (sizeof (MEMORY_PROFILE_MEMORY_RANGE) + mFullSmramRangeCount * sizeof (MEMORY_PROFILE_DESCRIPTOR));\r
+\r
+ return TotalSize;\r
+}\r
+\r
+/**\r
+ Copy SMRAM profile data.\r
+\r
+ @param ProfileBuffer The buffer to hold SMRAM profile data.\r
+\r
+**/\r
+VOID\r
+SmramProfileCopyData (\r
+ IN VOID *ProfileBuffer\r
+ )\r
+{\r
+ MEMORY_PROFILE_CONTEXT *Context;\r
+ MEMORY_PROFILE_DRIVER_INFO *DriverInfo;\r
+ MEMORY_PROFILE_ALLOC_INFO *AllocInfo;\r
+ MEMORY_PROFILE_CONTEXT_DATA *ContextData;\r
+ MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;\r
+ MEMORY_PROFILE_ALLOC_INFO_DATA *AllocInfoData;\r
+ LIST_ENTRY *DriverInfoList;\r
+ LIST_ENTRY *DriverLink;\r
+ LIST_ENTRY *AllocInfoList;\r
+ LIST_ENTRY *AllocLink;\r
+ LIST_ENTRY *Node;\r
+ FREE_PAGE_LIST *Pages;\r
+ LIST_ENTRY *FreePageList;\r
+ LIST_ENTRY *FreePoolList;\r
+ FREE_POOL_HEADER *Pool;\r
+ UINTN PoolListIndex;\r
+ UINT32 Index;\r
+ MEMORY_PROFILE_FREE_MEMORY *FreeMemory;\r
+ MEMORY_PROFILE_MEMORY_RANGE *MemoryRange;\r
+ MEMORY_PROFILE_DESCRIPTOR *MemoryProfileDescriptor;\r
+\r
+ ContextData = GetSmramProfileContext ();\r
+ if (ContextData == NULL) {\r
+ return ;\r
+ }\r
+\r
+ Context = ProfileBuffer;\r
+ CopyMem (Context, &ContextData->Context, sizeof (MEMORY_PROFILE_CONTEXT));\r
+ DriverInfo = (MEMORY_PROFILE_DRIVER_INFO *) (Context + 1);\r
+\r
+ DriverInfoList = ContextData->DriverInfoList;\r
+ for (DriverLink = DriverInfoList->ForwardLink;\r
+ DriverLink != DriverInfoList;\r
+ DriverLink = DriverLink->ForwardLink) {\r
+ DriverInfoData = CR (\r
+ DriverLink,\r
+ MEMORY_PROFILE_DRIVER_INFO_DATA,\r
+ Link,\r
+ MEMORY_PROFILE_DRIVER_INFO_SIGNATURE\r
+ );\r
+ CopyMem (DriverInfo, &DriverInfoData->DriverInfo, sizeof (MEMORY_PROFILE_DRIVER_INFO));\r
+ AllocInfo = (MEMORY_PROFILE_ALLOC_INFO *) (DriverInfo + 1);\r
+\r
+ AllocInfoList = DriverInfoData->AllocInfoList;\r
+ for (AllocLink = AllocInfoList->ForwardLink;\r
+ AllocLink != AllocInfoList;\r
+ AllocLink = AllocLink->ForwardLink) {\r
+ AllocInfoData = CR (\r
+ AllocLink,\r
+ MEMORY_PROFILE_ALLOC_INFO_DATA,\r
+ Link,\r
+ MEMORY_PROFILE_ALLOC_INFO_SIGNATURE\r
+ );\r
+ CopyMem (AllocInfo, &AllocInfoData->AllocInfo, sizeof (MEMORY_PROFILE_ALLOC_INFO));\r
+ AllocInfo += 1;\r
+ }\r
+\r
+ DriverInfo = (MEMORY_PROFILE_DRIVER_INFO *) ((UINTN) (DriverInfo + 1) + sizeof (MEMORY_PROFILE_ALLOC_INFO) * (UINTN) DriverInfo->AllocRecordCount);\r
+ }\r
+\r
+\r
+ FreeMemory = (MEMORY_PROFILE_FREE_MEMORY *) DriverInfo;\r
+ CopyMem (FreeMemory, &mSmramFreeMemory, sizeof (MEMORY_PROFILE_FREE_MEMORY));\r
+ MemoryProfileDescriptor = (MEMORY_PROFILE_DESCRIPTOR *) (FreeMemory + 1);\r
+ Index = 0;\r
+ FreePageList = &mSmmMemoryMap;\r
+ for (Node = FreePageList->BackLink;\r
+ Node != FreePageList;\r
+ Node = Node->BackLink) {\r
+ Pages = BASE_CR (Node, FREE_PAGE_LIST, Link);\r
+ MemoryProfileDescriptor->Header.Signature = MEMORY_PROFILE_DESCRIPTOR_SIGNATURE;\r
+ MemoryProfileDescriptor->Header.Length = sizeof (MEMORY_PROFILE_DESCRIPTOR);\r
+ MemoryProfileDescriptor->Header.Revision = MEMORY_PROFILE_DESCRIPTOR_REVISION;\r
+ MemoryProfileDescriptor->Address = (PHYSICAL_ADDRESS) (UINTN) Pages;\r
+ MemoryProfileDescriptor->Size = EFI_PAGES_TO_SIZE (Pages->NumberOfPages);\r
+ MemoryProfileDescriptor++;\r
+ Index++;\r
+ }\r
+ for (PoolListIndex = 0; PoolListIndex < MAX_POOL_INDEX; PoolListIndex++) {\r
+ FreePoolList = &mSmmPoolLists[MAX_POOL_INDEX - PoolListIndex - 1];\r
+ for (Node = FreePoolList->BackLink;\r
+ Node != FreePoolList;\r
+ Node = Node->BackLink) {\r
+ Pool = BASE_CR (Node, FREE_POOL_HEADER, Link);\r
+ if (Pool->Header.Available) {\r
+ MemoryProfileDescriptor->Header.Signature = MEMORY_PROFILE_DESCRIPTOR_SIGNATURE;\r
+ MemoryProfileDescriptor->Header.Length = sizeof (MEMORY_PROFILE_DESCRIPTOR);\r
+ MemoryProfileDescriptor->Header.Revision = MEMORY_PROFILE_DESCRIPTOR_REVISION;\r
+ MemoryProfileDescriptor->Address = (PHYSICAL_ADDRESS) (UINTN) Pool;\r
+ MemoryProfileDescriptor->Size = Pool->Header.Size;\r
+ MemoryProfileDescriptor++;\r
+ Index++;\r
+ }\r
+ }\r
+ }\r
+ FreeMemory->FreeMemoryEntryCount = Index;\r
+\r
+ MemoryRange = (MEMORY_PROFILE_MEMORY_RANGE *) MemoryProfileDescriptor;\r
+ MemoryRange->Header.Signature = MEMORY_PROFILE_MEMORY_RANGE_SIGNATURE;\r
+ MemoryRange->Header.Length = sizeof (MEMORY_PROFILE_MEMORY_RANGE);\r
+ MemoryRange->Header.Revision = MEMORY_PROFILE_MEMORY_RANGE_REVISION;\r
+ MemoryRange->MemoryRangeCount = (UINT32) mFullSmramRangeCount;\r
+ MemoryProfileDescriptor = (MEMORY_PROFILE_DESCRIPTOR *) (MemoryRange + 1);\r
+ for (Index = 0; Index < mFullSmramRangeCount; Index++) {\r
+ MemoryProfileDescriptor->Header.Signature = MEMORY_PROFILE_DESCRIPTOR_SIGNATURE;\r
+ MemoryProfileDescriptor->Header.Length = sizeof (MEMORY_PROFILE_DESCRIPTOR);\r
+ MemoryProfileDescriptor->Header.Revision = MEMORY_PROFILE_DESCRIPTOR_REVISION;\r
+ MemoryProfileDescriptor->Address = mFullSmramRanges[Index].PhysicalStart;\r
+ MemoryProfileDescriptor->Size = mFullSmramRanges[Index].PhysicalSize;\r
+ MemoryProfileDescriptor++; \r
+ }\r
+}\r
+\r
+/**\r
+ SMRAM profile handler to get profile info.\r
+\r
+ @param SmramProfileParameterGetInfo The parameter of SMM profile get size.\r
+\r
+**/\r
+VOID\r
+SmramProfileHandlerGetInfo (\r
+ IN SMRAM_PROFILE_PARAMETER_GET_PROFILE_INFO *SmramProfileParameterGetInfo\r
+ )\r
+{\r
+ MEMORY_PROFILE_CONTEXT_DATA *ContextData;\r
+ BOOLEAN SmramProfileRecordingStatus;\r
+\r
+ ContextData = GetSmramProfileContext ();\r
+ if (ContextData == NULL) {\r
+ return ;\r
+ }\r
+\r
+ SmramProfileRecordingStatus = mSmramProfileRecordingStatus;\r
+ mSmramProfileRecordingStatus = FALSE;\r
+\r
+ SmramProfileParameterGetInfo->ProfileSize = SmramProfileGetDataSize();\r
+ SmramProfileParameterGetInfo->Header.ReturnStatus = 0;\r
+\r
+ mSmramProfileRecordingStatus = SmramProfileRecordingStatus;\r
+}\r
+\r
+/**\r
+ SMRAM profile handler to get profile data.\r
+\r
+ @param SmramProfileParameterGetData The parameter of SMM profile get data.\r
+\r
+**/\r
+VOID\r
+SmramProfileHandlerGetData (\r
+ IN SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA *SmramProfileParameterGetData\r
+ )\r
+{\r
+ UINT64 ProfileSize;\r
+ SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA SmramProfileGetData;\r
+ MEMORY_PROFILE_CONTEXT_DATA *ContextData;\r
+ BOOLEAN SmramProfileRecordingStatus;\r
+\r
+ ContextData = GetSmramProfileContext ();\r
+ if (ContextData == NULL) {\r
+ return ;\r
+ }\r
+\r
+ SmramProfileRecordingStatus = mSmramProfileRecordingStatus;\r
+ mSmramProfileRecordingStatus = FALSE;\r
+\r
+\r
+ CopyMem (&SmramProfileGetData, SmramProfileParameterGetData, sizeof (SmramProfileGetData));\r
+\r
+ ProfileSize = SmramProfileGetDataSize();\r
+\r
+ //\r
+ // Sanity check\r
+ //\r
+ if (!InternalIsAddressValid ((UINTN) SmramProfileGetData.ProfileBuffer, (UINTN) ProfileSize)) {\r
+ DEBUG ((EFI_D_ERROR, "SmramProfileHandlerGetData: SMM ProfileBuffer in SMRAM or overflow!\n"));\r
+ SmramProfileParameterGetData->ProfileSize = ProfileSize;\r
+ SmramProfileParameterGetData->Header.ReturnStatus = (UINT64) (INT64) (INTN) EFI_ACCESS_DENIED;\r
+ goto Done;\r
+ }\r
+\r
+ if (SmramProfileGetData.ProfileSize < ProfileSize) {\r
+ SmramProfileParameterGetData->ProfileSize = ProfileSize;\r
+ SmramProfileParameterGetData->Header.ReturnStatus = (UINT64) (INT64) (INTN) EFI_BUFFER_TOO_SMALL;\r
+ goto Done;\r
+ }\r
+\r
+ SmramProfileParameterGetData->ProfileSize = ProfileSize;\r
+ SmramProfileCopyData ((VOID *) (UINTN) SmramProfileGetData.ProfileBuffer);\r
+ SmramProfileParameterGetData->Header.ReturnStatus = 0;\r
+\r
+Done:\r
+ mSmramProfileRecordingStatus = SmramProfileRecordingStatus;\r
+}\r
+\r
+/**\r
+ SMRAM profile handler to register SMM image.\r
+\r
+ @param SmramProfileParameterRegisterImage The parameter of SMM profile register image.\r
+\r
+**/\r
+VOID\r
+SmramProfileHandlerRegisterImage (\r
+ IN SMRAM_PROFILE_PARAMETER_REGISTER_IMAGE *SmramProfileParameterRegisterImage\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SMM_DRIVER_ENTRY DriverEntry;\r
+ VOID *EntryPointInImage;\r
+ BOOLEAN Ret;\r
+\r
+ ZeroMem (&DriverEntry, sizeof (DriverEntry));\r
+ CopyMem (&DriverEntry.FileName, &SmramProfileParameterRegisterImage->FileName, sizeof(EFI_GUID));\r
+ DriverEntry.ImageBuffer = SmramProfileParameterRegisterImage->ImageBuffer;\r
+ DriverEntry.NumberOfPage = (UINTN) SmramProfileParameterRegisterImage->NumberOfPage;\r
+ Status = InternalPeCoffGetEntryPoint ((VOID *) (UINTN) DriverEntry.ImageBuffer, &EntryPointInImage);\r
+ ASSERT_EFI_ERROR (Status);\r
+ DriverEntry.ImageEntryPoint = (PHYSICAL_ADDRESS) (UINTN) EntryPointInImage;\r
+\r
+ Ret = RegisterSmramProfileImage (&DriverEntry, FALSE);\r
+ if (Ret) {\r
+ SmramProfileParameterRegisterImage->Header.ReturnStatus = 0;\r
+ }\r
+}\r
+\r
+/**\r
+ SMRAM profile handler to unregister SMM image.\r
+\r
+ @param SmramProfileParameterUnregisterImage The parameter of SMM profile unregister image.\r
+\r
+**/\r
+VOID\r
+SmramProfileHandlerUnregisterImage (\r
+ IN SMRAM_PROFILE_PARAMETER_UNREGISTER_IMAGE *SmramProfileParameterUnregisterImage\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SMM_DRIVER_ENTRY DriverEntry;\r
+ VOID *EntryPointInImage;\r
+ BOOLEAN Ret;\r
+\r
+ ZeroMem (&DriverEntry, sizeof (DriverEntry));\r
+ CopyMem (&DriverEntry.FileName, &SmramProfileParameterUnregisterImage->FileName, sizeof (EFI_GUID));\r
+ DriverEntry.ImageBuffer = SmramProfileParameterUnregisterImage->ImageBuffer;\r
+ DriverEntry.NumberOfPage = (UINTN) SmramProfileParameterUnregisterImage->NumberOfPage;\r
+ Status = InternalPeCoffGetEntryPoint ((VOID *) (UINTN) DriverEntry.ImageBuffer, &EntryPointInImage);\r
+ ASSERT_EFI_ERROR (Status);\r
+ DriverEntry.ImageEntryPoint = (PHYSICAL_ADDRESS) (UINTN) EntryPointInImage;\r
+\r
+ Ret = UnregisterSmramProfileImage (&DriverEntry, FALSE);\r
+ if (Ret) {\r
+ SmramProfileParameterUnregisterImage->Header.ReturnStatus = 0;\r
+ }\r
+}\r
+\r
+/**\r
+ Dispatch function for a Software SMI handler.\r
+\r
+ Caution: This function may receive untrusted input.\r
+ Communicate buffer and buffer size are external input, so this function will do basic validation.\r
+\r
+ @param DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().\r
+ @param Context Points to an optional handler context which was specified when the\r
+ handler was registered.\r
+ @param CommBuffer A pointer to a collection of data in memory that will\r
+ be conveyed from a non-SMM environment into an SMM environment.\r
+ @param CommBufferSize The size of the CommBuffer.\r
+\r
+ @retval EFI_SUCCESS Command is handled successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmramProfileHandler (\r
+ IN EFI_HANDLE DispatchHandle,\r
+ IN CONST VOID *Context OPTIONAL,\r
+ IN OUT VOID *CommBuffer OPTIONAL,\r
+ IN OUT UINTN *CommBufferSize OPTIONAL\r
+ )\r
+{\r
+ SMRAM_PROFILE_PARAMETER_HEADER *SmramProfileParameterHeader;\r
+ UINTN TempCommBufferSize;\r
+\r
+ DEBUG ((EFI_D_ERROR, "SmramProfileHandler Enter\n"));\r
+\r
+ //\r
+ // If input is invalid, stop processing this SMI\r
+ //\r
+ if (CommBuffer == NULL || CommBufferSize == NULL) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ TempCommBufferSize = *CommBufferSize;\r
+\r
+ if (TempCommBufferSize < sizeof (SMRAM_PROFILE_PARAMETER_HEADER)) {\r
+ DEBUG ((EFI_D_ERROR, "SmramProfileHandler: SMM communication buffer size invalid!\n"));\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ if (mSmramReadyToLock && !InternalIsAddressValid ((UINTN)CommBuffer, TempCommBufferSize)) {\r
+ DEBUG ((EFI_D_ERROR, "SmramProfileHandler: SMM communication buffer in SMRAM or overflow!\n"));\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ SmramProfileParameterHeader = (SMRAM_PROFILE_PARAMETER_HEADER *) ((UINTN) CommBuffer);\r
+\r
+ SmramProfileParameterHeader->ReturnStatus = (UINT64)-1;\r
+\r
+ if (GetSmramProfileContext () == NULL) {\r
+ SmramProfileParameterHeader->ReturnStatus = (UINT64) (INT64) (INTN) EFI_UNSUPPORTED;\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ switch (SmramProfileParameterHeader->Command) {\r
+ case SMRAM_PROFILE_COMMAND_GET_PROFILE_INFO:\r
+ DEBUG ((EFI_D_ERROR, "SmramProfileHandlerGetInfo\n"));\r
+ if (TempCommBufferSize != sizeof (SMRAM_PROFILE_PARAMETER_GET_PROFILE_INFO)) {\r
+ DEBUG ((EFI_D_ERROR, "SmramProfileHandler: SMM communication buffer size invalid!\n"));\r
+ return EFI_SUCCESS;\r
+ }\r
+ SmramProfileHandlerGetInfo ((SMRAM_PROFILE_PARAMETER_GET_PROFILE_INFO *) (UINTN) CommBuffer);\r
+ break;\r
+ case SMRAM_PROFILE_COMMAND_GET_PROFILE_DATA:\r
+ DEBUG ((EFI_D_ERROR, "SmramProfileHandlerGetData\n"));\r
+ if (TempCommBufferSize != sizeof (SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA)) {\r
+ DEBUG ((EFI_D_ERROR, "SmramProfileHandler: SMM communication buffer size invalid!\n"));\r
+ return EFI_SUCCESS;\r
+ }\r
+ SmramProfileHandlerGetData ((SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA *) (UINTN) CommBuffer);\r
+ break;\r
+ case SMRAM_PROFILE_COMMAND_REGISTER_IMAGE:\r
+ DEBUG ((EFI_D_ERROR, "SmramProfileHandlerRegisterImage\n"));\r
+ if (TempCommBufferSize != sizeof (SMRAM_PROFILE_PARAMETER_REGISTER_IMAGE)) {\r
+ DEBUG ((EFI_D_ERROR, "SmramProfileHandler: SMM communication buffer size invalid!\n"));\r
+ return EFI_SUCCESS;\r
+ }\r
+ if (mSmramReadyToLock) {\r
+ return EFI_SUCCESS;\r
+ }\r
+ SmramProfileHandlerRegisterImage ((SMRAM_PROFILE_PARAMETER_REGISTER_IMAGE *) (UINTN) CommBuffer);\r
+ break;\r
+ case SMRAM_PROFILE_COMMAND_UNREGISTER_IMAGE:\r
+ DEBUG ((EFI_D_ERROR, "SmramProfileHandlerUnregisterImage\n"));\r
+ if (TempCommBufferSize != sizeof (SMRAM_PROFILE_PARAMETER_UNREGISTER_IMAGE)) {\r
+ DEBUG ((EFI_D_ERROR, "SmramProfileHandler: SMM communication buffer size invalid!\n"));\r
+ return EFI_SUCCESS;\r
+ }\r
+ if (mSmramReadyToLock) {\r
+ return EFI_SUCCESS;\r
+ }\r
+ SmramProfileHandlerUnregisterImage ((SMRAM_PROFILE_PARAMETER_UNREGISTER_IMAGE *) (UINTN) CommBuffer);\r
+ break;\r
+ default:\r
+ break;\r
+ }\r
+\r
+ DEBUG ((EFI_D_ERROR, "SmramProfileHandler Exit\n"));\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Register SMRAM profile handler.\r
+\r
+**/\r
+VOID\r
+RegisterSmramProfileHandler (\r
+ VOID\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_HANDLE DispatchHandle;\r
+\r
+ if (!IS_SMRAM_PROFILE_ENABLED) {\r
+ return;\r
+ }\r
+\r
+ Status = SmiHandlerRegister (\r
+ SmramProfileHandler,\r
+ &gEdkiiMemoryProfileGuid,\r
+ &DispatchHandle\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+}\r
+\r
+////////////////////\r
+\r
+/**\r
+ Dump SMRAM range.\r
+\r
+**/\r
+VOID\r
+DumpSmramRange (\r
+ VOID\r
+ )\r
+{\r
+ UINTN Index;\r
+ MEMORY_PROFILE_CONTEXT_DATA *ContextData;\r
+ BOOLEAN SmramProfileRecordingStatus;\r
+\r
+ ContextData = GetSmramProfileContext ();\r
+ if (ContextData == NULL) {\r
+ return ;\r
+ }\r
+\r
+ SmramProfileRecordingStatus = mSmramProfileRecordingStatus;\r
+ mSmramProfileRecordingStatus = FALSE;\r
+\r
+ DEBUG ((EFI_D_INFO, "FullSmramRange address - 0x%08x\n", mFullSmramRanges));\r
+\r
+ DEBUG ((EFI_D_INFO, "======= SmramProfile begin =======\n"));\r
+\r
+ DEBUG ((EFI_D_INFO, "FullSmramRange:\n"));\r
+ for (Index = 0; Index < mFullSmramRangeCount; Index++) {\r
+ DEBUG ((EFI_D_INFO, " FullSmramRange (0x%x)\n", Index));\r
+ DEBUG ((EFI_D_INFO, " PhysicalStart - 0x%016lx\n", mFullSmramRanges[Index].PhysicalStart));\r
+ DEBUG ((EFI_D_INFO, " CpuStart - 0x%016lx\n", mFullSmramRanges[Index].CpuStart));\r
+ DEBUG ((EFI_D_INFO, " PhysicalSize - 0x%016lx\n", mFullSmramRanges[Index].PhysicalSize));\r
+ DEBUG ((EFI_D_INFO, " RegionState - 0x%016lx\n", mFullSmramRanges[Index].RegionState));\r
+ }\r
+\r
+ DEBUG ((EFI_D_INFO, "======= SmramProfile end =======\n"));\r
+\r
+ mSmramProfileRecordingStatus = SmramProfileRecordingStatus;\r
+}\r
+\r
+/**\r
+ Dump SMRAM free page list.\r
+\r
+**/\r
+VOID\r
+DumpFreePagesList (\r
+ VOID\r
+ )\r
+{\r
+ LIST_ENTRY *FreePageList;\r
+ LIST_ENTRY *Node;\r
+ FREE_PAGE_LIST *Pages;\r
+ UINTN Index;\r
+ MEMORY_PROFILE_CONTEXT_DATA *ContextData;\r
+ BOOLEAN SmramProfileRecordingStatus;\r
+\r
+ ContextData = GetSmramProfileContext ();\r
+ if (ContextData == NULL) {\r
+ return ;\r
+ }\r
+\r
+ SmramProfileRecordingStatus = mSmramProfileRecordingStatus;\r
+ mSmramProfileRecordingStatus = FALSE;\r
+\r
+ DEBUG ((EFI_D_INFO, "======= SmramProfile begin =======\n"));\r
+\r
+ DEBUG ((EFI_D_INFO, "FreePagesList:\n"));\r
+ FreePageList = &mSmmMemoryMap;\r
+ for (Node = FreePageList->BackLink, Index = 0;\r
+ Node != FreePageList;\r
+ Node = Node->BackLink, Index++) {\r
+ Pages = BASE_CR (Node, FREE_PAGE_LIST, Link);\r
+ DEBUG ((EFI_D_INFO, " Index - 0x%x\n", Index));\r
+ DEBUG ((EFI_D_INFO, " PhysicalStart - 0x%016lx\n", (PHYSICAL_ADDRESS) (UINTN) Pages));\r
+ DEBUG ((EFI_D_INFO, " NumberOfPages - 0x%08x\n", Pages->NumberOfPages));\r
+ }\r
+\r
+ DEBUG ((EFI_D_INFO, "======= SmramProfile end =======\n"));\r
+\r
+ mSmramProfileRecordingStatus = SmramProfileRecordingStatus;\r
+}\r
+\r
+/**\r
+ Dump SMRAM free pool list.\r
+\r
+**/\r
+VOID\r
+DumpFreePoolList (\r
+ VOID\r
+ )\r
+{\r
+ LIST_ENTRY *FreePoolList;\r
+ LIST_ENTRY *Node;\r
+ FREE_POOL_HEADER *Pool;\r
+ UINTN Index;\r
+ UINTN PoolListIndex;\r
+ MEMORY_PROFILE_CONTEXT_DATA *ContextData;\r
+ BOOLEAN SmramProfileRecordingStatus;\r
+\r
+ ContextData = GetSmramProfileContext ();\r
+ if (ContextData == NULL) {\r
+ return ;\r
+ }\r
+\r
+ SmramProfileRecordingStatus = mSmramProfileRecordingStatus;\r
+ mSmramProfileRecordingStatus = FALSE;\r
+\r
+ DEBUG ((EFI_D_INFO, "======= SmramProfile begin =======\n"));\r
+\r
+ for (PoolListIndex = 0; PoolListIndex < MAX_POOL_INDEX; PoolListIndex++) {\r
+ DEBUG ((EFI_D_INFO, "FreePoolList (%d):\n", PoolListIndex));\r
+ FreePoolList = &mSmmPoolLists[PoolListIndex];\r
+ for (Node = FreePoolList->BackLink, Index = 0;\r
+ Node != FreePoolList;\r
+ Node = Node->BackLink, Index++) {\r
+ Pool = BASE_CR (Node, FREE_POOL_HEADER, Link);\r
+ DEBUG ((EFI_D_INFO, " Index - 0x%x\n", Index));\r
+ DEBUG ((EFI_D_INFO, " PhysicalStart - 0x%016lx\n", (PHYSICAL_ADDRESS) (UINTN) Pool));\r
+ DEBUG ((EFI_D_INFO, " Size - 0x%08x\n", Pool->Header.Size));\r
+ DEBUG ((EFI_D_INFO, " Available - 0x%02x\n", Pool->Header.Available));\r
+ }\r
+ }\r
+\r
+ DEBUG ((EFI_D_INFO, "======= SmramProfile end =======\n"));\r
+\r
+ mSmramProfileRecordingStatus = SmramProfileRecordingStatus;\r
+}\r
+\r
+GLOBAL_REMOVE_IF_UNREFERENCED CHAR16 *mActionString[] = {\r
+ L"Unknown",\r
+ L"AllocatePages",\r
+ L"FreePages",\r
+ L"AllocatePool",\r
+ L"FreePool",\r
+};\r
+\r
+GLOBAL_REMOVE_IF_UNREFERENCED CHAR16 *mMemoryTypeString[] = {\r
+ L"EfiReservedMemoryType",\r
+ L"EfiLoaderCode",\r
+ L"EfiLoaderData",\r
+ L"EfiBootServicesCode",\r
+ L"EfiBootServicesData",\r
+ L"EfiRuntimeServicesCode",\r
+ L"EfiRuntimeServicesData",\r
+ L"EfiConventionalMemory",\r
+ L"EfiUnusableMemory",\r
+ L"EfiACPIReclaimMemory",\r
+ L"EfiACPIMemoryNVS",\r
+ L"EfiMemoryMappedIO",\r
+ L"EfiMemoryMappedIOPortSpace",\r
+ L"EfiPalCode",\r
+ L"EfiOSReserved",\r
+};\r
+\r
+\r
+/**\r
+ Dump SMRAM profile.\r
+\r
+**/\r
+VOID\r
+DumpSmramProfile (\r
+ VOID\r
+ )\r
+{\r
+ MEMORY_PROFILE_CONTEXT *Context;\r
+ MEMORY_PROFILE_DRIVER_INFO *DriverInfo;\r
+ MEMORY_PROFILE_ALLOC_INFO *AllocInfo;\r
+ MEMORY_PROFILE_CONTEXT_DATA *ContextData;\r
+ MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;\r
+ MEMORY_PROFILE_ALLOC_INFO_DATA *AllocInfoData;\r
+ LIST_ENTRY *SmramDriverInfoList;\r
+ UINTN DriverIndex;\r
+ LIST_ENTRY *DriverLink;\r
+ LIST_ENTRY *AllocInfoList;\r
+ UINTN AllocIndex;\r
+ LIST_ENTRY *AllocLink;\r
+ BOOLEAN SmramProfileRecordingStatus;\r
+ UINTN TypeIndex;\r
+\r
+ ContextData = GetSmramProfileContext ();\r
+ if (ContextData == NULL) {\r
+ return ;\r
+ }\r
+\r
+ SmramProfileRecordingStatus = mSmramProfileRecordingStatus;\r
+ mSmramProfileRecordingStatus = FALSE;\r
+\r
+ Context = &ContextData->Context;\r
+ DEBUG ((EFI_D_INFO, "======= SmramProfile begin =======\n"));\r
+ DEBUG ((EFI_D_INFO, "MEMORY_PROFILE_CONTEXT\n"));\r
+\r
+ DEBUG ((EFI_D_INFO, " CurrentTotalUsage - 0x%016lx\n", Context->CurrentTotalUsage));\r
+ DEBUG ((EFI_D_INFO, " PeakTotalUsage - 0x%016lx\n", Context->PeakTotalUsage));\r
+ for (TypeIndex = 0; TypeIndex <= EfiMaxMemoryType; TypeIndex++) {\r
+ if ((Context->CurrentTotalUsageByType[TypeIndex] != 0) ||\r
+ (Context->PeakTotalUsageByType[TypeIndex] != 0)) {\r
+ DEBUG ((EFI_D_INFO, " CurrentTotalUsage[0x%02x] - 0x%016lx (%s)\n", TypeIndex, Context->CurrentTotalUsageByType[TypeIndex], mMemoryTypeString[TypeIndex]));\r
+ DEBUG ((EFI_D_INFO, " PeakTotalUsage[0x%02x] - 0x%016lx (%s)\n", TypeIndex, Context->PeakTotalUsageByType[TypeIndex], mMemoryTypeString[TypeIndex]));\r
+ }\r
+ }\r
+ DEBUG ((EFI_D_INFO, " TotalImageSize - 0x%016lx\n", Context->TotalImageSize));\r
+ DEBUG ((EFI_D_INFO, " ImageCount - 0x%08x\n", Context->ImageCount));\r
+ DEBUG ((EFI_D_INFO, " SequenceCount - 0x%08x\n", Context->SequenceCount));\r
+\r
+ SmramDriverInfoList = ContextData->DriverInfoList;\r
+ for (DriverLink = SmramDriverInfoList->ForwardLink, DriverIndex = 0;\r
+ DriverLink != SmramDriverInfoList;\r
+ DriverLink = DriverLink->ForwardLink, DriverIndex++) {\r
+ DriverInfoData = CR (\r
+ DriverLink,\r
+ MEMORY_PROFILE_DRIVER_INFO_DATA,\r
+ Link,\r
+ MEMORY_PROFILE_DRIVER_INFO_SIGNATURE\r
+ );\r
+ DriverInfo = &DriverInfoData->DriverInfo;\r
+ DEBUG ((EFI_D_INFO, " MEMORY_PROFILE_DRIVER_INFO (0x%x)\n", DriverIndex));\r
+ DEBUG ((EFI_D_INFO, " FileName - %g\n", &DriverInfo->FileName));\r
+ DEBUG ((EFI_D_INFO, " ImageBase - 0x%016lx\n", DriverInfo->ImageBase));\r
+ DEBUG ((EFI_D_INFO, " ImageSize - 0x%016lx\n", DriverInfo->ImageSize));\r
+ DEBUG ((EFI_D_INFO, " EntryPoint - 0x%016lx\n", DriverInfo->EntryPoint));\r
+ DEBUG ((EFI_D_INFO, " ImageSubsystem - 0x%04x\n", DriverInfo->ImageSubsystem));\r
+ DEBUG ((EFI_D_INFO, " FileType - 0x%02x\n", DriverInfo->FileType));\r
+ DEBUG ((EFI_D_INFO, " CurrentUsage - 0x%016lx\n", DriverInfo->CurrentUsage));\r
+ DEBUG ((EFI_D_INFO, " PeakUsage - 0x%016lx\n", DriverInfo->PeakUsage));\r
+ for (TypeIndex = 0; TypeIndex <= EfiMaxMemoryType; TypeIndex++) {\r
+ if ((DriverInfo->CurrentUsageByType[TypeIndex] != 0) ||\r
+ (DriverInfo->PeakUsageByType[TypeIndex] != 0)) {\r
+ DEBUG ((EFI_D_INFO, " CurrentUsage[0x%02x] - 0x%016lx (%s)\n", TypeIndex, DriverInfo->CurrentUsageByType[TypeIndex], mMemoryTypeString[TypeIndex]));\r
+ DEBUG ((EFI_D_INFO, " PeakUsage[0x%02x] - 0x%016lx (%s)\n", TypeIndex, DriverInfo->PeakUsageByType[TypeIndex], mMemoryTypeString[TypeIndex]));\r
+ }\r
+ }\r
+ DEBUG ((EFI_D_INFO, " AllocRecordCount - 0x%08x\n", DriverInfo->AllocRecordCount));\r
+\r
+ AllocInfoList = DriverInfoData->AllocInfoList;\r
+ for (AllocLink = AllocInfoList->ForwardLink, AllocIndex = 0;\r
+ AllocLink != AllocInfoList;\r
+ AllocLink = AllocLink->ForwardLink, AllocIndex++) {\r
+ AllocInfoData = CR (\r
+ AllocLink,\r
+ MEMORY_PROFILE_ALLOC_INFO_DATA,\r
+ Link,\r
+ MEMORY_PROFILE_ALLOC_INFO_SIGNATURE\r
+ );\r
+ AllocInfo = &AllocInfoData->AllocInfo;\r
+ DEBUG ((EFI_D_INFO, " MEMORY_PROFILE_ALLOC_INFO (0x%x)\n", AllocIndex));\r
+ DEBUG ((EFI_D_INFO, " CallerAddress - 0x%016lx (Offset: 0x%08x)\n", AllocInfo->CallerAddress, AllocInfo->CallerAddress - DriverInfo->ImageBase));\r
+ DEBUG ((EFI_D_INFO, " SequenceId - 0x%08x\n", AllocInfo->SequenceId));\r
+ DEBUG ((EFI_D_INFO, " Action - 0x%08x (%s)\n", AllocInfo->Action, mActionString[(AllocInfo->Action < sizeof(mActionString)/sizeof(mActionString[0])) ? AllocInfo->Action : 0]));\r
+ DEBUG ((EFI_D_INFO, " MemoryType - 0x%08x\n", AllocInfo->MemoryType));\r
+ DEBUG ((EFI_D_INFO, " Buffer - 0x%016lx\n", AllocInfo->Buffer));\r
+ DEBUG ((EFI_D_INFO, " Size - 0x%016lx\n", AllocInfo->Size));\r
+ }\r
+ }\r
+\r
+ DEBUG ((EFI_D_INFO, "======= SmramProfile end =======\n"));\r
+\r
+ mSmramProfileRecordingStatus = SmramProfileRecordingStatus;\r
+}\r
+\r
+/**\r
+ Dump SMRAM infromation.\r
+\r
+**/\r
+VOID\r
+DumpSmramInfo (\r
+ VOID\r
+ )\r
+{\r
+ DEBUG_CODE (\r
+ if (IS_SMRAM_PROFILE_ENABLED) {\r
+ DumpSmramProfile ();\r
+ DumpFreePagesList ();\r
+ DumpFreePoolList ();\r
+ DumpSmramRange ();\r
+ }\r
+ );\r
+}\r
+\r