audk/MdeModulePkg/Core/PiSmmCore/SmramProfileRecord.c

2104 lines
70 KiB
C

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