/** @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; | |
} |