From 94092aa60341a3e4b1e1ea7c362781b8404ac538 Mon Sep 17 00:00:00 2001 From: Star Zeng Date: Tue, 31 May 2016 13:40:24 +0800 Subject: [PATCH] MdeModulePkg: Extend memory profile definitions for memory leak detection Current memory profile feature: 1. Shows which line of code calls gBS->AllocateXXX(). But most entries are from MemoryAllocationLib. 2. Records at the start. 3. Records all modules. Enhanced memory profile feature: 1. User can know which line of code calls AllocateXXX() API instead of gBS->Allocate(). 2. User can know which line of code calls a specific API that will call AllocateXXX(). 3. User can know total memory allocated by a specific line of code. 4. User can configure to record single module. 5. User can configure when to enable recording. 6. User can know RVA<->Symbol (Function, Source, Line). For the enhanced memory profile feature, 1. Extend MEMORY_PROFILE_DRIVER_INFO to include PdbString. 2. Extend MEMORY_PROFILE_ALLOC_INFO to include ActionString. 3. Extend MEMORY_PROFILE_ACTION to indicate action in memory allocation lib and user defined action. 4. Extend memory profile protocol to include GetRecordingState/ SetRecordingState/Record. 5. Define SMM memory profile protocol. 6. Extend PcdMemoryProfilePropertyMask to support disable recording at the start. 7. Introduce new PCD PcdMemoryProfileDriverPath to control which drivers need memory profile data. Cc: Jiewen Yao Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Star Zeng Reviewed-by: Jiewen Yao --- MdeModulePkg/Include/Guid/MemoryProfile.h | 189 ++++++++++++++++++++-- MdeModulePkg/MdeModulePkg.dec | 18 ++- MdeModulePkg/MdeModulePkg.uni | 17 +- 3 files changed, 213 insertions(+), 11 deletions(-) diff --git a/MdeModulePkg/Include/Guid/MemoryProfile.h b/MdeModulePkg/Include/Guid/MemoryProfile.h index 9c70b9df39..38a64945e3 100644 --- a/MdeModulePkg/Include/Guid/MemoryProfile.h +++ b/MdeModulePkg/Include/Guid/MemoryProfile.h @@ -15,6 +15,8 @@ #ifndef _MEMORY_PROFILE_H_ #define _MEMORY_PROFILE_H_ +#include + // // For BIOS MemoryType (0 ~ EfiMaxMemoryType - 1), it is recorded in UsageByType[MemoryType]. (Each valid entry has one entry) // For OS MemoryType (0x80000000 ~ 0xFFFFFFFF), it is recorded in UsageByType[EfiMaxMemoryType]. (All types are combined into one entry) @@ -42,7 +44,7 @@ typedef struct { } MEMORY_PROFILE_CONTEXT; #define MEMORY_PROFILE_DRIVER_INFO_SIGNATURE SIGNATURE_32 ('M','P','D','I') -#define MEMORY_PROFILE_DRIVER_INFO_REVISION 0x0002 +#define MEMORY_PROFILE_DRIVER_INFO_REVISION 0x0003 typedef struct { MEMORY_PROFILE_COMMON_HEADER Header; @@ -58,6 +60,9 @@ typedef struct { UINT64 PeakUsage; UINT64 CurrentUsageByType[EfiMaxMemoryType + 2]; UINT64 PeakUsageByType[EfiMaxMemoryType + 2]; + UINT16 PdbStringOffset; + UINT8 Reserved2[6]; +//CHAR8 PdbString[]; } MEMORY_PROFILE_DRIVER_INFO; typedef enum { @@ -67,8 +72,75 @@ typedef enum { MemoryProfileActionFreePool = 4, } MEMORY_PROFILE_ACTION; +// +// Below is the detailed MEMORY_PROFILE_ACTION definition. +// +// 31 15 9 8 8 7 7 6 6 5-4 3 - 0 +// +----------------------------------------------+ +// |User | |Lib| |Re|Copy|Zero|Align|Type|Basic| +// +----------------------------------------------+ +// + +// +// Basic Action +// 1 : AllocatePages +// 2 : FreePages +// 3 : AllocatePool +// 4 : FreePool +// +#define MEMORY_PROFILE_ACTION_BASIC_MASK 0xF + +// +// Extension +// +#define MEMORY_PROFILE_ACTION_EXTENSION_MASK 0xFFF0 +#define MEMORY_PROFILE_ACTION_EXTENSION_LIB_MASK 0x8000 +#define MEMORY_PROFILE_ACTION_EXTENSION_REALLOC_MASK 0x0200 +#define MEMORY_PROFILE_ACTION_EXTENSION_COPY_MASK 0x0100 +#define MEMORY_PROFILE_ACTION_EXTENSION_ZERO_MASK 0x0080 +#define MEMORY_PROFILE_ACTION_EXTENSION_ALIGN_MASK 0x0040 +#define MEMORY_PROFILE_ACTION_EXTENSION_MEM_TYPE_MASK 0x0030 +#define MEMORY_PROFILE_ACTION_EXTENSION_MEM_TYPE_BASIC 0x0000 +#define MEMORY_PROFILE_ACTION_EXTENSION_MEM_TYPE_RUNTIME 0x0010 +#define MEMORY_PROFILE_ACTION_EXTENSION_MEM_TYPE_RESERVED 0x0020 + +// +// Extension (used by memory allocation lib) +// +#define MEMORY_PROFILE_ACTION_LIB_ALLOCATE_PAGES 0x8001 +#define MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RUNTIME_PAGES 0x8011 +#define MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RESERVED_PAGES 0x8021 +#define MEMORY_PROFILE_ACTION_LIB_FREE_PAGES 0x8002 +#define MEMORY_PROFILE_ACTION_LIB_ALLOCATE_ALIGNED_PAGES 0x8041 +#define MEMORY_PROFILE_ACTION_LIB_ALLOCATE_ALIGNED_RUNTIME_PAGES 0x8051 +#define MEMORY_PROFILE_ACTION_LIB_ALLOCATE_ALIGNED_RESERVED_PAGES 0x8061 +#define MEMORY_PROFILE_ACTION_LIB_FREE_ALIGNED_PAGES 0x8042 +#define MEMORY_PROFILE_ACTION_LIB_ALLOCATE_POOL 0x8003 +#define MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RUNTIME_POOL 0x8013 +#define MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RESERVED_POOL 0x8023 +#define MEMORY_PROFILE_ACTION_LIB_FREE_POOL 0x8004 +#define MEMORY_PROFILE_ACTION_LIB_ALLOCATE_ZERO_POOL 0x8083 +#define MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RUNTIME_ZERO_POOL 0x8093 +#define MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RESERVED_ZERO_POOL 0x80a3 +#define MEMORY_PROFILE_ACTION_LIB_ALLOCATE_COPY_POOL 0x8103 +#define MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RUNTIME_COPY_POOL 0x8113 +#define MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RESERVED_COPY_POOL 0x8123 +#define MEMORY_PROFILE_ACTION_LIB_REALLOCATE_POOL 0x8203 +#define MEMORY_PROFILE_ACTION_LIB_REALLOCATE_RUNTIME_POOL 0x8213 +#define MEMORY_PROFILE_ACTION_LIB_REALLOCATE_RESERVED_POOL 0x8223 + +// +// User defined: 0x80000000~0xFFFFFFFF +// +// NOTE: User defined action MUST OR the basic action, +// so that core can know the action is allocate or free, +// and the type is pages (can be freed partially) +// or pool (cannot be freed partially). +// +#define MEMORY_PROFILE_ACTION_USER_DEFINED_MASK 0x80000000 + #define MEMORY_PROFILE_ALLOC_INFO_SIGNATURE SIGNATURE_32 ('M','P','A','I') -#define MEMORY_PROFILE_ALLOC_INFO_REVISION 0x0001 +#define MEMORY_PROFILE_ALLOC_INFO_REVISION 0x0002 typedef struct { MEMORY_PROFILE_COMMON_HEADER Header; @@ -79,6 +151,9 @@ typedef struct { EFI_MEMORY_TYPE MemoryType; PHYSICAL_ADDRESS Buffer; UINT64 Size; + UINT16 ActionStringOffset; + UINT8 Reserved2[6]; +//CHAR8 ActionString[]; } MEMORY_PROFILE_ALLOC_INFO; #define MEMORY_PROFILE_DESCRIPTOR_SIGNATURE SIGNATURE_32 ('M','P','D','R') @@ -141,6 +216,7 @@ typedef struct _EDKII_MEMORY_PROFILE_PROTOCOL EDKII_MEMORY_PROFILE_PROTOCOL; @param[out] ProfileBuffer Profile buffer. @return EFI_SUCCESS Get the memory profile data successfully. + @return EFI_UNSUPPORTED Memory profile is unsupported. @return EFI_BUFFER_TO_SMALL The ProfileSize is too small for the resulting data. ProfileSize is updated with the size required. @@ -162,8 +238,10 @@ EFI_STATUS @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. + @return EFI_SUCCESS Register successfully. + @return EFI_UNSUPPORTED Memory profile is unsupported, + or memory profile for the image is not required. + @return EFI_OUT_OF_RESOURCES No enough resource for this register. **/ typedef @@ -184,7 +262,9 @@ EFI_STATUS @param[in] ImageBase Image base address. @param[in] ImageSize Image size. - @return EFI_SUCCESS Unregister success. + @return EFI_SUCCESS Unregister successfully. + @return EFI_UNSUPPORTED Memory profile is unsupported, + or memory profile for the image is not required. @return EFI_NOT_FOUND The image is not found. **/ @@ -197,10 +277,86 @@ EFI_STATUS IN UINT64 ImageSize ); +#define MEMORY_PROFILE_RECORDING_ENABLE TRUE +#define MEMORY_PROFILE_RECORDING_DISABLE FALSE + +/** + Get memory profile recording state. + + @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance. + @param[out] RecordingState Recording state. + + @return EFI_SUCCESS Memory profile recording state is returned. + @return EFI_UNSUPPORTED Memory profile is unsupported. + @return EFI_INVALID_PARAMETER RecordingState is NULL. + +**/ +typedef +EFI_STATUS +(EFIAPI *EDKII_MEMORY_PROFILE_GET_RECORDING_STATE) ( + IN EDKII_MEMORY_PROFILE_PROTOCOL *This, + OUT BOOLEAN *RecordingState + ); + +/** + Set memory profile recording state. + + @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance. + @param[in] RecordingState Recording state. + + @return EFI_SUCCESS Set memory profile recording state successfully. + @return EFI_UNSUPPORTED Memory profile is unsupported. + +**/ +typedef +EFI_STATUS +(EFIAPI *EDKII_MEMORY_PROFILE_SET_RECORDING_STATE) ( + IN EDKII_MEMORY_PROFILE_PROTOCOL *This, + IN BOOLEAN RecordingState + ); + +/** + Record memory profile of multilevel caller. + + @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance. + @param[in] CallerAddress Address of caller. + @param[in] Action Memory profile action. + @param[in] MemoryType Memory type. + EfiMaxMemoryType means the MemoryType is unknown. + @param[in] Buffer Buffer address. + @param[in] Size Buffer size. + @param[in] ActionString String for memory profile action. + Only needed for user defined allocate action. + + @return EFI_SUCCESS Memory profile is updated. + @return EFI_UNSUPPORTED Memory profile is unsupported, + or memory profile for the image is not required, + or memory profile for the memory type is not required. + @return EFI_ACCESS_DENIED It is during memory profile data getting. + @return EFI_ABORTED Memory profile recording is not enabled. + @return EFI_OUT_OF_RESOURCES No enough resource to update memory profile for allocate action. + @return EFI_NOT_FOUND No matched allocate info found for free action. + +**/ +typedef +EFI_STATUS +(EFIAPI *EDKII_MEMORY_PROFILE_RECORD) ( + IN EDKII_MEMORY_PROFILE_PROTOCOL *This, + IN PHYSICAL_ADDRESS CallerAddress, + IN MEMORY_PROFILE_ACTION Action, + IN EFI_MEMORY_TYPE MemoryType, + IN VOID *Buffer, + IN UINTN Size, + IN CHAR8 *ActionString OPTIONAL + ); + struct _EDKII_MEMORY_PROFILE_PROTOCOL { - EDKII_MEMORY_PROFILE_GET_DATA GetData; - EDKII_MEMORY_PROFILE_REGISTER_IMAGE RegisterImage; - EDKII_MEMORY_PROFILE_UNREGISTER_IMAGE UnregisterImage; + EDKII_MEMORY_PROFILE_GET_DATA GetData; + EDKII_MEMORY_PROFILE_REGISTER_IMAGE RegisterImage; + EDKII_MEMORY_PROFILE_UNREGISTER_IMAGE UnregisterImage; + EDKII_MEMORY_PROFILE_GET_RECORDING_STATE GetRecordingState; + EDKII_MEMORY_PROFILE_SET_RECORDING_STATE SetRecordingState; + EDKII_MEMORY_PROFILE_RECORD Record; }; // @@ -246,6 +402,8 @@ struct _EDKII_MEMORY_PROFILE_PROTOCOL { #define SMRAM_PROFILE_COMMAND_UNREGISTER_IMAGE 0x4 #define SMRAM_PROFILE_COMMAND_GET_PROFILE_DATA_BY_OFFSET 0x5 +#define SMRAM_PROFILE_COMMAND_GET_RECORDING_STATE 0x6 +#define SMRAM_PROFILE_COMMAND_SET_RECORDING_STATE 0x7 typedef struct { UINT32 Command; @@ -279,6 +437,11 @@ typedef struct { UINT64 ProfileOffset; } SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA_BY_OFFSET; +typedef struct { + SMRAM_PROFILE_PARAMETER_HEADER Header; + BOOLEAN RecordingState; +} SMRAM_PROFILE_PARAMETER_RECORDING_STATE; + typedef struct { SMRAM_PROFILE_PARAMETER_HEADER Header; EFI_GUID FileName; @@ -295,10 +458,18 @@ typedef struct { #define EDKII_MEMORY_PROFILE_GUID { \ - 0x821c9a09, 0x541a, 0x40f6, 0x9f, 0x43, 0xa, 0xd1, 0x93, 0xa1, 0x2c, 0xfe \ + 0x821c9a09, 0x541a, 0x40f6, { 0x9f, 0x43, 0xa, 0xd1, 0x93, 0xa1, 0x2c, 0xfe } \ } extern EFI_GUID gEdkiiMemoryProfileGuid; +typedef EDKII_MEMORY_PROFILE_PROTOCOL EDKII_SMM_MEMORY_PROFILE_PROTOCOL; + +#define EDKII_SMM_MEMORY_PROFILE_GUID { \ + 0xe22bbcca, 0x516a, 0x46a8, { 0x80, 0xe2, 0x67, 0x45, 0xe8, 0x36, 0x93, 0xbd } \ +} + +extern EFI_GUID gEdkiiSmmMemoryProfileGuid; + #endif diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec index 27efb378bd..9014635736 100644 --- a/MdeModulePkg/MdeModulePkg.dec +++ b/MdeModulePkg/MdeModulePkg.dec @@ -327,6 +327,7 @@ ## Include/Guid/MemoryProfile.h gEdkiiMemoryProfileGuid = { 0x821c9a09, 0x541a, 0x40f6, { 0x9f, 0x43, 0xa, 0xd1, 0x93, 0xa1, 0x2c, 0xfe }} + gEdkiiSmmMemoryProfileGuid = { 0xe22bbcca, 0x516a, 0x46a8, { 0x80, 0xe2, 0x67, 0x45, 0xe8, 0x36, 0x93, 0xbd }} ## Include/Protocol/VarErrorFlag.h gEdkiiVarErrorFlagGuid = { 0x4b37fe8, 0xf6ae, 0x480b, { 0xbd, 0xd5, 0x37, 0xd9, 0x8c, 0x5e, 0x89, 0xaa } } @@ -995,8 +996,9 @@ ## The mask is used to control memory profile behavior.

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

