blob: 326603503f153ee7d2ba855a83abf8221ae38a84 [file] [log] [blame]
/** @file
Copyright (c) 2014 - 2017, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include <Uefi.h>
#include <PiDxe.h>
#include <Library/BaseLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/UefiLib.h>
#include <Library/UefiApplicationEntryPoint.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiRuntimeServicesTableLib.h>
#include <Library/DebugLib.h>
#include <Library/DxeServicesLib.h>
#include <Library/PrintLib.h>
#include <Protocol/SmmCommunication.h>
#include <Protocol/SmmAccess2.h>
#include <Guid/MemoryProfile.h>
#include <Guid/PiSmmCommunicationRegionTable.h>
CHAR8 *mActionString[] = {
"Unknown",
"gBS->AllocatePages",
"gBS->FreePages",
"gBS->AllocatePool",
"gBS->FreePool",
};
CHAR8 *mSmmActionString[] = {
"SmmUnknown",
"gSmst->SmmAllocatePages",
"gSmst->SmmFreePages",
"gSmst->SmmAllocatePool",
"gSmst->SmmFreePool",
};
typedef struct {
MEMORY_PROFILE_ACTION Action;
CHAR8 *String;
} ACTION_STRING;
ACTION_STRING mExtActionString[] = {
{ MEMORY_PROFILE_ACTION_LIB_ALLOCATE_PAGES, "Lib:AllocatePages" },
{ MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RUNTIME_PAGES, "Lib:AllocateRuntimePages" },
{ MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RESERVED_PAGES, "Lib:AllocateReservedPages" },
{ MEMORY_PROFILE_ACTION_LIB_FREE_PAGES, "Lib:FreePages" },
{ MEMORY_PROFILE_ACTION_LIB_ALLOCATE_ALIGNED_PAGES, "Lib:AllocateAlignedPages" },
{ MEMORY_PROFILE_ACTION_LIB_ALLOCATE_ALIGNED_RUNTIME_PAGES, "Lib:AllocateAlignedRuntimePages" },
{ MEMORY_PROFILE_ACTION_LIB_ALLOCATE_ALIGNED_RESERVED_PAGES, "Lib:AllocateAlignedReservedPages" },
{ MEMORY_PROFILE_ACTION_LIB_FREE_ALIGNED_PAGES, "Lib:FreeAlignedPages" },
{ MEMORY_PROFILE_ACTION_LIB_ALLOCATE_POOL, "Lib:AllocatePool" },
{ MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RUNTIME_POOL, "Lib:AllocateRuntimePool" },
{ MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RESERVED_POOL, "Lib:AllocateReservedPool" },
{ MEMORY_PROFILE_ACTION_LIB_FREE_POOL, "Lib:FreePool" },
{ MEMORY_PROFILE_ACTION_LIB_ALLOCATE_ZERO_POOL, "Lib:AllocateZeroPool" },
{ MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RUNTIME_ZERO_POOL, "Lib:AllocateRuntimeZeroPool" },
{ MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RESERVED_ZERO_POOL, "Lib:AllocateReservedZeroPool" },
{ MEMORY_PROFILE_ACTION_LIB_ALLOCATE_COPY_POOL, "Lib:AllocateCopyPool" },
{ MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RUNTIME_COPY_POOL, "Lib:AllocateRuntimeCopyPool" },
{ MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RESERVED_COPY_POOL, "Lib:AllocateReservedCopyPool" },
{ MEMORY_PROFILE_ACTION_LIB_REALLOCATE_POOL, "Lib:ReallocatePool" },
{ MEMORY_PROFILE_ACTION_LIB_REALLOCATE_RUNTIME_POOL, "Lib:ReallocateRuntimePool" },
{ MEMORY_PROFILE_ACTION_LIB_REALLOCATE_RESERVED_POOL, "Lib:ReallocateReservedPool" },
};
CHAR8 mUserDefinedActionString[] = { "UserDefined-0x80000000" };
CHAR8 *mMemoryTypeString[] = {
"EfiReservedMemoryType",
"EfiLoaderCode",
"EfiLoaderData",
"EfiBootServicesCode",
"EfiBootServicesData",
"EfiRuntimeServicesCode",
"EfiRuntimeServicesData",
"EfiConventionalMemory",
"EfiUnusableMemory",
"EfiACPIReclaimMemory",
"EfiACPIMemoryNVS",
"EfiMemoryMappedIO",
"EfiMemoryMappedIOPortSpace",
"EfiPalCode",
"EfiPersistentMemory",
"EfiOSReserved",
"EfiOemReserved",
};
CHAR8 *mSubsystemString[] = {
"Unknown",
"NATIVE",
"WINDOWS_GUI",
"WINDOWS_CUI",
"Unknown",
"Unknown",
"Unknown",
"POSIX_CUI",
"Unknown",
"WINDOWS_CE_GUI",
"EFI_APPLICATION",
"EFI_BOOT_SERVICE_DRIVER",
"EFI_RUNTIME_DRIVER",
"EFI_ROM",
"XBOX",
"Unknown",
};
CHAR8 *mFileTypeString[] = {
"Unknown",
"RAW",
"FREEFORM",
"SECURITY_CORE",
"PEI_CORE",
"DXE_CORE",
"PEIM",
"DRIVER",
"COMBINED_PEIM_DRIVER",
"APPLICATION",
"SMM",
"FIRMWARE_VOLUME_IMAGE",
"COMBINED_SMM_DXE",
"SMM_CORE",
};
#define PROFILE_NAME_STRING_LENGTH 64
CHAR8 mNameString[PROFILE_NAME_STRING_LENGTH + 1];
//
// Profile summary information
//
#define MEMORY_PROFILE_ALLOC_SUMMARY_INFO_SIGNATURE SIGNATURE_32 ('M','P','A','S')
#define MEMORY_PROFILE_ALLOC_SUMMARY_INFO_REVISION 0x0001
typedef struct {
MEMORY_PROFILE_COMMON_HEADER Header;
PHYSICAL_ADDRESS CallerAddress;
MEMORY_PROFILE_ACTION Action;
CHAR8 *ActionString;
UINT32 AllocateCount;
UINT64 TotalSize;
} MEMORY_PROFILE_ALLOC_SUMMARY_INFO;
typedef struct {
UINT32 Signature;
MEMORY_PROFILE_ALLOC_SUMMARY_INFO AllocSummaryInfo;
LIST_ENTRY Link;
} MEMORY_PROFILE_ALLOC_SUMMARY_INFO_DATA;
typedef struct {
UINT32 Signature;
MEMORY_PROFILE_DRIVER_INFO *DriverInfo;
LIST_ENTRY *AllocSummaryInfoList;
LIST_ENTRY Link;
} MEMORY_PROFILE_DRIVER_SUMMARY_INFO_DATA;
typedef struct {
UINT32 Signature;
MEMORY_PROFILE_CONTEXT *Context;
LIST_ENTRY *DriverSummaryInfoList;
} MEMORY_PROFILE_CONTEXT_SUMMARY_DATA;
LIST_ENTRY mImageSummaryQueue = INITIALIZE_LIST_HEAD_VARIABLE (mImageSummaryQueue);
MEMORY_PROFILE_CONTEXT_SUMMARY_DATA mMemoryProfileContextSummary;
/**
Get the file name portion of the Pdb File Name.
The portion of the Pdb File Name between the last backslash and
either a following period or the end of the string is copied into
AsciiBuffer. The name is truncated, if necessary, to ensure that
AsciiBuffer is not overrun.
@param[in] PdbFileName Pdb file name.
@param[out] AsciiBuffer The resultant Ascii File Name.
**/
VOID
GetShortPdbFileName (
IN CHAR8 *PdbFileName,
OUT CHAR8 *AsciiBuffer
)
{
UINTN IndexPdb; // Current work location within a Pdb string.
UINTN IndexBuffer; // Current work location within a Buffer string.
UINTN StartIndex;
UINTN EndIndex;
ZeroMem (AsciiBuffer, PROFILE_NAME_STRING_LENGTH + 1);
if (PdbFileName == NULL) {
AsciiStrnCpyS (AsciiBuffer, PROFILE_NAME_STRING_LENGTH + 1, " ", 1);
} else {
StartIndex = 0;
for (EndIndex = 0; PdbFileName[EndIndex] != 0; EndIndex++) {
}
for (IndexPdb = 0; PdbFileName[IndexPdb] != 0; IndexPdb++) {
if ((PdbFileName[IndexPdb] == '\\') || (PdbFileName[IndexPdb] == '/')) {
StartIndex = IndexPdb + 1;
}
if (PdbFileName[IndexPdb] == '.') {
EndIndex = IndexPdb;
}
}
IndexBuffer = 0;
for (IndexPdb = StartIndex; IndexPdb < EndIndex; IndexPdb++) {
AsciiBuffer[IndexBuffer] = PdbFileName[IndexPdb];
IndexBuffer++;
if (IndexBuffer >= PROFILE_NAME_STRING_LENGTH) {
AsciiBuffer[PROFILE_NAME_STRING_LENGTH] = 0;
break;
}
}
}
}
/**
Get a human readable name for an image.
The following methods will be tried orderly:
1. Image PDB
2. FFS UI section
3. Image GUID
@param[in] DriverInfo Pointer to memory profile driver info.
@return The resulting Ascii name string is stored in the mNameString global array.
**/
CHAR8 *
GetDriverNameString (
IN MEMORY_PROFILE_DRIVER_INFO *DriverInfo
)
{
EFI_STATUS Status;
CHAR16 *NameString;
UINTN StringSize;
//
// Method 1: Get the name string from image PDB
//
if (DriverInfo->PdbStringOffset != 0) {
GetShortPdbFileName ((CHAR8 *)((UINTN)DriverInfo + DriverInfo->PdbStringOffset), mNameString);
return mNameString;
}
if (!IsZeroGuid (&DriverInfo->FileName)) {
//
// Try to get the image's FFS UI section by image GUID
//
NameString = NULL;
StringSize = 0;
Status = GetSectionFromAnyFv (
&DriverInfo->FileName,
EFI_SECTION_USER_INTERFACE,
0,
(VOID **)&NameString,
&StringSize
);
if (!EFI_ERROR (Status)) {
//
// Method 2: Get the name string from FFS UI section
//
if (StrLen (NameString) > PROFILE_NAME_STRING_LENGTH) {
NameString[PROFILE_NAME_STRING_LENGTH] = 0;
}
UnicodeStrToAsciiStrS (NameString, mNameString, sizeof (mNameString));
FreePool (NameString);
return mNameString;
}
}
//
// Method 3: Get the name string from image GUID
//
AsciiSPrint (mNameString, sizeof (mNameString), "%g", &DriverInfo->FileName);
return mNameString;
}
/**
Memory type to string.
@param[in] MemoryType Memory type.
@return Pointer to string.
**/
CHAR8 *
ProfileMemoryTypeToStr (
IN EFI_MEMORY_TYPE MemoryType
)
{
UINTN Index;
if ((UINT32)MemoryType >= 0x80000000) {
//
// OS reserved memory type.
//
Index = EfiMaxMemoryType;
} else if ((UINT32)MemoryType >= 0x70000000) {
//
// OEM reserved memory type.
//
Index = EfiMaxMemoryType + 1;
} else {
Index = MemoryType;
}
return mMemoryTypeString[Index];
}
/**
Action to string.
@param[in] Action Profile action.
@param[in] UserDefinedActionString Pointer to user defined action string.
@param[in] IsForSmm TRUE - SMRAM profile.
FALSE - UEFI memory profile.
@return Pointer to string.
**/
CHAR8 *
ProfileActionToStr (
IN MEMORY_PROFILE_ACTION Action,
IN CHAR8 *UserDefinedActionString,
IN BOOLEAN IsForSmm
)
{
UINTN Index;
UINTN ActionStringCount;
CHAR8 **ActionString;
if (IsForSmm) {
ActionString = mSmmActionString;
ActionStringCount = ARRAY_SIZE (mSmmActionString);
} else {
ActionString = mActionString;
ActionStringCount = ARRAY_SIZE (mActionString);
}
if ((UINTN)(UINT32)Action < ActionStringCount) {
return ActionString[Action];
}
for (Index = 0; Index < ARRAY_SIZE (mExtActionString); Index++) {
if (mExtActionString[Index].Action == Action) {
return mExtActionString[Index].String;
}
}
if ((Action & MEMORY_PROFILE_ACTION_USER_DEFINED_MASK) != 0) {
if (UserDefinedActionString != NULL) {
return UserDefinedActionString;
}
AsciiSPrint (mUserDefinedActionString, sizeof (mUserDefinedActionString), "UserDefined-0x%08x", Action);
return mUserDefinedActionString;
}
return ActionString[0];
}
/**
Dump memory profile allocate information.
@param[in] DriverInfo Pointer to memory profile driver info.
@param[in] AllocIndex Memory profile alloc info index.
@param[in] AllocInfo Pointer to memory profile alloc info.
@param[in] IsForSmm TRUE - SMRAM profile.
FALSE - UEFI memory profile.
@return Pointer to next memory profile alloc info.
**/
MEMORY_PROFILE_ALLOC_INFO *
DumpMemoryProfileAllocInfo (
IN MEMORY_PROFILE_DRIVER_INFO *DriverInfo,
IN UINTN AllocIndex,
IN MEMORY_PROFILE_ALLOC_INFO *AllocInfo,
IN BOOLEAN IsForSmm
)
{
CHAR8 *ActionString;
if (AllocInfo->Header.Signature != MEMORY_PROFILE_ALLOC_INFO_SIGNATURE) {
return NULL;
}
if (AllocInfo->ActionStringOffset != 0) {
ActionString = (CHAR8 *)((UINTN)AllocInfo + AllocInfo->ActionStringOffset);
} else {
ActionString = NULL;
}
Print (L" MEMORY_PROFILE_ALLOC_INFO (0x%x)\n", AllocIndex);
Print (L" Signature - 0x%08x\n", AllocInfo->Header.Signature);
Print (L" Length - 0x%04x\n", AllocInfo->Header.Length);
Print (L" Revision - 0x%04x\n", AllocInfo->Header.Revision);
Print (L" CallerAddress - 0x%016lx (Offset: 0x%08x)\n", AllocInfo->CallerAddress, (UINTN)(AllocInfo->CallerAddress - DriverInfo->ImageBase));
Print (L" SequenceId - 0x%08x\n", AllocInfo->SequenceId);
Print (L" Action - 0x%08x (%a)\n", AllocInfo->Action, ProfileActionToStr (AllocInfo->Action, ActionString, IsForSmm));
Print (L" MemoryType - 0x%08x (%a)\n", AllocInfo->MemoryType, ProfileMemoryTypeToStr (AllocInfo->MemoryType));
Print (L" Buffer - 0x%016lx\n", AllocInfo->Buffer);
Print (L" Size - 0x%016lx\n", AllocInfo->Size);
return (MEMORY_PROFILE_ALLOC_INFO *)((UINTN)AllocInfo + AllocInfo->Header.Length);
}
/**
Dump memory profile driver information.
@param[in] DriverIndex Memory profile driver info index.
@param[in] DriverInfo Pointer to memory profile driver info.
@param[in] IsForSmm TRUE - SMRAM profile.
FALSE - UEFI memory profile.
@return Pointer to next memory profile driver info.
**/
MEMORY_PROFILE_DRIVER_INFO *
DumpMemoryProfileDriverInfo (
IN UINTN DriverIndex,
IN MEMORY_PROFILE_DRIVER_INFO *DriverInfo,
IN BOOLEAN IsForSmm
)
{
UINTN TypeIndex;
MEMORY_PROFILE_ALLOC_INFO *AllocInfo;
UINTN AllocIndex;
CHAR8 *NameString;
if (DriverInfo->Header.Signature != MEMORY_PROFILE_DRIVER_INFO_SIGNATURE) {
return NULL;
}
Print (L" MEMORY_PROFILE_DRIVER_INFO (0x%x)\n", DriverIndex);
Print (L" Signature - 0x%08x\n", DriverInfo->Header.Signature);
Print (L" Length - 0x%04x\n", DriverInfo->Header.Length);
Print (L" Revision - 0x%04x\n", DriverInfo->Header.Revision);
NameString = GetDriverNameString (DriverInfo);
Print (L" FileName - %a\n", NameString);
if (DriverInfo->PdbStringOffset != 0) {
Print (L" Pdb - %a\n", (CHAR8 *)((UINTN)DriverInfo + DriverInfo->PdbStringOffset));
}
Print (L" ImageBase - 0x%016lx\n", DriverInfo->ImageBase);
Print (L" ImageSize - 0x%016lx\n", DriverInfo->ImageSize);
Print (L" EntryPoint - 0x%016lx\n", DriverInfo->EntryPoint);
Print (L" ImageSubsystem - 0x%04x (%a)\n", DriverInfo->ImageSubsystem, mSubsystemString[(DriverInfo->ImageSubsystem < sizeof (mSubsystemString)/sizeof (mSubsystemString[0])) ? DriverInfo->ImageSubsystem : 0]);
Print (L" FileType - 0x%02x (%a)\n", DriverInfo->FileType, mFileTypeString[(DriverInfo->FileType < sizeof (mFileTypeString)/sizeof (mFileTypeString[0])) ? DriverInfo->FileType : 0]);
Print (L" CurrentUsage - 0x%016lx\n", DriverInfo->CurrentUsage);
Print (L" PeakUsage - 0x%016lx\n", DriverInfo->PeakUsage);
for (TypeIndex = 0; TypeIndex < sizeof (DriverInfo->CurrentUsageByType) / sizeof (DriverInfo->CurrentUsageByType[0]); TypeIndex++) {
if ((DriverInfo->CurrentUsageByType[TypeIndex] != 0) ||
(DriverInfo->PeakUsageByType[TypeIndex] != 0))
{
Print (L" CurrentUsage[0x%02x] - 0x%016lx (%a)\n", TypeIndex, DriverInfo->CurrentUsageByType[TypeIndex], mMemoryTypeString[TypeIndex]);
Print (L" PeakUsage[0x%02x] - 0x%016lx (%a)\n", TypeIndex, DriverInfo->PeakUsageByType[TypeIndex], mMemoryTypeString[TypeIndex]);
}
}
Print (L" AllocRecordCount - 0x%08x\n", DriverInfo->AllocRecordCount);
AllocInfo = (MEMORY_PROFILE_ALLOC_INFO *)((UINTN)DriverInfo + DriverInfo->Header.Length);
for (AllocIndex = 0; AllocIndex < DriverInfo->AllocRecordCount; AllocIndex++) {
AllocInfo = DumpMemoryProfileAllocInfo (DriverInfo, AllocIndex, AllocInfo, IsForSmm);
if (AllocInfo == NULL) {
return NULL;
}
}
return (MEMORY_PROFILE_DRIVER_INFO *)AllocInfo;
}
/**
Dump memory profile context information.
@param[in] Context Pointer to memory profile context.
@param[in] IsForSmm TRUE - SMRAM profile.
FALSE - UEFI memory profile.
@return Pointer to the end of memory profile context buffer.
**/
VOID *
DumpMemoryProfileContext (
IN MEMORY_PROFILE_CONTEXT *Context,
IN BOOLEAN IsForSmm
)
{
UINTN TypeIndex;
MEMORY_PROFILE_DRIVER_INFO *DriverInfo;
UINTN DriverIndex;
if (Context->Header.Signature != MEMORY_PROFILE_CONTEXT_SIGNATURE) {
return NULL;
}
Print (L"MEMORY_PROFILE_CONTEXT\n");
Print (L" Signature - 0x%08x\n", Context->Header.Signature);
Print (L" Length - 0x%04x\n", Context->Header.Length);
Print (L" Revision - 0x%04x\n", Context->Header.Revision);
Print (L" CurrentTotalUsage - 0x%016lx\n", Context->CurrentTotalUsage);
Print (L" PeakTotalUsage - 0x%016lx\n", Context->PeakTotalUsage);
for (TypeIndex = 0; TypeIndex < sizeof (Context->CurrentTotalUsageByType) / sizeof (Context->CurrentTotalUsageByType[0]); TypeIndex++) {
if ((Context->CurrentTotalUsageByType[TypeIndex] != 0) ||
(Context->PeakTotalUsageByType[TypeIndex] != 0))
{
Print (L" CurrentTotalUsage[0x%02x] - 0x%016lx (%a)\n", TypeIndex, Context->CurrentTotalUsageByType[TypeIndex], mMemoryTypeString[TypeIndex]);
Print (L" PeakTotalUsage[0x%02x] - 0x%016lx (%a)\n", TypeIndex, Context->PeakTotalUsageByType[TypeIndex], mMemoryTypeString[TypeIndex]);
}
}
Print (L" TotalImageSize - 0x%016lx\n", Context->TotalImageSize);
Print (L" ImageCount - 0x%08x\n", Context->ImageCount);
Print (L" SequenceCount - 0x%08x\n", Context->SequenceCount);
DriverInfo = (MEMORY_PROFILE_DRIVER_INFO *)((UINTN)Context + Context->Header.Length);
for (DriverIndex = 0; DriverIndex < Context->ImageCount; DriverIndex++) {
DriverInfo = DumpMemoryProfileDriverInfo (DriverIndex, DriverInfo, IsForSmm);
if (DriverInfo == NULL) {
return NULL;
}
}
return (VOID *)DriverInfo;
}
/**
Dump memory profile descriptor information.
@param[in] DescriptorIndex Memory profile descriptor index.
@param[in] Descriptor Pointer to memory profile descriptor.
@return Pointer to next memory profile descriptor.
**/
MEMORY_PROFILE_DESCRIPTOR *
DumpMemoryProfileDescriptor (
IN UINTN DescriptorIndex,
IN MEMORY_PROFILE_DESCRIPTOR *Descriptor
)
{
if (Descriptor->Header.Signature != MEMORY_PROFILE_DESCRIPTOR_SIGNATURE) {
return NULL;
}
Print (L" MEMORY_PROFILE_DESCRIPTOR (0x%x)\n", DescriptorIndex);
Print (L" Signature - 0x%08x\n", Descriptor->Header.Signature);
Print (L" Length - 0x%04x\n", Descriptor->Header.Length);
Print (L" Revision - 0x%04x\n", Descriptor->Header.Revision);
Print (L" Address - 0x%016lx\n", Descriptor->Address);
Print (L" Size - 0x%016lx\n", Descriptor->Size);
return (MEMORY_PROFILE_DESCRIPTOR *)((UINTN)Descriptor + Descriptor->Header.Length);
}
/**
Dump memory profile free memory information.
@param[in] FreeMemory Pointer to memory profile free memory.
@return Pointer to the end of memory profile free memory buffer.
**/
VOID *
DumpMemoryProfileFreeMemory (
IN MEMORY_PROFILE_FREE_MEMORY *FreeMemory
)
{
MEMORY_PROFILE_DESCRIPTOR *Descriptor;
UINTN DescriptorIndex;
if (FreeMemory->Header.Signature != MEMORY_PROFILE_FREE_MEMORY_SIGNATURE) {
return NULL;
}
Print (L"MEMORY_PROFILE_FREE_MEMORY\n");
Print (L" Signature - 0x%08x\n", FreeMemory->Header.Signature);
Print (L" Length - 0x%04x\n", FreeMemory->Header.Length);
Print (L" Revision - 0x%04x\n", FreeMemory->Header.Revision);
Print (L" TotalFreeMemoryPages - 0x%016lx\n", FreeMemory->TotalFreeMemoryPages);
Print (L" FreeMemoryEntryCount - 0x%08x\n", FreeMemory->FreeMemoryEntryCount);
Descriptor = (MEMORY_PROFILE_DESCRIPTOR *)((UINTN)FreeMemory + FreeMemory->Header.Length);
for (DescriptorIndex = 0; DescriptorIndex < FreeMemory->FreeMemoryEntryCount; DescriptorIndex++) {
Descriptor = DumpMemoryProfileDescriptor (DescriptorIndex, Descriptor);
if (Descriptor == NULL) {
return NULL;
}
}
return (VOID *)Descriptor;
}
/**
Dump memory profile memory range information.
@param[in] MemoryRange Pointer to memory profile memory range.
@return Pointer to the end of memory profile memory range buffer.
**/
VOID *
DumpMemoryProfileMemoryRange (
IN MEMORY_PROFILE_MEMORY_RANGE *MemoryRange
)
{
MEMORY_PROFILE_DESCRIPTOR *Descriptor;
UINTN DescriptorIndex;
if (MemoryRange->Header.Signature != MEMORY_PROFILE_MEMORY_RANGE_SIGNATURE) {
return NULL;
}
Print (L"MEMORY_PROFILE_MEMORY_RANGE\n");
Print (L" Signature - 0x%08x\n", MemoryRange->Header.Signature);
Print (L" Length - 0x%04x\n", MemoryRange->Header.Length);
Print (L" Revision - 0x%04x\n", MemoryRange->Header.Revision);
Print (L" MemoryRangeCount - 0x%08x\n", MemoryRange->MemoryRangeCount);
Descriptor = (MEMORY_PROFILE_DESCRIPTOR *)((UINTN)MemoryRange + MemoryRange->Header.Length);
for (DescriptorIndex = 0; DescriptorIndex < MemoryRange->MemoryRangeCount; DescriptorIndex++) {
Descriptor = DumpMemoryProfileDescriptor (DescriptorIndex, Descriptor);
if (Descriptor == NULL) {
return NULL;
}
}
return (VOID *)Descriptor;
}
/**
Scan memory profile by Signature.
@param[in] ProfileBuffer Memory profile base address.
@param[in] ProfileSize Memory profile size.
@param[in] Signature Signature.
@return Pointer to the structure with the signature.
**/
VOID *
ScanMemoryProfileBySignature (
IN PHYSICAL_ADDRESS ProfileBuffer,
IN UINT64 ProfileSize,
IN UINT32 Signature
)
{
MEMORY_PROFILE_COMMON_HEADER *CommonHeader;
UINTN ProfileEnd;
ProfileEnd = (UINTN)(ProfileBuffer + ProfileSize);
CommonHeader = (MEMORY_PROFILE_COMMON_HEADER *)(UINTN)ProfileBuffer;
while ((UINTN)CommonHeader < ProfileEnd) {
if (CommonHeader->Signature == Signature) {
//
// Found it.
//
return (VOID *)CommonHeader;
}
if (CommonHeader->Length == 0) {
ASSERT (FALSE);
return NULL;
}
CommonHeader = (MEMORY_PROFILE_COMMON_HEADER *)((UINTN)CommonHeader + CommonHeader->Length);
}
return NULL;
}
/**
Dump memory profile information.
@param[in] ProfileBuffer Memory profile base address.
@param[in] ProfileSize Memory profile size.
@param[in] IsForSmm TRUE - SMRAM profile.
FALSE - UEFI memory profile.
**/
VOID
DumpMemoryProfile (
IN PHYSICAL_ADDRESS ProfileBuffer,
IN UINT64 ProfileSize,
IN BOOLEAN IsForSmm
)
{
MEMORY_PROFILE_CONTEXT *Context;
MEMORY_PROFILE_FREE_MEMORY *FreeMemory;
MEMORY_PROFILE_MEMORY_RANGE *MemoryRange;
Context = (MEMORY_PROFILE_CONTEXT *)ScanMemoryProfileBySignature (ProfileBuffer, ProfileSize, MEMORY_PROFILE_CONTEXT_SIGNATURE);
if (Context != NULL) {
DumpMemoryProfileContext (Context, IsForSmm);
}
FreeMemory = (MEMORY_PROFILE_FREE_MEMORY *)ScanMemoryProfileBySignature (ProfileBuffer, ProfileSize, MEMORY_PROFILE_FREE_MEMORY_SIGNATURE);
if (FreeMemory != NULL) {
DumpMemoryProfileFreeMemory (FreeMemory);
}
MemoryRange = (MEMORY_PROFILE_MEMORY_RANGE *)ScanMemoryProfileBySignature (ProfileBuffer, ProfileSize, MEMORY_PROFILE_MEMORY_RANGE_SIGNATURE);
if (MemoryRange != NULL) {
DumpMemoryProfileMemoryRange (MemoryRange);
}
}
/**
Get Allocate summary information structure by caller address.
@param[in] CallerAddress Caller address.
@param[in] DriverSummaryInfoData Driver summary information data structure.
@return Allocate summary information structure by caller address.
**/
MEMORY_PROFILE_ALLOC_SUMMARY_INFO_DATA *
GetAllocSummaryInfoByCallerAddress (
IN PHYSICAL_ADDRESS CallerAddress,
IN MEMORY_PROFILE_DRIVER_SUMMARY_INFO_DATA *DriverSummaryInfoData
)
{
LIST_ENTRY *AllocSummaryInfoList;
LIST_ENTRY *AllocSummaryLink;
MEMORY_PROFILE_ALLOC_SUMMARY_INFO *AllocSummaryInfo;
MEMORY_PROFILE_ALLOC_SUMMARY_INFO_DATA *AllocSummaryInfoData;
AllocSummaryInfoList = DriverSummaryInfoData->AllocSummaryInfoList;
for (AllocSummaryLink = AllocSummaryInfoList->ForwardLink;
AllocSummaryLink != AllocSummaryInfoList;
AllocSummaryLink = AllocSummaryLink->ForwardLink)
{
AllocSummaryInfoData = CR (
AllocSummaryLink,
MEMORY_PROFILE_ALLOC_SUMMARY_INFO_DATA,
Link,
MEMORY_PROFILE_ALLOC_SUMMARY_INFO_SIGNATURE
);
AllocSummaryInfo = &AllocSummaryInfoData->AllocSummaryInfo;
if (AllocSummaryInfo->CallerAddress == CallerAddress) {
return AllocSummaryInfoData;
}
}
return NULL;
}
/**
Create Allocate summary information structure and
link to Driver summary information data structure.
@param[in, out] DriverSummaryInfoData Driver summary information data structure.
@param[in] AllocInfo Pointer to memory profile alloc info.
@return Pointer to next memory profile alloc info.
**/
MEMORY_PROFILE_ALLOC_INFO *
CreateAllocSummaryInfo (
IN OUT MEMORY_PROFILE_DRIVER_SUMMARY_INFO_DATA *DriverSummaryInfoData,
IN MEMORY_PROFILE_ALLOC_INFO *AllocInfo
)
{
MEMORY_PROFILE_ALLOC_SUMMARY_INFO_DATA *AllocSummaryInfoData;
MEMORY_PROFILE_ALLOC_SUMMARY_INFO *AllocSummaryInfo;
if (AllocInfo->Header.Signature != MEMORY_PROFILE_ALLOC_INFO_SIGNATURE) {
return NULL;
}
AllocSummaryInfoData = GetAllocSummaryInfoByCallerAddress (AllocInfo->CallerAddress, DriverSummaryInfoData);
if (AllocSummaryInfoData == NULL) {
AllocSummaryInfoData = AllocatePool (sizeof (*AllocSummaryInfoData));
if (AllocSummaryInfoData == NULL) {
return NULL;
}
AllocSummaryInfoData->Signature = MEMORY_PROFILE_ALLOC_SUMMARY_INFO_SIGNATURE;
AllocSummaryInfo = &AllocSummaryInfoData->AllocSummaryInfo;
AllocSummaryInfo->Header.Signature = MEMORY_PROFILE_ALLOC_SUMMARY_INFO_SIGNATURE;
AllocSummaryInfo->Header.Length = sizeof (*AllocSummaryInfo);
AllocSummaryInfo->Header.Revision = MEMORY_PROFILE_ALLOC_SUMMARY_INFO_REVISION;
AllocSummaryInfo->CallerAddress = AllocInfo->CallerAddress;
AllocSummaryInfo->Action = AllocInfo->Action;
if (AllocInfo->ActionStringOffset != 0) {
AllocSummaryInfo->ActionString = (CHAR8 *)((UINTN)AllocInfo + AllocInfo->ActionStringOffset);
} else {
AllocSummaryInfo->ActionString = NULL;
}
AllocSummaryInfo->AllocateCount = 0;
AllocSummaryInfo->TotalSize = 0;
InsertTailList (DriverSummaryInfoData->AllocSummaryInfoList, &AllocSummaryInfoData->Link);
}
AllocSummaryInfo = &AllocSummaryInfoData->AllocSummaryInfo;
AllocSummaryInfo->AllocateCount++;
AllocSummaryInfo->TotalSize += AllocInfo->Size;
return (MEMORY_PROFILE_ALLOC_INFO *)((UINTN)AllocInfo + AllocInfo->Header.Length);
}
/**
Create Driver summary information structure and
link to Context summary information data structure.
@param[in, out] ContextSummaryData Context summary information data structure.
@param[in] DriverInfo Pointer to memory profile driver info.
@return Pointer to next memory profile driver info.
**/
MEMORY_PROFILE_DRIVER_INFO *
CreateDriverSummaryInfo (
IN OUT MEMORY_PROFILE_CONTEXT_SUMMARY_DATA *ContextSummaryData,
IN MEMORY_PROFILE_DRIVER_INFO *DriverInfo
)
{
MEMORY_PROFILE_DRIVER_SUMMARY_INFO_DATA *DriverSummaryInfoData;
MEMORY_PROFILE_ALLOC_INFO *AllocInfo;
UINTN AllocIndex;
if (DriverInfo->Header.Signature != MEMORY_PROFILE_DRIVER_INFO_SIGNATURE) {
return NULL;
}
DriverSummaryInfoData = AllocatePool (sizeof (*DriverSummaryInfoData) + sizeof (LIST_ENTRY));
if (DriverSummaryInfoData == NULL) {
return NULL;
}
DriverSummaryInfoData->Signature = MEMORY_PROFILE_DRIVER_INFO_SIGNATURE;
DriverSummaryInfoData->DriverInfo = DriverInfo;
DriverSummaryInfoData->AllocSummaryInfoList = (LIST_ENTRY *)(DriverSummaryInfoData + 1);
InitializeListHead (DriverSummaryInfoData->AllocSummaryInfoList);
InsertTailList (ContextSummaryData->DriverSummaryInfoList, &DriverSummaryInfoData->Link);
AllocInfo = (MEMORY_PROFILE_ALLOC_INFO *)((UINTN)DriverInfo + DriverInfo->Header.Length);
for (AllocIndex = 0; AllocIndex < DriverInfo->AllocRecordCount; AllocIndex++) {
AllocInfo = CreateAllocSummaryInfo (DriverSummaryInfoData, AllocInfo);
if (AllocInfo == NULL) {
return NULL;
}
}
return (MEMORY_PROFILE_DRIVER_INFO *)AllocInfo;
}
/**
Create Context summary information structure.
@param[in] ProfileBuffer Memory profile base address.
@param[in] ProfileSize Memory profile size.
@return Context summary information structure.
**/
MEMORY_PROFILE_CONTEXT_SUMMARY_DATA *
CreateContextSummaryData (
IN PHYSICAL_ADDRESS ProfileBuffer,
IN UINT64 ProfileSize
)
{
MEMORY_PROFILE_CONTEXT *Context;
MEMORY_PROFILE_DRIVER_INFO *DriverInfo;
UINTN DriverIndex;
Context = (MEMORY_PROFILE_CONTEXT *)ScanMemoryProfileBySignature (ProfileBuffer, ProfileSize, MEMORY_PROFILE_CONTEXT_SIGNATURE);
if (Context == NULL) {
return NULL;
}
mMemoryProfileContextSummary.Signature = MEMORY_PROFILE_CONTEXT_SIGNATURE;
mMemoryProfileContextSummary.Context = Context;
mMemoryProfileContextSummary.DriverSummaryInfoList = &mImageSummaryQueue;
DriverInfo = (MEMORY_PROFILE_DRIVER_INFO *)((UINTN)Context + Context->Header.Length);
for (DriverIndex = 0; DriverIndex < Context->ImageCount; DriverIndex++) {
DriverInfo = CreateDriverSummaryInfo (&mMemoryProfileContextSummary, DriverInfo);
if (DriverInfo == NULL) {
return NULL;
}
}
return &mMemoryProfileContextSummary;
}
/**
Dump Context summary information.
@param[in] ContextSummaryData Context summary information data.
@param[in] IsForSmm TRUE - SMRAM profile.
FALSE - UEFI memory profile.
**/
VOID
DumpContextSummaryData (
IN MEMORY_PROFILE_CONTEXT_SUMMARY_DATA *ContextSummaryData,
IN BOOLEAN IsForSmm
)
{
MEMORY_PROFILE_DRIVER_SUMMARY_INFO_DATA *DriverSummaryInfoData;
MEMORY_PROFILE_ALLOC_SUMMARY_INFO_DATA *AllocSummaryInfoData;
LIST_ENTRY *DriverSummaryInfoList;
LIST_ENTRY *DriverSummaryLink;
LIST_ENTRY *AllocSummaryInfoList;
LIST_ENTRY *AllocSummaryLink;
MEMORY_PROFILE_DRIVER_INFO *DriverInfo;
MEMORY_PROFILE_ALLOC_SUMMARY_INFO *AllocSummaryInfo;
CHAR8 *NameString;
if (ContextSummaryData == NULL) {
return;
}
Print (L"\nSummary Data:\n");
DriverSummaryInfoList = ContextSummaryData->DriverSummaryInfoList;
for (DriverSummaryLink = DriverSummaryInfoList->ForwardLink;
DriverSummaryLink != DriverSummaryInfoList;
DriverSummaryLink = DriverSummaryLink->ForwardLink)
{
DriverSummaryInfoData = CR (
DriverSummaryLink,
MEMORY_PROFILE_DRIVER_SUMMARY_INFO_DATA,
Link,
MEMORY_PROFILE_DRIVER_INFO_SIGNATURE
);
DriverInfo = DriverSummaryInfoData->DriverInfo;
NameString = GetDriverNameString (DriverInfo);
Print (L"\nDriver - %a (Usage - 0x%08x)", NameString, DriverInfo->CurrentUsage);
if (DriverInfo->CurrentUsage == 0) {
Print (L"\n");
continue;
}
if (DriverInfo->PdbStringOffset != 0) {
Print (L" (Pdb - %a)\n", (CHAR8 *)((UINTN)DriverInfo + DriverInfo->PdbStringOffset));
} else {
Print (L"\n");
}
Print (L"Caller List:\n");
Print (L" Count Size RVA Action\n");
Print (L"========== ================== ================== (================================)\n");
AllocSummaryInfoList = DriverSummaryInfoData->AllocSummaryInfoList;
for (AllocSummaryLink = AllocSummaryInfoList->ForwardLink;
AllocSummaryLink != AllocSummaryInfoList;
AllocSummaryLink = AllocSummaryLink->ForwardLink)
{
AllocSummaryInfoData = CR (
AllocSummaryLink,
MEMORY_PROFILE_ALLOC_SUMMARY_INFO_DATA,
Link,
MEMORY_PROFILE_ALLOC_SUMMARY_INFO_SIGNATURE
);
AllocSummaryInfo = &AllocSummaryInfoData->AllocSummaryInfo;
Print (
L"0x%08x 0x%016lx <== 0x%016lx",
AllocSummaryInfo->AllocateCount,
AllocSummaryInfo->TotalSize,
AllocSummaryInfo->CallerAddress - DriverInfo->ImageBase
);
Print (L" (%a)\n", ProfileActionToStr (AllocSummaryInfo->Action, AllocSummaryInfo->ActionString, IsForSmm));
}
}
return;
}
/**
Destroy Context summary information.
@param[in, out] ContextSummaryData Context summary information data.
**/
VOID
DestroyContextSummaryData (
IN OUT MEMORY_PROFILE_CONTEXT_SUMMARY_DATA *ContextSummaryData
)
{
MEMORY_PROFILE_DRIVER_SUMMARY_INFO_DATA *DriverSummaryInfoData;
MEMORY_PROFILE_ALLOC_SUMMARY_INFO_DATA *AllocSummaryInfoData;
LIST_ENTRY *DriverSummaryInfoList;
LIST_ENTRY *DriverSummaryLink;
LIST_ENTRY *AllocSummaryInfoList;
LIST_ENTRY *AllocSummaryLink;
if (ContextSummaryData == NULL) {
return;
}
DriverSummaryInfoList = ContextSummaryData->DriverSummaryInfoList;
for (DriverSummaryLink = DriverSummaryInfoList->ForwardLink;
DriverSummaryLink != DriverSummaryInfoList;
)
{
DriverSummaryInfoData = CR (
DriverSummaryLink,
MEMORY_PROFILE_DRIVER_SUMMARY_INFO_DATA,
Link,
MEMORY_PROFILE_DRIVER_INFO_SIGNATURE
);
DriverSummaryLink = DriverSummaryLink->ForwardLink;
AllocSummaryInfoList = DriverSummaryInfoData->AllocSummaryInfoList;
for (AllocSummaryLink = AllocSummaryInfoList->ForwardLink;
AllocSummaryLink != AllocSummaryInfoList;
)
{
AllocSummaryInfoData = CR (
AllocSummaryLink,
MEMORY_PROFILE_ALLOC_SUMMARY_INFO_DATA,
Link,
MEMORY_PROFILE_ALLOC_SUMMARY_INFO_SIGNATURE
);
AllocSummaryLink = AllocSummaryLink->ForwardLink;
RemoveEntryList (&AllocSummaryInfoData->Link);
FreePool (AllocSummaryInfoData);
}
RemoveEntryList (&DriverSummaryInfoData->Link);
FreePool (DriverSummaryInfoData);
}
return;
}
/**
Get and dump UEFI memory profile data.
@return EFI_SUCCESS Get the memory profile data successfully.
@return other Fail to get the memory profile data.
**/
EFI_STATUS
GetUefiMemoryProfileData (
VOID
)
{
EFI_STATUS Status;
EDKII_MEMORY_PROFILE_PROTOCOL *ProfileProtocol;
VOID *Data;
UINT64 Size;
MEMORY_PROFILE_CONTEXT_SUMMARY_DATA *MemoryProfileContextSummaryData;
BOOLEAN RecordingState;
Status = gBS->LocateProtocol (&gEdkiiMemoryProfileGuid, NULL, (VOID **)&ProfileProtocol);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "UefiMemoryProfile: Locate MemoryProfile protocol - %r\n", Status));
return Status;
}
//
// Set recording state if needed.
//
RecordingState = MEMORY_PROFILE_RECORDING_DISABLE;
Status = ProfileProtocol->GetRecordingState (ProfileProtocol, &RecordingState);
if (RecordingState == MEMORY_PROFILE_RECORDING_ENABLE) {
ProfileProtocol->SetRecordingState (ProfileProtocol, MEMORY_PROFILE_RECORDING_DISABLE);
}
Size = 0;
Data = NULL;
Status = ProfileProtocol->GetData (
ProfileProtocol,
&Size,
Data
);
if (Status != EFI_BUFFER_TOO_SMALL) {
Print (L"UefiMemoryProfile: GetData - %r\n", Status);
goto Done;
}
Data = AllocateZeroPool ((UINTN)Size);
if (Data == NULL) {
Status = EFI_OUT_OF_RESOURCES;
Print (L"UefiMemoryProfile: AllocateZeroPool (0x%x) - %r\n", Size, Status);
return Status;
}
Status = ProfileProtocol->GetData (
ProfileProtocol,
&Size,
Data
);
if (EFI_ERROR (Status)) {
Print (L"UefiMemoryProfile: GetData - %r\n", Status);
goto Done;
}
Print (L"UefiMemoryProfileSize - 0x%x\n", Size);
Print (L"======= UefiMemoryProfile begin =======\n");
DumpMemoryProfile ((PHYSICAL_ADDRESS)(UINTN)Data, Size, FALSE);
//
// Dump summary information
//
MemoryProfileContextSummaryData = CreateContextSummaryData ((PHYSICAL_ADDRESS)(UINTN)Data, Size);
if (MemoryProfileContextSummaryData != NULL) {
DumpContextSummaryData (MemoryProfileContextSummaryData, FALSE);
DestroyContextSummaryData (MemoryProfileContextSummaryData);
}
Print (L"======= UefiMemoryProfile end =======\n\n\n");
Done:
if (Data != NULL) {
FreePool (Data);
}
//
// Restore recording state if needed.
//
if (RecordingState == MEMORY_PROFILE_RECORDING_ENABLE) {
ProfileProtocol->SetRecordingState (ProfileProtocol, MEMORY_PROFILE_RECORDING_ENABLE);
}
return Status;
}
/**
Get and dump SMRAM profile data.
@return EFI_SUCCESS Get the SMRAM profile data successfully.
@return other Fail to get the SMRAM profile data.
**/
EFI_STATUS
GetSmramProfileData (
VOID
)
{
EFI_STATUS Status;
UINTN CommSize;
UINT8 *CommBuffer;
EFI_SMM_COMMUNICATE_HEADER *CommHeader;
SMRAM_PROFILE_PARAMETER_GET_PROFILE_INFO *CommGetProfileInfo;
SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA_BY_OFFSET *CommGetProfileData;
SMRAM_PROFILE_PARAMETER_RECORDING_STATE *CommRecordingState;
UINTN ProfileSize;
VOID *ProfileBuffer;
EFI_SMM_COMMUNICATION_PROTOCOL *SmmCommunication;
UINTN MinimalSizeNeeded;
EDKII_PI_SMM_COMMUNICATION_REGION_TABLE *PiSmmCommunicationRegionTable;
UINT32 Index;
EFI_MEMORY_DESCRIPTOR *Entry;
VOID *Buffer;
UINTN Size;
UINTN Offset;
MEMORY_PROFILE_CONTEXT_SUMMARY_DATA *MemoryProfileContextSummaryData;
BOOLEAN RecordingState;
ProfileBuffer = NULL;
Status = gBS->LocateProtocol (&gEfiSmmCommunicationProtocolGuid, NULL, (VOID **)&SmmCommunication);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "SmramProfile: Locate SmmCommunication protocol - %r\n", Status));
return Status;
}
MinimalSizeNeeded = sizeof (EFI_GUID) +
sizeof (UINTN) +
MAX (
sizeof (SMRAM_PROFILE_PARAMETER_GET_PROFILE_INFO),
MAX (
sizeof (SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA_BY_OFFSET),
sizeof (SMRAM_PROFILE_PARAMETER_RECORDING_STATE)
)
);
MinimalSizeNeeded += MAX (
sizeof (MEMORY_PROFILE_CONTEXT),
MAX (
sizeof (MEMORY_PROFILE_DRIVER_INFO),
MAX (
sizeof (MEMORY_PROFILE_ALLOC_INFO),
MAX (
sizeof (MEMORY_PROFILE_DESCRIPTOR),
MAX (
sizeof (MEMORY_PROFILE_FREE_MEMORY),
sizeof (MEMORY_PROFILE_MEMORY_RANGE)
)
)
)
)
);
Status = EfiGetSystemConfigurationTable (
&gEdkiiPiSmmCommunicationRegionTableGuid,
(VOID **)&PiSmmCommunicationRegionTable
);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "SmramProfile: Get PiSmmCommunicationRegionTable - %r\n", Status));
return Status;
}
ASSERT (PiSmmCommunicationRegionTable != NULL);
Entry = (EFI_MEMORY_DESCRIPTOR *)(PiSmmCommunicationRegionTable + 1);
Size = 0;
for (Index = 0; Index < PiSmmCommunicationRegionTable->NumberOfEntries; Index++) {
if (Entry->Type == EfiConventionalMemory) {
Size = EFI_PAGES_TO_SIZE ((UINTN)Entry->NumberOfPages);
if (Size >= MinimalSizeNeeded) {
break;
}
}
Entry = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)Entry + PiSmmCommunicationRegionTable->DescriptorSize);
}
ASSERT (Index < PiSmmCommunicationRegionTable->NumberOfEntries);
CommBuffer = (UINT8 *)(UINTN)Entry->PhysicalStart;
//
// Set recording state if needed.
//
RecordingState = MEMORY_PROFILE_RECORDING_DISABLE;
CommHeader = (EFI_SMM_COMMUNICATE_HEADER *)&CommBuffer[0];
CopyMem (&CommHeader->HeaderGuid, &gEdkiiMemoryProfileGuid, sizeof (gEdkiiMemoryProfileGuid));
CommHeader->MessageLength = sizeof (SMRAM_PROFILE_PARAMETER_RECORDING_STATE);
CommRecordingState = (SMRAM_PROFILE_PARAMETER_RECORDING_STATE *)&CommBuffer[OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data)];
CommRecordingState->Header.Command = SMRAM_PROFILE_COMMAND_GET_RECORDING_STATE;
CommRecordingState->Header.DataLength = sizeof (*CommRecordingState);
CommRecordingState->Header.ReturnStatus = (UINT64)-1;
CommRecordingState->RecordingState = MEMORY_PROFILE_RECORDING_DISABLE;
CommSize = sizeof (EFI_GUID) + sizeof (UINTN) + CommHeader->MessageLength;
Status = SmmCommunication->Communicate (SmmCommunication, CommBuffer, &CommSize);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "SmramProfile: SmmCommunication - %r\n", Status));
return Status;
}
if (CommRecordingState->Header.ReturnStatus != 0) {
Print (L"SmramProfile: GetRecordingState - 0x%0x\n", CommRecordingState->Header.ReturnStatus);
return EFI_SUCCESS;
}
RecordingState = CommRecordingState->RecordingState;
if (RecordingState == MEMORY_PROFILE_RECORDING_ENABLE) {
CommHeader = (EFI_SMM_COMMUNICATE_HEADER *)&CommBuffer[0];
CopyMem (&CommHeader->HeaderGuid, &gEdkiiMemoryProfileGuid, sizeof (gEdkiiMemoryProfileGuid));
CommHeader->MessageLength = sizeof (SMRAM_PROFILE_PARAMETER_RECORDING_STATE);
CommRecordingState = (SMRAM_PROFILE_PARAMETER_RECORDING_STATE *)&CommBuffer[OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data)];
CommRecordingState->Header.Command = SMRAM_PROFILE_COMMAND_SET_RECORDING_STATE;
CommRecordingState->Header.DataLength = sizeof (*CommRecordingState);
CommRecordingState->Header.ReturnStatus = (UINT64)-1;
CommRecordingState->RecordingState = MEMORY_PROFILE_RECORDING_DISABLE;
CommSize = sizeof (EFI_GUID) + sizeof (UINTN) + CommHeader->MessageLength;
SmmCommunication->Communicate (SmmCommunication, CommBuffer, &CommSize);
}
//
// Get Size
//
CommHeader = (EFI_SMM_COMMUNICATE_HEADER *)&CommBuffer[0];
CopyMem (&CommHeader->HeaderGuid, &gEdkiiMemoryProfileGuid, sizeof (gEdkiiMemoryProfileGuid));
CommHeader->MessageLength = sizeof (SMRAM_PROFILE_PARAMETER_GET_PROFILE_INFO);
CommGetProfileInfo = (SMRAM_PROFILE_PARAMETER_GET_PROFILE_INFO *)&CommBuffer[OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data)];
CommGetProfileInfo->Header.Command = SMRAM_PROFILE_COMMAND_GET_PROFILE_INFO;
CommGetProfileInfo->Header.DataLength = sizeof (*CommGetProfileInfo);
CommGetProfileInfo->Header.ReturnStatus = (UINT64)-1;
CommGetProfileInfo->ProfileSize = 0;
CommSize = sizeof (EFI_GUID) + sizeof (UINTN) + CommHeader->MessageLength;
Status = SmmCommunication->Communicate (SmmCommunication, CommBuffer, &CommSize);
ASSERT_EFI_ERROR (Status);
if (CommGetProfileInfo->Header.ReturnStatus != 0) {
Status = EFI_SUCCESS;
Print (L"SmramProfile: GetProfileInfo - 0x%0x\n", CommGetProfileInfo->Header.ReturnStatus);
goto Done;
}
ProfileSize = (UINTN)CommGetProfileInfo->ProfileSize;
//
// Get Data
//
ProfileBuffer = AllocateZeroPool (ProfileSize);
if (ProfileBuffer == NULL) {
Status = EFI_OUT_OF_RESOURCES;
Print (L"SmramProfile: AllocateZeroPool (0x%x) for profile buffer - %r\n", ProfileSize, Status);
goto Done;
}
CommHeader = (EFI_SMM_COMMUNICATE_HEADER *)&CommBuffer[0];
CopyMem (&CommHeader->HeaderGuid, &gEdkiiMemoryProfileGuid, sizeof (gEdkiiMemoryProfileGuid));
CommHeader->MessageLength = sizeof (SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA_BY_OFFSET);
CommGetProfileData = (SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA_BY_OFFSET *)&CommBuffer[OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data)];
CommGetProfileData->Header.Command = SMRAM_PROFILE_COMMAND_GET_PROFILE_DATA_BY_OFFSET;
CommGetProfileData->Header.DataLength = sizeof (*CommGetProfileData);
CommGetProfileData->Header.ReturnStatus = (UINT64)-1;
CommSize = sizeof (EFI_GUID) + sizeof (UINTN) + CommHeader->MessageLength;
Buffer = (UINT8 *)CommHeader + CommSize;
Size -= CommSize;
CommGetProfileData->ProfileBuffer = (PHYSICAL_ADDRESS)(UINTN)Buffer;
CommGetProfileData->ProfileOffset = 0;
while (CommGetProfileData->ProfileOffset < ProfileSize) {
Offset = (UINTN)CommGetProfileData->ProfileOffset;
if (Size <= (ProfileSize - CommGetProfileData->ProfileOffset)) {
CommGetProfileData->ProfileSize = (UINT64)Size;
} else {
CommGetProfileData->ProfileSize = (UINT64)(ProfileSize - CommGetProfileData->ProfileOffset);
}
Status = SmmCommunication->Communicate (SmmCommunication, CommBuffer, &CommSize);
ASSERT_EFI_ERROR (Status);
if (CommGetProfileData->Header.ReturnStatus != 0) {
Status = EFI_SUCCESS;
Print (L"GetProfileData - 0x%x\n", CommGetProfileData->Header.ReturnStatus);
goto Done;
}
CopyMem ((UINT8 *)ProfileBuffer + Offset, (VOID *)(UINTN)CommGetProfileData->ProfileBuffer, (UINTN)CommGetProfileData->ProfileSize);
}
Print (L"SmramProfileSize - 0x%x\n", ProfileSize);
Print (L"======= SmramProfile begin =======\n");
DumpMemoryProfile ((PHYSICAL_ADDRESS)(UINTN)ProfileBuffer, ProfileSize, TRUE);
//
// Dump summary information
//
MemoryProfileContextSummaryData = CreateContextSummaryData ((PHYSICAL_ADDRESS)(UINTN)ProfileBuffer, ProfileSize);
if (MemoryProfileContextSummaryData != NULL) {
DumpContextSummaryData (MemoryProfileContextSummaryData, TRUE);
DestroyContextSummaryData (MemoryProfileContextSummaryData);
}
Print (L"======= SmramProfile end =======\n\n\n");
Done:
if (ProfileBuffer != NULL) {
FreePool (ProfileBuffer);
}
//
// Restore recording state if needed.
//
if (RecordingState == MEMORY_PROFILE_RECORDING_ENABLE) {
CommHeader = (EFI_SMM_COMMUNICATE_HEADER *)&CommBuffer[0];
CopyMem (&CommHeader->HeaderGuid, &gEdkiiMemoryProfileGuid, sizeof (gEdkiiMemoryProfileGuid));
CommHeader->MessageLength = sizeof (SMRAM_PROFILE_PARAMETER_RECORDING_STATE);
CommRecordingState = (SMRAM_PROFILE_PARAMETER_RECORDING_STATE *)&CommBuffer[OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data)];
CommRecordingState->Header.Command = SMRAM_PROFILE_COMMAND_SET_RECORDING_STATE;
CommRecordingState->Header.DataLength = sizeof (*CommRecordingState);
CommRecordingState->Header.ReturnStatus = (UINT64)-1;
CommRecordingState->RecordingState = MEMORY_PROFILE_RECORDING_ENABLE;
CommSize = sizeof (EFI_GUID) + sizeof (UINTN) + CommHeader->MessageLength;
SmmCommunication->Communicate (SmmCommunication, CommBuffer, &CommSize);
}
return Status;
}
/**
The user Entry Point for Application. The user code starts with this function
as the real entry point for the image goes into a library that calls this function.
@param[in] ImageHandle The firmware allocated handle for the EFI image.
@param[in] SystemTable A pointer to the EFI System Table.
@retval EFI_SUCCESS The entry point is executed successfully.
@retval other Some error occurs when executing this entry point.
**/
EFI_STATUS
EFIAPI
UefiMain (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
Status = GetUefiMemoryProfileData ();
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "GetUefiMemoryProfileData - %r\n", Status));
}
Status = GetSmramProfileData ();
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "GetSmramProfileData - %r\n", Status));
}
return EFI_SUCCESS;
}