From 84edd20bd0756ef5719835498d4283435d6b5e77 Mon Sep 17 00:00:00 2001 From: Star Zeng Date: Wed, 12 Nov 2014 03:27:48 +0000 Subject: 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 --- MdeModulePkg/Core/Dxe/DxeMain.h | 197 ++ MdeModulePkg/Core/Dxe/DxeMain.inf | 7 +- MdeModulePkg/Core/Dxe/DxeMain/DxeMain.c | 4 + MdeModulePkg/Core/Dxe/Image/Image.c | 2 + MdeModulePkg/Core/Dxe/Image/Image.h | 50 - MdeModulePkg/Core/Dxe/Mem/MemoryProfileRecord.c | 1377 ++++++++++++++ MdeModulePkg/Core/Dxe/Mem/Page.c | 66 +- MdeModulePkg/Core/Dxe/Mem/Pool.c | 55 +- MdeModulePkg/Core/PiSmmCore/Dispatcher.c | 2 + MdeModulePkg/Core/PiSmmCore/Page.c | 72 +- MdeModulePkg/Core/PiSmmCore/PiSmmCore.c | 21 +- MdeModulePkg/Core/PiSmmCore/PiSmmCore.h | 180 +- MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf | 9 +- MdeModulePkg/Core/PiSmmCore/PiSmmCorePrivateData.h | 53 +- MdeModulePkg/Core/PiSmmCore/PiSmmIpl.c | 15 + MdeModulePkg/Core/PiSmmCore/Pool.c | 101 +- MdeModulePkg/Core/PiSmmCore/SmramProfileRecord.c | 1975 ++++++++++++++++++++ 17 files changed, 4082 insertions(+), 104 deletions(-) create mode 100644 MdeModulePkg/Core/Dxe/Mem/MemoryProfileRecord.c create mode 100644 MdeModulePkg/Core/PiSmmCore/SmramProfileRecord.c (limited to 'MdeModulePkg/Core') 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 (); + } + ); +} + -- cgit v1.2.3