@@ -1026,6 +1028,20 @@ # @Prompt Memory profile memory type. gEfiMdeModulePkgTokenSpaceGuid.PcdMemoryProfileMemoryType|0x0|UINT64|0x30001042 + ## This PCD is to control which drivers need memory profile data.

+ # For example:
+ # One image only (Shell):
+ # Header GUID
+ # {0x04, 0x06, 0x14, 0x00, 0x83, 0xA5, 0x04, 0x7C, 0x3E, 0x9E, 0x1C, 0x4F, 0xAD, 0x65, 0xE0, 0x52, 0x68, 0xD0, 0xB4, 0xD1,
+ # 0x7F, 0xFF, 0x04, 0x00}
+ # Two or more images (Shell + WinNtSimpleFileSystem):
+ # {0x04, 0x06, 0x14, 0x00, 0x83, 0xA5, 0x04, 0x7C, 0x3E, 0x9E, 0x1C, 0x4F, 0xAD, 0x65, 0xE0, 0x52, 0x68, 0xD0, 0xB4, 0xD1,
+ # 0x7F, 0x01, 0x04, 0x00,
+ # 0x04, 0x06, 0x14, 0x00, 0x8B, 0xE1, 0x25, 0x9C, 0xBA, 0x76, 0xDA, 0x43, 0xA1, 0x32, 0xDB, 0xB0, 0x99, 0x7C, 0xEF, 0xEF,
+ # 0x7F, 0xFF, 0x04, 0x00}
+ # @Prompt Memory profile driver path. + gEfiMdeModulePkgTokenSpaceGuid.PcdMemoryProfileDriverPath|{0x0}|VOID*|0x00001043 + ## PCI Serial Device Info. It is an array of Device, Function, and Power Management # information that describes the path that contains zero or more PCI to PCI briges # followed by a PCI serial device. Each array entry is 4-bytes in length. The diff --git a/MdeModulePkg/MdeModulePkg.uni b/MdeModulePkg/MdeModulePkg.uni index f529dced6f..1a5f24efbf 100644 --- a/MdeModulePkg/MdeModulePkg.uni +++ b/MdeModulePkg/MdeModulePkg.uni @@ -266,7 +266,8 @@ #string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdMemoryProfilePropertyMask_HELP #language en-US "The mask is used to control memory profile behavior.

