From: Star Zeng Date: Wed, 12 Nov 2014 03:27:48 +0000 (+0000) Subject: MdeModulePkg DxeCore/PiSmmCore: Add UEFI memory and SMRAM profile support. X-Git-Tag: edk2-stable201903~10675 X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=commitdiff_plain;h=84edd20bd0756ef5719835498d4283435d6b5e77 MdeModulePkg DxeCore/PiSmmCore: Add UEFI memory and SMRAM profile support. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Star Zeng Reviewed-by: Jiewen Yao git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@16335 6f19259b-4bc3-4df7-8a09-765794883524 --- diff --git a/MdeModulePkg/Application/MemoryProfileInfo/MemoryProfileInfo.c b/MdeModulePkg/Application/MemoryProfileInfo/MemoryProfileInfo.c new file mode 100644 index 0000000000..4896ebd1ff --- /dev/null +++ b/MdeModulePkg/Application/MemoryProfileInfo/MemoryProfileInfo.c @@ -0,0 +1,712 @@ +/** @file + + Copyright (c) 2014, Intel Corporation. All rights reserved.
+ 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +CHAR16 *mActionString[] = { + L"Unknown", + L"AllocatePages", + L"FreePages", + L"AllocatePool", + L"FreePool", +}; + +CHAR16 *mMemoryTypeString[] = { + L"EfiReservedMemoryType", + L"EfiLoaderCode", + L"EfiLoaderData", + L"EfiBootServicesCode", + L"EfiBootServicesData", + L"EfiRuntimeServicesCode", + L"EfiRuntimeServicesData", + L"EfiConventionalMemory", + L"EfiUnusableMemory", + L"EfiACPIReclaimMemory", + L"EfiACPIMemoryNVS", + L"EfiMemoryMappedIO", + L"EfiMemoryMappedIOPortSpace", + L"EfiPalCode", + L"EfiOSReserved", +}; + +CHAR16 *mSubsystemString[] = { + L"Unknown", + L"NATIVE", + L"WINDOWS_GUI", + L"WINDOWS_CUI", + L"Unknown", + L"Unknown", + L"Unknown", + L"POSIX_CUI", + L"Unknown", + L"WINDOWS_CE_GUI", + L"EFI_APPLICATION", + L"EFI_BOOT_SERVICE_DRIVER", + L"EFI_RUNTIME_DRIVER", + L"EFI_ROM", + L"XBOX", + L"Unknown", +}; + +CHAR16 *mFileTypeString[] = { + L"Unknown", + L"RAW", + L"FREEFORM", + L"SECURITY_CORE", + L"PEI_CORE", + L"DXE_CORE", + L"PEIM", + L"DRIVER", + L"COMBINED_PEIM_DRIVER", + L"APPLICATION", + L"SMM", + L"FIRMWARE_VOLUME_IMAGE", + L"COMBINED_SMM_DXE", + L"SMM_CORE", +}; + +#define PROFILE_NAME_STRING_LENGTH 36 +CHAR16 mNameString[PROFILE_NAME_STRING_LENGTH + 1]; + +/** + Get the file name portion of the Pdb File Name. + + The portion of the Pdb File Name between the last backslash and + either a following period or the end of the string is converted + to Unicode and copied into UnicodeBuffer. The name is truncated, + if necessary, to ensure that UnicodeBuffer is not overrun. + + @param[in] PdbFileName Pdb file name. + @param[out] UnicodeBuffer The resultant Unicode File Name. + +**/ +VOID +GetShortPdbFileName ( + IN CHAR8 *PdbFileName, + OUT CHAR16 *UnicodeBuffer + ) +{ + UINTN IndexA; // Current work location within an ASCII string. + UINTN IndexU; // Current work location within a Unicode string. + UINTN StartIndex; + UINTN EndIndex; + + ZeroMem (UnicodeBuffer, PROFILE_NAME_STRING_LENGTH * sizeof (CHAR16)); + + if (PdbFileName == NULL) { + StrnCpy (UnicodeBuffer, L" ", 1); + } else { + StartIndex = 0; + for (EndIndex = 0; PdbFileName[EndIndex] != 0; EndIndex++); + for (IndexA = 0; PdbFileName[IndexA] != 0; IndexA++) { + if (PdbFileName[IndexA] == '\\') { + StartIndex = IndexA + 1; + } + + if (PdbFileName[IndexA] == '.') { + EndIndex = IndexA; + } + } + + IndexU = 0; + for (IndexA = StartIndex; IndexA < EndIndex; IndexA++) { + UnicodeBuffer[IndexU] = (CHAR16) PdbFileName[IndexA]; + IndexU++; + if (IndexU >= PROFILE_NAME_STRING_LENGTH) { + UnicodeBuffer[PROFILE_NAME_STRING_LENGTH] = 0; + break; + } + } + } +} + +/** + Get a human readable name for an image. + The following methods will be tried orderly: + 1. Image PDB + 2. FFS UI section + 3. Image GUID + + @param[in] DriverInfo Pointer to memory profile driver info. + + @post The resulting Unicode name string is stored in the mNameString global array. + +**/ +VOID +GetDriverNameString ( + IN MEMORY_PROFILE_DRIVER_INFO *DriverInfo + ) +{ + EFI_STATUS Status; + CHAR8 *PdbFileName; + CHAR16 *NameString; + UINTN StringSize; + + // + // Method 1: Get the name string from image PDB + // + if ((DriverInfo->ImageBase != 0) && (DriverInfo->FileType != EFI_FV_FILETYPE_SMM) && (DriverInfo->FileType != EFI_FV_FILETYPE_SMM_CORE)) { + PdbFileName = PeCoffLoaderGetPdbPointer ((VOID *) (UINTN) DriverInfo->ImageBase); + + if (PdbFileName != NULL) { + GetShortPdbFileName (PdbFileName, mNameString); + return; + } + } + + if (!CompareGuid (&DriverInfo->FileName, &gZeroGuid)) { + // + // Try to get the image's FFS UI section by image GUID + // + NameString = NULL; + StringSize = 0; + Status = GetSectionFromAnyFv ( + &DriverInfo->FileName, + EFI_SECTION_USER_INTERFACE, + 0, + (VOID **) &NameString, + &StringSize + ); + if (!EFI_ERROR (Status)) { + // + // Method 2: Get the name string from FFS UI section + // + StrnCpy (mNameString, NameString, PROFILE_NAME_STRING_LENGTH); + mNameString[PROFILE_NAME_STRING_LENGTH] = 0; + FreePool (NameString); + return; + } + } + + // + // Method 3: Get the name string from image GUID + // + UnicodeSPrint (mNameString, sizeof (mNameString), L"%g", &DriverInfo->FileName); +} + +/** + Dump memory profile allocate information. + + @param[in] DriverInfo Pointer to memory profile driver info. + @param[in] AllocIndex Memory profile alloc info index. + @param[in] AllocInfo Pointer to memory profile alloc info. + + @return Pointer to next memory profile alloc info. + +**/ +MEMORY_PROFILE_ALLOC_INFO * +DumpMemoryProfileAllocInfo ( + IN MEMORY_PROFILE_DRIVER_INFO *DriverInfo, + IN UINTN AllocIndex, + IN MEMORY_PROFILE_ALLOC_INFO *AllocInfo + ) +{ + if (AllocInfo->Header.Signature != MEMORY_PROFILE_ALLOC_INFO_SIGNATURE) { + return NULL; + } + Print (L" MEMORY_PROFILE_ALLOC_INFO (0x%x)\n", AllocIndex); + Print (L" Signature - 0x%08x\n", AllocInfo->Header.Signature); + Print (L" Length - 0x%04x\n", AllocInfo->Header.Length); + Print (L" Revision - 0x%04x\n", AllocInfo->Header.Revision); + Print (L" CallerAddress - 0x%016lx (Offset: 0x%08x)\n", AllocInfo->CallerAddress, (UINTN) (AllocInfo->CallerAddress - DriverInfo->ImageBase)); + Print (L" SequenceId - 0x%08x\n", AllocInfo->SequenceId); + Print (L" Action - 0x%08x (%s)\n", AllocInfo->Action, mActionString[(AllocInfo->Action < sizeof(mActionString)/sizeof(mActionString[0])) ? AllocInfo->Action : 0]); + Print (L" MemoryType - 0x%08x (%s)\n", AllocInfo->MemoryType, mMemoryTypeString[(AllocInfo->MemoryType < sizeof(mMemoryTypeString)/sizeof(mMemoryTypeString[0])) ? AllocInfo->MemoryType : (sizeof(mMemoryTypeString)/sizeof(mMemoryTypeString[0]) - 1)]); + Print (L" Buffer - 0x%016lx\n", AllocInfo->Buffer); + Print (L" Size - 0x%016lx\n", AllocInfo->Size); + + return (MEMORY_PROFILE_ALLOC_INFO *) ((UINTN) AllocInfo + AllocInfo->Header.Length); +} + +/** + Dump memory profile driver information. + + @param[in] DriverIndex Memory profile driver info index. + @param[in] DriverInfo Pointer to memory profile driver info. + + @return Pointer to next memory profile driver info. + +**/ +MEMORY_PROFILE_DRIVER_INFO * +DumpMemoryProfileDriverInfo ( + IN UINTN DriverIndex, + IN MEMORY_PROFILE_DRIVER_INFO *DriverInfo + ) +{ + UINTN TypeIndex; + MEMORY_PROFILE_ALLOC_INFO *AllocInfo; + UINTN AllocIndex; + + if (DriverInfo->Header.Signature != MEMORY_PROFILE_DRIVER_INFO_SIGNATURE) { + return NULL; + } + Print (L" MEMORY_PROFILE_DRIVER_INFO (0x%x)\n", DriverIndex); + Print (L" Signature - 0x%08x\n", DriverInfo->Header.Signature); + Print (L" Length - 0x%04x\n", DriverInfo->Header.Length); + Print (L" Revision - 0x%04x\n", DriverInfo->Header.Revision); + GetDriverNameString (DriverInfo); + Print (L" FileName - %s\n", &mNameString); + Print (L" ImageBase - 0x%016lx\n", DriverInfo->ImageBase); + Print (L" ImageSize - 0x%016lx\n", DriverInfo->ImageSize); + Print (L" EntryPoint - 0x%016lx\n", DriverInfo->EntryPoint); + Print (L" ImageSubsystem - 0x%04x (%s)\n", DriverInfo->ImageSubsystem, mSubsystemString[(DriverInfo->ImageSubsystem < sizeof(mSubsystemString)/sizeof(mSubsystemString[0])) ? DriverInfo->ImageSubsystem : 0]); + Print (L" FileType - 0x%02x (%s)\n", DriverInfo->FileType, mFileTypeString[(DriverInfo->FileType < sizeof(mFileTypeString)/sizeof(mFileTypeString[0])) ? DriverInfo->FileType : 0]); + Print (L" CurrentUsage - 0x%016lx\n", DriverInfo->CurrentUsage); + Print (L" PeakUsage - 0x%016lx\n", DriverInfo->PeakUsage); + for (TypeIndex = 0; TypeIndex <= EfiMaxMemoryType; TypeIndex++) { + if ((DriverInfo->CurrentUsageByType[TypeIndex] != 0) || + (DriverInfo->PeakUsageByType[TypeIndex] != 0)) { + Print (L" CurrentUsage[0x%02x] - 0x%016lx (%s)\n", TypeIndex, DriverInfo->CurrentUsageByType[TypeIndex], mMemoryTypeString[TypeIndex]); + Print (L" PeakUsage[0x%02x] - 0x%016lx (%s)\n", TypeIndex, DriverInfo->PeakUsageByType[TypeIndex], mMemoryTypeString[TypeIndex]); + } + } + Print (L" AllocRecordCount - 0x%08x\n", DriverInfo->AllocRecordCount); + + AllocInfo = (MEMORY_PROFILE_ALLOC_INFO *) ((UINTN) DriverInfo + DriverInfo->Header.Length); + for (AllocIndex = 0; AllocIndex < DriverInfo->AllocRecordCount; AllocIndex++) { + AllocInfo = DumpMemoryProfileAllocInfo (DriverInfo, AllocIndex, AllocInfo); + if (AllocInfo == NULL) { + return NULL; + } + } + return (MEMORY_PROFILE_DRIVER_INFO *) AllocInfo; +} + +/** + Dump memory profile context information. + + @param[in] Context Pointer to memory profile context. + + @return Pointer to the end of memory profile context buffer. + +**/ +VOID * +DumpMemoryProfileContext ( + IN MEMORY_PROFILE_CONTEXT *Context + ) +{ + UINTN TypeIndex; + MEMORY_PROFILE_DRIVER_INFO *DriverInfo; + UINTN DriverIndex; + + if (Context->Header.Signature != MEMORY_PROFILE_CONTEXT_SIGNATURE) { + return NULL; + } + Print (L"MEMORY_PROFILE_CONTEXT\n"); + Print (L" Signature - 0x%08x\n", Context->Header.Signature); + Print (L" Length - 0x%04x\n", Context->Header.Length); + Print (L" Revision - 0x%04x\n", Context->Header.Revision); + Print (L" CurrentTotalUsage - 0x%016lx\n", Context->CurrentTotalUsage); + Print (L" PeakTotalUsage - 0x%016lx\n", Context->PeakTotalUsage); + for (TypeIndex = 0; TypeIndex <= EfiMaxMemoryType; TypeIndex++) { + if ((Context->CurrentTotalUsageByType[TypeIndex] != 0) || + (Context->PeakTotalUsageByType[TypeIndex] != 0)) { + Print (L" CurrentTotalUsage[0x%02x] - 0x%016lx (%s)\n", TypeIndex, Context->CurrentTotalUsageByType[TypeIndex], mMemoryTypeString[TypeIndex]); + Print (L" PeakTotalUsage[0x%02x] - 0x%016lx (%s)\n", TypeIndex, Context->PeakTotalUsageByType[TypeIndex], mMemoryTypeString[TypeIndex]); + } + } + Print (L" TotalImageSize - 0x%016lx\n", Context->TotalImageSize); + Print (L" ImageCount - 0x%08x\n", Context->ImageCount); + Print (L" SequenceCount - 0x%08x\n", Context->SequenceCount); + + DriverInfo = (MEMORY_PROFILE_DRIVER_INFO *) ((UINTN) Context + Context->Header.Length); + for (DriverIndex = 0; DriverIndex < Context->ImageCount; DriverIndex++) { + DriverInfo = DumpMemoryProfileDriverInfo (DriverIndex, DriverInfo); + if (DriverInfo == NULL) { + return NULL; + } + } + return (VOID *) DriverInfo; +} + +/** + Dump memory profile descriptor information. + + @param[in] DescriptorIndex Memory profile descriptor index. + @param[in] Descriptor Pointer to memory profile descriptor. + + @return Pointer to next memory profile descriptor. + +**/ +MEMORY_PROFILE_DESCRIPTOR * +DumpMemoryProfileDescriptor ( + IN UINTN DescriptorIndex, + IN MEMORY_PROFILE_DESCRIPTOR *Descriptor + ) +{ + if (Descriptor->Header.Signature != MEMORY_PROFILE_DESCRIPTOR_SIGNATURE) { + return NULL; + } + Print (L" MEMORY_PROFILE_DESCRIPTOR (0x%x)\n", DescriptorIndex); + Print (L" Signature - 0x%08x\n", Descriptor->Header.Signature); + Print (L" Length - 0x%04x\n", Descriptor->Header.Length); + Print (L" Revision - 0x%04x\n", Descriptor->Header.Revision); + Print (L" Address - 0x%016lx\n", Descriptor->Address); + Print (L" Size - 0x%016lx\n", Descriptor->Size); + + return (MEMORY_PROFILE_DESCRIPTOR *) ((UINTN) Descriptor + Descriptor->Header.Length); +} + +/** + Dump memory profile free memory information. + + @param[in] FreeMemory Pointer to memory profile free memory. + + @return Pointer to the end of memory profile free memory buffer. + +**/ +VOID * +DumpMemoryProfileFreeMemory ( + IN MEMORY_PROFILE_FREE_MEMORY *FreeMemory + ) +{ + MEMORY_PROFILE_DESCRIPTOR *Descriptor; + UINTN DescriptorIndex; + + if (FreeMemory->Header.Signature != MEMORY_PROFILE_FREE_MEMORY_SIGNATURE) { + return NULL; + } + Print (L"MEMORY_PROFILE_FREE_MEMORY\n"); + Print (L" Signature - 0x%08x\n", FreeMemory->Header.Signature); + Print (L" Length - 0x%04x\n", FreeMemory->Header.Length); + Print (L" Revision - 0x%04x\n", FreeMemory->Header.Revision); + Print (L" TotalFreeMemoryPages - 0x%016lx\n", FreeMemory->TotalFreeMemoryPages); + Print (L" FreeMemoryEntryCount - 0x%08x\n", FreeMemory->FreeMemoryEntryCount); + + Descriptor = (MEMORY_PROFILE_DESCRIPTOR *) ((UINTN) FreeMemory + FreeMemory->Header.Length); + for (DescriptorIndex = 0; DescriptorIndex < FreeMemory->FreeMemoryEntryCount; DescriptorIndex++) { + Descriptor = DumpMemoryProfileDescriptor (DescriptorIndex, Descriptor); + if (Descriptor == NULL) { + return NULL; + } + } + + return (VOID *) Descriptor; +} + +/** + Dump memory profile memory range information. + + @param[in] MemoryRange Pointer to memory profile memory range. + + @return Pointer to the end of memory profile memory range buffer. + +**/ +VOID * +DumpMemoryProfileMemoryRange ( + IN MEMORY_PROFILE_MEMORY_RANGE *MemoryRange + ) +{ + MEMORY_PROFILE_DESCRIPTOR *Descriptor; + UINTN DescriptorIndex; + + if (MemoryRange->Header.Signature != MEMORY_PROFILE_MEMORY_RANGE_SIGNATURE) { + return NULL; + } + Print (L"MEMORY_PROFILE_MEMORY_RANGE\n"); + Print (L" Signature - 0x%08x\n", MemoryRange->Header.Signature); + Print (L" Length - 0x%04x\n", MemoryRange->Header.Length); + Print (L" Revision - 0x%04x\n", MemoryRange->Header.Revision); + Print (L" MemoryRangeCount - 0x%08x\n", MemoryRange->MemoryRangeCount); + + Descriptor = (MEMORY_PROFILE_DESCRIPTOR *) ((UINTN) MemoryRange + MemoryRange->Header.Length); + for (DescriptorIndex = 0; DescriptorIndex < MemoryRange->MemoryRangeCount; DescriptorIndex++) { + Descriptor = DumpMemoryProfileDescriptor (DescriptorIndex, Descriptor); + if (Descriptor == NULL) { + return NULL; + } + } + + return (VOID *) Descriptor; +} + +/** + Scan memory profile by Signature. + + @param[in] ProfileBuffer Memory profile base address. + @param[in] ProfileSize Memory profile size. + @param[in] Signature Signature. + + @return Pointer to the stucture with the signature. + +**/ +VOID * +ScanMemoryProfileBySignature ( + IN PHYSICAL_ADDRESS ProfileBuffer, + IN UINT64 ProfileSize, + IN UINT32 Signature + ) +{ + MEMORY_PROFILE_COMMON_HEADER *CommonHeader; + UINTN ProfileEnd; + + ProfileEnd = (UINTN) (ProfileBuffer + ProfileSize); + CommonHeader = (MEMORY_PROFILE_COMMON_HEADER *) (UINTN) ProfileBuffer; + while ((UINTN) CommonHeader < ProfileEnd) { + if (CommonHeader->Signature == Signature) { + // + // Found it. + // + return (VOID *) CommonHeader; + } + CommonHeader = (MEMORY_PROFILE_COMMON_HEADER *) ((UINTN) CommonHeader + CommonHeader->Length); + } + + return NULL; +} + +/** + Dump memory profile information. + + @param[in] ProfileBuffer Memory profile base address. + @param[in] ProfileSize Memory profile size. + +**/ +VOID +DumpMemoryProfile ( + IN PHYSICAL_ADDRESS ProfileBuffer, + IN UINT64 ProfileSize + ) +{ + MEMORY_PROFILE_CONTEXT *Context; + MEMORY_PROFILE_FREE_MEMORY *FreeMemory; + MEMORY_PROFILE_MEMORY_RANGE *MemoryRange; + + Context = (MEMORY_PROFILE_CONTEXT *) ScanMemoryProfileBySignature (ProfileBuffer, ProfileSize, MEMORY_PROFILE_CONTEXT_SIGNATURE); + if (Context != NULL) { + DumpMemoryProfileContext (Context); + } + + FreeMemory = (MEMORY_PROFILE_FREE_MEMORY *) ScanMemoryProfileBySignature (ProfileBuffer, ProfileSize, MEMORY_PROFILE_FREE_MEMORY_SIGNATURE); + if (FreeMemory != NULL) { + DumpMemoryProfileFreeMemory (FreeMemory); + } + + MemoryRange = (MEMORY_PROFILE_MEMORY_RANGE *) ScanMemoryProfileBySignature (ProfileBuffer, ProfileSize, MEMORY_PROFILE_MEMORY_RANGE_SIGNATURE); + if (MemoryRange != NULL) { + DumpMemoryProfileMemoryRange (MemoryRange); + } +} + +/** + Get and dump UEFI memory profile data. + + @return EFI_SUCCESS Get the memory profile data successfully. + @return other Fail to get the memory profile data. + +**/ +EFI_STATUS +GetUefiMemoryProfileData ( + VOID + ) +{ + EFI_STATUS Status; + EDKII_MEMORY_PROFILE_PROTOCOL *ProfileProtocol; + VOID *Data; + UINT64 Size; + + Status = gBS->LocateProtocol (&gEdkiiMemoryProfileGuid, NULL, (VOID **) &ProfileProtocol); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "UefiMemoryProfile: Locate MemoryProfile protocol - %r\n", Status)); + return Status; + } + + Size = 0; + Data = NULL; + Status = ProfileProtocol->GetData ( + ProfileProtocol, + &Size, + Data + ); + if (Status != EFI_BUFFER_TOO_SMALL) { + Print (L"UefiMemoryProfile: GetData - %r\n", Status); + return Status; + } + + // + // Add one sizeof (MEMORY_PROFILE_ALLOC_INFO) to Size for this AllocatePool action. + // + Size = Size + sizeof (MEMORY_PROFILE_ALLOC_INFO); + Data = AllocateZeroPool ((UINTN) Size); + if (Data == NULL) { + Print (L"UefiMemoryProfile: AllocateZeroPool (0x%x) - %r\n", Size, Status); + return Status; + } + + Status = ProfileProtocol->GetData ( + ProfileProtocol, + &Size, + Data + ); + if (EFI_ERROR (Status)) { + FreePool (Data); + Print (L"UefiMemoryProfile: GetData - %r\n", Status); + return Status; + } + + + Print (L"UefiMemoryProfileSize - 0x%x\n", Size); + Print (L"======= UefiMemoryProfile begin =======\n"); + DumpMemoryProfile ((PHYSICAL_ADDRESS) (UINTN) Data, Size); + Print (L"======= UefiMemoryProfile end =======\n\n\n"); + + FreePool (Data); + + return EFI_SUCCESS; +} + +/** + Get and dump SMRAM profile data. + + @return EFI_SUCCESS Get the SMRAM profile data successfully. + @return other Fail to get the SMRAM profile data. + +**/ +EFI_STATUS +GetSmramProfileData ( + VOID + ) +{ + EFI_STATUS Status; + UINTN CommSize; + UINT8 CommBuffer[sizeof (EFI_GUID) + sizeof (UINTN) + sizeof (SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA)]; + EFI_SMM_COMMUNICATE_HEADER *CommHeader; + SMRAM_PROFILE_PARAMETER_GET_PROFILE_INFO *CommGetProfileInfo; + SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA *CommGetProfileData; + UINT64 ProfileSize; + PHYSICAL_ADDRESS ProfileBuffer; + EFI_SMM_COMMUNICATION_PROTOCOL *SmmCommunication; + + Status = gBS->LocateProtocol (&gEfiSmmCommunicationProtocolGuid, NULL, (VOID **) &SmmCommunication); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "SmramProfile: Locate SmmCommunication protocol - %r\n", Status)); + return Status; + } + + // + // Get Size + // + CommHeader = (EFI_SMM_COMMUNICATE_HEADER *) &CommBuffer[0]; + CopyMem (&CommHeader->HeaderGuid, &gEdkiiMemoryProfileGuid, sizeof (gEdkiiMemoryProfileGuid)); + CommHeader->MessageLength = sizeof (SMRAM_PROFILE_PARAMETER_GET_PROFILE_INFO); + + CommGetProfileInfo = (SMRAM_PROFILE_PARAMETER_GET_PROFILE_INFO *) &CommBuffer[OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data)]; + CommGetProfileInfo->Header.Command = SMRAM_PROFILE_COMMAND_GET_PROFILE_INFO; + CommGetProfileInfo->Header.DataLength = sizeof (*CommGetProfileInfo); + CommGetProfileInfo->Header.ReturnStatus = (UINT64)-1; + CommGetProfileInfo->ProfileSize = 0; + + CommSize = sizeof (EFI_GUID) + sizeof (UINTN) + CommHeader->MessageLength; + Status = SmmCommunication->Communicate (SmmCommunication, CommBuffer, &CommSize); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "SmramProfile: SmmCommunication - %r\n", Status)); + return Status; + } + + if (CommGetProfileInfo->Header.ReturnStatus != 0) { + Print (L"SmramProfile: GetProfileInfo - 0x%0x\n", CommGetProfileInfo->Header.ReturnStatus); + return EFI_SUCCESS; + } + + ProfileSize = CommGetProfileInfo->ProfileSize; + + // + // Get Data + // + ProfileBuffer = (PHYSICAL_ADDRESS) (UINTN) AllocateZeroPool ((UINTN) ProfileSize); + if (ProfileBuffer == 0) { + Print (L"UefiMemoryProfile: AllocateZeroPool (0x%x) - %r\n", (UINTN) ProfileSize, Status); + return EFI_SUCCESS; + } + + CommHeader = (EFI_SMM_COMMUNICATE_HEADER *) &CommBuffer[0]; + CopyMem (&CommHeader->HeaderGuid, &gEdkiiMemoryProfileGuid, sizeof(gEdkiiMemoryProfileGuid)); + CommHeader->MessageLength = sizeof (SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA); + + CommGetProfileData = (SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA *)&CommBuffer[OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data)]; + CommGetProfileData->Header.Command = SMRAM_PROFILE_COMMAND_GET_PROFILE_DATA; + CommGetProfileData->Header.DataLength = sizeof (*CommGetProfileData); + CommGetProfileData->Header.ReturnStatus = (UINT64)-1; + CommGetProfileData->ProfileSize = ProfileSize; + CommGetProfileData->ProfileBuffer = ProfileBuffer; + + CommSize = sizeof (EFI_GUID) + sizeof (UINTN) + CommHeader->MessageLength; + Status = SmmCommunication->Communicate (SmmCommunication, CommBuffer, &CommSize); + ASSERT_EFI_ERROR (Status); + + if (CommGetProfileData->Header.ReturnStatus != 0) { + Print (L"GetProfileData - 0x%x\n", CommGetProfileData->Header.ReturnStatus); + return EFI_SUCCESS; + } + + + Print (L"SmramProfileSize - 0x%x\n", CommGetProfileData->ProfileSize); + Print (L"======= SmramProfile begin =======\n"); + DumpMemoryProfile (CommGetProfileData->ProfileBuffer, CommGetProfileData->ProfileSize); + Print (L"======= SmramProfile end =======\n\n\n"); + + FreePool ((VOID *) (UINTN) CommGetProfileData->ProfileBuffer); + + return EFI_SUCCESS; +} + +/** + The user Entry Point for Application. The user code starts with this function + as the real entry point for the image goes into a library that calls this function. + + @param[in] ImageHandle The firmware allocated handle for the EFI image. + @param[in] SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The entry point is executed successfully. + @retval other Some error occurs when executing this entry point. + +**/ +EFI_STATUS +EFIAPI +UefiMain ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + Status = GetUefiMemoryProfileData (); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "GetUefiMemoryProfileData - %r\n", Status)); + } + + Status = GetSmramProfileData (); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "GetSmramProfileData - %r\n", Status)); + } + + return EFI_SUCCESS; +} diff --git a/MdeModulePkg/Application/MemoryProfileInfo/MemoryProfileInfo.inf b/MdeModulePkg/Application/MemoryProfileInfo/MemoryProfileInfo.inf new file mode 100644 index 0000000000..6fd1f7b828 --- /dev/null +++ b/MdeModulePkg/Application/MemoryProfileInfo/MemoryProfileInfo.inf @@ -0,0 +1,62 @@ +## @file +# Shell application to dump UEFI memory and SMRAM profile information. +# +# Note that if the feature is not enabled by setting PcdMemoryProfilePropertyMask, +# the application will not display memory profile information. +# +# Copyright (c) 2014, Intel Corporation. All rights reserved.
+# 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. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = MemoryProfileInfo + MODULE_UNI_FILE = MemoryProfileInfo.uni + FILE_GUID = 21429B90-5F67-4e93-AF55-1D314D646E12 + MODULE_TYPE = UEFI_APPLICATION + VERSION_STRING = 1.0 + ENTRY_POINT = UefiMain + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources] + MemoryProfileInfo.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + UefiApplicationEntryPoint + BaseLib + BaseMemoryLib + UefiBootServicesTableLib + UefiRuntimeServicesTableLib + DebugLib + UefiLib + MemoryAllocationLib + DxeServicesLib + PeCoffGetEntryPointLib + PrintLib + +[Guids] + ## SOMETIMES_CONSUMES ## GUID # Locate protocol + ## SOMETIMES_CONSUMES ## GUID # SmiHandlerRegister + gEdkiiMemoryProfileGuid + gZeroGuid ## SOMETIMES_CONSUMES ## GUID + +[Protocols] + gEfiSmmCommunicationProtocolGuid ## SOMETIMES_CONSUMES + +[UserExtensions.TianoCore."ExtraFiles"] + MemoryProfileInfoExtra.uni diff --git a/MdeModulePkg/Application/MemoryProfileInfo/MemoryProfileInfo.uni b/MdeModulePkg/Application/MemoryProfileInfo/MemoryProfileInfo.uni new file mode 100644 index 0000000000..fe4882605d Binary files /dev/null and b/MdeModulePkg/Application/MemoryProfileInfo/MemoryProfileInfo.uni differ diff --git a/MdeModulePkg/Application/MemoryProfileInfo/MemoryProfileInfoExtra.uni b/MdeModulePkg/Application/MemoryProfileInfo/MemoryProfileInfoExtra.uni new file mode 100644 index 0000000000..32905119ec Binary files /dev/null and b/MdeModulePkg/Application/MemoryProfileInfo/MemoryProfileInfoExtra.uni differ diff --git a/MdeModulePkg/Core/Dxe/DxeMain.h b/MdeModulePkg/Core/Dxe/DxeMain.h index 75542b3432..bb2bfab370 100644 --- a/MdeModulePkg/Core/Dxe/DxeMain.h +++ b/MdeModulePkg/Core/Dxe/DxeMain.h @@ -69,6 +69,8 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include #include #include +#include +#include #include #include @@ -191,6 +193,56 @@ typedef struct { EFI_HANDLE DeviceHandle; } EFI_GCD_MAP_ENTRY; + +#define LOADED_IMAGE_PRIVATE_DATA_SIGNATURE SIGNATURE_32('l','d','r','i') + +typedef struct { + UINTN Signature; + /// Image handle + EFI_HANDLE Handle; + /// Image type + UINTN Type; + /// If entrypoint has been called + BOOLEAN Started; + /// The image's entry point + EFI_IMAGE_ENTRY_POINT EntryPoint; + /// loaded image protocol + EFI_LOADED_IMAGE_PROTOCOL Info; + /// Location in memory + EFI_PHYSICAL_ADDRESS ImageBasePage; + /// Number of pages + UINTN NumberOfPages; + /// Original fixup data + CHAR8 *FixupData; + /// Tpl of started image + EFI_TPL Tpl; + /// Status returned by started image + EFI_STATUS Status; + /// Size of ExitData from started image + UINTN ExitDataSize; + /// Pointer to exit data from started image + VOID *ExitData; + /// Pointer to pool allocation for context save/retore + VOID *JumpBuffer; + /// Pointer to buffer for context save/retore + BASE_LIBRARY_JUMP_BUFFER *JumpContext; + /// Machine type from PE image + UINT16 Machine; + /// EBC Protocol pointer + EFI_EBC_PROTOCOL *Ebc; + /// Runtime image list + EFI_RUNTIME_IMAGE_ENTRY *RuntimeData; + /// Pointer to Loaded Image Device Path Protocl + EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath; + /// PeCoffLoader ImageContext + PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; + /// Status returned by LoadImage() service. + EFI_STATUS LoadImageStatus; +} LOADED_IMAGE_PRIVATE_DATA; + +#define LOADED_IMAGE_PRIVATE_DATA_FROM_THIS(a) \ + CR(a, LOADED_IMAGE_PRIVATE_DATA, Info, LOADED_IMAGE_PRIVATE_DATA_SIGNATURE) + // // DXE Core Global Variables // @@ -1192,7 +1244,32 @@ CoreAllocatePages ( IN OUT EFI_PHYSICAL_ADDRESS *Memory ); +/** + Allocates pages from the memory map. + + @param Type The type of allocation to perform + @param MemoryType The type of memory to turn the allocated pages + into + @param NumberOfPages The number of pages to allocate + @param Memory A pointer to receive the base allocated memory + address + + @return Status. On success, Memory is filled in with the base address allocated + @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in + spec. + @retval EFI_NOT_FOUND Could not allocate pages match the requirement. + @retval EFI_OUT_OF_RESOURCES No enough pages to allocate. + @retval EFI_SUCCESS Pages successfully allocated. +**/ +EFI_STATUS +EFIAPI +CoreInternalAllocatePages ( + IN EFI_ALLOCATE_TYPE Type, + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN NumberOfPages, + IN OUT EFI_PHYSICAL_ADDRESS *Memory + ); /** Frees previous allocated pages. @@ -1212,7 +1289,23 @@ CoreFreePages ( IN UINTN NumberOfPages ); +/** + Frees previous allocated pages. + + @param Memory Base address of memory being freed + @param NumberOfPages The number of pages to free + + @retval EFI_NOT_FOUND Could not find the entry that covers the range + @retval EFI_INVALID_PARAMETER Address not aligned + @return EFI_SUCCESS -Pages successfully freed. +**/ +EFI_STATUS +EFIAPI +CoreInternalFreePages ( + IN EFI_PHYSICAL_ADDRESS Memory, + IN UINTN NumberOfPages + ); /** This function returns a copy of the current memory map. The map is an array of @@ -1277,7 +1370,26 @@ CoreAllocatePool ( OUT VOID **Buffer ); +/** + Allocate pool of a particular type. + + @param PoolType Type of pool to allocate + @param Size The amount of pool to allocate + @param Buffer The address to return a pointer to the allocated + pool + @retval EFI_INVALID_PARAMETER PoolType not valid or Buffer is NULL + @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed. + @retval EFI_SUCCESS Pool successfully allocated. + +**/ +EFI_STATUS +EFIAPI +CoreInternalAllocatePool ( + IN EFI_MEMORY_TYPE PoolType, + IN UINTN Size, + OUT VOID **Buffer + ); /** Frees pool. @@ -1294,7 +1406,20 @@ CoreFreePool ( IN VOID *Buffer ); +/** + Frees pool. + + @param Buffer The allocated pool entry to free + @retval EFI_INVALID_PARAMETER Buffer is not a valid value. + @retval EFI_SUCCESS Pool successfully freed. + +**/ +EFI_STATUS +EFIAPI +CoreInternalFreePool ( + IN VOID *Buffer + ); /** Loads an EFI image into memory and returns a handle to the image. @@ -2619,4 +2744,76 @@ VerifyFvHeaderChecksum ( IN EFI_FIRMWARE_VOLUME_HEADER *FvHeader ); +/** + Initialize memory profile. + + @param HobStart The start address of the HOB. + +**/ +VOID +MemoryProfileInit ( + IN VOID *HobStart + ); + +/** + Install memory profile protocol. + +**/ +VOID +MemoryProfileInstallProtocol ( + VOID + ); + +/** + Register image to memory profile. + + @param DriverEntry Image info. + @param FileType Image file type. + + @retval TRUE Register success. + @retval FALSE Register fail. + +**/ +BOOLEAN +RegisterMemoryProfileImage ( + IN LOADED_IMAGE_PRIVATE_DATA *DriverEntry, + IN EFI_FV_FILETYPE FileType + ); + +/** + Unregister image from memory profile. + + @param DriverEntry Image info. + + @retval TRUE Unregister success. + @retval FALSE Unregister fail. + +**/ +BOOLEAN +UnregisterMemoryProfileImage ( + IN LOADED_IMAGE_PRIVATE_DATA *DriverEntry + ); + +/** + Update memory 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 +CoreUpdateProfile ( + IN EFI_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 + ); + #endif diff --git a/MdeModulePkg/Core/Dxe/DxeMain.inf b/MdeModulePkg/Core/Dxe/DxeMain.inf index adac56041a..0a63f3cb92 100644 --- a/MdeModulePkg/Core/Dxe/DxeMain.inf +++ b/MdeModulePkg/Core/Dxe/DxeMain.inf @@ -52,6 +52,7 @@ Mem/Page.c Mem/MemData.c Mem/Imem.h + Mem/MemoryProfileRecord.c FwVolBlock/FwVolBlock.c FwVolBlock/FwVolBlock.h FwVol/FwVolWrite.c @@ -120,6 +121,8 @@ gIdleLoopEventGuid gEventExitBootServicesFailedGuid ## SOMETIMES_PRODUCES ## Event gEfiVectorHandoffTableGuid ## SOMETIMES_PRODUCES ## SystemTable + gEdkiiMemoryProfileGuid ## SOMETIMES_PRODUCES ## GUID # Install protocol + gZeroGuid ## SOMETIMES_CONSUMES ## GUID [Ppis] gEfiVectorHandoffInfoPpiGuid ## UNDEFINED # HOB @@ -177,6 +180,8 @@ gEfiMdeModulePkgTokenSpaceGuid.PcdLoadFixAddressRuntimeCodePageNumber ## SOMETIMES_CONSUMES gEfiMdeModulePkgTokenSpaceGuid.PcdLoadModuleAtFixAddressEnable ## CONSUMES gEfiMdeModulePkgTokenSpaceGuid.PcdMaxEfiSystemTablePointerAddress ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdMemoryProfileMemoryType ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdMemoryProfilePropertyMask ## CONSUMES # [Hob] # RESOURCE_DESCRIPTOR ## CONSUMES @@ -190,4 +195,4 @@ # [UserExtensions.TianoCore."ExtraFiles"] - DxeCoreExtra.uni \ No newline at end of file + DxeCoreExtra.uni diff --git a/MdeModulePkg/Core/Dxe/DxeMain/DxeMain.c b/MdeModulePkg/Core/Dxe/DxeMain/DxeMain.c index 5a8814041c..1ac5cc1721 100644 --- a/MdeModulePkg/Core/Dxe/DxeMain/DxeMain.c +++ b/MdeModulePkg/Core/Dxe/DxeMain/DxeMain.c @@ -268,6 +268,8 @@ DxeMain ( // CoreInitializeMemoryServices (&HobStart, &MemoryBaseAddress, &MemoryLength); + MemoryProfileInit (HobStart); + // // Allocate the EFI System Table and EFI Runtime Service Table from EfiRuntimeServicesData // Use the templates to initialize the contents of the EFI System Table and EFI Runtime Services Table @@ -382,6 +384,8 @@ DxeMain ( Status = CoreInitializeEventServices (); ASSERT_EFI_ERROR (Status); + MemoryProfileInstallProtocol (); + // // Get persisted vector hand-off info from GUIDeed HOB again due to HobStart may be updated, // and install configuration table diff --git a/MdeModulePkg/Core/Dxe/Image/Image.c b/MdeModulePkg/Core/Dxe/Image/Image.c index e7ad450db5..5b441f03fb 100644 --- a/MdeModulePkg/Core/Dxe/Image/Image.c +++ b/MdeModulePkg/Core/Dxe/Image/Image.c @@ -1626,6 +1626,7 @@ CoreStartImage ( // Subsequent calls to LongJump() cause a non-zero value to be returned by SetJump(). // if (SetJumpFlag == 0) { + RegisterMemoryProfileImage (Image, (Image->ImageContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION ? EFI_FV_FILETYPE_APPLICATION : EFI_FV_FILETYPE_DRIVER)); // // Call the image's entry point // @@ -1851,6 +1852,7 @@ CoreUnloadImage ( Status = EFI_INVALID_PARAMETER; goto Done; } + UnregisterMemoryProfileImage (Image); if (Image->Started) { // diff --git a/MdeModulePkg/Core/Dxe/Image/Image.h b/MdeModulePkg/Core/Dxe/Image/Image.h index e9240c03b0..7fb8c9368e 100644 --- a/MdeModulePkg/Core/Dxe/Image/Image.h +++ b/MdeModulePkg/Core/Dxe/Image/Image.h @@ -16,56 +16,6 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #ifndef _IMAGE_H_ #define _IMAGE_H_ -#define LOADED_IMAGE_PRIVATE_DATA_SIGNATURE SIGNATURE_32('l','d','r','i') - -typedef struct { - UINTN Signature; - /// Image handle - EFI_HANDLE Handle; - /// Image type - UINTN Type; - /// If entrypoint has been called - BOOLEAN Started; - /// The image's entry point - EFI_IMAGE_ENTRY_POINT EntryPoint; - /// loaded image protocol - EFI_LOADED_IMAGE_PROTOCOL Info; - /// Location in memory - EFI_PHYSICAL_ADDRESS ImageBasePage; - /// Number of pages - UINTN NumberOfPages; - /// Original fixup data - CHAR8 *FixupData; - /// Tpl of started image - EFI_TPL Tpl; - /// Status returned by started image - EFI_STATUS Status; - /// Size of ExitData from started image - UINTN ExitDataSize; - /// Pointer to exit data from started image - VOID *ExitData; - /// Pointer to pool allocation for context save/retore - VOID *JumpBuffer; - /// Pointer to buffer for context save/retore - BASE_LIBRARY_JUMP_BUFFER *JumpContext; - /// Machine type from PE image - UINT16 Machine; - /// EBC Protocol pointer - EFI_EBC_PROTOCOL *Ebc; - /// Runtime image list - EFI_RUNTIME_IMAGE_ENTRY *RuntimeData; - /// Pointer to Loaded Image Device Path Protocl - EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath; - /// PeCoffLoader ImageContext - PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; - /// Status returned by LoadImage() service. - EFI_STATUS LoadImageStatus; -} LOADED_IMAGE_PRIVATE_DATA; - -#define LOADED_IMAGE_PRIVATE_DATA_FROM_THIS(a) \ - CR(a, LOADED_IMAGE_PRIVATE_DATA, Info, LOADED_IMAGE_PRIVATE_DATA_SIGNATURE) - - #define LOAD_PE32_IMAGE_PRIVATE_DATA_SIGNATURE SIGNATURE_32('l','p','e','i') typedef struct { diff --git a/MdeModulePkg/Core/Dxe/Mem/MemoryProfileRecord.c b/MdeModulePkg/Core/Dxe/Mem/MemoryProfileRecord.c new file mode 100644 index 0000000000..1602fdb8e1 --- /dev/null +++ b/MdeModulePkg/Core/Dxe/Mem/MemoryProfileRecord.c @@ -0,0 +1,1377 @@ +/** @file + Support routines for UEFI memory profile. + + Copyright (c) 2014, Intel Corporation. All rights reserved.
+ 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 "DxeMain.h" + +#define IS_UEFI_MEMORY_PROFILE_ENABLED ((PcdGet8 (PcdMemoryProfilePropertyMask) & BIT0) != 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; + + +GLOBAL_REMOVE_IF_UNREFERENCED LIST_ENTRY mImageQueue = INITIALIZE_LIST_HEAD_VARIABLE (mImageQueue); +GLOBAL_REMOVE_IF_UNREFERENCED MEMORY_PROFILE_CONTEXT_DATA mMemoryProfileContext = { + 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 *mMemoryProfileContextPtr = NULL; + +BOOLEAN mMemoryProfileRecordingStatus = FALSE; + +/** + Get memory profile data. + + @param[in] This The EDKII_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_BUFFER_TO_SMALL The ProfileSize is too small for the resulting data. + ProfileSize is updated with the size required. + +**/ +EFI_STATUS +EFIAPI +ProfileProtocolGetData ( + IN EDKII_MEMORY_PROFILE_PROTOCOL *This, + IN OUT UINT64 *ProfileSize, + OUT VOID *ProfileBuffer + ); + +/** + Register image to memory profile. + + @param[in] This The EDKII_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 success. + @return EFI_OUT_OF_RESOURCE No enough resource for this register. + +**/ +EFI_STATUS +EFIAPI +ProfileProtocolRegisterImage ( + IN EDKII_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_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 success. + @return EFI_NOT_FOUND The image is not found. + +**/ +EFI_STATUS +EFIAPI +ProfileProtocolUnregisterImage ( + IN EDKII_MEMORY_PROFILE_PROTOCOL *This, + IN EFI_DEVICE_PATH_PROTOCOL *FilePath, + IN PHYSICAL_ADDRESS ImageBase, + IN UINT64 ImageSize + ); + +EDKII_MEMORY_PROFILE_PROTOCOL mProfileProtocol = { + ProfileProtocolGetData, + ProfileProtocolRegisterImage, + ProfileProtocolUnregisterImage +}; + +/** + Return memory profile context. + + @return Memory profile context. + +**/ +MEMORY_PROFILE_CONTEXT_DATA * +GetMemoryProfileContext ( + VOID + ) +{ + return mMemoryProfileContextPtr; +} + +/** + 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 CoreInternalAllocatePool() that will not update profile for this AllocatePool action. + // + Status = CoreInternalAllocatePool ( + EfiBootServicesData, + 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 DXE Core to memory profile. + + @param HobStart The start address of the HOB. + @param ContextData Memory profile context. + + @retval TRUE Register success. + @retval FALSE Register fail. + +**/ +BOOLEAN +RegisterDxeCore ( + IN VOID *HobStart, + IN MEMORY_PROFILE_CONTEXT_DATA *ContextData + ) +{ + EFI_PEI_HOB_POINTERS DxeCoreHob; + MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData; + PHYSICAL_ADDRESS ImageBase; + + ASSERT (ContextData != NULL); + + // + // Searching for image hob + // + DxeCoreHob.Raw = HobStart; + while ((DxeCoreHob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, DxeCoreHob.Raw)) != NULL) { + if (CompareGuid (&DxeCoreHob.MemoryAllocationModule->MemoryAllocationHeader.Name, &gEfiHobMemoryAllocModuleGuid)) { + // + // Find Dxe Core HOB + // + break; + } + DxeCoreHob.Raw = GET_NEXT_HOB (DxeCoreHob); + } + ASSERT (DxeCoreHob.Raw != NULL); + + ImageBase = DxeCoreHob.MemoryAllocationModule->MemoryAllocationHeader.MemoryBaseAddress; + DriverInfoData = BuildDriverInfo ( + ContextData, + &DxeCoreHob.MemoryAllocationModule->ModuleName, + ImageBase, + DxeCoreHob.MemoryAllocationModule->MemoryAllocationHeader.MemoryLength, + DxeCoreHob.MemoryAllocationModule->EntryPoint, + InternalPeCoffGetSubsystem ((VOID *) (UINTN) ImageBase), + EFI_FV_FILETYPE_DXE_CORE + ); + if (DriverInfoData == NULL) { + return FALSE; + } + + return TRUE; +} + +/** + Initialize memory profile. + + @param HobStart The start address of the HOB. + +**/ +VOID +MemoryProfileInit ( + IN VOID *HobStart + ) +{ + MEMORY_PROFILE_CONTEXT_DATA *ContextData; + + if (!IS_UEFI_MEMORY_PROFILE_ENABLED) { + return; + } + + ContextData = GetMemoryProfileContext (); + if (ContextData != NULL) { + return; + } + + mMemoryProfileRecordingStatus = TRUE; + mMemoryProfileContextPtr = &mMemoryProfileContext; + + RegisterDxeCore (HobStart, &mMemoryProfileContext); + + DEBUG ((EFI_D_INFO, "MemoryProfileInit MemoryProfileContext - 0x%x\n", &mMemoryProfileContext)); +} + +/** + Install memory profile protocol. + +**/ +VOID +MemoryProfileInstallProtocol ( + VOID + ) +{ + EFI_HANDLE Handle; + EFI_STATUS Status; + + if (!IS_UEFI_MEMORY_PROFILE_ENABLED) { + return; + } + + Handle = NULL; + Status = CoreInstallMultipleProtocolInterfaces ( + &Handle, + &gEdkiiMemoryProfileGuid, + &mProfileProtocol, + NULL + ); + 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; + 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 image to memory profile. + + @param DriverEntry Image info. + @param FileType Image file type. + + @retval TRUE Register success. + @retval FALSE Register fail. + +**/ +BOOLEAN +RegisterMemoryProfileImage ( + IN LOADED_IMAGE_PRIVATE_DATA *DriverEntry, + IN EFI_FV_FILETYPE FileType + ) +{ + MEMORY_PROFILE_CONTEXT_DATA *ContextData; + MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData; + + if (!IS_UEFI_MEMORY_PROFILE_ENABLED) { + return FALSE; + } + + ContextData = GetMemoryProfileContext (); + if (ContextData == NULL) { + return FALSE; + } + + DriverInfoData = BuildDriverInfo ( + ContextData, + GetFileNameFromFilePath (DriverEntry->Info.FilePath), + DriverEntry->ImageContext.ImageAddress, + DriverEntry->ImageContext.ImageSize, + DriverEntry->ImageContext.EntryPoint, + DriverEntry->ImageContext.ImageType, + FileType + ); + 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 memory 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 memory profile. + + @param DriverEntry Image info. + + @retval TRUE Unregister success. + @retval FALSE Unregister fail. + +**/ +BOOLEAN +UnregisterMemoryProfileImage ( + IN LOADED_IMAGE_PRIVATE_DATA *DriverEntry + ) +{ + EFI_STATUS Status; + MEMORY_PROFILE_CONTEXT_DATA *ContextData; + MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData; + EFI_GUID *FileName; + PHYSICAL_ADDRESS ImageAddress; + VOID *EntryPointInImage; + + if (!IS_UEFI_MEMORY_PROFILE_ENABLED) { + return FALSE; + } + + ContextData = GetMemoryProfileContext (); + if (ContextData == NULL) { + return FALSE; + } + + DriverInfoData = NULL; + FileName = GetFileNameFromFilePath (DriverEntry->Info.FilePath); + ImageAddress = DriverEntry->ImageContext.ImageAddress; + if ((DriverEntry->ImageContext.EntryPoint < ImageAddress) || (DriverEntry->ImageContext.EntryPoint >= (ImageAddress + DriverEntry->ImageContext.ImageSize))) { + // + // 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->ImageContext.EntryPoint - (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 CoreInternalFreePool() that will not update profile for this FreePool action. + // + CoreInternalFreePool (DriverInfoData); + } + + return TRUE; +} + +/** + Return if this memory type needs to be recorded into memory profile. + If BIOS memory type (0 ~ EfiMaxMemoryType), it checks bit (1 << MemoryType). + If OS memory type (0x80000000 ~ 0xFFFFFFFF), it checks bit63 - 0x8000000000000000. + + @param MemoryType Memory type. + + @retval TRUE This memory type need to be recorded. + @retval FALSE This memory type need not to be recorded. + +**/ +BOOLEAN +CoreNeedRecordProfile ( + IN EFI_MEMORY_TYPE MemoryType + ) +{ + UINT64 TestBit; + + if ((UINT32) MemoryType >= 0x80000000) { + TestBit = BIT63; + } else { + 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), ProfileMemoryIndex = MemoryType. + If OS memory type (0x80000000 ~ 0xFFFFFFFF), ProfileMemoryIndex = EfiMaxMemoryType. + + @param MemoryType Memory type. + + @return EFI memory type as profile memory index. + +**/ +EFI_MEMORY_TYPE +GetProfileMemoryIndex ( + IN EFI_MEMORY_TYPE MemoryType + ) +{ + if ((UINT32) MemoryType >= 0x80000000) { + return EfiMaxMemoryType; + } else { + return MemoryType; + } +} + +/** + Update memory 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 +CoreUpdateProfileAllocate ( + 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; + + ContextData = GetMemoryProfileContext (); + if (ContextData == NULL) { + return FALSE; + } + + DriverInfoData = GetMemoryProfileDriverInfoFromAddress (ContextData, CallerAddress); + ASSERT (DriverInfoData != NULL); + + // + // Use CoreInternalAllocatePool() that will not update profile for this AllocatePool action. + // + Status = CoreInternalAllocatePool ( + EfiBootServicesData, + 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 ++; + + 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 memory 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 +CoreUpdateProfileFree ( + 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 = GetMemoryProfileContext (); + 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) { + CoreUpdateProfileAllocate ( + 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)) { + CoreUpdateProfileAllocate ( + AllocInfo->CallerAddress, + MemoryProfileActionAllocatePages, + AllocInfo->MemoryType, + (UINTN) ((AllocInfo->Buffer + AllocInfo->Size) - ((PHYSICAL_ADDRESS) (UINTN) Buffer + Size)), + (VOID *) ((UINTN) Buffer + Size) + ); + } + } + + // + // Use CoreInternalFreePool() that will not update profile for this FreePool action. + // + CoreInternalFreePool (AllocInfoData); + + return TRUE; +} + +/** + Update memory 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 +CoreUpdateProfile ( + 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_UEFI_MEMORY_PROFILE_ENABLED) { + return FALSE; + } + + if (!mMemoryProfileRecordingStatus) { + return FALSE; + } + + // + // Free operations have no memory type information, so skip the check. + // + if ((Action == MemoryProfileActionAllocatePages) || (Action == MemoryProfileActionAllocatePool)) { + // + // Only record limited MemoryType. + // + if (!CoreNeedRecordProfile (MemoryType)) { + return FALSE; + } + } + + ContextData = GetMemoryProfileContext (); + if (ContextData == NULL) { + return FALSE; + } + + switch (Action) { + case MemoryProfileActionAllocatePages: + CoreUpdateProfileAllocate (CallerAddress, Action, MemoryType, Size, Buffer); + break; + case MemoryProfileActionFreePages: + CoreUpdateProfileFree (CallerAddress, Action, Size, Buffer); + break; + case MemoryProfileActionAllocatePool: + CoreUpdateProfileAllocate (CallerAddress, Action, MemoryType, Size, Buffer); + break; + case MemoryProfileActionFreePool: + CoreUpdateProfileFree (CallerAddress, Action, 0, Buffer); + break; + default: + ASSERT (FALSE); + break; + } + return TRUE; +} + +//////////////////// + +/** + Get memory profile data size. + + @return Memory profile data size. + +**/ +UINTN +MemoryProfileGetDataSize ( + VOID + ) +{ + MEMORY_PROFILE_CONTEXT_DATA *ContextData; + MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData; + LIST_ENTRY *DriverInfoList; + LIST_ENTRY *DriverLink; + UINTN TotalSize; + + + ContextData = GetMemoryProfileContext (); + 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; + } + + return TotalSize; +} + +/** + Copy memory profile data. + + @param ProfileBuffer The buffer to hold memory profile data. + +**/ +VOID +MemoryProfileCopyData ( + IN VOID *ProfileBuffer + ) +{ + 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; + + ContextData = GetMemoryProfileContext (); + if (ContextData == NULL) { + return ; + } + + Context = ProfileBuffer; + CopyMem (Context, &ContextData->Context, sizeof (MEMORY_PROFILE_CONTEXT)); + DriverInfo = (MEMORY_PROFILE_DRIVER_INFO *) (Context + 1); + + 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 + ); + CopyMem (DriverInfo, &DriverInfoData->DriverInfo, sizeof (MEMORY_PROFILE_DRIVER_INFO)); + AllocInfo = (MEMORY_PROFILE_ALLOC_INFO *) (DriverInfo + 1); + + 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 + ); + CopyMem (AllocInfo, &AllocInfoData->AllocInfo, sizeof (MEMORY_PROFILE_ALLOC_INFO)); + AllocInfo += 1; + } + + DriverInfo = (MEMORY_PROFILE_DRIVER_INFO *) ((UINTN) (DriverInfo + 1) + sizeof (MEMORY_PROFILE_ALLOC_INFO) * (UINTN) DriverInfo->AllocRecordCount); + } +} + +/** + Get memory profile data. + + @param[in] This The EDKII_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_BUFFER_TO_SMALL The ProfileSize is too small for the resulting data. + ProfileSize is updated with the size required. + +**/ +EFI_STATUS +EFIAPI +ProfileProtocolGetData ( + IN EDKII_MEMORY_PROFILE_PROTOCOL *This, + IN OUT UINT64 *ProfileSize, + OUT VOID *ProfileBuffer + ) +{ + UINTN Size; + MEMORY_PROFILE_CONTEXT_DATA *ContextData; + BOOLEAN MemoryProfileRecordingStatus; + + ContextData = GetMemoryProfileContext (); + if (ContextData == NULL) { + return EFI_UNSUPPORTED; + } + + MemoryProfileRecordingStatus = mMemoryProfileRecordingStatus; + mMemoryProfileRecordingStatus = FALSE; + + Size = MemoryProfileGetDataSize (); + + if (*ProfileSize < Size) { + *ProfileSize = Size; + mMemoryProfileRecordingStatus = MemoryProfileRecordingStatus; + return EFI_BUFFER_TOO_SMALL; + } + + *ProfileSize = Size; + MemoryProfileCopyData (ProfileBuffer); + + mMemoryProfileRecordingStatus = MemoryProfileRecordingStatus; + return EFI_SUCCESS; +} + +/** + Register image to memory profile. + + @param[in] This The EDKII_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 success. + @return EFI_OUT_OF_RESOURCE No enough resource for this register. + +**/ +EFI_STATUS +EFIAPI +ProfileProtocolRegisterImage ( + IN EDKII_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; + LOADED_IMAGE_PRIVATE_DATA DriverEntry; + VOID *EntryPointInImage; + + ZeroMem (&DriverEntry, sizeof (DriverEntry)); + DriverEntry.Info.FilePath = FilePath; + DriverEntry.ImageContext.ImageAddress = ImageBase; + DriverEntry.ImageContext.ImageSize = ImageSize; + Status = InternalPeCoffGetEntryPoint ((VOID *) (UINTN) ImageBase, &EntryPointInImage); + ASSERT_EFI_ERROR (Status); + DriverEntry.ImageContext.EntryPoint = (PHYSICAL_ADDRESS) (UINTN) EntryPointInImage; + DriverEntry.ImageContext.ImageType = InternalPeCoffGetSubsystem ((VOID *) (UINTN) ImageBase); + + return RegisterMemoryProfileImage (&DriverEntry, FileType) ? EFI_SUCCESS: EFI_OUT_OF_RESOURCES; +} + +/** + Unregister image from memory profile. + + @param[in] This The EDKII_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 success. + @return EFI_NOT_FOUND The image is not found. + +**/ +EFI_STATUS +EFIAPI +ProfileProtocolUnregisterImage ( + IN EDKII_MEMORY_PROFILE_PROTOCOL *This, + IN EFI_DEVICE_PATH_PROTOCOL *FilePath, + IN PHYSICAL_ADDRESS ImageBase, + IN UINT64 ImageSize + ) +{ + EFI_STATUS Status; + LOADED_IMAGE_PRIVATE_DATA DriverEntry; + VOID *EntryPointInImage; + + ZeroMem (&DriverEntry, sizeof (DriverEntry)); + DriverEntry.Info.FilePath = FilePath; + DriverEntry.ImageContext.ImageAddress = ImageBase; + DriverEntry.ImageContext.ImageSize = ImageSize; + Status = InternalPeCoffGetEntryPoint ((VOID *) (UINTN) ImageBase, &EntryPointInImage); + ASSERT_EFI_ERROR (Status); + DriverEntry.ImageContext.EntryPoint = (PHYSICAL_ADDRESS) (UINTN) EntryPointInImage; + + return UnregisterMemoryProfileImage (&DriverEntry) ? EFI_SUCCESS: EFI_NOT_FOUND; +} + +//////////////////// diff --git a/MdeModulePkg/Core/Dxe/Mem/Page.c b/MdeModulePkg/Core/Dxe/Mem/Page.c index f5067f663e..18780070c5 100644 --- a/MdeModulePkg/Core/Dxe/Mem/Page.c +++ b/MdeModulePkg/Core/Dxe/Mem/Page.c @@ -1106,7 +1106,7 @@ FindFreePages ( **/ EFI_STATUS EFIAPI -CoreAllocatePages ( +CoreInternalAllocatePages ( IN EFI_ALLOCATE_TYPE Type, IN EFI_MEMORY_TYPE MemoryType, IN UINTN NumberOfPages, @@ -1192,6 +1192,41 @@ Done: return Status; } +/** + Allocates pages from the memory map. + + @param Type The type of allocation to perform + @param MemoryType The type of memory to turn the allocated pages + into + @param NumberOfPages The number of pages to allocate + @param Memory A pointer to receive the base allocated memory + address + + @return Status. On success, Memory is filled in with the base address allocated + @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in + spec. + @retval EFI_NOT_FOUND Could not allocate pages match the requirement. + @retval EFI_OUT_OF_RESOURCES No enough pages to allocate. + @retval EFI_SUCCESS Pages successfully allocated. + +**/ +EFI_STATUS +EFIAPI +CoreAllocatePages ( + IN EFI_ALLOCATE_TYPE Type, + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN NumberOfPages, + OUT EFI_PHYSICAL_ADDRESS *Memory + ) +{ + EFI_STATUS Status; + + Status = CoreInternalAllocatePages (Type, MemoryType, NumberOfPages, Memory); + if (!EFI_ERROR (Status)) { + CoreUpdateProfile ((EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0), MemoryProfileActionAllocatePages, MemoryType, EFI_PAGES_TO_SIZE (NumberOfPages), (VOID *) (UINTN) *Memory); + } + return Status; +} /** Frees previous allocated pages. @@ -1206,7 +1241,7 @@ Done: **/ EFI_STATUS EFIAPI -CoreFreePages ( +CoreInternalFreePages ( IN EFI_PHYSICAL_ADDRESS Memory, IN UINTN NumberOfPages ) @@ -1267,6 +1302,33 @@ Done: return Status; } +/** + Frees previous allocated pages. + + @param Memory Base address of memory being freed + @param NumberOfPages The number of pages to free + + @retval EFI_NOT_FOUND Could not find the entry that covers the range + @retval EFI_INVALID_PARAMETER Address not aligned + @return EFI_SUCCESS -Pages successfully freed. + +**/ +EFI_STATUS +EFIAPI +CoreFreePages ( + IN EFI_PHYSICAL_ADDRESS Memory, + IN UINTN NumberOfPages + ) +{ + EFI_STATUS Status; + + Status = CoreInternalFreePages (Memory, NumberOfPages); + if (!EFI_ERROR (Status)) { + CoreUpdateProfile ((EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0), MemoryProfileActionFreePages, 0, EFI_PAGES_TO_SIZE (NumberOfPages), (VOID *) (UINTN) Memory); + } + return Status; +} + /** This function checks to see if the last memory map descriptor in a memory map can be merged with any of the other memory map descriptors in a memorymap. diff --git a/MdeModulePkg/Core/Dxe/Mem/Pool.c b/MdeModulePkg/Core/Dxe/Mem/Pool.c index 7d250980f0..1891bb7387 100644 --- a/MdeModulePkg/Core/Dxe/Mem/Pool.c +++ b/MdeModulePkg/Core/Dxe/Mem/Pool.c @@ -175,7 +175,7 @@ LookupPoolHead ( **/ EFI_STATUS EFIAPI -CoreAllocatePool ( +CoreInternalAllocatePool ( IN EFI_MEMORY_TYPE PoolType, IN UINTN Size, OUT VOID **Buffer @@ -218,7 +218,35 @@ CoreAllocatePool ( return (*Buffer != NULL) ? EFI_SUCCESS : EFI_OUT_OF_RESOURCES; } +/** + Allocate pool of a particular type. + + @param PoolType Type of pool to allocate + @param Size The amount of pool to allocate + @param Buffer The address to return a pointer to the allocated + pool + + @retval EFI_INVALID_PARAMETER PoolType not valid or Buffer is NULL. + @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed. + @retval EFI_SUCCESS Pool successfully allocated. + +**/ +EFI_STATUS +EFIAPI +CoreAllocatePool ( + IN EFI_MEMORY_TYPE PoolType, + IN UINTN Size, + OUT VOID **Buffer + ) +{ + EFI_STATUS Status; + Status = CoreInternalAllocatePool (PoolType, Size, Buffer); + if (!EFI_ERROR (Status)) { + CoreUpdateProfile ((EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0), MemoryProfileActionAllocatePool, PoolType, Size, *Buffer); + } + return Status; +} /** Internal function to allocate pool of a particular type. @@ -373,7 +401,7 @@ Done: **/ EFI_STATUS EFIAPI -CoreFreePool ( +CoreInternalFreePool ( IN VOID *Buffer ) { @@ -389,7 +417,29 @@ CoreFreePool ( return Status; } +/** + Frees pool. + + @param Buffer The allocated pool entry to free + + @retval EFI_INVALID_PARAMETER Buffer is not a valid value. + @retval EFI_SUCCESS Pool successfully freed. + +**/ +EFI_STATUS +EFIAPI +CoreFreePool ( + IN VOID *Buffer + ) +{ + EFI_STATUS Status; + Status = CoreInternalFreePool (Buffer); + if (!EFI_ERROR (Status)) { + CoreUpdateProfile ((EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0), MemoryProfileActionFreePool, 0, 0, Buffer); + } + return Status; +} /** Internal function to free a pool entry. @@ -558,3 +608,4 @@ CoreFreePoolI ( return EFI_SUCCESS; } + diff --git a/MdeModulePkg/Core/PiSmmCore/Dispatcher.c b/MdeModulePkg/Core/PiSmmCore/Dispatcher.c index a4686306f6..178681ec90 100644 --- a/MdeModulePkg/Core/PiSmmCore/Dispatcher.c +++ b/MdeModulePkg/Core/PiSmmCore/Dispatcher.c @@ -874,10 +874,12 @@ SmmDispatcher ( // // For each SMM driver, pass NULL as ImageHandle // + RegisterSmramProfileImage (DriverEntry, TRUE); PERF_START (DriverEntry->ImageHandle, "StartImage:", NULL, 0); Status = ((EFI_IMAGE_ENTRY_POINT)(UINTN)DriverEntry->ImageEntryPoint)(DriverEntry->ImageHandle, gST); PERF_END (DriverEntry->ImageHandle, "StartImage:", NULL, 0); if (EFI_ERROR(Status)){ + UnregisterSmramProfileImage (DriverEntry, TRUE); SmmFreePages(DriverEntry->ImageBuffer, DriverEntry->NumberOfPage); } diff --git a/MdeModulePkg/Core/PiSmmCore/Page.c b/MdeModulePkg/Core/PiSmmCore/Page.c index 5b6e849a2d..9cc2a4cabc 100644 --- a/MdeModulePkg/Core/PiSmmCore/Page.c +++ b/MdeModulePkg/Core/PiSmmCore/Page.c @@ -1,7 +1,7 @@ /** @file SMM Memory page management functions. - Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+ Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.
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 @@ -16,11 +16,6 @@ #define TRUNCATE_TO_PAGES(a) ((a) >> EFI_PAGE_SHIFT) -typedef struct { - LIST_ENTRY Link; - UINTN NumberOfPages; -} FREE_PAGE_LIST; - LIST_ENTRY mSmmMemoryMap = INITIALIZE_LIST_HEAD_VARIABLE (mSmmMemoryMap); /** @@ -151,7 +146,7 @@ InternalAllocAddress ( **/ EFI_STATUS EFIAPI -SmmAllocatePages ( +SmmInternalAllocatePages ( IN EFI_ALLOCATE_TYPE Type, IN EFI_MEMORY_TYPE MemoryType, IN UINTN NumberOfPages, @@ -202,6 +197,40 @@ SmmAllocatePages ( return EFI_SUCCESS; } +/** + Allocates pages from the memory map. + + @param Type The type of allocation to perform. + @param MemoryType The type of memory to turn the allocated pages + into. + @param NumberOfPages The number of pages to allocate. + @param Memory A pointer to receive the base allocated memory + address. + + @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in spec. + @retval EFI_NOT_FOUND Could not allocate pages match the requirement. + @retval EFI_OUT_OF_RESOURCES No enough pages to allocate. + @retval EFI_SUCCESS Pages successfully allocated. + +**/ +EFI_STATUS +EFIAPI +SmmAllocatePages ( + IN EFI_ALLOCATE_TYPE Type, + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN NumberOfPages, + OUT EFI_PHYSICAL_ADDRESS *Memory + ) +{ + EFI_STATUS Status; + + Status = SmmInternalAllocatePages (Type, MemoryType, NumberOfPages, Memory); + if (!EFI_ERROR (Status)) { + SmmCoreUpdateProfile ((EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0), MemoryProfileActionAllocatePages, MemoryType, EFI_PAGES_TO_SIZE (NumberOfPages), (VOID *) (UINTN) *Memory); + } + return Status; +} + /** Internal Function. Merge two adjacent nodes. @@ -242,7 +271,7 @@ InternalMergeNodes ( **/ EFI_STATUS EFIAPI -SmmFreePages ( +SmmInternalFreePages ( IN EFI_PHYSICAL_ADDRESS Memory, IN UINTN NumberOfPages ) @@ -293,6 +322,33 @@ SmmFreePages ( return EFI_SUCCESS; } +/** + Frees previous allocated pages. + + @param Memory Base address of memory being freed. + @param NumberOfPages The number of pages to free. + + @retval EFI_NOT_FOUND Could not find the entry that covers the range. + @retval EFI_INVALID_PARAMETER Address not aligned. + @return EFI_SUCCESS Pages successfully freed. + +**/ +EFI_STATUS +EFIAPI +SmmFreePages ( + IN EFI_PHYSICAL_ADDRESS Memory, + IN UINTN NumberOfPages + ) +{ + EFI_STATUS Status; + + Status = SmmInternalFreePages (Memory, NumberOfPages); + if (!EFI_ERROR (Status)) { + SmmCoreUpdateProfile ((EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0), MemoryProfileActionFreePages, 0, EFI_PAGES_TO_SIZE (NumberOfPages), (VOID *) (UINTN) Memory); + } + return Status; +} + /** Add free SMRAM region for use by memory service. diff --git a/MdeModulePkg/Core/PiSmmCore/PiSmmCore.c b/MdeModulePkg/Core/PiSmmCore/PiSmmCore.c index a7220e4235..d16baedec9 100644 --- a/MdeModulePkg/Core/PiSmmCore/PiSmmCore.c +++ b/MdeModulePkg/Core/PiSmmCore/PiSmmCore.c @@ -1,7 +1,7 @@ /** @file SMM Core Main Entry Point - Copyright (c) 2009 - 2012, Intel Corporation. All rights reserved.
+ Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.
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 @@ -82,6 +82,9 @@ SMM_CORE_SMI_HANDLERS mSmmCoreSmiHandlers[] = { { NULL, NULL, NULL, FALSE } }; +UINTN mFullSmramRangeCount; +EFI_SMRAM_DESCRIPTOR *mFullSmramRanges; + /** Place holder function until all the SMM System Table Service are available. @@ -226,6 +229,8 @@ SmmReadyToLockHandler ( gST = NULL; gBS = NULL; + SmramProfileReadyToLock (); + return Status; } @@ -401,6 +406,16 @@ SmmMain ( // SmmInitializeMemoryServices (gSmmCorePrivate->SmramRangeCount, gSmmCorePrivate->SmramRanges); + SmramProfileInit (); + + // + // Copy FullSmramRanges to SMRAM + // + mFullSmramRangeCount = gSmmCorePrivate->FullSmramRangeCount; + mFullSmramRanges = AllocatePool (mFullSmramRangeCount * sizeof (EFI_SMRAM_DESCRIPTOR)); + ASSERT (mFullSmramRanges != NULL); + CopyMem (mFullSmramRanges, gSmmCorePrivate->FullSmramRanges, mFullSmramRangeCount * sizeof (EFI_SMRAM_DESCRIPTOR)); + // // Register all SMI Handlers required by the SMM Core // @@ -412,6 +427,8 @@ SmmMain ( ); ASSERT_EFI_ERROR (Status); } - + + RegisterSmramProfileHandler (); + return EFI_SUCCESS; } diff --git a/MdeModulePkg/Core/PiSmmCore/PiSmmCore.h b/MdeModulePkg/Core/PiSmmCore/PiSmmCore.h index 5392fb2315..d494519d2c 100644 --- a/MdeModulePkg/Core/PiSmmCore/PiSmmCore.h +++ b/MdeModulePkg/Core/PiSmmCore/PiSmmCore.h @@ -2,7 +2,7 @@ The internal header file includes the common header files, defines internal structure and functions used by SmmCore module. - Copyright (c) 2009 - 2012, Intel Corporation. All rights reserved.
+ Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.
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 @@ -33,6 +33,8 @@ #include #include #include +#include +#include #include #include @@ -271,6 +273,31 @@ SmmAllocatePages ( OUT EFI_PHYSICAL_ADDRESS *Memory ); +/** + Allocates pages from the memory map. + + @param Type The type of allocation to perform + @param MemoryType The type of memory to turn the allocated pages + into + @param NumberOfPages The number of pages to allocate + @param Memory A pointer to receive the base allocated memory + address + + @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in spec. + @retval EFI_NOT_FOUND Could not allocate pages match the requirement. + @retval EFI_OUT_OF_RESOURCES No enough pages to allocate. + @retval EFI_SUCCESS Pages successfully allocated. + +**/ +EFI_STATUS +EFIAPI +SmmInternalAllocatePages ( + IN EFI_ALLOCATE_TYPE Type, + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN NumberOfPages, + OUT EFI_PHYSICAL_ADDRESS *Memory + ); + /** Frees previous allocated pages. @@ -289,6 +316,24 @@ SmmFreePages ( IN UINTN NumberOfPages ); +/** + Frees previous allocated pages. + + @param Memory Base address of memory being freed + @param NumberOfPages The number of pages to free + + @retval EFI_NOT_FOUND Could not find the entry that covers the range + @retval EFI_INVALID_PARAMETER Address not aligned + @return EFI_SUCCESS Pages successfully freed. + +**/ +EFI_STATUS +EFIAPI +SmmInternalFreePages ( + IN EFI_PHYSICAL_ADDRESS Memory, + IN UINTN NumberOfPages + ); + /** Allocate pool of a particular type. @@ -310,6 +355,27 @@ SmmAllocatePool ( OUT VOID **Buffer ); +/** + Allocate pool of a particular type. + + @param PoolType Type of pool to allocate + @param Size The amount of pool to allocate + @param Buffer The address to return a pointer to the allocated + pool + + @retval EFI_INVALID_PARAMETER PoolType not valid + @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed. + @retval EFI_SUCCESS Pool successfully allocated. + +**/ +EFI_STATUS +EFIAPI +SmmInternalAllocatePool ( + IN EFI_MEMORY_TYPE PoolType, + IN UINTN Size, + OUT VOID **Buffer + ); + /** Frees pool. @@ -325,6 +391,21 @@ SmmFreePool ( IN VOID *Buffer ); +/** + Frees pool. + + @param Buffer The allocated pool entry to free + + @retval EFI_INVALID_PARAMETER Buffer is not a valid value. + @retval EFI_SUCCESS Pool successfully freed. + +**/ +EFI_STATUS +EFIAPI +SmmInternalFreePool ( + IN VOID *Buffer + ); + /** Installs a protocol interface into the boot services environment. @@ -741,4 +822,101 @@ SmmIsSchedulable ( IN EFI_SMM_DRIVER_ENTRY *DriverEntry ); +// +// SmramProfile +// + +/** + Initialize SMRAM profile. + +**/ +VOID +SmramProfileInit ( + VOID + ); + +/** + 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 + ); + +/** + Unregister image from SMRAM profile. + + @param DriverEntry SMM image info. + @param UnregisterToDxe Unregister image from DXE. + + @retval TRUE Unregister success. + @retval FALSE Unregister fail. + +**/ +BOOLEAN +UnregisterSmramProfileImage ( + IN EFI_SMM_DRIVER_ENTRY *DriverEntry, + IN BOOLEAN UnregisterToDxe + ); + +/** + 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 EFI_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 + ); + +/** + Register SMRAM profile handler. + +**/ +VOID +RegisterSmramProfileHandler ( + VOID + ); + +/** + SMRAM profile ready to lock callback function. + +**/ +VOID +SmramProfileReadyToLock ( + VOID + ); + +/** + Dump SMRAM infromation. + +**/ +VOID +DumpSmramInfo ( + VOID + ); + +extern UINTN mFullSmramRangeCount; +extern EFI_SMRAM_DESCRIPTOR *mFullSmramRanges; + #endif diff --git a/MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf b/MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf index 1225a20f2a..0c8e690846 100644 --- a/MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf +++ b/MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf @@ -37,6 +37,7 @@ Dispatcher.c Smi.c InstallConfigurationTable.c + SmramProfileRecord.c [Packages] MdePkg/MdePkg.dec @@ -73,12 +74,18 @@ [Pcd] gEfiMdeModulePkgTokenSpaceGuid.PcdLoadFixAddressSmmCodePageNumber ## SOMETIMES_CONSUMES gEfiMdeModulePkgTokenSpaceGuid.PcdLoadModuleAtFixAddressEnable ## CONSUMES - + gEfiMdeModulePkgTokenSpaceGuid.PcdMemoryProfileMemoryType ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdMemoryProfilePropertyMask ## CONSUMES + [Guids] gAprioriGuid ## SOMETIMES_CONSUMES ## File gEfiEventDxeDispatchGuid ## PRODUCES ## GUID # SmiHandlerRegister gEfiEventLegacyBootGuid ## PRODUCES ## GUID # SmiHandlerRegister gEfiEndOfDxeEventGroupGuid ## PRODUCES ## GUID # SmiHandlerRegister + ## SOMETIMES_CONSUMES ## GUID # Locate protocol + ## SOMETIMES_PRODUCES ## GUID # SmiHandlerRegister + gEdkiiMemoryProfileGuid + gZeroGuid ## SOMETIMES_CONSUMES ## GUID [UserExtensions.TianoCore."ExtraFiles"] PiSmmCoreExtra.uni diff --git a/MdeModulePkg/Core/PiSmmCore/PiSmmCorePrivateData.h b/MdeModulePkg/Core/PiSmmCore/PiSmmCorePrivateData.h index 411ebd823f..3934d2f2ec 100644 --- a/MdeModulePkg/Core/PiSmmCore/PiSmmCorePrivateData.h +++ b/MdeModulePkg/Core/PiSmmCore/PiSmmCorePrivateData.h @@ -2,7 +2,7 @@ The internal header file that declared a data structure that is shared between the SMM IPL and the SMM Core. - Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
+ Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.
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 @@ -116,6 +116,57 @@ typedef struct { /// a software SMI handler back to the caller of the SMM Communication Protocol. /// EFI_STATUS ReturnStatus; + + EFI_PHYSICAL_ADDRESS PiSmmCoreImageBase; + UINT64 PiSmmCoreImageSize; + EFI_PHYSICAL_ADDRESS PiSmmCoreEntryPoint; + + UINTN FullSmramRangeCount; + EFI_SMRAM_DESCRIPTOR *FullSmramRanges; } SMM_CORE_PRIVATE_DATA; +// +// Page management +// + +typedef struct { + LIST_ENTRY Link; + UINTN NumberOfPages; +} FREE_PAGE_LIST; + +extern LIST_ENTRY mSmmMemoryMap; + +// +// Pool management +// + +// +// MIN_POOL_SHIFT must not be less than 5 +// +#define MIN_POOL_SHIFT 6 +#define MIN_POOL_SIZE (1 << MIN_POOL_SHIFT) + +// +// MAX_POOL_SHIFT must not be less than EFI_PAGE_SHIFT - 1 +// +#define MAX_POOL_SHIFT (EFI_PAGE_SHIFT - 1) +#define MAX_POOL_SIZE (1 << MAX_POOL_SHIFT) + +// +// MAX_POOL_INDEX are calculated by maximum and minimum pool sizes +// +#define MAX_POOL_INDEX (MAX_POOL_SHIFT - MIN_POOL_SHIFT + 1) + +typedef struct { + UINTN Size; + BOOLEAN Available; +} POOL_HEADER; + +typedef struct { + POOL_HEADER Header; + LIST_ENTRY Link; +} FREE_POOL_HEADER; + +extern LIST_ENTRY mSmmPoolLists[MAX_POOL_INDEX]; + #endif diff --git a/MdeModulePkg/Core/PiSmmCore/PiSmmIpl.c b/MdeModulePkg/Core/PiSmmCore/PiSmmIpl.c index b0e387401c..21c69ca6ef 100644 --- a/MdeModulePkg/Core/PiSmmCore/PiSmmIpl.c +++ b/MdeModulePkg/Core/PiSmmCore/PiSmmIpl.c @@ -979,6 +979,13 @@ ExecuteSmmCoreFromSmram ( // DEBUG ((DEBUG_INFO, "SMM IPL calling SMM Core at SMRAM address %p\n", (VOID *)(UINTN)ImageContext.EntryPoint)); + gSmmCorePrivate->PiSmmCoreImageBase = ImageContext.ImageAddress; + gSmmCorePrivate->PiSmmCoreImageSize = ImageContext.ImageSize; + DEBUG ((DEBUG_INFO, "PiSmmCoreImageBase - 0x%016lx\n", gSmmCorePrivate->PiSmmCoreImageBase)); + DEBUG ((DEBUG_INFO, "PiSmmCoreImageSize - 0x%016lx\n", gSmmCorePrivate->PiSmmCoreImageSize)); + + gSmmCorePrivate->PiSmmCoreEntryPoint = ImageContext.EntryPoint; + // // Execute image // @@ -1076,6 +1083,14 @@ SmmIplEntry ( gSmmCorePrivate->SmramRangeCount = Size / sizeof (EFI_SMRAM_DESCRIPTOR); + // + // Save a full copy + // + gSmmCorePrivate->FullSmramRangeCount = gSmmCorePrivate->SmramRangeCount; + gSmmCorePrivate->FullSmramRanges = (EFI_SMRAM_DESCRIPTOR *) AllocatePool (Size); + ASSERT (gSmmCorePrivate->FullSmramRanges != NULL); + CopyMem (gSmmCorePrivate->FullSmramRanges, gSmmCorePrivate->SmramRanges, Size); + // // Open all SMRAM ranges // diff --git a/MdeModulePkg/Core/PiSmmCore/Pool.c b/MdeModulePkg/Core/PiSmmCore/Pool.c index beb5cd965e..34dcc93f1a 100644 --- a/MdeModulePkg/Core/PiSmmCore/Pool.c +++ b/MdeModulePkg/Core/PiSmmCore/Pool.c @@ -1,7 +1,7 @@ /** @file SMM Memory pool management functions. - Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
+ Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.
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 @@ -14,33 +14,6 @@ #include "PiSmmCore.h" -// -// MIN_POOL_SHIFT must not be less than 5 -// -#define MIN_POOL_SHIFT 6 -#define MIN_POOL_SIZE (1 << MIN_POOL_SHIFT) - -// -// MAX_POOL_SHIFT must not be less than EFI_PAGE_SHIFT - 1 -// -#define MAX_POOL_SHIFT (EFI_PAGE_SHIFT - 1) -#define MAX_POOL_SIZE (1 << MAX_POOL_SHIFT) - -// -// MAX_POOL_INDEX are calculated by maximum and minimum pool sizes -// -#define MAX_POOL_INDEX (MAX_POOL_SHIFT - MIN_POOL_SHIFT + 1) - -typedef struct { - UINTN Size; - BOOLEAN Available; -} POOL_HEADER; - -typedef struct { - POOL_HEADER Header; - LIST_ENTRY Link; -} FREE_POOL_HEADER; - LIST_ENTRY mSmmPoolLists[MAX_POOL_INDEX]; // // To cache the SMRAM base since when Loading modules At fixed address feature is enabled, @@ -141,16 +114,18 @@ InternalAllocPoolByIndex ( OUT FREE_POOL_HEADER **FreePoolHdr ) { - EFI_STATUS Status; - FREE_POOL_HEADER *Hdr; + EFI_STATUS Status; + FREE_POOL_HEADER *Hdr; + EFI_PHYSICAL_ADDRESS Address; ASSERT (PoolIndex <= MAX_POOL_INDEX); Status = EFI_SUCCESS; if (PoolIndex == MAX_POOL_INDEX) { - Hdr = (FREE_POOL_HEADER *)AllocatePages (EFI_SIZE_TO_PAGES (MAX_POOL_SIZE << 1)); - if (Hdr == NULL) { + Status = SmmInternalAllocatePages (AllocateAnyPages, EfiRuntimeServicesData, EFI_SIZE_TO_PAGES (MAX_POOL_SIZE << 1), &Address); + if (EFI_ERROR (Status)) { return EFI_OUT_OF_RESOURCES; } + Hdr = (FREE_POOL_HEADER *) (UINTN) Address; } else if (!IsListEmpty (&mSmmPoolLists[PoolIndex])) { Hdr = BASE_CR (GetFirstNode (&mSmmPoolLists[PoolIndex]), FREE_POOL_HEADER, Link); RemoveEntryList (&Hdr->Link); @@ -214,7 +189,7 @@ InternalFreePoolByIndex ( **/ EFI_STATUS EFIAPI -SmmAllocatePool ( +SmmInternalAllocatePool ( IN EFI_MEMORY_TYPE PoolType, IN UINTN Size, OUT VOID **Buffer @@ -234,7 +209,7 @@ SmmAllocatePool ( Size += sizeof (*PoolHdr); if (Size > MAX_POOL_SIZE) { Size = EFI_SIZE_TO_PAGES (Size); - Status = SmmAllocatePages (AllocateAnyPages, PoolType, Size, &Address); + Status = SmmInternalAllocatePages (AllocateAnyPages, PoolType, Size, &Address); if (EFI_ERROR (Status)) { return Status; } @@ -257,6 +232,36 @@ SmmAllocatePool ( return Status; } +/** + Allocate pool of a particular type. + + @param PoolType Type of pool to allocate. + @param Size The amount of pool to allocate. + @param Buffer The address to return a pointer to the allocated + pool. + + @retval EFI_INVALID_PARAMETER PoolType not valid. + @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed. + @retval EFI_SUCCESS Pool successfully allocated. + +**/ +EFI_STATUS +EFIAPI +SmmAllocatePool ( + IN EFI_MEMORY_TYPE PoolType, + IN UINTN Size, + OUT VOID **Buffer + ) +{ + EFI_STATUS Status; + + Status = SmmInternalAllocatePool (PoolType, Size, Buffer); + if (!EFI_ERROR (Status)) { + SmmCoreUpdateProfile ((EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0), MemoryProfileActionAllocatePool, PoolType, Size, *Buffer); + } + return Status; +} + /** Frees pool. @@ -268,7 +273,7 @@ SmmAllocatePool ( **/ EFI_STATUS EFIAPI -SmmFreePool ( +SmmInternalFreePool ( IN VOID *Buffer ) { @@ -284,10 +289,34 @@ SmmFreePool ( if (FreePoolHdr->Header.Size > MAX_POOL_SIZE) { ASSERT (((UINTN)FreePoolHdr & EFI_PAGE_MASK) == 0); ASSERT ((FreePoolHdr->Header.Size & EFI_PAGE_MASK) == 0); - return SmmFreePages ( + return SmmInternalFreePages ( (EFI_PHYSICAL_ADDRESS)(UINTN)FreePoolHdr, EFI_SIZE_TO_PAGES (FreePoolHdr->Header.Size) ); } return InternalFreePoolByIndex (FreePoolHdr); } + +/** + Frees pool. + + @param Buffer The allocated pool entry to free. + + @retval EFI_INVALID_PARAMETER Buffer is not a valid value. + @retval EFI_SUCCESS Pool successfully freed. + +**/ +EFI_STATUS +EFIAPI +SmmFreePool ( + IN VOID *Buffer + ) +{ + EFI_STATUS Status; + + Status = SmmInternalFreePool (Buffer); + if (!EFI_ERROR (Status)) { + SmmCoreUpdateProfile ((EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0), MemoryProfileActionFreePool, 0, 0, Buffer); + } + return Status; +} diff --git a/MdeModulePkg/Core/PiSmmCore/SmramProfileRecord.c b/MdeModulePkg/Core/PiSmmCore/SmramProfileRecord.c new file mode 100644 index 0000000000..24ab1b1de4 --- /dev/null +++ b/MdeModulePkg/Core/PiSmmCore/SmramProfileRecord.c @@ -0,0 +1,1975 @@ +/** @file + Support routines for SMRAM profile. + + Copyright (c) 2014, Intel Corporation. All rights reserved.
+ 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; + +BOOLEAN mSmramReadyToLock; +BOOLEAN mSmramProfileRecordingStatus = FALSE; + +/** + 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. + If BIOS memory type (0 ~ EfiMaxMemoryType), it checks bit (1 << MemoryType). + If OS memory type (0x80000000 ~ 0xFFFFFFFF), it checks bit63 - 0x8000000000000000. + + @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 ((UINT32) MemoryType >= 0x80000000) { + TestBit = BIT63; + } else { + 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), ProfileMemoryIndex = MemoryType. + If OS memory type (0x80000000 ~ 0xFFFFFFFF), ProfileMemoryIndex = EfiMaxMemoryType. + + @param MemoryType Memory type. + + @return EFI memory type as profile memory index. + +**/ +EFI_MEMORY_TYPE +GetProfileMemoryIndex ( + IN EFI_MEMORY_TYPE MemoryType + ) +{ + if ((UINT32) MemoryType >= 0x80000000) { + return EfiMaxMemoryType; + } else { + 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; + + 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; +} + +//////////////////// + +/** + This function check if the address is in SMRAM. + + @param Buffer the buffer address to be checked. + @param Length the buffer length to be checked. + + @retval TRUE this address is in SMRAM. + @retval FALSE this address is NOT in SMRAM. + +**/ +BOOLEAN +InternalIsAddressInSmram ( + IN PHYSICAL_ADDRESS Buffer, + IN UINT64 Length + ) +{ + UINTN Index; + + for (Index = 0; Index < mFullSmramRangeCount; Index ++) { + if (((Buffer >= mFullSmramRanges[Index].CpuStart) && (Buffer < mFullSmramRanges[Index].CpuStart + mFullSmramRanges[Index].PhysicalSize)) || + ((mFullSmramRanges[Index].CpuStart >= Buffer) && (mFullSmramRanges[Index].CpuStart < Buffer + Length))) { + return TRUE; + } + } + + return FALSE; +} + +/** + This function check if the address refered by Buffer and Length is valid. + + @param Buffer the buffer address to be checked. + @param Length the buffer length to be checked. + + @retval TRUE this address is valid. + @retval FALSE this address is NOT valid. +**/ +BOOLEAN +InternalIsAddressValid ( + IN UINTN Buffer, + IN UINTN Length + ) +{ + if (Buffer > (MAX_ADDRESS - Length)) { + // + // Overflow happen + // + return FALSE; + } + if (InternalIsAddressInSmram ((PHYSICAL_ADDRESS) Buffer, (UINT64)Length)) { + return FALSE; + } + return 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. + +**/ +VOID +SmramProfileCopyData ( + IN VOID *ProfileBuffer + ) +{ + 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; + + ContextData = GetSmramProfileContext (); + if (ContextData == NULL) { + return ; + } + + Context = ProfileBuffer; + CopyMem (Context, &ContextData->Context, sizeof (MEMORY_PROFILE_CONTEXT)); + DriverInfo = (MEMORY_PROFILE_DRIVER_INFO *) (Context + 1); + + 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 + ); + CopyMem (DriverInfo, &DriverInfoData->DriverInfo, sizeof (MEMORY_PROFILE_DRIVER_INFO)); + AllocInfo = (MEMORY_PROFILE_ALLOC_INFO *) (DriverInfo + 1); + + 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 + ); + CopyMem (AllocInfo, &AllocInfoData->AllocInfo, sizeof (MEMORY_PROFILE_ALLOC_INFO)); + AllocInfo += 1; + } + + DriverInfo = (MEMORY_PROFILE_DRIVER_INFO *) ((UINTN) (DriverInfo + 1) + sizeof (MEMORY_PROFILE_ALLOC_INFO) * (UINTN) DriverInfo->AllocRecordCount); + } + + + FreeMemory = (MEMORY_PROFILE_FREE_MEMORY *) DriverInfo; + CopyMem (FreeMemory, &mSmramFreeMemory, sizeof (MEMORY_PROFILE_FREE_MEMORY)); + MemoryProfileDescriptor = (MEMORY_PROFILE_DESCRIPTOR *) (FreeMemory + 1); + Index = 0; + FreePageList = &mSmmMemoryMap; + for (Node = FreePageList->BackLink; + Node != FreePageList; + Node = Node->BackLink) { + Pages = BASE_CR (Node, FREE_PAGE_LIST, Link); + 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); + MemoryProfileDescriptor++; + 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) { + 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; + MemoryProfileDescriptor++; + Index++; + } + } + } + FreeMemory->FreeMemoryEntryCount = Index; + + MemoryRange = (MEMORY_PROFILE_MEMORY_RANGE *) MemoryProfileDescriptor; + 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; + MemoryProfileDescriptor = (MEMORY_PROFILE_DESCRIPTOR *) (MemoryRange + 1); + for (Index = 0; Index < mFullSmramRangeCount; Index++) { + 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; + MemoryProfileDescriptor++; + } +} + +/** + 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; + 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 (!InternalIsAddressValid ((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; + } + + SmramProfileParameterGetData->ProfileSize = ProfileSize; + SmramProfileCopyData ((VOID *) (UINTN) SmramProfileGetData.ProfileBuffer); + SmramProfileParameterGetData->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 && !InternalIsAddressValid ((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_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", +}; + +GLOBAL_REMOVE_IF_UNREFERENCED CHAR16 *mMemoryTypeString[] = { + L"EfiReservedMemoryType", + L"EfiLoaderCode", + L"EfiLoaderData", + L"EfiBootServicesCode", + L"EfiBootServicesData", + L"EfiRuntimeServicesCode", + L"EfiRuntimeServicesData", + L"EfiConventionalMemory", + L"EfiUnusableMemory", + L"EfiACPIReclaimMemory", + L"EfiACPIMemoryNVS", + L"EfiMemoryMappedIO", + L"EfiMemoryMappedIOPortSpace", + L"EfiPalCode", + L"EfiOSReserved", +}; + + +/** + 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 <= EfiMaxMemoryType; 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], mMemoryTypeString[TypeIndex])); + DEBUG ((EFI_D_INFO, " PeakTotalUsage[0x%02x] - 0x%016lx (%s)\n", TypeIndex, Context->PeakTotalUsageByType[TypeIndex], mMemoryTypeString[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 <= EfiMaxMemoryType; 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], mMemoryTypeString[TypeIndex])); + DEBUG ((EFI_D_INFO, " PeakUsage[0x%02x] - 0x%016lx (%s)\n", TypeIndex, DriverInfo->PeakUsageByType[TypeIndex], mMemoryTypeString[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 (); + } + ); +} + diff --git a/MdeModulePkg/Include/Guid/MemoryProfile.h b/MdeModulePkg/Include/Guid/MemoryProfile.h new file mode 100644 index 0000000000..3c1e5e79ca --- /dev/null +++ b/MdeModulePkg/Include/Guid/MemoryProfile.h @@ -0,0 +1,286 @@ +/** @file + Memory profile data structure. + + Copyright (c) 2014, Intel Corporation. All rights reserved.
+ 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. + +**/ + +#ifndef _MEMORY_PROFILE_H_ +#define _MEMORY_PROFILE_H_ + +// +// For BIOS MemoryType (0 ~ EfiMaxMemoryType), it is recorded in UsageByType[MemoryType]. (Each valid entry has one entry) +// For OS MemoryType (0x80000000 ~ 0xFFFFFFFF), it is recorded in UsageByType[EfiMaxMemoryType]. (All types are combined into one entry) +// + +typedef struct { + UINT32 Signature; + UINT16 Length; + UINT16 Revision; +} MEMORY_PROFILE_COMMON_HEADER; + +#define MEMORY_PROFILE_CONTEXT_SIGNATURE SIGNATURE_32 ('M','P','C','T') +#define MEMORY_PROFILE_CONTEXT_REVISION 0x0001 + +typedef struct { + MEMORY_PROFILE_COMMON_HEADER Header; + UINT64 CurrentTotalUsage; + UINT64 PeakTotalUsage; + UINT64 CurrentTotalUsageByType[EfiMaxMemoryType + 1]; + UINT64 PeakTotalUsageByType[EfiMaxMemoryType + 1]; + UINT64 TotalImageSize; + UINT32 ImageCount; + UINT32 SequenceCount; +} MEMORY_PROFILE_CONTEXT; + +#define MEMORY_PROFILE_DRIVER_INFO_SIGNATURE SIGNATURE_32 ('M','P','D','I') +#define MEMORY_PROFILE_DRIVER_INFO_REVISION 0x0001 + +typedef struct { + MEMORY_PROFILE_COMMON_HEADER Header; + EFI_GUID FileName; + PHYSICAL_ADDRESS ImageBase; + UINT64 ImageSize; + PHYSICAL_ADDRESS EntryPoint; + UINT16 ImageSubsystem; + EFI_FV_FILETYPE FileType; + UINT8 Reserved[1]; + UINT32 AllocRecordCount; + UINT64 CurrentUsage; + UINT64 PeakUsage; + UINT64 CurrentUsageByType[EfiMaxMemoryType + 1]; + UINT64 PeakUsageByType[EfiMaxMemoryType + 1]; +} MEMORY_PROFILE_DRIVER_INFO; + +typedef enum { + MemoryProfileActionAllocatePages = 1, + MemoryProfileActionFreePages = 2, + MemoryProfileActionAllocatePool = 3, + MemoryProfileActionFreePool = 4, +} MEMORY_PROFILE_ACTION; + +#define MEMORY_PROFILE_ALLOC_INFO_SIGNATURE SIGNATURE_32 ('M','P','A','I') +#define MEMORY_PROFILE_ALLOC_INFO_REVISION 0x0001 + +typedef struct { + MEMORY_PROFILE_COMMON_HEADER Header; + PHYSICAL_ADDRESS CallerAddress; + UINT32 SequenceId; + UINT8 Reserved[4]; + MEMORY_PROFILE_ACTION Action; + EFI_MEMORY_TYPE MemoryType; + PHYSICAL_ADDRESS Buffer; + UINT64 Size; +} MEMORY_PROFILE_ALLOC_INFO; + +#define MEMORY_PROFILE_DESCRIPTOR_SIGNATURE SIGNATURE_32 ('M','P','D','R') +#define MEMORY_PROFILE_DESCRIPTOR_REVISION 0x0001 + +typedef struct { + MEMORY_PROFILE_COMMON_HEADER Header; + PHYSICAL_ADDRESS Address; + UINT64 Size; +} MEMORY_PROFILE_DESCRIPTOR; + +#define MEMORY_PROFILE_FREE_MEMORY_SIGNATURE SIGNATURE_32 ('M','P','R','M') +#define MEMORY_PROFILE_FREE_MEMORY_REVISION 0x0001 + +typedef struct { + MEMORY_PROFILE_COMMON_HEADER Header; + UINT64 TotalFreeMemoryPages; + UINT32 FreeMemoryEntryCount; + UINT8 Reserved[4]; + //MEMORY_PROFILE_DESCRIPTOR MemoryDescriptor[FreeMemoryEntryCount]; +} MEMORY_PROFILE_FREE_MEMORY; + +#define MEMORY_PROFILE_MEMORY_RANGE_SIGNATURE SIGNATURE_32 ('M','P','M','R') +#define MEMORY_PROFILE_MEMORY_RANGE_REVISION 0x0001 + +typedef struct { + MEMORY_PROFILE_COMMON_HEADER Header; + UINT32 MemoryRangeCount; + UINT8 Reserved[4]; + //MEMORY_PROFILE_DESCRIPTOR MemoryDescriptor[MemoryRangeCount]; +} MEMORY_PROFILE_MEMORY_RANGE; + +// +// UEFI memory profile layout: +// +--------------------------------+ +// | CONTEXT | +// +--------------------------------+ +// | DRIVER_INFO(1) | +// +--------------------------------+ +// | ALLOC_INFO(1, 1) | +// +--------------------------------+ +// | ALLOC_INFO(1, m1) | +// +--------------------------------+ +// | DRIVER_INFO(n) | +// +--------------------------------+ +// | ALLOC_INFO(n, 1) | +// +--------------------------------+ +// | ALLOC_INFO(n, mn) | +// +--------------------------------+ +// + +typedef struct _EDKII_MEMORY_PROFILE_PROTOCOL EDKII_MEMORY_PROFILE_PROTOCOL; + +/** + Get memory profile data. + + @param[in] This The EDKII_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_BUFFER_TO_SMALL The ProfileSize is too small for the resulting data. + ProfileSize is updated with the size required. + +**/ +typedef +EFI_STATUS +(EFIAPI *EDKII_MEMORY_PROFILE_GET_DATA)( + IN EDKII_MEMORY_PROFILE_PROTOCOL *This, + IN OUT UINT64 *ProfileSize, + OUT VOID *ProfileBuffer + ); + +/** + Register image to memory profile. + + @param[in] This The EDKII_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 success. + @return EFI_OUT_OF_RESOURCE No enough resource for this register. + +**/ +typedef +EFI_STATUS +(EFIAPI *EDKII_MEMORY_PROFILE_REGISTER_IMAGE)( + IN EDKII_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_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 success. + @return EFI_NOT_FOUND The image is not found. + +**/ +typedef +EFI_STATUS +(EFIAPI *EDKII_MEMORY_PROFILE_UNREGISTER_IMAGE)( + IN EDKII_MEMORY_PROFILE_PROTOCOL *This, + IN EFI_DEVICE_PATH_PROTOCOL *FilePath, + IN PHYSICAL_ADDRESS ImageBase, + IN UINT64 ImageSize + ); + +struct _EDKII_MEMORY_PROFILE_PROTOCOL { + EDKII_MEMORY_PROFILE_GET_DATA GetData; + EDKII_MEMORY_PROFILE_REGISTER_IMAGE RegisterImage; + EDKII_MEMORY_PROFILE_UNREGISTER_IMAGE UnregisterImage; +}; + +// +// SMRAM profile layout: +// +--------------------------------+ +// | CONTEXT | +// +--------------------------------+ +// | DRIVER_INFO(1) | +// +--------------------------------+ +// | ALLOC_INFO(1, 1) | +// +--------------------------------+ +// | ALLOC_INFO(1, m1) | +// +--------------------------------+ +// | DRIVER_INFO(n) | +// +--------------------------------+ +// | ALLOC_INFO(n, 1) | +// +--------------------------------+ +// | ALLOC_INFO(n, mn) | +// +--------------------------------+ +// | FREE_MEMORY | +// +--------------------------------+ +// | FREE MEMORY DESCRIPTOR(1) | +// +--------------------------------+ +// | FREE MEMORY DESCRIPTOR(p) | +// +--------------------------------+ +// | MEMORY_RANGE | +// +--------------------------------+ +// | MEMORY RANGE DESCRIPTOR(1) | +// +--------------------------------+ +// | MEMORY RANGE DESCRIPTOR(q) | +// +--------------------------------+ +// + +// +// SMRAM profile command +// +#define SMRAM_PROFILE_COMMAND_GET_PROFILE_INFO 0x1 +#define SMRAM_PROFILE_COMMAND_GET_PROFILE_DATA 0x2 +// +// Below 2 commands are now used by ECP only and only valid before SmmReadyToLock +// +#define SMRAM_PROFILE_COMMAND_REGISTER_IMAGE 0x3 +#define SMRAM_PROFILE_COMMAND_UNREGISTER_IMAGE 0x4 + +typedef struct { + UINT32 Command; + UINT32 DataLength; + UINT64 ReturnStatus; +} SMRAM_PROFILE_PARAMETER_HEADER; + +typedef struct { + SMRAM_PROFILE_PARAMETER_HEADER Header; + UINT64 ProfileSize; +} SMRAM_PROFILE_PARAMETER_GET_PROFILE_INFO; + +typedef struct { + SMRAM_PROFILE_PARAMETER_HEADER Header; + UINT64 ProfileSize; + PHYSICAL_ADDRESS ProfileBuffer; +} SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA; + +typedef struct { + SMRAM_PROFILE_PARAMETER_HEADER Header; + EFI_GUID FileName; + PHYSICAL_ADDRESS ImageBuffer; + UINT64 NumberOfPage; +} SMRAM_PROFILE_PARAMETER_REGISTER_IMAGE; + +typedef struct { + SMRAM_PROFILE_PARAMETER_HEADER Header; + EFI_GUID FileName; + PHYSICAL_ADDRESS ImageBuffer; + UINT64 NumberOfPage; +} SMRAM_PROFILE_PARAMETER_UNREGISTER_IMAGE; + + +#define EDKII_MEMORY_PROFILE_GUID { \ + 0x821c9a09, 0x541a, 0x40f6, 0x9f, 0x43, 0xa, 0xd1, 0x93, 0xa1, 0x2c, 0xfe \ +} + +extern EFI_GUID gEdkiiMemoryProfileGuid; + +#endif + diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec index 60fb209385..0384e5614f 100644 --- a/MdeModulePkg/MdeModulePkg.dec +++ b/MdeModulePkg/MdeModulePkg.dec @@ -272,6 +272,9 @@ ## Include/Guid/StatusCodeDataTypeVariable.h gEdkiiStatusCodeDataTypeVariableGuid = { 0xf6ee6dbb, 0xd67f, 0x4ea0, { 0x8b, 0x96, 0x6a, 0x71, 0xb1, 0x9d, 0x84, 0xad }} + + ## Include/Guid/MemoryProfile.h + gEdkiiMemoryProfileGuid = { 0x821c9a09, 0x541a, 0x40f6, { 0x9f, 0x43, 0xa, 0xd1, 0x93, 0xa1, 0x2c, 0xfe }} [Ppis] ## Include/Ppi/AtaController.h @@ -812,6 +815,38 @@ # @Prompt Default Creator Revision for ACPI table creation. gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorRevision|0x01000013|UINT32|0x30001038 + ## The mask is used to control memory profile behavior.

+ # BIT0 - Enable UEFI memory profile.
+ # BIT1 - Enable SMRAM profile.
+ # @Prompt Memory Profile Property. + # @Expression 0x80000002 | (gEfiMdeModulePkgTokenSpaceGuid.PcdMemoryProfilePropertyMask & 0xFC) == 0 + gEfiMdeModulePkgTokenSpaceGuid.PcdMemoryProfilePropertyMask|0x0|UINT8|0x30001041 + + ## This flag is to control which memory types of alloc info will be recorded by DxeCore & SmmCore.

+ # For SmmCore, only EfiRuntimeServicesCode and EfiRuntimeServicesData are valid.
+ # + # Below is bit mask for this PCD: (Order is same as UEFI spec)
+ # EfiReservedMemoryType 0x0001
+ # EfiLoaderCode 0x0002
+ # EfiLoaderData 0x0004
+ # EfiBootServicesCode 0x0008
+ # EfiBootServicesData 0x0010
+ # EfiRuntimeServicesCode 0x0020
+ # EfiRuntimeServicesData 0x0040
+ # EfiConventionalMemory 0x0080
+ # EfiUnusableMemory 0x0100
+ # EfiACPIReclaimMemory 0x0200
+ # EfiACPIMemoryNVS 0x0400
+ # EfiMemoryMappedIO 0x0800
+ # EfiMemoryMappedIOPortSpace 0x1000
+ # EfiPalCode 0x2000
+ # OS Reserved 0x8000000000000000
+ # + # e.g. Reserved+ACPINvs+ACPIReclaim+RuntimeCode+RuntimeData are needed, 0x661 should be used.
+ # + # @Prompt Memory profile memory type. + gEfiMdeModulePkgTokenSpaceGuid.PcdMemoryProfileMemoryType|0x0|UINT64|0x30001042 + ## UART clock frequency is for the baud rate configuration. # @Prompt Serial Port Clock Rate. gEfiMdeModulePkgTokenSpaceGuid.PcdSerialClockRate|1843200|UINT32|0x00010066 diff --git a/MdeModulePkg/MdeModulePkg.dsc b/MdeModulePkg/MdeModulePkg.dsc index f7a88ffb2b..f15dfdf23e 100644 --- a/MdeModulePkg/MdeModulePkg.dsc +++ b/MdeModulePkg/MdeModulePkg.dsc @@ -194,6 +194,7 @@ [Components] MdeModulePkg/Application/HelloWorld/HelloWorld.inf + MdeModulePkg/Application/MemoryProfileInfo/MemoryProfileInfo.inf MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf MdeModulePkg/Bus/Pci/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupportDxe.inf diff --git a/MdeModulePkg/MdeModulePkg.uni b/MdeModulePkg/MdeModulePkg.uni index 30bc563e26..b6a80b4f6a 100644 Binary files a/MdeModulePkg/MdeModulePkg.uni and b/MdeModulePkg/MdeModulePkg.uni differ diff --git a/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/BootScriptExecutorDxe.inf b/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/BootScriptExecutorDxe.inf index 2eba9d4263..c761f609b9 100644 --- a/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/BootScriptExecutorDxe.inf +++ b/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/BootScriptExecutorDxe.inf @@ -64,10 +64,12 @@ DebugAgentLib LockBoxLib CpuExceptionHandlerLib + DevicePathLib [Guids] gEfiBootScriptExecutorVariableGuid ## PRODUCES ## UNDEFINED # SaveLockBox gEfiBootScriptExecutorContextGuid ## PRODUCES ## UNDEFINED # SaveLockBox + gEdkiiMemoryProfileGuid ## SOMETIMES_CONSUMES ## GUID # Locate protocol [Protocols] ## NOTIFY @@ -78,7 +80,8 @@ gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSwitchToLongMode ## CONSUMES [Pcd] - gEfiMdeModulePkgTokenSpaceGuid.PcdUse1GPageTable ## SOMETIMES_CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdUse1GPageTable ## SOMETIMES_CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdMemoryProfilePropertyMask ## CONSUMES [Depex] gEfiLockBoxProtocolGuid diff --git a/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/ScriptExecute.c b/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/ScriptExecute.c index 6c1c304a15..3fbdf5cd83 100644 --- a/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/ScriptExecute.c +++ b/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/ScriptExecute.c @@ -208,6 +208,47 @@ S3BootScriptExecutorEntryFunction ( return EFI_UNSUPPORTED; } +/** + Register image to memory profile. + + @param FileName File name of the image. + @param ImageBase Image base address. + @param ImageSize Image size. + @param FileType File type of the image. + +**/ +VOID +RegisterMemoryProfileImage ( + 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 ((PcdGet8 (PcdMemoryProfilePropertyMask) & BIT0) != 0) { + + 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 + ); + } + } +} + /** This is the Event notification function to reload BootScriptExecutor image to RESERVED mem and save it to LockBox. @@ -302,6 +343,14 @@ ReadyToLockEventNotify ( // Flush the instruction cache so the image data is written before we execute it // InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize); + + RegisterMemoryProfileImage ( + &gEfiCallerIdGuid, + ImageContext.ImageAddress, + ImageContext.ImageSize, + EFI_FV_FILETYPE_DRIVER + ); + Status = ((EFI_IMAGE_ENTRY_POINT)(UINTN)(ImageContext.EntryPoint)) (NewImageHandle, gST); ASSERT_EFI_ERROR (Status); diff --git a/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/ScriptExecute.h b/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/ScriptExecute.h index a3522905a8..772347a57e 100644 --- a/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/ScriptExecute.h +++ b/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/ScriptExecute.h @@ -4,7 +4,7 @@ This driver is dispatched by Dxe core and the driver will reload itself to ACPI reserved memory in the entry point. The functionality is to interpret and restore the S3 boot script -Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.
+Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License @@ -36,9 +36,12 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include #include #include +#include #include #include +#include + #include #include /**