]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Application/MemoryProfileInfo/MemoryProfileInfo.c
MdeModulePkg DxeCore/PiSmmCore: Add UEFI memory and SMRAM profile support.
[mirror_edk2.git] / MdeModulePkg / Application / MemoryProfileInfo / MemoryProfileInfo.c
diff --git a/MdeModulePkg/Application/MemoryProfileInfo/MemoryProfileInfo.c b/MdeModulePkg/Application/MemoryProfileInfo/MemoryProfileInfo.c
new file mode 100644 (file)
index 0000000..4896ebd
--- /dev/null
@@ -0,0 +1,712 @@
+/** @file\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 <Uefi.h>\r
+#include <PiDxe.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/UefiApplicationEntryPoint.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/UefiRuntimeServicesTableLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/DxeServicesLib.h>\r
+#include <Library/PeCoffGetEntryPointLib.h>\r
+#include <Library/PrintLib.h>\r
+\r
+#include <Protocol/SmmCommunication.h>\r
+#include <Protocol/SmmAccess2.h>\r
+\r
+#include <Guid/ZeroGuid.h>\r
+#include <Guid/MemoryProfile.h>\r
+\r
+CHAR16 *mActionString[] = {\r
+  L"Unknown",\r
+  L"AllocatePages",\r
+  L"FreePages",\r
+  L"AllocatePool",\r
+  L"FreePool",\r
+};\r
+\r
+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
+CHAR16 *mSubsystemString[] = {\r
+  L"Unknown",\r
+  L"NATIVE",\r
+  L"WINDOWS_GUI",\r
+  L"WINDOWS_CUI",\r
+  L"Unknown",\r
+  L"Unknown",\r
+  L"Unknown",\r
+  L"POSIX_CUI",\r
+  L"Unknown",\r
+  L"WINDOWS_CE_GUI",\r
+  L"EFI_APPLICATION",\r
+  L"EFI_BOOT_SERVICE_DRIVER",\r
+  L"EFI_RUNTIME_DRIVER",\r
+  L"EFI_ROM",\r
+  L"XBOX",\r
+  L"Unknown",\r
+};\r
+\r
+CHAR16 *mFileTypeString[] = {\r
+  L"Unknown",\r
+  L"RAW",\r
+  L"FREEFORM",\r
+  L"SECURITY_CORE",\r
+  L"PEI_CORE",\r
+  L"DXE_CORE",\r
+  L"PEIM",\r
+  L"DRIVER",\r
+  L"COMBINED_PEIM_DRIVER",\r
+  L"APPLICATION",\r
+  L"SMM",\r
+  L"FIRMWARE_VOLUME_IMAGE",\r
+  L"COMBINED_SMM_DXE",\r
+  L"SMM_CORE",\r
+};\r
+\r
+#define PROFILE_NAME_STRING_LENGTH  36\r
+CHAR16 mNameString[PROFILE_NAME_STRING_LENGTH + 1];\r
+\r
+/** \r
+  Get the file name portion of the Pdb File Name.\r
+  \r
+  The portion of the Pdb File Name between the last backslash and\r
+  either a following period or the end of the string is converted\r
+  to Unicode and copied into UnicodeBuffer.  The name is truncated,\r
+  if necessary, to ensure that UnicodeBuffer is not overrun.\r
+  \r
+  @param[in]  PdbFileName     Pdb file name.\r
+  @param[out] UnicodeBuffer   The resultant Unicode File Name.\r
+  \r
+**/\r
+VOID\r
+GetShortPdbFileName (\r
+  IN  CHAR8     *PdbFileName,\r
+  OUT CHAR16    *UnicodeBuffer\r
+  )\r
+{\r
+  UINTN IndexA;     // Current work location within an ASCII string.\r
+  UINTN IndexU;     // Current work location within a Unicode string.\r
+  UINTN StartIndex;\r
+  UINTN EndIndex;\r
+\r
+  ZeroMem (UnicodeBuffer, PROFILE_NAME_STRING_LENGTH * sizeof (CHAR16));\r
+\r
+  if (PdbFileName == NULL) {\r
+    StrnCpy (UnicodeBuffer, L" ", 1);\r
+  } else {\r
+    StartIndex = 0;\r
+    for (EndIndex = 0; PdbFileName[EndIndex] != 0; EndIndex++);\r
+    for (IndexA = 0; PdbFileName[IndexA] != 0; IndexA++) {\r
+      if (PdbFileName[IndexA] == '\\') {\r
+        StartIndex = IndexA + 1;\r
+      }\r
+\r
+      if (PdbFileName[IndexA] == '.') {\r
+        EndIndex = IndexA;\r
+      }\r
+    }\r
+\r
+    IndexU = 0;\r
+    for (IndexA = StartIndex; IndexA < EndIndex; IndexA++) {\r
+      UnicodeBuffer[IndexU] = (CHAR16) PdbFileName[IndexA];\r
+      IndexU++;\r
+      if (IndexU >= PROFILE_NAME_STRING_LENGTH) {\r
+        UnicodeBuffer[PROFILE_NAME_STRING_LENGTH] = 0;\r
+        break;\r
+      }\r
+    }\r
+  }\r
+}\r
+\r
+/** \r
+  Get a human readable name for an image.\r
+  The following methods will be tried orderly:\r
+    1. Image PDB\r
+    2. FFS UI section\r
+    3. Image GUID\r
+\r
+  @param[in] DriverInfo Pointer to memory profile driver info.\r
+\r
+  @post The resulting Unicode name string is stored in the mNameString global array.\r
+\r
+**/\r
+VOID\r
+GetDriverNameString (\r
+ IN MEMORY_PROFILE_DRIVER_INFO  *DriverInfo\r
+ )\r
+{\r
+  EFI_STATUS                  Status;\r
+  CHAR8                       *PdbFileName;\r
+  CHAR16                      *NameString;\r
+  UINTN                       StringSize;\r
+\r
+  //\r
+  // Method 1: Get the name string from image PDB\r
+  //\r
+  if ((DriverInfo->ImageBase != 0) && (DriverInfo->FileType != EFI_FV_FILETYPE_SMM) && (DriverInfo->FileType != EFI_FV_FILETYPE_SMM_CORE)) {\r
+    PdbFileName = PeCoffLoaderGetPdbPointer ((VOID *) (UINTN) DriverInfo->ImageBase);\r
+\r
+    if (PdbFileName != NULL) {\r
+      GetShortPdbFileName (PdbFileName, mNameString);\r
+      return;\r
+    }\r
+  }\r
+\r
+  if (!CompareGuid (&DriverInfo->FileName, &gZeroGuid)) {\r
+    //\r
+    // Try to get the image's FFS UI section by image GUID\r
+    //\r
+    NameString = NULL;\r
+    StringSize = 0;\r
+    Status = GetSectionFromAnyFv (\r
+              &DriverInfo->FileName,\r
+              EFI_SECTION_USER_INTERFACE,\r
+              0,\r
+              (VOID **) &NameString,\r
+              &StringSize\r
+              );\r
+    if (!EFI_ERROR (Status)) {\r
+      //\r
+      // Method 2: Get the name string from FFS UI section\r
+      //\r
+      StrnCpy (mNameString, NameString, PROFILE_NAME_STRING_LENGTH);\r
+      mNameString[PROFILE_NAME_STRING_LENGTH] = 0;\r
+      FreePool (NameString);\r
+      return;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Method 3: Get the name string from image GUID\r
+  //\r
+  UnicodeSPrint (mNameString, sizeof (mNameString), L"%g", &DriverInfo->FileName);\r
+}\r
+\r
+/**\r
+  Dump memory profile allocate information.\r
+\r
+  @param[in] DriverInfo         Pointer to memory profile driver info.\r
+  @param[in] AllocIndex         Memory profile alloc info index.\r
+  @param[in] AllocInfo          Pointer to memory profile alloc info.\r
+\r
+  @return Pointer to next memory profile alloc info.\r
+\r
+**/\r
+MEMORY_PROFILE_ALLOC_INFO *\r
+DumpMemoryProfileAllocInfo (\r
+  IN MEMORY_PROFILE_DRIVER_INFO *DriverInfo,\r
+  IN UINTN                      AllocIndex,\r
+  IN MEMORY_PROFILE_ALLOC_INFO  *AllocInfo\r
+  )\r
+{\r
+  if (AllocInfo->Header.Signature != MEMORY_PROFILE_ALLOC_INFO_SIGNATURE) {\r
+    return NULL;\r
+  }\r
+  Print (L"    MEMORY_PROFILE_ALLOC_INFO (0x%x)\n", AllocIndex);\r
+  Print (L"      Signature     - 0x%08x\n", AllocInfo->Header.Signature);\r
+  Print (L"      Length        - 0x%04x\n", AllocInfo->Header.Length);\r
+  Print (L"      Revision      - 0x%04x\n", AllocInfo->Header.Revision);  \r
+  Print (L"      CallerAddress - 0x%016lx (Offset: 0x%08x)\n", AllocInfo->CallerAddress, (UINTN) (AllocInfo->CallerAddress - DriverInfo->ImageBase));\r
+  Print (L"      SequenceId    - 0x%08x\n", AllocInfo->SequenceId);\r
+  Print (L"      Action        - 0x%08x (%s)\n", AllocInfo->Action, mActionString[(AllocInfo->Action < sizeof(mActionString)/sizeof(mActionString[0])) ? AllocInfo->Action : 0]);\r
+  Print (L"      MemoryType    - 0x%08x (%s)\n", AllocInfo->MemoryType, mMemoryTypeString[(AllocInfo->MemoryType < sizeof(mMemoryTypeString)/sizeof(mMemoryTypeString[0])) ? AllocInfo->MemoryType : (sizeof(mMemoryTypeString)/sizeof(mMemoryTypeString[0]) - 1)]);\r
+  Print (L"      Buffer        - 0x%016lx\n", AllocInfo->Buffer);\r
+  Print (L"      Size          - 0x%016lx\n", AllocInfo->Size);\r
+\r
+  return (MEMORY_PROFILE_ALLOC_INFO *) ((UINTN) AllocInfo + AllocInfo->Header.Length);\r
+}\r
+\r
+/**\r
+  Dump memory profile driver information.\r
+\r
+  @param[in] DriverIndex        Memory profile driver info index.\r
+  @param[in] DriverInfo         Pointer to memory profile driver info.\r
+\r
+  @return Pointer to next memory profile driver info.\r
+\r
+**/\r
+MEMORY_PROFILE_DRIVER_INFO *\r
+DumpMemoryProfileDriverInfo (\r
+  IN UINTN                      DriverIndex,\r
+  IN MEMORY_PROFILE_DRIVER_INFO *DriverInfo\r
+  )\r
+{\r
+  UINTN                         TypeIndex;\r
+  MEMORY_PROFILE_ALLOC_INFO     *AllocInfo;\r
+  UINTN                         AllocIndex;\r
+\r
+  if (DriverInfo->Header.Signature != MEMORY_PROFILE_DRIVER_INFO_SIGNATURE) {\r
+    return NULL;\r
+  }\r
+  Print (L"  MEMORY_PROFILE_DRIVER_INFO (0x%x)\n", DriverIndex);\r
+  Print (L"    Signature               - 0x%08x\n", DriverInfo->Header.Signature);\r
+  Print (L"    Length                  - 0x%04x\n", DriverInfo->Header.Length);\r
+  Print (L"    Revision                - 0x%04x\n", DriverInfo->Header.Revision);  \r
+  GetDriverNameString (DriverInfo);\r
+  Print (L"    FileName                - %s\n", &mNameString);\r
+  Print (L"    ImageBase               - 0x%016lx\n", DriverInfo->ImageBase);\r
+  Print (L"    ImageSize               - 0x%016lx\n", DriverInfo->ImageSize);\r
+  Print (L"    EntryPoint              - 0x%016lx\n", DriverInfo->EntryPoint);\r
+  Print (L"    ImageSubsystem          - 0x%04x (%s)\n", DriverInfo->ImageSubsystem, mSubsystemString[(DriverInfo->ImageSubsystem < sizeof(mSubsystemString)/sizeof(mSubsystemString[0])) ? DriverInfo->ImageSubsystem : 0]);\r
+  Print (L"    FileType                - 0x%02x (%s)\n", DriverInfo->FileType, mFileTypeString[(DriverInfo->FileType < sizeof(mFileTypeString)/sizeof(mFileTypeString[0])) ? DriverInfo->FileType : 0]);\r
+  Print (L"    CurrentUsage            - 0x%016lx\n", DriverInfo->CurrentUsage);\r
+  Print (L"    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
+      Print (L"    CurrentUsage[0x%02x]      - 0x%016lx (%s)\n", TypeIndex, DriverInfo->CurrentUsageByType[TypeIndex], mMemoryTypeString[TypeIndex]);\r
+      Print (L"    PeakUsage[0x%02x]         - 0x%016lx (%s)\n", TypeIndex, DriverInfo->PeakUsageByType[TypeIndex], mMemoryTypeString[TypeIndex]);\r
+    }\r
+  }\r
+  Print (L"    AllocRecordCount        - 0x%08x\n", DriverInfo->AllocRecordCount);\r
+\r
+  AllocInfo = (MEMORY_PROFILE_ALLOC_INFO *) ((UINTN) DriverInfo + DriverInfo->Header.Length);\r
+  for (AllocIndex = 0; AllocIndex < DriverInfo->AllocRecordCount; AllocIndex++) {\r
+    AllocInfo = DumpMemoryProfileAllocInfo (DriverInfo, AllocIndex, AllocInfo);\r
+    if (AllocInfo == NULL) {\r
+      return NULL;\r
+    }\r
+  }\r
+  return (MEMORY_PROFILE_DRIVER_INFO *) AllocInfo;\r
+}\r
+\r
+/**\r
+  Dump memory profile context information.\r
+\r
+  @param[in] Context            Pointer to memory profile context.\r
+\r
+  @return Pointer to the end of memory profile context buffer.\r
+\r
+**/\r
+VOID *\r
+DumpMemoryProfileContext (\r
+  IN MEMORY_PROFILE_CONTEXT     *Context\r
+  )\r
+{\r
+  UINTN                         TypeIndex;\r
+  MEMORY_PROFILE_DRIVER_INFO    *DriverInfo;\r
+  UINTN                         DriverIndex;\r
+\r
+  if (Context->Header.Signature != MEMORY_PROFILE_CONTEXT_SIGNATURE) {\r
+    return NULL;\r
+  }\r
+  Print (L"MEMORY_PROFILE_CONTEXT\n");\r
+  Print (L"  Signature                     - 0x%08x\n", Context->Header.Signature);\r
+  Print (L"  Length                        - 0x%04x\n", Context->Header.Length);\r
+  Print (L"  Revision                      - 0x%04x\n", Context->Header.Revision);  \r
+  Print (L"  CurrentTotalUsage             - 0x%016lx\n", Context->CurrentTotalUsage);\r
+  Print (L"  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
+      Print (L"  CurrentTotalUsage[0x%02x]       - 0x%016lx (%s)\n", TypeIndex, Context->CurrentTotalUsageByType[TypeIndex], mMemoryTypeString[TypeIndex]);\r
+      Print (L"  PeakTotalUsage[0x%02x]          - 0x%016lx (%s)\n", TypeIndex, Context->PeakTotalUsageByType[TypeIndex], mMemoryTypeString[TypeIndex]);\r
+    }\r
+  }\r
+  Print (L"  TotalImageSize                - 0x%016lx\n", Context->TotalImageSize);\r
+  Print (L"  ImageCount                    - 0x%08x\n", Context->ImageCount);\r
+  Print (L"  SequenceCount                 - 0x%08x\n", Context->SequenceCount);\r
+\r
+  DriverInfo = (MEMORY_PROFILE_DRIVER_INFO *) ((UINTN) Context + Context->Header.Length);\r
+  for (DriverIndex = 0; DriverIndex < Context->ImageCount; DriverIndex++) {\r
+    DriverInfo = DumpMemoryProfileDriverInfo (DriverIndex, DriverInfo);\r
+    if (DriverInfo == NULL) {\r
+      return NULL;\r
+    }\r
+  }\r
+  return (VOID *) DriverInfo;\r
+}\r
+\r
+/**\r
+  Dump memory profile descriptor information.\r
+\r
+  @param[in] DescriptorIndex    Memory profile descriptor index.\r
+  @param[in] Descriptor         Pointer to memory profile descriptor.\r
+\r
+  @return Pointer to next memory profile descriptor.\r
+\r
+**/\r
+MEMORY_PROFILE_DESCRIPTOR *\r
+DumpMemoryProfileDescriptor (\r
+  IN UINTN                      DescriptorIndex,\r
+  IN MEMORY_PROFILE_DESCRIPTOR  *Descriptor\r
+  )\r
+{\r
+  if (Descriptor->Header.Signature != MEMORY_PROFILE_DESCRIPTOR_SIGNATURE) {\r
+    return NULL;\r
+  }\r
+  Print (L"  MEMORY_PROFILE_DESCRIPTOR (0x%x)\n", DescriptorIndex);\r
+  Print (L"    Signature               - 0x%08x\n", Descriptor->Header.Signature);\r
+  Print (L"    Length                  - 0x%04x\n", Descriptor->Header.Length);\r
+  Print (L"    Revision                - 0x%04x\n", Descriptor->Header.Revision);  \r
+  Print (L"    Address                 - 0x%016lx\n", Descriptor->Address);\r
+  Print (L"    Size                    - 0x%016lx\n", Descriptor->Size);\r
+\r
+  return (MEMORY_PROFILE_DESCRIPTOR *) ((UINTN) Descriptor + Descriptor->Header.Length);\r
+}\r
+\r
+/**\r
+  Dump memory profile free memory information.\r
+\r
+  @param[in] FreeMemory         Pointer to memory profile free memory.\r
+\r
+  @return Pointer to the end of memory profile free memory buffer.\r
+\r
+**/\r
+VOID *\r
+DumpMemoryProfileFreeMemory (\r
+  IN MEMORY_PROFILE_FREE_MEMORY *FreeMemory\r
+  )\r
+{\r
+  MEMORY_PROFILE_DESCRIPTOR     *Descriptor;\r
+  UINTN                         DescriptorIndex;\r
+\r
+  if (FreeMemory->Header.Signature != MEMORY_PROFILE_FREE_MEMORY_SIGNATURE) {\r
+    return NULL;\r
+  }\r
+  Print (L"MEMORY_PROFILE_FREE_MEMORY\n");\r
+  Print (L"  Signature                     - 0x%08x\n", FreeMemory->Header.Signature);\r
+  Print (L"  Length                        - 0x%04x\n", FreeMemory->Header.Length);\r
+  Print (L"  Revision                      - 0x%04x\n", FreeMemory->Header.Revision);  \r
+  Print (L"  TotalFreeMemoryPages          - 0x%016lx\n", FreeMemory->TotalFreeMemoryPages);\r
+  Print (L"  FreeMemoryEntryCount          - 0x%08x\n", FreeMemory->FreeMemoryEntryCount);\r
+\r
+  Descriptor = (MEMORY_PROFILE_DESCRIPTOR *) ((UINTN) FreeMemory + FreeMemory->Header.Length);\r
+  for (DescriptorIndex = 0; DescriptorIndex < FreeMemory->FreeMemoryEntryCount; DescriptorIndex++) {\r
+    Descriptor = DumpMemoryProfileDescriptor (DescriptorIndex, Descriptor);\r
+    if (Descriptor == NULL) {\r
+      return NULL;\r
+    }\r
+  }\r
+\r
+  return (VOID *) Descriptor;\r
+}\r
+\r
+/**\r
+  Dump memory profile memory range information.\r
+\r
+  @param[in] MemoryRange        Pointer to memory profile memory range.\r
+\r
+  @return Pointer to the end of memory profile memory range buffer.\r
+\r
+**/\r
+VOID *\r
+DumpMemoryProfileMemoryRange (\r
+  IN MEMORY_PROFILE_MEMORY_RANGE    *MemoryRange\r
+  )\r
+{\r
+  MEMORY_PROFILE_DESCRIPTOR     *Descriptor;\r
+  UINTN                         DescriptorIndex;\r
+\r
+  if (MemoryRange->Header.Signature != MEMORY_PROFILE_MEMORY_RANGE_SIGNATURE) {\r
+    return NULL;\r
+  }\r
+  Print (L"MEMORY_PROFILE_MEMORY_RANGE\n");\r
+  Print (L"  Signature                     - 0x%08x\n", MemoryRange->Header.Signature);\r
+  Print (L"  Length                        - 0x%04x\n", MemoryRange->Header.Length);\r
+  Print (L"  Revision                      - 0x%04x\n", MemoryRange->Header.Revision);  \r
+  Print (L"  MemoryRangeCount              - 0x%08x\n", MemoryRange->MemoryRangeCount);\r
+\r
+  Descriptor = (MEMORY_PROFILE_DESCRIPTOR *) ((UINTN) MemoryRange + MemoryRange->Header.Length);\r
+  for (DescriptorIndex = 0; DescriptorIndex < MemoryRange->MemoryRangeCount; DescriptorIndex++) {\r
+    Descriptor = DumpMemoryProfileDescriptor (DescriptorIndex, Descriptor);\r
+    if (Descriptor == NULL) {\r
+      return NULL;\r
+    }\r
+  }\r
+\r
+  return (VOID *) Descriptor;\r
+}\r
+\r
+/**\r
+  Scan memory profile by Signature.\r
+\r
+  @param[in] ProfileBuffer      Memory profile base address.\r
+  @param[in] ProfileSize        Memory profile size.\r
+  @param[in] Signature          Signature.\r
+\r
+  @return Pointer to the stucture with the signature.\r
+\r
+**/\r
+VOID *\r
+ScanMemoryProfileBySignature (\r
+  IN PHYSICAL_ADDRESS           ProfileBuffer,\r
+  IN UINT64                     ProfileSize,\r
+  IN UINT32                     Signature\r
+  )\r
+{\r
+  MEMORY_PROFILE_COMMON_HEADER  *CommonHeader;\r
+  UINTN                          ProfileEnd;\r
+\r
+  ProfileEnd = (UINTN) (ProfileBuffer + ProfileSize);\r
+  CommonHeader = (MEMORY_PROFILE_COMMON_HEADER *) (UINTN) ProfileBuffer;\r
+  while ((UINTN) CommonHeader < ProfileEnd) {\r
+    if (CommonHeader->Signature == Signature) {\r
+      //\r
+      // Found it.\r
+      //\r
+      return (VOID *) CommonHeader;\r
+    }\r
+    CommonHeader = (MEMORY_PROFILE_COMMON_HEADER *) ((UINTN) CommonHeader + CommonHeader->Length);\r
+  }\r
+\r
+  return NULL;\r
+}\r
+\r
+/**\r
+  Dump memory profile information.\r
+\r
+  @param[in] ProfileBuffer      Memory profile base address.\r
+  @param[in] ProfileSize        Memory profile size.\r
+\r
+**/\r
+VOID\r
+DumpMemoryProfile (\r
+  IN PHYSICAL_ADDRESS           ProfileBuffer,\r
+  IN UINT64                     ProfileSize\r
+  )\r
+{\r
+  MEMORY_PROFILE_CONTEXT        *Context;\r
+  MEMORY_PROFILE_FREE_MEMORY    *FreeMemory;\r
+  MEMORY_PROFILE_MEMORY_RANGE   *MemoryRange;\r
+\r
+  Context = (MEMORY_PROFILE_CONTEXT *) ScanMemoryProfileBySignature (ProfileBuffer, ProfileSize, MEMORY_PROFILE_CONTEXT_SIGNATURE);\r
+  if (Context != NULL) {\r
+    DumpMemoryProfileContext (Context);\r
+  }\r
+\r
+  FreeMemory = (MEMORY_PROFILE_FREE_MEMORY *) ScanMemoryProfileBySignature (ProfileBuffer, ProfileSize, MEMORY_PROFILE_FREE_MEMORY_SIGNATURE);\r
+  if (FreeMemory != NULL) {\r
+    DumpMemoryProfileFreeMemory (FreeMemory);\r
+  }\r
+\r
+  MemoryRange = (MEMORY_PROFILE_MEMORY_RANGE *) ScanMemoryProfileBySignature (ProfileBuffer, ProfileSize, MEMORY_PROFILE_MEMORY_RANGE_SIGNATURE);\r
+  if (MemoryRange != NULL) {\r
+    DumpMemoryProfileMemoryRange (MemoryRange);\r
+  }\r
+}\r
+\r
+/**\r
+  Get and dump UEFI memory profile data.\r
+\r
+  @return EFI_SUCCESS   Get the memory profile data successfully.\r
+  @return other         Fail to get the memory profile data.\r
+\r
+**/\r
+EFI_STATUS\r
+GetUefiMemoryProfileData (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  EDKII_MEMORY_PROFILE_PROTOCOL *ProfileProtocol;\r
+  VOID                          *Data;\r
+  UINT64                        Size;\r
+\r
+  Status = gBS->LocateProtocol (&gEdkiiMemoryProfileGuid, NULL, (VOID **) &ProfileProtocol);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "UefiMemoryProfile: Locate MemoryProfile protocol - %r\n", Status));\r
+    return Status;\r
+  }\r
+\r
+  Size = 0;\r
+  Data = NULL;\r
+  Status = ProfileProtocol->GetData (\r
+                              ProfileProtocol,\r
+                              &Size,\r
+                              Data\r
+                              );\r
+  if (Status != EFI_BUFFER_TOO_SMALL) {\r
+    Print (L"UefiMemoryProfile: GetData - %r\n", Status);\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Add one sizeof (MEMORY_PROFILE_ALLOC_INFO) to Size for this AllocatePool action.\r
+  //\r
+  Size = Size + sizeof (MEMORY_PROFILE_ALLOC_INFO);\r
+  Data = AllocateZeroPool ((UINTN) Size);\r
+  if (Data == NULL) {\r
+    Print (L"UefiMemoryProfile: AllocateZeroPool (0x%x) - %r\n", Size, Status);\r
+    return Status;\r
+  }\r
+\r
+  Status = ProfileProtocol->GetData (\r
+                              ProfileProtocol,\r
+                              &Size,\r
+                              Data\r
+                              );\r
+  if (EFI_ERROR (Status)) {\r
+    FreePool (Data);\r
+    Print (L"UefiMemoryProfile: GetData - %r\n", Status);\r
+    return Status;\r
+  }\r
+\r
+\r
+  Print (L"UefiMemoryProfileSize - 0x%x\n", Size);\r
+  Print (L"======= UefiMemoryProfile begin =======\n");\r
+  DumpMemoryProfile ((PHYSICAL_ADDRESS) (UINTN) Data, Size);\r
+  Print (L"======= UefiMemoryProfile end =======\n\n\n");\r
+\r
+  FreePool (Data);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Get and dump SMRAM profile data.\r
+\r
+  @return EFI_SUCCESS   Get the SMRAM profile data successfully.\r
+  @return other         Fail to get the SMRAM profile data.\r
+\r
+**/\r
+EFI_STATUS\r
+GetSmramProfileData (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS                                    Status;\r
+  UINTN                                         CommSize;\r
+  UINT8                                         CommBuffer[sizeof (EFI_GUID) + sizeof (UINTN) + sizeof (SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA)];\r
+  EFI_SMM_COMMUNICATE_HEADER                    *CommHeader;\r
+  SMRAM_PROFILE_PARAMETER_GET_PROFILE_INFO      *CommGetProfileInfo;\r
+  SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA      *CommGetProfileData;\r
+  UINT64                                        ProfileSize;\r
+  PHYSICAL_ADDRESS                              ProfileBuffer;\r
+  EFI_SMM_COMMUNICATION_PROTOCOL                *SmmCommunication;\r
+\r
+  Status = gBS->LocateProtocol (&gEfiSmmCommunicationProtocolGuid, NULL, (VOID **) &SmmCommunication);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "SmramProfile: Locate SmmCommunication protocol - %r\n", Status));\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Get Size\r
+  //\r
+  CommHeader = (EFI_SMM_COMMUNICATE_HEADER *) &CommBuffer[0];\r
+  CopyMem (&CommHeader->HeaderGuid, &gEdkiiMemoryProfileGuid, sizeof (gEdkiiMemoryProfileGuid));\r
+  CommHeader->MessageLength = sizeof (SMRAM_PROFILE_PARAMETER_GET_PROFILE_INFO);\r
+\r
+  CommGetProfileInfo = (SMRAM_PROFILE_PARAMETER_GET_PROFILE_INFO *) &CommBuffer[OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data)];\r
+  CommGetProfileInfo->Header.Command      = SMRAM_PROFILE_COMMAND_GET_PROFILE_INFO;\r
+  CommGetProfileInfo->Header.DataLength   = sizeof (*CommGetProfileInfo);\r
+  CommGetProfileInfo->Header.ReturnStatus = (UINT64)-1;\r
+  CommGetProfileInfo->ProfileSize         = 0;\r
+\r
+  CommSize = sizeof (EFI_GUID) + sizeof (UINTN) + CommHeader->MessageLength;\r
+  Status = SmmCommunication->Communicate (SmmCommunication, CommBuffer, &CommSize);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "SmramProfile: SmmCommunication - %r\n", Status));\r
+    return Status;\r
+  }\r
+\r
+  if (CommGetProfileInfo->Header.ReturnStatus != 0) {\r
+    Print (L"SmramProfile: GetProfileInfo - 0x%0x\n", CommGetProfileInfo->Header.ReturnStatus);\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  ProfileSize = CommGetProfileInfo->ProfileSize;\r
+\r
+  //\r
+  // Get Data\r
+  //\r
+  ProfileBuffer = (PHYSICAL_ADDRESS) (UINTN) AllocateZeroPool ((UINTN) ProfileSize);\r
+  if (ProfileBuffer == 0) {\r
+    Print (L"UefiMemoryProfile: AllocateZeroPool (0x%x) - %r\n", (UINTN) ProfileSize, Status);\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  CommHeader = (EFI_SMM_COMMUNICATE_HEADER *) &CommBuffer[0];\r
+  CopyMem (&CommHeader->HeaderGuid, &gEdkiiMemoryProfileGuid, sizeof(gEdkiiMemoryProfileGuid));\r
+  CommHeader->MessageLength = sizeof (SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA);\r
+\r
+  CommGetProfileData = (SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA *)&CommBuffer[OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data)];\r
+  CommGetProfileData->Header.Command      = SMRAM_PROFILE_COMMAND_GET_PROFILE_DATA;\r
+  CommGetProfileData->Header.DataLength   = sizeof (*CommGetProfileData);\r
+  CommGetProfileData->Header.ReturnStatus = (UINT64)-1;\r
+  CommGetProfileData->ProfileSize         = ProfileSize;\r
+  CommGetProfileData->ProfileBuffer       = ProfileBuffer;\r
+\r
+  CommSize = sizeof (EFI_GUID) + sizeof (UINTN) + CommHeader->MessageLength;\r
+  Status = SmmCommunication->Communicate (SmmCommunication, CommBuffer, &CommSize);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  if (CommGetProfileData->Header.ReturnStatus != 0) {\r
+    Print (L"GetProfileData - 0x%x\n", CommGetProfileData->Header.ReturnStatus);\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+\r
+  Print (L"SmramProfileSize - 0x%x\n", CommGetProfileData->ProfileSize);\r
+  Print (L"======= SmramProfile begin =======\n");\r
+  DumpMemoryProfile (CommGetProfileData->ProfileBuffer, CommGetProfileData->ProfileSize);\r
+  Print (L"======= SmramProfile end =======\n\n\n");\r
+\r
+  FreePool ((VOID *) (UINTN) CommGetProfileData->ProfileBuffer);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  The user Entry Point for Application. The user code starts with this function\r
+  as the real entry point for the image goes into a library that calls this function.\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 entry point is executed successfully.\r
+  @retval other             Some error occurs when executing this entry point.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UefiMain (\r
+  IN EFI_HANDLE         ImageHandle,\r
+  IN EFI_SYSTEM_TABLE   *SystemTable\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+\r
+  Status = GetUefiMemoryProfileData ();\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "GetUefiMemoryProfileData - %r\n", Status));\r
+  }\r
+\r
+  Status = GetSmramProfileData ();\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "GetSmramProfileData - %r\n", Status));\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r