\n" "BIT0 - Enable UEFI memory profile.
\n" - "BIT1 - Enable SMRAM profile.
" + "BIT1 - Enable SMRAM profile.
\n" + "BIT7 - Disable recording at the start.
" #string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdMemoryProfileMemoryType_PROMPT #language en-US "Memory profile memory type" @@ -292,6 +293,20 @@ " OS Reserved 0x80000000
\n" "e.g. Reserved+ACPINvs+ACPIReclaim+RuntimeCode+RuntimeData are needed, 0x661 should be used.
\n" +#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdMemoryProfileDriverPath_PROMPT #language en-US "Memory profile driver path" + +#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdMemoryProfileDriverPath_HELP #language en-US "This PCD is to control which drivers need memory profile data.

\n" + "For example:
\n" + "One image only (Shell):
\n" + " Header GUID
\n" + " {0x04, 0x06, 0x14, 0x00, 0x83, 0xA5, 0x04, 0x7C, 0x3E, 0x9E, 0x1C, 0x4F, 0xAD, 0x65, 0xE0, 0x52, 0x68, 0xD0, 0xB4, 0xD1,
\n" + " 0x7F, 0xFF, 0x04, 0x00}
\n" + "Two or more images (Shell + WinNtSimpleFileSystem):
\n" + " {0x04, 0x06, 0x14, 0x00, 0x83, 0xA5, 0x04, 0x7C, 0x3E, 0x9E, 0x1C, 0x4F, 0xAD, 0x65, 0xE0, 0x52, 0x68, 0xD0, 0xB4, 0xD1,
\n" + " 0x7F, 0x01, 0x04, 0x00,
\n" + " 0x04, 0x06, 0x14, 0x00, 0x8B, 0xE1, 0x25, 0x9C, 0xBA, 0x76, 0xDA, 0x43, 0xA1, 0x32, 0xDB, 0xB0, 0x99, 0x7C, 0xEF, 0xEF,
\n" + " 0x7F, 0xFF, 0x04, 0x00}
\n" + #string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdSerialClockRate_PROMPT #language en-US "Serial Port Clock Rate" #string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdSerialClockRate_HELP #language en-US "UART clock frequency is for the baud rate configuration." -- 2.39.2