blob: 1b302c810cc927d6757a088ef7ac98896d9190d2 [file] [log] [blame]
/** @file
Support routines for SMRAM profile.
Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "PiSmmCore.h"
#define IS_SMRAM_PROFILE_ENABLED ((PcdGet8 (PcdMemoryProfilePropertyMask) & BIT1) != 0)
#define IS_UEFI_MEMORY_PROFILE_ENABLED ((PcdGet8 (PcdMemoryProfilePropertyMask) & BIT0) != 0)
#define GET_OCCUPIED_SIZE(ActualSize, Alignment) \
((ActualSize) + (((Alignment) - ((ActualSize) & ((Alignment) - 1))) & ((Alignment) - 1)))
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;
CHAR8 *PdbString;
LIST_ENTRY Link;
} MEMORY_PROFILE_DRIVER_INFO_DATA;
typedef struct {
UINT32 Signature;
MEMORY_PROFILE_ALLOC_INFO AllocInfo;
CHAR8 *ActionString;
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;
GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mSmramReadyToLock;
GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mSmramProfileGettingStatus = FALSE;
GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mSmramProfileRecordingEnable = MEMORY_PROFILE_RECORDING_DISABLE;
GLOBAL_REMOVE_IF_UNREFERENCED EFI_DEVICE_PATH_PROTOCOL *mSmramProfileDriverPath;
GLOBAL_REMOVE_IF_UNREFERENCED UINTN mSmramProfileDriverPathSize;
/**
Dump SMRAM information.
**/
VOID
DumpSmramInfo (
VOID
);
/**
Get memory profile data.
@param[in] This The EDKII_SMM_MEMORY_PROFILE_PROTOCOL instance.
@param[in, out] ProfileSize On entry, points to the size in bytes of the ProfileBuffer.
On return, points to the size of the data returned in ProfileBuffer.
@param[out] ProfileBuffer Profile buffer.
@return EFI_SUCCESS Get the memory profile data successfully.
@return EFI_UNSUPPORTED Memory profile is unsupported.
@return EFI_BUFFER_TO_SMALL The ProfileSize is too small for the resulting data.
ProfileSize is updated with the size required.
**/
EFI_STATUS
EFIAPI
SmramProfileProtocolGetData (
IN EDKII_SMM_MEMORY_PROFILE_PROTOCOL *This,
IN OUT UINT64 *ProfileSize,
OUT VOID *ProfileBuffer
);
/**
Register image to memory profile.
@param[in] This The EDKII_SMM_MEMORY_PROFILE_PROTOCOL instance.
@param[in] FilePath File path of the image.
@param[in] ImageBase Image base address.
@param[in] ImageSize Image size.
@param[in] FileType File type of the image.
@return EFI_SUCCESS Register successfully.
@return EFI_UNSUPPORTED Memory profile is unsupported,
or memory profile for the image is not required.
@return EFI_OUT_OF_RESOURCE No enough resource for this register.
**/
EFI_STATUS
EFIAPI
SmramProfileProtocolRegisterImage (
IN EDKII_SMM_MEMORY_PROFILE_PROTOCOL *This,
IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
IN PHYSICAL_ADDRESS ImageBase,
IN UINT64 ImageSize,
IN EFI_FV_FILETYPE FileType
);
/**
Unregister image from memory profile.
@param[in] This The EDKII_SMM_MEMORY_PROFILE_PROTOCOL instance.
@param[in] FilePath File path of the image.
@param[in] ImageBase Image base address.
@param[in] ImageSize Image size.
@return EFI_SUCCESS Unregister successfully.
@return EFI_UNSUPPORTED Memory profile is unsupported,
or memory profile for the image is not required.
@return EFI_NOT_FOUND The image is not found.
**/
EFI_STATUS
EFIAPI
SmramProfileProtocolUnregisterImage (
IN EDKII_SMM_MEMORY_PROFILE_PROTOCOL *This,
IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
IN PHYSICAL_ADDRESS ImageBase,
IN UINT64 ImageSize
);
/**
Get memory profile recording state.
@param[in] This The EDKII_SMM_MEMORY_PROFILE_PROTOCOL instance.
@param[out] RecordingState Recording state.
@return EFI_SUCCESS Memory profile recording state is returned.
@return EFI_UNSUPPORTED Memory profile is unsupported.
@return EFI_INVALID_PARAMETER RecordingState is NULL.
**/
EFI_STATUS
EFIAPI
SmramProfileProtocolGetRecordingState (
IN EDKII_SMM_MEMORY_PROFILE_PROTOCOL *This,
OUT BOOLEAN *RecordingState
);
/**
Set memory profile recording state.
@param[in] This The EDKII_SMM_MEMORY_PROFILE_PROTOCOL instance.
@param[in] RecordingState Recording state.
@return EFI_SUCCESS Set memory profile recording state successfully.
@return EFI_UNSUPPORTED Memory profile is unsupported.
**/
EFI_STATUS
EFIAPI
SmramProfileProtocolSetRecordingState (
IN EDKII_SMM_MEMORY_PROFILE_PROTOCOL *This,
IN BOOLEAN RecordingState
);
/**
Record memory profile of multilevel caller.
@param[in] This The EDKII_SMM_MEMORY_PROFILE_PROTOCOL instance.
@param[in] CallerAddress Address of caller.
@param[in] Action Memory profile action.
@param[in] MemoryType Memory type.
EfiMaxMemoryType means the MemoryType is unknown.
@param[in] Buffer Buffer address.
@param[in] Size Buffer size.
@param[in] ActionString String for memory profile action.
Only needed for user defined allocate action.
@return EFI_SUCCESS Memory profile is updated.
@return EFI_UNSUPPORTED Memory profile is unsupported,
or memory profile for the image is not required,
or memory profile for the memory type is not required.
@return EFI_ACCESS_DENIED It is during memory profile data getting.
@return EFI_ABORTED Memory profile recording is not enabled.
@return EFI_OUT_OF_RESOURCES No enough resource to update memory profile for allocate action.
@return EFI_NOT_FOUND No matched allocate info found for free action.
**/
EFI_STATUS
EFIAPI
SmramProfileProtocolRecord (
IN EDKII_SMM_MEMORY_PROFILE_PROTOCOL *This,
IN PHYSICAL_ADDRESS CallerAddress,
IN MEMORY_PROFILE_ACTION Action,
IN EFI_MEMORY_TYPE MemoryType,
IN VOID *Buffer,
IN UINTN Size,
IN CHAR8 *ActionString OPTIONAL
);
GLOBAL_REMOVE_IF_UNREFERENCED EDKII_SMM_MEMORY_PROFILE_PROTOCOL mSmmProfileProtocol = {
SmramProfileProtocolGetData,
SmramProfileProtocolRegisterImage,
SmramProfileProtocolUnregisterImage,
SmramProfileProtocolGetRecordingState,
SmramProfileProtocolSetRecordingState,
SmramProfileProtocolRecord,
};
/**
Return SMRAM profile context.
@return SMRAM profile context.
**/
MEMORY_PROFILE_CONTEXT_DATA *
GetSmramProfileContext (
VOID
)
{
return mSmramProfileContextPtr;
}
/**
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 = Hdr.Pe32->OptionalHeader.Magic;
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;
CHAR8 *PdbString;
UINTN PdbSize;
UINTN PdbOccupiedSize;
PdbSize = 0;
PdbOccupiedSize = 0;
PdbString = NULL;
if (ImageBase != 0) {
PdbString = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageBase);
if (PdbString != NULL) {
PdbSize = AsciiStrSize (PdbString);
PdbOccupiedSize = GET_OCCUPIED_SIZE (PdbSize, sizeof (UINT64));
}
}
//
// Use SmmInternalAllocatePool() that will not update profile for this AllocatePool action.
//
Status = SmmInternalAllocatePool (
EfiRuntimeServicesData,
sizeof (*DriverInfoData) + sizeof (LIST_ENTRY) + PdbSize,
(VOID **) &DriverInfoData
);
if (EFI_ERROR (Status)) {
return NULL;
}
ASSERT (DriverInfoData != 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 = (UINT16) (sizeof (MEMORY_PROFILE_DRIVER_INFO) + PdbOccupiedSize);
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;
if (PdbSize != 0) {
DriverInfo->PdbStringOffset = (UINT16) sizeof (MEMORY_PROFILE_DRIVER_INFO);
DriverInfoData->PdbString = (CHAR8 *) (DriverInfoData->AllocInfoList + 1);
CopyMem (DriverInfoData->PdbString, PdbString, PdbSize);
} else {
DriverInfo->PdbStringOffset = 0;
DriverInfoData->PdbString = NULL;
}
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_UEFI_MEMORY_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_UEFI_MEMORY_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
);
}
}
}
/**
Return if record for this driver is needed..
@param DriverFilePath Driver file path.
@retval TRUE Record for this driver is needed.
@retval FALSE Record for this driver is not needed.
**/
BOOLEAN
NeedRecordThisDriver (
IN EFI_DEVICE_PATH_PROTOCOL *DriverFilePath
)
{
EFI_DEVICE_PATH_PROTOCOL *TmpDevicePath;
EFI_DEVICE_PATH_PROTOCOL *DevicePathInstance;
UINTN DevicePathSize;
UINTN FilePathSize;
if (!IsDevicePathValid (mSmramProfileDriverPath, mSmramProfileDriverPathSize)) {
//
// Invalid Device Path means record all.
//
return TRUE;
}
//
// Record FilePath without end node.
//
FilePathSize = GetDevicePathSize (DriverFilePath) - sizeof(EFI_DEVICE_PATH_PROTOCOL);
DevicePathInstance = mSmramProfileDriverPath;
do {
//
// Find End node (it might be END_ENTIRE or END_INSTANCE)
//
TmpDevicePath = DevicePathInstance;
while (!IsDevicePathEndType (TmpDevicePath)) {
TmpDevicePath = NextDevicePathNode (TmpDevicePath);
}
//
// Do not compare END node
//
DevicePathSize = (UINTN)TmpDevicePath - (UINTN)DevicePathInstance;
if ((FilePathSize == DevicePathSize) &&
(CompareMem (DriverFilePath, DevicePathInstance, DevicePathSize) == 0)) {
return TRUE;
}
//
// Get next instance
//
DevicePathInstance = (EFI_DEVICE_PATH_PROTOCOL *)((UINTN)DevicePathInstance + DevicePathSize + DevicePathNodeLength(TmpDevicePath));
} while (DevicePathSubType (TmpDevicePath) != END_ENTIRE_DEVICE_PATH_SUBTYPE);
return FALSE;
}
/**
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;
UINT8 TempBuffer[sizeof(MEDIA_FW_VOL_FILEPATH_DEVICE_PATH) + sizeof(EFI_DEVICE_PATH_PROTOCOL)];
MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FilePath;
FilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) TempBuffer;
EfiInitializeFwVolDevicepathNode (FilePath, &gEfiCallerIdGuid);
SetDevicePathEndNode (FilePath + 1);
if (!NeedRecordThisDriver ((EFI_DEVICE_PATH_PROTOCOL *) FilePath)) {
return FALSE;
}
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;
RegisterImageToDxe (
&gEfiCallerIdGuid,
gSmmCorePrivate->PiSmmCoreImageBase,
gSmmCorePrivate->PiSmmCoreImageSize,
EFI_FV_FILETYPE_SMM_CORE
);
if (!IS_SMRAM_PROFILE_ENABLED) {
return;
}
SmramProfileContext = GetSmramProfileContext ();
if (SmramProfileContext != NULL) {
return;
}
mSmramProfileGettingStatus = FALSE;
if ((PcdGet8 (PcdMemoryProfilePropertyMask) & BIT7) != 0) {
mSmramProfileRecordingEnable = MEMORY_PROFILE_RECORDING_DISABLE;
} else {
mSmramProfileRecordingEnable = MEMORY_PROFILE_RECORDING_ENABLE;
}
mSmramProfileDriverPathSize = PcdGetSize (PcdMemoryProfileDriverPath);
mSmramProfileDriverPath = AllocateCopyPool (mSmramProfileDriverPathSize, PcdGetPtr (PcdMemoryProfileDriverPath));
mSmramProfileContextPtr = &mSmramProfileContext;
RegisterSmmCore (&mSmramProfileContext);
DEBUG ((EFI_D_INFO, "SmramProfileInit SmramProfileContext - 0x%x\n", &mSmramProfileContext));
}
/**
Install SMRAM profile protocol.
**/
VOID
SmramProfileInstallProtocol (
VOID
)
{
EFI_HANDLE Handle;
EFI_STATUS Status;
if (!IS_SMRAM_PROFILE_ENABLED) {
return;
}
Handle = NULL;
Status = SmmInstallProtocolInterface (
&Handle,
&gEdkiiSmmMemoryProfileGuid,
EFI_NATIVE_INTERFACE,
&mSmmProfileProtocol
);
ASSERT_EFI_ERROR (Status);
}
/**
Get the GUID file name from the file path.
@param FilePath File path.
@return The GUID file name from the file path.
**/
EFI_GUID *
GetFileNameFromFilePath (
IN EFI_DEVICE_PATH_PROTOCOL *FilePath
)
{
MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *ThisFilePath;
EFI_GUID *FileName;
FileName = NULL;
if (FilePath != NULL) {
ThisFilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) FilePath;
while (!IsDevicePathEnd (ThisFilePath)) {
FileName = EfiGetNameGuidFromFwVolDevicePathNode (ThisFilePath);
if (FileName != NULL) {
break;
}
ThisFilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) NextDevicePathNode (ThisFilePath);
}
}
return FileName;
}
/**
Register SMM image to SMRAM profile.
@param DriverEntry SMM image info.
@param RegisterToDxe Register image to DXE.
@return EFI_SUCCESS Register successfully.
@return EFI_UNSUPPORTED Memory profile is unsupported,
or memory profile for the image is not required.
@return EFI_OUT_OF_RESOURCES No enough resource for this register.
**/
EFI_STATUS
RegisterSmramProfileImage (
IN EFI_SMM_DRIVER_ENTRY *DriverEntry,
IN BOOLEAN RegisterToDxe
)
{
MEMORY_PROFILE_CONTEXT_DATA *ContextData;
MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
UINT8 TempBuffer[sizeof(MEDIA_FW_VOL_FILEPATH_DEVICE_PATH) + sizeof(EFI_DEVICE_PATH_PROTOCOL)];
MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FilePath;
if (RegisterToDxe) {
RegisterImageToDxe (
&DriverEntry->FileName,
DriverEntry->ImageBuffer,
EFI_PAGES_TO_SIZE (DriverEntry->NumberOfPage),
EFI_FV_FILETYPE_SMM
);
}
if (!IS_SMRAM_PROFILE_ENABLED) {
return EFI_UNSUPPORTED;
}
FilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) TempBuffer;
EfiInitializeFwVolDevicepathNode (FilePath, &DriverEntry->FileName);
SetDevicePathEndNode (FilePath + 1);
if (!NeedRecordThisDriver ((EFI_DEVICE_PATH_PROTOCOL *) FilePath)) {
return EFI_UNSUPPORTED;
}
ContextData = GetSmramProfileContext ();
if (ContextData == NULL) {
return EFI_UNSUPPORTED;
}
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 EFI_OUT_OF_RESOURCES;
}
return EFI_SUCCESS;
}
/**
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 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;
}
}
return NULL;
}
/**
Unregister image from SMRAM profile.
@param DriverEntry SMM image info.
@param UnregisterFromDxe Unregister image from DXE.
@return EFI_SUCCESS Unregister successfully.
@return EFI_UNSUPPORTED Memory profile is unsupported,
or memory profile for the image is not required.
@return EFI_NOT_FOUND The image is not found.
**/
EFI_STATUS
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;
UINT8 TempBuffer[sizeof(MEDIA_FW_VOL_FILEPATH_DEVICE_PATH) + sizeof(EFI_DEVICE_PATH_PROTOCOL)];
MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FilePath;
if (UnregisterFromDxe) {
UnregisterImageFromDxe (
&DriverEntry->FileName,
DriverEntry->ImageBuffer,
EFI_PAGES_TO_SIZE (DriverEntry->NumberOfPage)
);
}
if (!IS_SMRAM_PROFILE_ENABLED) {
return EFI_UNSUPPORTED;
}
FilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) TempBuffer;
EfiInitializeFwVolDevicepathNode (FilePath, &DriverEntry->FileName);
SetDevicePathEndNode (FilePath + 1);
if (!NeedRecordThisDriver ((EFI_DEVICE_PATH_PROTOCOL *) FilePath)) {
return EFI_UNSUPPORTED;
}
ContextData = GetSmramProfileContext ();
if (ContextData == NULL) {
return EFI_UNSUPPORTED;
}
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 EFI_NOT_FOUND;
}
ContextData->Context.TotalImageSize -= DriverInfoData->DriverInfo.ImageSize;
// Keep the ImageBase for RVA calculation in Application.
//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 EFI_SUCCESS;
}
/**
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.
@param ActionString String for memory profile action.
@return EFI_SUCCESS Memory profile is updated.
@return EFI_UNSUPPORTED Memory profile is unsupported,
or memory profile for the image is not required.
@return EFI_OUT_OF_RESOURCES No enough resource to update memory profile for allocate action.
**/
EFI_STATUS
SmmCoreUpdateProfileAllocate (
IN PHYSICAL_ADDRESS CallerAddress,
IN MEMORY_PROFILE_ACTION Action,
IN EFI_MEMORY_TYPE MemoryType,
IN UINTN Size,
IN VOID *Buffer,
IN CHAR8 *ActionString OPTIONAL
)
{
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;
MEMORY_PROFILE_ACTION BasicAction;
UINTN ActionStringSize;
UINTN ActionStringOccupiedSize;
BasicAction = Action & MEMORY_PROFILE_ACTION_BASIC_MASK;
ContextData = GetSmramProfileContext ();
if (ContextData == NULL) {
return EFI_UNSUPPORTED;
}
DriverInfoData = GetMemoryProfileDriverInfoFromAddress (ContextData, CallerAddress);
if (DriverInfoData == NULL) {
return EFI_UNSUPPORTED;
}
ActionStringSize = 0;
ActionStringOccupiedSize = 0;
if (ActionString != NULL) {
ActionStringSize = AsciiStrSize (ActionString);
ActionStringOccupiedSize = GET_OCCUPIED_SIZE (ActionStringSize, sizeof (UINT64));
}
//
// Use SmmInternalAllocatePool() that will not update profile for this AllocatePool action.
//
AllocInfoData = NULL;
Status = SmmInternalAllocatePool (
EfiRuntimeServicesData,
sizeof (*AllocInfoData) + ActionStringSize,
(VOID **) &AllocInfoData
);
if (EFI_ERROR (Status)) {
return EFI_OUT_OF_RESOURCES;
}
ASSERT (AllocInfoData != NULL);
//
// Only update SequenceCount if and only if it is basic action.
//
if (Action == BasicAction) {
ContextData->Context.SequenceCount ++;
}
AllocInfo = &AllocInfoData->AllocInfo;
AllocInfoData->Signature = MEMORY_PROFILE_ALLOC_INFO_SIGNATURE;
AllocInfo->Header.Signature = MEMORY_PROFILE_ALLOC_INFO_SIGNATURE;
AllocInfo->Header.Length = (UINT16) (sizeof (MEMORY_PROFILE_ALLOC_INFO) + ActionStringOccupiedSize);
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;
if (ActionString != NULL) {
AllocInfo->ActionStringOffset = (UINT16) sizeof (MEMORY_PROFILE_ALLOC_INFO);
AllocInfoData->ActionString = (CHAR8 *) (AllocInfoData + 1);
CopyMem (AllocInfoData->ActionString, ActionString, ActionStringSize);
} else {
AllocInfo->ActionStringOffset = 0;
AllocInfoData->ActionString = NULL;
}
InsertTailList (DriverInfoData->AllocInfoList, &AllocInfoData->Link);
Context = &ContextData->Context;
DriverInfo = &DriverInfoData->DriverInfo;
DriverInfo->AllocRecordCount ++;
//
// Update summary if and only if it is basic action.
//
if (Action == BasicAction) {
ProfileMemoryIndex = GetProfileMemoryIndex (MemoryType);
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];
}
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];
}
SmramProfileUpdateFreePages (ContextData);
}
return EFI_SUCCESS;
}
/**
Get memory profile alloc info from memory profile
@param DriverInfoData Driver info
@param BasicAction This Free basic 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 BasicAction,
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 & MEMORY_PROFILE_ACTION_BASIC_MASK) != BasicAction) {
continue;
}
switch (BasicAction) {
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.
@return EFI_SUCCESS Memory profile is updated.
@return EFI_UNSUPPORTED Memory profile is unsupported.
@return EFI_NOT_FOUND No matched allocate info found for free action.
**/
EFI_STATUS
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;
MEMORY_PROFILE_ACTION BasicAction;
BOOLEAN Found;
BasicAction = Action & MEMORY_PROFILE_ACTION_BASIC_MASK;
ContextData = GetSmramProfileContext ();
if (ContextData == NULL) {
return EFI_UNSUPPORTED;
}
DriverInfoData = GetMemoryProfileDriverInfoFromAddress (ContextData, CallerAddress);
//
// Do not return if DriverInfoData == NULL here,
// because driver A might free memory allocated by driver B.
//
//
// Need use do-while loop to find all possible record,
// because one address might be recorded multiple times.
//
Found = FALSE;
AllocInfoData = NULL;
do {
if (DriverInfoData != NULL) {
switch (BasicAction) {
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 (BasicAction) {
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) {
//
// If (!Found), no matched allocate info is found for this free action.
// It is because the specified memory type allocate actions have been filtered by
// CoreNeedRecordProfile(), but free actions have no memory type information,
// they can not be filtered by CoreNeedRecordProfile(). Then, they will be
// filtered here.
//
// If (Found), it is normal exit path.
return (Found ? EFI_SUCCESS : EFI_NOT_FOUND);
}
}
ASSERT (DriverInfoData != NULL);
ASSERT (AllocInfoData != NULL);
Found = TRUE;
Context = &ContextData->Context;
DriverInfo = &DriverInfoData->DriverInfo;
AllocInfo = &AllocInfoData->AllocInfo;
DriverInfo->AllocRecordCount --;
//
// Update summary if and only if it is basic action.
//
if (AllocInfo->Action == (AllocInfo->Action & MEMORY_PROFILE_ACTION_BASIC_MASK)) {
ProfileMemoryIndex = GetProfileMemoryIndex (AllocInfo->MemoryType);
Context->CurrentTotalUsage -= AllocInfo->Size;
Context->CurrentTotalUsageByType[ProfileMemoryIndex] -= AllocInfo->Size;
DriverInfo->CurrentUsage -= AllocInfo->Size;
DriverInfo->CurrentUsageByType[ProfileMemoryIndex] -= AllocInfo->Size;
}
RemoveEntryList (&AllocInfoData->Link);
if (BasicAction == MemoryProfileActionFreePages) {
if (AllocInfo->Buffer != (PHYSICAL_ADDRESS) (UINTN) Buffer) {
SmmCoreUpdateProfileAllocate (
AllocInfo->CallerAddress,
AllocInfo->Action,
AllocInfo->MemoryType,
(UINTN) ((PHYSICAL_ADDRESS) (UINTN) Buffer - AllocInfo->Buffer),
(VOID *) (UINTN) AllocInfo->Buffer,
AllocInfoData->ActionString
);
}
if (AllocInfo->Buffer + AllocInfo->Size != ((PHYSICAL_ADDRESS) (UINTN) Buffer + Size)) {
SmmCoreUpdateProfileAllocate (
AllocInfo->CallerAddress,
AllocInfo->Action,
AllocInfo->MemoryType,
(UINTN) ((AllocInfo->Buffer + AllocInfo->Size) - ((PHYSICAL_ADDRESS) (UINTN) Buffer + Size)),
(VOID *) ((UINTN) Buffer + Size),
AllocInfoData->ActionString
);
}
}
//
// Use SmmInternalFreePool() that will not update profile for this FreePool action.
//
SmmInternalFreePool (AllocInfoData);
} while (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.
EfiMaxMemoryType means the MemoryType is unknown.
@param Size Buffer size.
@param Buffer Buffer address.
@param ActionString String for memory profile action.
Only needed for user defined allocate action.
@return EFI_SUCCESS Memory profile is updated.
@return EFI_UNSUPPORTED Memory profile is unsupported,
or memory profile for the image is not required,
or memory profile for the memory type is not required.
@return EFI_ACCESS_DENIED It is during memory profile data getting.
@return EFI_ABORTED Memory profile recording is not enabled.
@return EFI_OUT_OF_RESOURCES No enough resource to update memory profile for allocate action.
@return EFI_NOT_FOUND No matched allocate info found for free action.
**/
EFI_STATUS
EFIAPI
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,
IN CHAR8 *ActionString OPTIONAL
)
{
EFI_STATUS Status;
MEMORY_PROFILE_CONTEXT_DATA *ContextData;
MEMORY_PROFILE_ACTION BasicAction;
if (!IS_SMRAM_PROFILE_ENABLED) {
return EFI_UNSUPPORTED;
}
if (mSmramProfileGettingStatus) {
return EFI_ACCESS_DENIED;
}
if (!mSmramProfileRecordingEnable) {
return EFI_ABORTED;
}
//
// Get the basic action to know how to process the record
//
BasicAction = Action & MEMORY_PROFILE_ACTION_BASIC_MASK;
//
// Free operations have no memory type information, so skip the check.
//
if ((BasicAction == MemoryProfileActionAllocatePages) || (BasicAction == MemoryProfileActionAllocatePool)) {
//
// Only record limited MemoryType.
//
if (!SmmCoreNeedRecordProfile (MemoryType)) {
return EFI_UNSUPPORTED;
}
}
ContextData = GetSmramProfileContext ();
if (ContextData == NULL) {
return EFI_UNSUPPORTED;
}
switch (BasicAction) {
case MemoryProfileActionAllocatePages:
Status = SmmCoreUpdateProfileAllocate (CallerAddress, Action, MemoryType, Size, Buffer, ActionString);
break;
case MemoryProfileActionFreePages:
Status = SmmCoreUpdateProfileFree (CallerAddress, Action, Size, Buffer);
break;
case MemoryProfileActionAllocatePool:
Status = SmmCoreUpdateProfileAllocate (CallerAddress, Action, MemoryType, Size, Buffer, ActionString);
break;
case MemoryProfileActionFreePool:
Status = SmmCoreUpdateProfileFree (CallerAddress, Action, 0, Buffer);
break;
default:
ASSERT (FALSE);
Status = EFI_UNSUPPORTED;
break;
}
return Status;
}
/**
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;
MEMORY_PROFILE_ALLOC_INFO_DATA *AllocInfoData;
LIST_ENTRY *DriverInfoList;
LIST_ENTRY *DriverLink;
LIST_ENTRY *AllocInfoList;
LIST_ENTRY *AllocLink;
UINTN TotalSize;
LIST_ENTRY *Node;
LIST_ENTRY *FreePageList;
LIST_ENTRY *FreePoolList;
FREE_POOL_HEADER *Pool;
UINTN PoolListIndex;
UINTN Index;
UINTN SmmPoolTypeIndex;
ContextData = GetSmramProfileContext ();
if (ContextData == NULL) {
return 0;
}
TotalSize = 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
);
TotalSize += DriverInfoData->DriverInfo.Header.Length;
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
);
TotalSize += AllocInfoData->AllocInfo.Header.Length;
}
}
Index = 0;
FreePageList = &mSmmMemoryMap;
for (Node = FreePageList->BackLink;
Node != FreePageList;
Node = Node->BackLink) {
Index++;
}
for (SmmPoolTypeIndex = 0; SmmPoolTypeIndex < SmmPoolTypeMax; SmmPoolTypeIndex++) {
for (PoolListIndex = 0; PoolListIndex < MAX_POOL_INDEX; PoolListIndex++) {
FreePoolList = &mSmmPoolLists[SmmPoolTypeIndex][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;
UINTN PdbSize;
UINTN ActionStringSize;
UINTN SmmPoolTypeIndex;
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 + DriverInfoData->DriverInfo.Header.Length)) {
if (RemainingSize >= DriverInfoData->DriverInfo.Header.Length) {
DriverInfo = ProfileBuffer;
CopyMem (DriverInfo, &DriverInfoData->DriverInfo, sizeof (MEMORY_PROFILE_DRIVER_INFO));
if (DriverInfo->PdbStringOffset != 0) {
PdbSize = AsciiStrSize (DriverInfoData->PdbString);
CopyMem ((VOID *) ((UINTN) DriverInfo + DriverInfo->PdbStringOffset), DriverInfoData->PdbString, PdbSize);
}
RemainingSize -= DriverInfo->Header.Length;
ProfileBuffer = (UINT8 *) ProfileBuffer + DriverInfo->Header.Length;
} else {
goto Done;
}
}
Offset += DriverInfoData->DriverInfo.Header.Length;
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 + AllocInfoData->AllocInfo.Header.Length)) {
if (RemainingSize >= AllocInfoData->AllocInfo.Header.Length) {
AllocInfo = ProfileBuffer;
CopyMem (AllocInfo, &AllocInfoData->AllocInfo, sizeof (MEMORY_PROFILE_ALLOC_INFO));
if (AllocInfo->ActionStringOffset) {
ActionStringSize = AsciiStrSize (AllocInfoData->ActionString);
CopyMem ((VOID *) ((UINTN) AllocInfo + AllocInfo->ActionStringOffset), AllocInfoData->ActionString, ActionStringSize);
}
RemainingSize -= AllocInfo->Header.Length;
ProfileBuffer = (UINT8 *) ProfileBuffer + AllocInfo->Header.Length;
} else {
goto Done;
}
}
Offset += AllocInfoData->AllocInfo.Header.Length;
}
}
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 (SmmPoolTypeIndex = 0; SmmPoolTypeIndex < SmmPoolTypeMax; SmmPoolTypeIndex++) {
for (PoolListIndex = 0; PoolListIndex < MAX_POOL_INDEX; PoolListIndex++) {
FreePoolList = &mSmmPoolLists[SmmPoolTypeIndex][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 (SmmPoolTypeIndex = 0; SmmPoolTypeIndex < SmmPoolTypeMax; SmmPoolTypeIndex++) {
for (PoolListIndex = 0; PoolListIndex < MAX_POOL_INDEX; PoolListIndex++) {
FreePoolList = &mSmmPoolLists[SmmPoolTypeIndex][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;
}
/**
Get memory profile data.
@param[in] This The EDKII_SMM_MEMORY_PROFILE_PROTOCOL instance.
@param[in, out] ProfileSize On entry, points to the size in bytes of the ProfileBuffer.
On return, points to the size of the data returned in ProfileBuffer.
@param[out] ProfileBuffer Profile buffer.
@return EFI_SUCCESS Get the memory profile data successfully.
@return EFI_UNSUPPORTED Memory profile is unsupported.
@return EFI_BUFFER_TO_SMALL The ProfileSize is too small for the resulting data.
ProfileSize is updated with the size required.
**/
EFI_STATUS
EFIAPI
SmramProfileProtocolGetData (
IN EDKII_SMM_MEMORY_PROFILE_PROTOCOL *This,
IN OUT UINT64 *ProfileSize,
OUT VOID *ProfileBuffer
)
{
UINT64 Size;
UINT64 Offset;
MEMORY_PROFILE_CONTEXT_DATA *ContextData;
BOOLEAN SmramProfileGettingStatus;
ContextData = GetSmramProfileContext ();
if (ContextData == NULL) {
return EFI_UNSUPPORTED;
}
SmramProfileGettingStatus = mSmramProfileGettingStatus;
mSmramProfileGettingStatus = TRUE;
Size = SmramProfileGetDataSize ();
if (*ProfileSize < Size) {
*ProfileSize = Size;
mSmramProfileGettingStatus = SmramProfileGettingStatus;
return EFI_BUFFER_TOO_SMALL;
}
Offset = 0;
SmramProfileCopyData (ProfileBuffer, &Size, &Offset);
*ProfileSize = Size;
mSmramProfileGettingStatus = SmramProfileGettingStatus;
return EFI_SUCCESS;
}
/**
Register image to memory profile.
@param[in] This The EDKII_SMM_MEMORY_PROFILE_PROTOCOL instance.
@param[in] FilePath File path of the image.
@param[in] ImageBase Image base address.
@param[in] ImageSize Image size.
@param[in] FileType File type of the image.
@return EFI_SUCCESS Register successfully.
@return EFI_UNSUPPORTED Memory profile is unsupported,
or memory profile for the image is not required.
@return EFI_OUT_OF_RESOURCES No enough resource for this register.
**/
EFI_STATUS
EFIAPI
SmramProfileProtocolRegisterImage (
IN EDKII_SMM_MEMORY_PROFILE_PROTOCOL *This,
IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
IN PHYSICAL_ADDRESS ImageBase,
IN UINT64 ImageSize,
IN EFI_FV_FILETYPE FileType
)
{
EFI_STATUS Status;
EFI_SMM_DRIVER_ENTRY DriverEntry;
VOID *EntryPointInImage;
EFI_GUID *Name;
ZeroMem (&DriverEntry, sizeof (DriverEntry));
Name = GetFileNameFromFilePath (FilePath);
if (Name != NULL) {
CopyMem (&DriverEntry.FileName, Name, sizeof (EFI_GUID));
}
DriverEntry.ImageBuffer = ImageBase;
DriverEntry.NumberOfPage = EFI_SIZE_TO_PAGES ((UINTN) ImageSize);
Status = InternalPeCoffGetEntryPoint ((VOID *) (UINTN) DriverEntry.ImageBuffer, &EntryPointInImage);
ASSERT_EFI_ERROR (Status);
DriverEntry.ImageEntryPoint = (PHYSICAL_ADDRESS) (UINTN) EntryPointInImage;
return RegisterSmramProfileImage (&DriverEntry, FALSE);
}
/**
Unregister image from memory profile.
@param[in] This The EDKII_SMM_MEMORY_PROFILE_PROTOCOL instance.
@param[in] FilePath File path of the image.
@param[in] ImageBase Image base address.
@param[in] ImageSize Image size.
@return EFI_SUCCESS Unregister successfully.
@return EFI_UNSUPPORTED Memory profile is unsupported,
or memory profile for the image is not required.
@return EFI_NOT_FOUND The image is not found.
**/
EFI_STATUS
EFIAPI
SmramProfileProtocolUnregisterImage (
IN EDKII_SMM_MEMORY_PROFILE_PROTOCOL *This,
IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
IN PHYSICAL_ADDRESS ImageBase,
IN UINT64 ImageSize
)
{
EFI_STATUS Status;
EFI_SMM_DRIVER_ENTRY DriverEntry;
VOID *EntryPointInImage;
EFI_GUID *Name;
ZeroMem (&DriverEntry, sizeof (DriverEntry));
Name = GetFileNameFromFilePath (FilePath);
if (Name != NULL) {
CopyMem (&DriverEntry.FileName, Name, sizeof (EFI_GUID));
}
DriverEntry.ImageBuffer = ImageBase;
DriverEntry.NumberOfPage = EFI_SIZE_TO_PAGES ((UINTN) ImageSize);
Status = InternalPeCoffGetEntryPoint ((VOID *) (UINTN) DriverEntry.ImageBuffer, &EntryPointInImage);
ASSERT_EFI_ERROR (Status);
DriverEntry.ImageEntryPoint = (PHYSICAL_ADDRESS) (UINTN) EntryPointInImage;
return UnregisterSmramProfileImage (&DriverEntry, FALSE);
}
/**
Get memory profile recording state.
@param[in] This The EDKII_SMM_MEMORY_PROFILE_PROTOCOL instance.
@param[out] RecordingState Recording state.
@return EFI_SUCCESS Memory profile recording state is returned.
@return EFI_UNSUPPORTED Memory profile is unsupported.
@return EFI_INVALID_PARAMETER RecordingState is NULL.
**/
EFI_STATUS
EFIAPI
SmramProfileProtocolGetRecordingState (
IN EDKII_SMM_MEMORY_PROFILE_PROTOCOL *This,
OUT BOOLEAN *RecordingState
)
{
MEMORY_PROFILE_CONTEXT_DATA *ContextData;
ContextData = GetSmramProfileContext ();
if (ContextData == NULL) {
return EFI_UNSUPPORTED;
}
if (RecordingState == NULL) {
return EFI_INVALID_PARAMETER;
}
*RecordingState = mSmramProfileRecordingEnable;
return EFI_SUCCESS;
}
/**
Set memory profile recording state.
@param[in] This The EDKII_SMM_MEMORY_PROFILE_PROTOCOL instance.
@param[in] RecordingState Recording state.
@return EFI_SUCCESS Set memory profile recording state successfully.
@return EFI_UNSUPPORTED Memory profile is unsupported.
**/
EFI_STATUS
EFIAPI
SmramProfileProtocolSetRecordingState (
IN EDKII_SMM_MEMORY_PROFILE_PROTOCOL *This,
IN BOOLEAN RecordingState
)
{
MEMORY_PROFILE_CONTEXT_DATA *ContextData;
ContextData = GetSmramProfileContext ();
if (ContextData == NULL) {
return EFI_UNSUPPORTED;
}
mSmramProfileRecordingEnable = RecordingState;
return EFI_SUCCESS;
}
/**
Record memory profile of multilevel caller.
@param[in] This The EDKII_SMM_MEMORY_PROFILE_PROTOCOL instance.
@param[in] CallerAddress Address of caller.
@param[in] Action Memory profile action.
@param[in] MemoryType Memory type.
EfiMaxMemoryType means the MemoryType is unknown.
@param[in] Buffer Buffer address.
@param[in] Size Buffer size.
@param[in] ActionString String for memory profile action.
Only needed for user defined allocate action.
@return EFI_SUCCESS Memory profile is updated.
@return EFI_UNSUPPORTED Memory profile is unsupported,
or memory profile for the image is not required,
or memory profile for the memory type is not required.
@return EFI_ACCESS_DENIED It is during memory profile data getting.
@return EFI_ABORTED Memory profile recording is not enabled.
@return EFI_OUT_OF_RESOURCES No enough resource to update memory profile for allocate action.
@return EFI_NOT_FOUND No matched allocate info found for free action.
**/
EFI_STATUS
EFIAPI
SmramProfileProtocolRecord (
IN EDKII_SMM_MEMORY_PROFILE_PROTOCOL *This,
IN PHYSICAL_ADDRESS CallerAddress,
IN MEMORY_PROFILE_ACTION Action,
IN EFI_MEMORY_TYPE MemoryType,
IN VOID *Buffer,
IN UINTN Size,
IN CHAR8 *ActionString OPTIONAL
)
{
return SmmCoreUpdateProfile (CallerAddress, Action, MemoryType, Size, Buffer, ActionString);
}
/**
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 SmramProfileGettingStatus;
ContextData = GetSmramProfileContext ();
if (ContextData == NULL) {
return ;
}
SmramProfileGettingStatus = mSmramProfileGettingStatus;
mSmramProfileGettingStatus = TRUE;
SmramProfileParameterGetInfo->ProfileSize = SmramProfileGetDataSize();
SmramProfileParameterGetInfo->Header.ReturnStatus = 0;
mSmramProfileGettingStatus = SmramProfileGettingStatus;
}
/**
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 SmramProfileGettingStatus;
ContextData = GetSmramProfileContext ();
if (ContextData == NULL) {
return ;
}
SmramProfileGettingStatus = mSmramProfileGettingStatus;
mSmramProfileGettingStatus = TRUE;
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:
mSmramProfileGettingStatus = SmramProfileGettingStatus;
}
/**
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 SmramProfileGettingStatus;
ContextData = GetSmramProfileContext ();
if (ContextData == NULL) {
return ;
}
SmramProfileGettingStatus = mSmramProfileGettingStatus;
mSmramProfileGettingStatus = TRUE;
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:
mSmramProfileGettingStatus = SmramProfileGettingStatus;
}
/**
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;
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;
Status = RegisterSmramProfileImage (&DriverEntry, FALSE);
if (!EFI_ERROR (Status)) {
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;
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;
Status = UnregisterSmramProfileImage (&DriverEntry, FALSE);
if (!EFI_ERROR (Status)) {
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;
SMRAM_PROFILE_PARAMETER_RECORDING_STATE *ParameterRecordingState;
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;
case SMRAM_PROFILE_COMMAND_GET_RECORDING_STATE:
DEBUG ((EFI_D_ERROR, "SmramProfileHandlerGetRecordingState\n"));
if (TempCommBufferSize != sizeof (SMRAM_PROFILE_PARAMETER_RECORDING_STATE)) {
DEBUG ((EFI_D_ERROR, "SmramProfileHandler: SMM communication buffer size invalid!\n"));
return EFI_SUCCESS;
}
ParameterRecordingState = (SMRAM_PROFILE_PARAMETER_RECORDING_STATE *) (UINTN) CommBuffer;
ParameterRecordingState->RecordingState = mSmramProfileRecordingEnable;
ParameterRecordingState->Header.ReturnStatus = 0;
break;
case SMRAM_PROFILE_COMMAND_SET_RECORDING_STATE:
DEBUG ((EFI_D_ERROR, "SmramProfileHandlerSetRecordingState\n"));
if (TempCommBufferSize != sizeof (SMRAM_PROFILE_PARAMETER_RECORDING_STATE)) {
DEBUG ((EFI_D_ERROR, "SmramProfileHandler: SMM communication buffer size invalid!\n"));
return EFI_SUCCESS;
}
ParameterRecordingState = (SMRAM_PROFILE_PARAMETER_RECORDING_STATE *) (UINTN) CommBuffer;
mSmramProfileRecordingEnable = ParameterRecordingState->RecordingState;
ParameterRecordingState->Header.ReturnStatus = 0;
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 SmramProfileGettingStatus;
ContextData = GetSmramProfileContext ();
if (ContextData == NULL) {
return ;
}
SmramProfileGettingStatus = mSmramProfileGettingStatus;
mSmramProfileGettingStatus = TRUE;
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"));
mSmramProfileGettingStatus = SmramProfileGettingStatus;
}
/**
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 SmramProfileGettingStatus;
ContextData = GetSmramProfileContext ();
if (ContextData == NULL) {
return ;
}
SmramProfileGettingStatus = mSmramProfileGettingStatus;
mSmramProfileGettingStatus = TRUE;
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"));
mSmramProfileGettingStatus = SmramProfileGettingStatus;
}
/**
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 SmramProfileGettingStatus;
UINTN SmmPoolTypeIndex;
ContextData = GetSmramProfileContext ();
if (ContextData == NULL) {
return ;
}
SmramProfileGettingStatus = mSmramProfileGettingStatus;
mSmramProfileGettingStatus = TRUE;
DEBUG ((DEBUG_INFO, "======= SmramProfile begin =======\n"));
for (SmmPoolTypeIndex = 0; SmmPoolTypeIndex < SmmPoolTypeMax; SmmPoolTypeIndex++) {
for (PoolListIndex = 0; PoolListIndex < MAX_POOL_INDEX; PoolListIndex++) {
DEBUG ((DEBUG_INFO, "FreePoolList(%d)(%d):\n", SmmPoolTypeIndex, PoolListIndex));
FreePoolList = &mSmmPoolLists[SmmPoolTypeIndex][PoolListIndex];
for (Node = FreePoolList->BackLink, Index = 0;
Node != FreePoolList;
Node = Node->BackLink, Index++) {
Pool = BASE_CR (Node, FREE_POOL_HEADER, Link);
DEBUG ((DEBUG_INFO, " Index - 0x%x\n", Index));
DEBUG ((DEBUG_INFO, " PhysicalStart - 0x%016lx\n", (PHYSICAL_ADDRESS) (UINTN) Pool));
DEBUG ((DEBUG_INFO, " Size - 0x%08x\n", Pool->Header.Size));
DEBUG ((DEBUG_INFO, " Available - 0x%02x\n", Pool->Header.Available));
}
}
}
DEBUG ((DEBUG_INFO, "======= SmramProfile end =======\n"));
mSmramProfileGettingStatus = SmramProfileGettingStatus;
}
GLOBAL_REMOVE_IF_UNREFERENCED CHAR8 *mSmmActionString[] = {
"SmmUnknown",
"gSmst->SmmAllocatePages",
"gSmst->SmmFreePages",
"gSmst->SmmAllocatePool",
"gSmst->SmmFreePool",
};
typedef struct {
MEMORY_PROFILE_ACTION Action;
CHAR8 *String;
} ACTION_STRING;
GLOBAL_REMOVE_IF_UNREFERENCED 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"},
};
typedef struct {
EFI_MEMORY_TYPE MemoryType;
CHAR8 *MemoryTypeStr;
} PROFILE_MEMORY_TYPE_STRING;
GLOBAL_REMOVE_IF_UNREFERENCED PROFILE_MEMORY_TYPE_STRING mMemoryTypeString[] = {
{EfiRuntimeServicesCode, "EfiRuntimeServicesCode"},
{EfiRuntimeServicesData, "EfiRuntimeServicesData"}
};
/**
Memory type to string.
@param[in] MemoryType Memory type.
@return Pointer to string.
**/
CHAR8 *
ProfileMemoryTypeToStr (
IN EFI_MEMORY_TYPE MemoryType
)
{
UINTN Index;
for (Index = 0; Index < ARRAY_SIZE (mMemoryTypeString); Index++) {
if (mMemoryTypeString[Index].MemoryType == MemoryType) {
return mMemoryTypeString[Index].MemoryTypeStr;
}
}
return "UnexpectedMemoryType";
}
/**
Action to string.
@param[in] Action Profile action.
@return Pointer to string.
**/
CHAR8 *
ProfileActionToStr (
IN MEMORY_PROFILE_ACTION Action
)
{
UINTN Index;
UINTN ActionStringCount;
CHAR8 **ActionString;
ActionString = mSmmActionString;
ActionStringCount = ARRAY_SIZE (mSmmActionString);
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;
}
}
return ActionString[0];
}
/**
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 SmramProfileGettingStatus;
UINTN TypeIndex;
ContextData = GetSmramProfileContext ();
if (ContextData == NULL) {
return ;
}
SmramProfileGettingStatus = mSmramProfileGettingStatus;
mSmramProfileGettingStatus = TRUE;
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 (%a)\n", TypeIndex, Context->CurrentTotalUsageByType[TypeIndex], ProfileMemoryTypeToStr (TypeIndex)));
DEBUG ((EFI_D_INFO, " PeakTotalUsage[0x%02x] - 0x%016lx (%a)\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 (%a)\n", TypeIndex, DriverInfo->CurrentUsageByType[TypeIndex], ProfileMemoryTypeToStr (TypeIndex)));
DEBUG ((EFI_D_INFO, " PeakUsage[0x%02x] - 0x%016lx (%a)\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));
if ((AllocInfo->Action & MEMORY_PROFILE_ACTION_USER_DEFINED_MASK) != 0) {
if (AllocInfoData->ActionString != NULL) {
DEBUG ((EFI_D_INFO, " Action - 0x%08x (%a)\n", AllocInfo->Action, AllocInfoData->ActionString));
} else {
DEBUG ((EFI_D_INFO, " Action - 0x%08x (UserDefined-0x%08x)\n", AllocInfo->Action, AllocInfo->Action));
}
} else {
DEBUG ((EFI_D_INFO, " Action - 0x%08x (%a)\n", AllocInfo->Action, ProfileActionToStr (AllocInfo->Action)));
}
DEBUG ((EFI_D_INFO, " MemoryType - 0x%08x (%a)\n", AllocInfo->MemoryType, ProfileMemoryTypeToStr (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"));
mSmramProfileGettingStatus = SmramProfileGettingStatus;
}
/**
Dump SMRAM information.
**/
VOID
DumpSmramInfo (
VOID
)
{
DEBUG_CODE (
if (IS_SMRAM_PROFILE_ENABLED) {
DumpSmramProfile ();
DumpFreePagesList ();
DumpFreePoolList ();
DumpSmramRange ();
}
);
}