Home | History | Annotate | Download | only in PiSmmCore
      1 /** @file
      2   Support routines for SMRAM profile.
      3 
      4   Copyright (c) 2014 - 2016, Intel Corporation. All rights reserved.<BR>
      5   This program and the accompanying materials
      6   are licensed and made available under the terms and conditions of the BSD License
      7   which accompanies this distribution.  The full text of the license may be found at
      8   http://opensource.org/licenses/bsd-license.php.
      9 
     10   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 
     13 **/
     14 
     15 #include "PiSmmCore.h"
     16 
     17 #define IS_SMRAM_PROFILE_ENABLED ((PcdGet8 (PcdMemoryProfilePropertyMask) & BIT1) != 0)
     18 #define IS_UEFI_MEMORY_PROFILE_ENABLED ((PcdGet8 (PcdMemoryProfilePropertyMask) & BIT0) != 0)
     19 
     20 #define GET_OCCUPIED_SIZE(ActualSize, Alignment) \
     21   ((ActualSize) + (((Alignment) - ((ActualSize) & ((Alignment) - 1))) & ((Alignment) - 1)))
     22 
     23 typedef struct {
     24   UINT32                        Signature;
     25   MEMORY_PROFILE_CONTEXT        Context;
     26   LIST_ENTRY                    *DriverInfoList;
     27 } MEMORY_PROFILE_CONTEXT_DATA;
     28 
     29 typedef struct {
     30   UINT32                        Signature;
     31   MEMORY_PROFILE_DRIVER_INFO    DriverInfo;
     32   LIST_ENTRY                    *AllocInfoList;
     33   CHAR8                         *PdbString;
     34   LIST_ENTRY                    Link;
     35 } MEMORY_PROFILE_DRIVER_INFO_DATA;
     36 
     37 typedef struct {
     38   UINT32                        Signature;
     39   MEMORY_PROFILE_ALLOC_INFO     AllocInfo;
     40   CHAR8                         *ActionString;
     41   LIST_ENTRY                    Link;
     42 } MEMORY_PROFILE_ALLOC_INFO_DATA;
     43 
     44 //
     45 // When free memory less than 4 pages, dump it.
     46 //
     47 #define SMRAM_INFO_DUMP_PAGE_THRESHOLD  4
     48 
     49 GLOBAL_REMOVE_IF_UNREFERENCED MEMORY_PROFILE_FREE_MEMORY mSmramFreeMemory = {
     50   {
     51     MEMORY_PROFILE_FREE_MEMORY_SIGNATURE,
     52     sizeof (MEMORY_PROFILE_FREE_MEMORY),
     53     MEMORY_PROFILE_FREE_MEMORY_REVISION
     54   },
     55   0,
     56   0
     57 };
     58 
     59 GLOBAL_REMOVE_IF_UNREFERENCED LIST_ENTRY  mImageQueue = INITIALIZE_LIST_HEAD_VARIABLE (mImageQueue);
     60 GLOBAL_REMOVE_IF_UNREFERENCED MEMORY_PROFILE_CONTEXT_DATA mSmramProfileContext = {
     61   MEMORY_PROFILE_CONTEXT_SIGNATURE,
     62   {
     63     {
     64       MEMORY_PROFILE_CONTEXT_SIGNATURE,
     65       sizeof (MEMORY_PROFILE_CONTEXT),
     66       MEMORY_PROFILE_CONTEXT_REVISION
     67     },
     68     0,
     69     0,
     70     {0},
     71     {0},
     72     0,
     73     0,
     74     0
     75   },
     76   &mImageQueue,
     77 };
     78 GLOBAL_REMOVE_IF_UNREFERENCED MEMORY_PROFILE_CONTEXT_DATA *mSmramProfileContextPtr = NULL;
     79 
     80 BOOLEAN mSmramReadyToLock;
     81 BOOLEAN mSmramProfileGettingStatus = FALSE;
     82 BOOLEAN mSmramProfileRecordingEnable = MEMORY_PROFILE_RECORDING_DISABLE;
     83 EFI_DEVICE_PATH_PROTOCOL *mSmramProfileDriverPath;
     84 UINTN                    mSmramProfileDriverPathSize;
     85 
     86 /**
     87   Dump SMRAM infromation.
     88 
     89 **/
     90 VOID
     91 DumpSmramInfo (
     92   VOID
     93   );
     94 
     95 /**
     96   Get memory profile data.
     97 
     98   @param[in]      This              The EDKII_SMM_MEMORY_PROFILE_PROTOCOL instance.
     99   @param[in, out] ProfileSize       On entry, points to the size in bytes of the ProfileBuffer.
    100                                     On return, points to the size of the data returned in ProfileBuffer.
    101   @param[out]     ProfileBuffer     Profile buffer.
    102 
    103   @return EFI_SUCCESS               Get the memory profile data successfully.
    104   @return EFI_UNSUPPORTED           Memory profile is unsupported.
    105   @return EFI_BUFFER_TO_SMALL       The ProfileSize is too small for the resulting data.
    106                                     ProfileSize is updated with the size required.
    107 
    108 **/
    109 EFI_STATUS
    110 EFIAPI
    111 SmramProfileProtocolGetData (
    112   IN     EDKII_SMM_MEMORY_PROFILE_PROTOCOL  *This,
    113   IN OUT UINT64                             *ProfileSize,
    114      OUT VOID                               *ProfileBuffer
    115   );
    116 
    117 /**
    118   Register image to memory profile.
    119 
    120   @param[in] This               The EDKII_SMM_MEMORY_PROFILE_PROTOCOL instance.
    121   @param[in] FilePath           File path of the image.
    122   @param[in] ImageBase          Image base address.
    123   @param[in] ImageSize          Image size.
    124   @param[in] FileType           File type of the image.
    125 
    126   @return EFI_SUCCESS           Register successfully.
    127   @return EFI_UNSUPPORTED       Memory profile is unsupported,
    128                                 or memory profile for the image is not required.
    129   @return EFI_OUT_OF_RESOURCE   No enough resource for this register.
    130 
    131 **/
    132 EFI_STATUS
    133 EFIAPI
    134 SmramProfileProtocolRegisterImage (
    135   IN EDKII_SMM_MEMORY_PROFILE_PROTOCOL  *This,
    136   IN EFI_DEVICE_PATH_PROTOCOL           *FilePath,
    137   IN PHYSICAL_ADDRESS                   ImageBase,
    138   IN UINT64                             ImageSize,
    139   IN EFI_FV_FILETYPE                    FileType
    140   );
    141 
    142 /**
    143   Unregister image from memory profile.
    144 
    145   @param[in] This               The EDKII_SMM_MEMORY_PROFILE_PROTOCOL instance.
    146   @param[in] FilePath           File path of the image.
    147   @param[in] ImageBase          Image base address.
    148   @param[in] ImageSize          Image size.
    149 
    150   @return EFI_SUCCESS           Unregister successfully.
    151   @return EFI_UNSUPPORTED       Memory profile is unsupported,
    152                                 or memory profile for the image is not required.
    153   @return EFI_NOT_FOUND         The image is not found.
    154 
    155 **/
    156 EFI_STATUS
    157 EFIAPI
    158 SmramProfileProtocolUnregisterImage (
    159   IN EDKII_SMM_MEMORY_PROFILE_PROTOCOL  *This,
    160   IN EFI_DEVICE_PATH_PROTOCOL           *FilePath,
    161   IN PHYSICAL_ADDRESS                   ImageBase,
    162   IN UINT64                             ImageSize
    163   );
    164 
    165 /**
    166   Get memory profile recording state.
    167 
    168   @param[in]  This              The EDKII_SMM_MEMORY_PROFILE_PROTOCOL instance.
    169   @param[out] RecordingState    Recording state.
    170 
    171   @return EFI_SUCCESS           Memory profile recording state is returned.
    172   @return EFI_UNSUPPORTED       Memory profile is unsupported.
    173   @return EFI_INVALID_PARAMETER RecordingState is NULL.
    174 
    175 **/
    176 EFI_STATUS
    177 EFIAPI
    178 SmramProfileProtocolGetRecordingState (
    179   IN EDKII_SMM_MEMORY_PROFILE_PROTOCOL  *This,
    180   OUT BOOLEAN                           *RecordingState
    181   );
    182 
    183 /**
    184   Set memory profile recording state.
    185 
    186   @param[in] This               The EDKII_SMM_MEMORY_PROFILE_PROTOCOL instance.
    187   @param[in] RecordingState     Recording state.
    188 
    189   @return EFI_SUCCESS           Set memory profile recording state successfully.
    190   @return EFI_UNSUPPORTED       Memory profile is unsupported.
    191 
    192 **/
    193 EFI_STATUS
    194 EFIAPI
    195 SmramProfileProtocolSetRecordingState (
    196   IN EDKII_SMM_MEMORY_PROFILE_PROTOCOL  *This,
    197   IN BOOLEAN                            RecordingState
    198   );
    199 
    200 /**
    201   Record memory profile of multilevel caller.
    202 
    203   @param[in] This               The EDKII_SMM_MEMORY_PROFILE_PROTOCOL instance.
    204   @param[in] CallerAddress      Address of caller.
    205   @param[in] Action             Memory profile action.
    206   @param[in] MemoryType         Memory type.
    207                                 EfiMaxMemoryType means the MemoryType is unknown.
    208   @param[in] Buffer             Buffer address.
    209   @param[in] Size               Buffer size.
    210   @param[in] ActionString       String for memory profile action.
    211                                 Only needed for user defined allocate action.
    212 
    213   @return EFI_SUCCESS           Memory profile is updated.
    214   @return EFI_UNSUPPORTED       Memory profile is unsupported,
    215                                 or memory profile for the image is not required,
    216                                 or memory profile for the memory type is not required.
    217   @return EFI_ACCESS_DENIED     It is during memory profile data getting.
    218   @return EFI_ABORTED           Memory profile recording is not enabled.
    219   @return EFI_OUT_OF_RESOURCES  No enough resource to update memory profile for allocate action.
    220   @return EFI_NOT_FOUND         No matched allocate info found for free action.
    221 
    222 **/
    223 EFI_STATUS
    224 EFIAPI
    225 SmramProfileProtocolRecord (
    226   IN EDKII_SMM_MEMORY_PROFILE_PROTOCOL  *This,
    227   IN PHYSICAL_ADDRESS                   CallerAddress,
    228   IN MEMORY_PROFILE_ACTION              Action,
    229   IN EFI_MEMORY_TYPE                    MemoryType,
    230   IN VOID                               *Buffer,
    231   IN UINTN                              Size,
    232   IN CHAR8                              *ActionString OPTIONAL
    233   );
    234 
    235 EDKII_SMM_MEMORY_PROFILE_PROTOCOL mSmmProfileProtocol = {
    236   SmramProfileProtocolGetData,
    237   SmramProfileProtocolRegisterImage,
    238   SmramProfileProtocolUnregisterImage,
    239   SmramProfileProtocolGetRecordingState,
    240   SmramProfileProtocolSetRecordingState,
    241   SmramProfileProtocolRecord,
    242 };
    243 
    244 /**
    245   Return SMRAM profile context.
    246 
    247   @return SMRAM profile context.
    248 
    249 **/
    250 MEMORY_PROFILE_CONTEXT_DATA *
    251 GetSmramProfileContext (
    252   VOID
    253   )
    254 {
    255   return mSmramProfileContextPtr;
    256 }
    257 
    258 /**
    259   Retrieves the magic value from the PE/COFF header.
    260 
    261   @param Hdr    The buffer in which to return the PE32, PE32+, or TE header.
    262 
    263   @return EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC - Image is PE32
    264   @return EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC - Image is PE32+
    265 
    266 **/
    267 UINT16
    268 InternalPeCoffGetPeHeaderMagicValue (
    269   IN  EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION  Hdr
    270   )
    271 {
    272   //
    273   // NOTE: Some versions of Linux ELILO for Itanium have an incorrect magic value
    274   //       in the PE/COFF Header.  If the MachineType is Itanium(IA64) and the
    275   //       Magic value in the OptionalHeader is  EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
    276   //       then override the returned value to EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
    277   //
    278   if (Hdr.Pe32->FileHeader.Machine == IMAGE_FILE_MACHINE_IA64 && Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
    279     return EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;
    280   }
    281   //
    282   // Return the magic value from the PC/COFF Optional Header
    283   //
    284   return Hdr.Pe32->OptionalHeader.Magic;
    285 }
    286 
    287 /**
    288   Retrieves and returns the Subsystem of a PE/COFF image that has been loaded into system memory.
    289   If Pe32Data is NULL, then ASSERT().
    290 
    291   @param Pe32Data   The pointer to the PE/COFF image that is loaded in system memory.
    292 
    293   @return The Subsystem of the PE/COFF image.
    294 
    295 **/
    296 UINT16
    297 InternalPeCoffGetSubsystem (
    298   IN VOID  *Pe32Data
    299   )
    300 {
    301   EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION  Hdr;
    302   EFI_IMAGE_DOS_HEADER                 *DosHdr;
    303   UINT16                               Magic;
    304 
    305   ASSERT (Pe32Data != NULL);
    306 
    307   DosHdr = (EFI_IMAGE_DOS_HEADER *) Pe32Data;
    308   if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
    309     //
    310     // DOS image header is present, so read the PE header after the DOS image header.
    311     //
    312     Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *) ((UINTN) Pe32Data + (UINTN) ((DosHdr->e_lfanew) & 0x0ffff));
    313   } else {
    314     //
    315     // DOS image header is not present, so PE header is at the image base.
    316     //
    317     Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *) Pe32Data;
    318   }
    319 
    320   if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {
    321     return Hdr.Te->Subsystem;
    322   } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE)  {
    323     Magic = InternalPeCoffGetPeHeaderMagicValue (Hdr);
    324     if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
    325       return Hdr.Pe32->OptionalHeader.Subsystem;
    326     } else if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
    327       return Hdr.Pe32Plus->OptionalHeader.Subsystem;
    328     }
    329   }
    330 
    331   return 0x0000;
    332 }
    333 
    334 /**
    335   Retrieves and returns a pointer to the entry point to a PE/COFF image that has been loaded
    336   into system memory with the PE/COFF Loader Library functions.
    337 
    338   Retrieves the entry point to the PE/COFF image specified by Pe32Data and returns this entry
    339   point in EntryPoint.  If the entry point could not be retrieved from the PE/COFF image, then
    340   return RETURN_INVALID_PARAMETER.  Otherwise return RETURN_SUCCESS.
    341   If Pe32Data is NULL, then ASSERT().
    342   If EntryPoint is NULL, then ASSERT().
    343 
    344   @param  Pe32Data                  The pointer to the PE/COFF image that is loaded in system memory.
    345   @param  EntryPoint                The pointer to entry point to the PE/COFF image to return.
    346 
    347   @retval RETURN_SUCCESS            EntryPoint was returned.
    348   @retval RETURN_INVALID_PARAMETER  The entry point could not be found in the PE/COFF image.
    349 
    350 **/
    351 RETURN_STATUS
    352 InternalPeCoffGetEntryPoint (
    353   IN  VOID  *Pe32Data,
    354   OUT VOID  **EntryPoint
    355   )
    356 {
    357   EFI_IMAGE_DOS_HEADER                  *DosHdr;
    358   EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION   Hdr;
    359 
    360   ASSERT (Pe32Data   != NULL);
    361   ASSERT (EntryPoint != NULL);
    362 
    363   DosHdr = (EFI_IMAGE_DOS_HEADER *) Pe32Data;
    364   if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
    365     //
    366     // DOS image header is present, so read the PE header after the DOS image header.
    367     //
    368     Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *) ((UINTN) Pe32Data + (UINTN) ((DosHdr->e_lfanew) & 0x0ffff));
    369   } else {
    370     //
    371     // DOS image header is not present, so PE header is at the image base.
    372     //
    373     Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *) Pe32Data;
    374   }
    375 
    376   //
    377   // Calculate the entry point relative to the start of the image.
    378   // AddressOfEntryPoint is common for PE32 & PE32+
    379   //
    380   if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {
    381     *EntryPoint = (VOID *) ((UINTN) Pe32Data + (UINTN) (Hdr.Te->AddressOfEntryPoint & 0x0ffffffff) + sizeof (EFI_TE_IMAGE_HEADER) - Hdr.Te->StrippedSize);
    382     return RETURN_SUCCESS;
    383   } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {
    384     *EntryPoint = (VOID *) ((UINTN) Pe32Data + (UINTN) (Hdr.Pe32->OptionalHeader.AddressOfEntryPoint & 0x0ffffffff));
    385     return RETURN_SUCCESS;
    386   }
    387 
    388   return RETURN_UNSUPPORTED;
    389 }
    390 
    391 /**
    392   Build driver info.
    393 
    394   @param ContextData    Memory profile context.
    395   @param FileName       File name of the image.
    396   @param ImageBase      Image base address.
    397   @param ImageSize      Image size.
    398   @param EntryPoint     Entry point of the image.
    399   @param ImageSubsystem Image subsystem of the image.
    400   @param FileType       File type of the image.
    401 
    402   @return Pointer to memory profile driver info.
    403 
    404 **/
    405 MEMORY_PROFILE_DRIVER_INFO_DATA *
    406 BuildDriverInfo (
    407   IN MEMORY_PROFILE_CONTEXT_DATA    *ContextData,
    408   IN EFI_GUID                       *FileName,
    409   IN PHYSICAL_ADDRESS               ImageBase,
    410   IN UINT64                         ImageSize,
    411   IN PHYSICAL_ADDRESS               EntryPoint,
    412   IN UINT16                         ImageSubsystem,
    413   IN EFI_FV_FILETYPE                FileType
    414   )
    415 {
    416   EFI_STATUS                        Status;
    417   MEMORY_PROFILE_DRIVER_INFO        *DriverInfo;
    418   MEMORY_PROFILE_DRIVER_INFO_DATA   *DriverInfoData;
    419   VOID                              *EntryPointInImage;
    420   CHAR8                             *PdbString;
    421   UINTN                             PdbSize;
    422   UINTN                             PdbOccupiedSize;
    423 
    424   PdbSize = 0;
    425   PdbOccupiedSize = 0;
    426   PdbString = NULL;
    427   if (ImageBase != 0) {
    428     PdbString = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageBase);
    429     if (PdbString != NULL) {
    430       PdbSize = AsciiStrSize (PdbString);
    431       PdbOccupiedSize = GET_OCCUPIED_SIZE (PdbSize, sizeof (UINT64));
    432     }
    433   }
    434 
    435   //
    436   // Use SmmInternalAllocatePool() that will not update profile for this AllocatePool action.
    437   //
    438   Status = SmmInternalAllocatePool (
    439              EfiRuntimeServicesData,
    440              sizeof (*DriverInfoData) + sizeof (LIST_ENTRY) + PdbSize,
    441              (VOID **) &DriverInfoData
    442              );
    443   if (EFI_ERROR (Status)) {
    444     return NULL;
    445   }
    446   ASSERT (DriverInfoData != NULL);
    447 
    448   ZeroMem (DriverInfoData, sizeof (*DriverInfoData));
    449 
    450   DriverInfo = &DriverInfoData->DriverInfo;
    451   DriverInfoData->Signature = MEMORY_PROFILE_DRIVER_INFO_SIGNATURE;
    452   DriverInfo->Header.Signature = MEMORY_PROFILE_DRIVER_INFO_SIGNATURE;
    453   DriverInfo->Header.Length = (UINT16) (sizeof (MEMORY_PROFILE_DRIVER_INFO) + PdbOccupiedSize);
    454   DriverInfo->Header.Revision = MEMORY_PROFILE_DRIVER_INFO_REVISION;
    455   if (FileName != NULL) {
    456     CopyMem (&DriverInfo->FileName, FileName, sizeof (EFI_GUID));
    457   }
    458   DriverInfo->ImageBase = ImageBase;
    459   DriverInfo->ImageSize = ImageSize;
    460   DriverInfo->EntryPoint = EntryPoint;
    461   DriverInfo->ImageSubsystem = ImageSubsystem;
    462   if ((EntryPoint != 0) && ((EntryPoint < ImageBase) || (EntryPoint >= (ImageBase + ImageSize)))) {
    463     //
    464     // If the EntryPoint is not in the range of image buffer, it should come from emulation environment.
    465     // So patch ImageBuffer here to align the EntryPoint.
    466     //
    467     Status = InternalPeCoffGetEntryPoint ((VOID *) (UINTN) ImageBase, &EntryPointInImage);
    468     ASSERT_EFI_ERROR (Status);
    469     DriverInfo->ImageBase = ImageBase + EntryPoint - (PHYSICAL_ADDRESS) (UINTN) EntryPointInImage;
    470   }
    471   DriverInfo->FileType = FileType;
    472   DriverInfoData->AllocInfoList = (LIST_ENTRY *) (DriverInfoData + 1);
    473   InitializeListHead (DriverInfoData->AllocInfoList);
    474   DriverInfo->CurrentUsage = 0;
    475   DriverInfo->PeakUsage = 0;
    476   DriverInfo->AllocRecordCount = 0;
    477   if (PdbSize != 0) {
    478     DriverInfo->PdbStringOffset = (UINT16) sizeof (MEMORY_PROFILE_DRIVER_INFO);
    479     DriverInfoData->PdbString = (CHAR8 *) (DriverInfoData->AllocInfoList + 1);
    480     CopyMem (DriverInfoData->PdbString, PdbString, PdbSize);
    481   } else {
    482     DriverInfo->PdbStringOffset = 0;
    483     DriverInfoData->PdbString = NULL;
    484   }
    485 
    486   InsertTailList (ContextData->DriverInfoList, &DriverInfoData->Link);
    487   ContextData->Context.ImageCount ++;
    488   ContextData->Context.TotalImageSize += DriverInfo->ImageSize;
    489 
    490   return DriverInfoData;
    491 }
    492 
    493 /**
    494   Register image to DXE.
    495 
    496   @param FileName       File name of the image.
    497   @param ImageBase      Image base address.
    498   @param ImageSize      Image size.
    499   @param FileType       File type of the image.
    500 
    501 **/
    502 VOID
    503 RegisterImageToDxe (
    504   IN EFI_GUID                       *FileName,
    505   IN PHYSICAL_ADDRESS               ImageBase,
    506   IN UINT64                         ImageSize,
    507   IN EFI_FV_FILETYPE                FileType
    508   )
    509 {
    510   EFI_STATUS                        Status;
    511   EDKII_MEMORY_PROFILE_PROTOCOL     *ProfileProtocol;
    512   MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FilePath;
    513   UINT8                             TempBuffer[sizeof (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH) + sizeof (EFI_DEVICE_PATH_PROTOCOL)];
    514 
    515   if (IS_UEFI_MEMORY_PROFILE_ENABLED) {
    516 
    517     FilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)TempBuffer;
    518     Status = gBS->LocateProtocol (&gEdkiiMemoryProfileGuid, NULL, (VOID **) &ProfileProtocol);
    519     if (!EFI_ERROR (Status)) {
    520       EfiInitializeFwVolDevicepathNode (FilePath, FileName);
    521       SetDevicePathEndNode (FilePath + 1);
    522 
    523       Status = ProfileProtocol->RegisterImage (
    524                                   ProfileProtocol,
    525                                   (EFI_DEVICE_PATH_PROTOCOL *) FilePath,
    526                                   ImageBase,
    527                                   ImageSize,
    528                                   FileType
    529                                   );
    530     }
    531   }
    532 }
    533 
    534 /**
    535   Unregister image from DXE.
    536 
    537   @param FileName       File name of the image.
    538   @param ImageBase      Image base address.
    539   @param ImageSize      Image size.
    540 
    541 **/
    542 VOID
    543 UnregisterImageFromDxe (
    544   IN EFI_GUID                       *FileName,
    545   IN PHYSICAL_ADDRESS               ImageBase,
    546   IN UINT64                         ImageSize
    547   )
    548 {
    549   EFI_STATUS                        Status;
    550   EDKII_MEMORY_PROFILE_PROTOCOL     *ProfileProtocol;
    551   MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FilePath;
    552   UINT8                             TempBuffer[sizeof (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH) + sizeof (EFI_DEVICE_PATH_PROTOCOL)];
    553 
    554   if (IS_UEFI_MEMORY_PROFILE_ENABLED) {
    555 
    556     FilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)TempBuffer;
    557     Status = gBS->LocateProtocol (&gEdkiiMemoryProfileGuid, NULL, (VOID *) &ProfileProtocol);
    558     if (!EFI_ERROR (Status)) {
    559       EfiInitializeFwVolDevicepathNode (FilePath, FileName);
    560       SetDevicePathEndNode (FilePath + 1);
    561 
    562       Status = ProfileProtocol->UnregisterImage (
    563                                   ProfileProtocol,
    564                                   (EFI_DEVICE_PATH_PROTOCOL *) FilePath,
    565                                   ImageBase,
    566                                   ImageSize
    567                                   );
    568     }
    569   }
    570 }
    571 
    572 /**
    573   Return if record for this driver is needed..
    574 
    575   @param DriverFilePath     Driver file path.
    576 
    577   @retval TRUE              Record for this driver is needed.
    578   @retval FALSE             Record for this driver is not needed.
    579 
    580 **/
    581 BOOLEAN
    582 NeedRecordThisDriver (
    583   IN EFI_DEVICE_PATH_PROTOCOL       *DriverFilePath
    584   )
    585 {
    586   EFI_DEVICE_PATH_PROTOCOL    *TmpDevicePath;
    587   EFI_DEVICE_PATH_PROTOCOL    *DevicePathInstance;
    588   UINTN                       DevicePathSize;
    589   UINTN                       FilePathSize;
    590 
    591   if (!IsDevicePathValid (mSmramProfileDriverPath, mSmramProfileDriverPathSize)) {
    592     //
    593     // Invalid Device Path means record all.
    594     //
    595     return TRUE;
    596   }
    597 
    598   //
    599   // Record FilePath without end node.
    600   //
    601   FilePathSize = GetDevicePathSize (DriverFilePath) - sizeof(EFI_DEVICE_PATH_PROTOCOL);
    602 
    603   DevicePathInstance = mSmramProfileDriverPath;
    604   do {
    605     //
    606     // Find End node (it might be END_ENTIRE or END_INSTANCE)
    607     //
    608     TmpDevicePath = DevicePathInstance;
    609     while (!IsDevicePathEndType (TmpDevicePath)) {
    610       TmpDevicePath = NextDevicePathNode (TmpDevicePath);
    611     }
    612 
    613     //
    614     // Do not compare END node
    615     //
    616     DevicePathSize = (UINTN)TmpDevicePath - (UINTN)DevicePathInstance;
    617     if ((FilePathSize == DevicePathSize) &&
    618         (CompareMem (DriverFilePath, DevicePathInstance, DevicePathSize) == 0)) {
    619       return TRUE;
    620     }
    621 
    622     //
    623     // Get next instance
    624     //
    625     DevicePathInstance = (EFI_DEVICE_PATH_PROTOCOL *)((UINTN)DevicePathInstance + DevicePathSize + DevicePathNodeLength(TmpDevicePath));
    626   } while (DevicePathSubType (TmpDevicePath) != END_ENTIRE_DEVICE_PATH_SUBTYPE);
    627 
    628   return FALSE;
    629 }
    630 
    631 /**
    632   Register SMM Core to SMRAM profile.
    633 
    634   @param ContextData    SMRAM profile context.
    635 
    636   @retval TRUE          Register success.
    637   @retval FALSE         Register fail.
    638 
    639 **/
    640 BOOLEAN
    641 RegisterSmmCore (
    642   IN MEMORY_PROFILE_CONTEXT_DATA    *ContextData
    643   )
    644 {
    645   MEMORY_PROFILE_DRIVER_INFO_DATA   *DriverInfoData;
    646   PHYSICAL_ADDRESS                  ImageBase;
    647   UINT8                             TempBuffer[sizeof(MEDIA_FW_VOL_FILEPATH_DEVICE_PATH) + sizeof(EFI_DEVICE_PATH_PROTOCOL)];
    648   MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FilePath;
    649 
    650   FilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) TempBuffer;
    651   EfiInitializeFwVolDevicepathNode (FilePath, &gEfiCallerIdGuid);
    652   SetDevicePathEndNode (FilePath + 1);
    653 
    654   if (!NeedRecordThisDriver ((EFI_DEVICE_PATH_PROTOCOL *) FilePath)) {
    655     return FALSE;
    656   }
    657 
    658   ImageBase = gSmmCorePrivate->PiSmmCoreImageBase;
    659   DriverInfoData = BuildDriverInfo (
    660                      ContextData,
    661                      &gEfiCallerIdGuid,
    662                      ImageBase,
    663                      gSmmCorePrivate->PiSmmCoreImageSize,
    664                      gSmmCorePrivate->PiSmmCoreEntryPoint,
    665                      InternalPeCoffGetSubsystem ((VOID *) (UINTN) ImageBase),
    666                      EFI_FV_FILETYPE_SMM_CORE
    667                      );
    668   if (DriverInfoData == NULL) {
    669     return FALSE;
    670   }
    671 
    672   return TRUE;
    673 }
    674 
    675 /**
    676   Initialize SMRAM profile.
    677 
    678 **/
    679 VOID
    680 SmramProfileInit (
    681   VOID
    682   )
    683 {
    684   MEMORY_PROFILE_CONTEXT_DATA *SmramProfileContext;
    685 
    686   RegisterImageToDxe (
    687     &gEfiCallerIdGuid,
    688     gSmmCorePrivate->PiSmmCoreImageBase,
    689     gSmmCorePrivate->PiSmmCoreImageSize,
    690     EFI_FV_FILETYPE_SMM_CORE
    691     );
    692 
    693   if (!IS_SMRAM_PROFILE_ENABLED) {
    694     return;
    695   }
    696 
    697   SmramProfileContext = GetSmramProfileContext ();
    698   if (SmramProfileContext != NULL) {
    699     return;
    700   }
    701 
    702   mSmramProfileGettingStatus = FALSE;
    703   if ((PcdGet8 (PcdMemoryProfilePropertyMask) & BIT7) != 0) {
    704     mSmramProfileRecordingEnable = MEMORY_PROFILE_RECORDING_DISABLE;
    705   } else {
    706     mSmramProfileRecordingEnable = MEMORY_PROFILE_RECORDING_ENABLE;
    707   }
    708   mSmramProfileDriverPathSize = PcdGetSize (PcdMemoryProfileDriverPath);
    709   mSmramProfileDriverPath = AllocateCopyPool (mSmramProfileDriverPathSize, PcdGetPtr (PcdMemoryProfileDriverPath));
    710   mSmramProfileContextPtr = &mSmramProfileContext;
    711 
    712   RegisterSmmCore (&mSmramProfileContext);
    713 
    714   DEBUG ((EFI_D_INFO, "SmramProfileInit SmramProfileContext - 0x%x\n", &mSmramProfileContext));
    715 }
    716 
    717 /**
    718   Install SMRAM profile protocol.
    719 
    720 **/
    721 VOID
    722 SmramProfileInstallProtocol (
    723   VOID
    724   )
    725 {
    726   EFI_HANDLE    Handle;
    727   EFI_STATUS    Status;
    728 
    729   if (!IS_SMRAM_PROFILE_ENABLED) {
    730     return;
    731   }
    732 
    733   Handle = NULL;
    734   Status = SmmInstallProtocolInterface (
    735              &Handle,
    736              &gEdkiiSmmMemoryProfileGuid,
    737              EFI_NATIVE_INTERFACE,
    738              &mSmmProfileProtocol
    739              );
    740   ASSERT_EFI_ERROR (Status);
    741 }
    742 
    743 /**
    744   Get the GUID file name from the file path.
    745 
    746   @param FilePath  File path.
    747 
    748   @return The GUID file name from the file path.
    749 
    750 **/
    751 EFI_GUID *
    752 GetFileNameFromFilePath (
    753   IN EFI_DEVICE_PATH_PROTOCOL   *FilePath
    754   )
    755 {
    756   MEDIA_FW_VOL_FILEPATH_DEVICE_PATH     *ThisFilePath;
    757   EFI_GUID                              *FileName;
    758 
    759   FileName = NULL;
    760   if (FilePath != NULL) {
    761     ThisFilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) FilePath;
    762     while (!IsDevicePathEnd (ThisFilePath)) {
    763       FileName = EfiGetNameGuidFromFwVolDevicePathNode (ThisFilePath);
    764       if (FileName != NULL) {
    765         break;
    766       }
    767       ThisFilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) NextDevicePathNode (ThisFilePath);
    768     }
    769   }
    770 
    771   return FileName;
    772 }
    773 
    774 /**
    775   Register SMM image to SMRAM profile.
    776 
    777   @param DriverEntry    SMM image info.
    778   @param RegisterToDxe  Register image to DXE.
    779 
    780   @return EFI_SUCCESS           Register successfully.
    781   @return EFI_UNSUPPORTED       Memory profile is unsupported,
    782                                 or memory profile for the image is not required.
    783   @return EFI_OUT_OF_RESOURCES  No enough resource for this register.
    784 
    785 **/
    786 EFI_STATUS
    787 RegisterSmramProfileImage (
    788   IN EFI_SMM_DRIVER_ENTRY   *DriverEntry,
    789   IN BOOLEAN                RegisterToDxe
    790   )
    791 {
    792   MEMORY_PROFILE_CONTEXT_DATA       *ContextData;
    793   MEMORY_PROFILE_DRIVER_INFO_DATA   *DriverInfoData;
    794   UINT8                             TempBuffer[sizeof(MEDIA_FW_VOL_FILEPATH_DEVICE_PATH) + sizeof(EFI_DEVICE_PATH_PROTOCOL)];
    795   MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FilePath;
    796 
    797   if (RegisterToDxe) {
    798     RegisterImageToDxe (
    799       &DriverEntry->FileName,
    800       DriverEntry->ImageBuffer,
    801       EFI_PAGES_TO_SIZE (DriverEntry->NumberOfPage),
    802       EFI_FV_FILETYPE_SMM
    803       );
    804   }
    805 
    806   if (!IS_SMRAM_PROFILE_ENABLED) {
    807     return EFI_UNSUPPORTED;
    808   }
    809 
    810   FilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) TempBuffer;
    811   EfiInitializeFwVolDevicepathNode (FilePath, &DriverEntry->FileName);
    812   SetDevicePathEndNode (FilePath + 1);
    813 
    814   if (!NeedRecordThisDriver ((EFI_DEVICE_PATH_PROTOCOL *) FilePath)) {
    815     return EFI_UNSUPPORTED;
    816   }
    817 
    818   ContextData = GetSmramProfileContext ();
    819   if (ContextData == NULL) {
    820     return EFI_UNSUPPORTED;
    821   }
    822 
    823   DriverInfoData = BuildDriverInfo (
    824                      ContextData,
    825                      &DriverEntry->FileName,
    826                      DriverEntry->ImageBuffer,
    827                      EFI_PAGES_TO_SIZE (DriverEntry->NumberOfPage),
    828                      DriverEntry->ImageEntryPoint,
    829                      InternalPeCoffGetSubsystem ((VOID *) (UINTN) DriverEntry->ImageBuffer),
    830                      EFI_FV_FILETYPE_SMM
    831                      );
    832   if (DriverInfoData == NULL) {
    833     return EFI_OUT_OF_RESOURCES;
    834   }
    835 
    836   return EFI_SUCCESS;
    837 }
    838 
    839 /**
    840   Search image from memory profile.
    841 
    842   @param ContextData    Memory profile context.
    843   @param FileName       Image file name.
    844   @param Address        Image Address.
    845 
    846   @return Pointer to memory profile driver info.
    847 
    848 **/
    849 MEMORY_PROFILE_DRIVER_INFO_DATA *
    850 GetMemoryProfileDriverInfoByFileNameAndAddress (
    851   IN MEMORY_PROFILE_CONTEXT_DATA    *ContextData,
    852   IN EFI_GUID                       *FileName,
    853   IN PHYSICAL_ADDRESS               Address
    854   )
    855 {
    856   MEMORY_PROFILE_DRIVER_INFO        *DriverInfo;
    857   MEMORY_PROFILE_DRIVER_INFO_DATA   *DriverInfoData;
    858   LIST_ENTRY                        *DriverLink;
    859   LIST_ENTRY                        *DriverInfoList;
    860 
    861   DriverInfoList = ContextData->DriverInfoList;
    862 
    863   for (DriverLink = DriverInfoList->ForwardLink;
    864        DriverLink != DriverInfoList;
    865        DriverLink = DriverLink->ForwardLink) {
    866     DriverInfoData = CR (
    867                        DriverLink,
    868                        MEMORY_PROFILE_DRIVER_INFO_DATA,
    869                        Link,
    870                        MEMORY_PROFILE_DRIVER_INFO_SIGNATURE
    871                        );
    872     DriverInfo = &DriverInfoData->DriverInfo;
    873     if ((CompareGuid (&DriverInfo->FileName, FileName)) &&
    874         (Address >= DriverInfo->ImageBase) &&
    875         (Address < (DriverInfo->ImageBase + DriverInfo->ImageSize))) {
    876       return DriverInfoData;
    877     }
    878   }
    879 
    880   return NULL;
    881 }
    882 
    883 /**
    884   Search image from memory profile.
    885   It will return image, if (Address >= ImageBuffer) AND (Address < ImageBuffer + ImageSize)
    886 
    887   @param ContextData    Memory profile context.
    888   @param Address        Image or Function address.
    889 
    890   @return Pointer to memory profile driver info.
    891 
    892 **/
    893 MEMORY_PROFILE_DRIVER_INFO_DATA *
    894 GetMemoryProfileDriverInfoFromAddress (
    895   IN MEMORY_PROFILE_CONTEXT_DATA    *ContextData,
    896   IN PHYSICAL_ADDRESS               Address
    897   )
    898 {
    899   MEMORY_PROFILE_DRIVER_INFO        *DriverInfo;
    900   MEMORY_PROFILE_DRIVER_INFO_DATA   *DriverInfoData;
    901   LIST_ENTRY                        *DriverLink;
    902   LIST_ENTRY                        *DriverInfoList;
    903 
    904   DriverInfoList = ContextData->DriverInfoList;
    905 
    906   for (DriverLink = DriverInfoList->ForwardLink;
    907        DriverLink != DriverInfoList;
    908        DriverLink = DriverLink->ForwardLink) {
    909     DriverInfoData = CR (
    910                        DriverLink,
    911                        MEMORY_PROFILE_DRIVER_INFO_DATA,
    912                        Link,
    913                        MEMORY_PROFILE_DRIVER_INFO_SIGNATURE
    914                        );
    915     DriverInfo = &DriverInfoData->DriverInfo;
    916     if ((Address >= DriverInfo->ImageBase) &&
    917         (Address < (DriverInfo->ImageBase + DriverInfo->ImageSize))) {
    918       return DriverInfoData;
    919     }
    920   }
    921 
    922   return NULL;
    923 }
    924 
    925 /**
    926   Unregister image from SMRAM profile.
    927 
    928   @param DriverEntry        SMM image info.
    929   @param UnregisterFromDxe  Unregister image from DXE.
    930 
    931   @return EFI_SUCCESS           Unregister successfully.
    932   @return EFI_UNSUPPORTED       Memory profile is unsupported,
    933                                 or memory profile for the image is not required.
    934   @return EFI_NOT_FOUND         The image is not found.
    935 
    936 **/
    937 EFI_STATUS
    938 UnregisterSmramProfileImage (
    939   IN EFI_SMM_DRIVER_ENTRY  *DriverEntry,
    940   IN BOOLEAN               UnregisterFromDxe
    941   )
    942 {
    943   EFI_STATUS                        Status;
    944   MEMORY_PROFILE_CONTEXT_DATA       *ContextData;
    945   MEMORY_PROFILE_DRIVER_INFO_DATA   *DriverInfoData;
    946   EFI_GUID                          *FileName;
    947   PHYSICAL_ADDRESS                  ImageAddress;
    948   VOID                              *EntryPointInImage;
    949   UINT8                             TempBuffer[sizeof(MEDIA_FW_VOL_FILEPATH_DEVICE_PATH) + sizeof(EFI_DEVICE_PATH_PROTOCOL)];
    950   MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FilePath;
    951 
    952   if (UnregisterFromDxe) {
    953     UnregisterImageFromDxe (
    954       &DriverEntry->FileName,
    955       DriverEntry->ImageBuffer,
    956       EFI_PAGES_TO_SIZE (DriverEntry->NumberOfPage)
    957       );
    958   }
    959 
    960   if (!IS_SMRAM_PROFILE_ENABLED) {
    961     return EFI_UNSUPPORTED;
    962   }
    963 
    964   FilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) TempBuffer;
    965   EfiInitializeFwVolDevicepathNode (FilePath, &DriverEntry->FileName);
    966   SetDevicePathEndNode (FilePath + 1);
    967 
    968   if (!NeedRecordThisDriver ((EFI_DEVICE_PATH_PROTOCOL *) FilePath)) {
    969     return EFI_UNSUPPORTED;
    970   }
    971 
    972   ContextData = GetSmramProfileContext ();
    973   if (ContextData == NULL) {
    974     return EFI_UNSUPPORTED;
    975   }
    976 
    977   DriverInfoData = NULL;
    978   FileName = &DriverEntry->FileName;
    979   ImageAddress = DriverEntry->ImageBuffer;
    980   if ((DriverEntry->ImageEntryPoint < ImageAddress) || (DriverEntry->ImageEntryPoint >= (ImageAddress + EFI_PAGES_TO_SIZE (DriverEntry->NumberOfPage)))) {
    981     //
    982     // If the EntryPoint is not in the range of image buffer, it should come from emulation environment.
    983     // So patch ImageAddress here to align the EntryPoint.
    984     //
    985     Status = InternalPeCoffGetEntryPoint ((VOID *) (UINTN) ImageAddress, &EntryPointInImage);
    986     ASSERT_EFI_ERROR (Status);
    987     ImageAddress = ImageAddress + (UINTN) DriverEntry->ImageEntryPoint - (UINTN) EntryPointInImage;
    988   }
    989   if (FileName != NULL) {
    990     DriverInfoData = GetMemoryProfileDriverInfoByFileNameAndAddress (ContextData, FileName, ImageAddress);
    991   }
    992   if (DriverInfoData == NULL) {
    993     DriverInfoData = GetMemoryProfileDriverInfoFromAddress (ContextData, ImageAddress);
    994   }
    995   if (DriverInfoData == NULL) {
    996     return EFI_NOT_FOUND;
    997   }
    998 
    999   ContextData->Context.TotalImageSize -= DriverInfoData->DriverInfo.ImageSize;
   1000 
   1001   // Keep the ImageBase for RVA calculation in Application.
   1002   //DriverInfoData->DriverInfo.ImageBase = 0;
   1003   DriverInfoData->DriverInfo.ImageSize = 0;
   1004 
   1005   if (DriverInfoData->DriverInfo.PeakUsage == 0) {
   1006     ContextData->Context.ImageCount --;
   1007     RemoveEntryList (&DriverInfoData->Link);
   1008     //
   1009     // Use SmmInternalFreePool() that will not update profile for this FreePool action.
   1010     //
   1011     SmmInternalFreePool (DriverInfoData);
   1012   }
   1013 
   1014   return EFI_SUCCESS;
   1015 }
   1016 
   1017 /**
   1018   Return if this memory type needs to be recorded into memory profile.
   1019   Only need to record EfiRuntimeServicesCode and EfiRuntimeServicesData for SMRAM profile.
   1020 
   1021   @param MemoryType     Memory type.
   1022 
   1023   @retval TRUE          This memory type need to be recorded.
   1024   @retval FALSE         This memory type need not to be recorded.
   1025 
   1026 **/
   1027 BOOLEAN
   1028 SmmCoreNeedRecordProfile (
   1029   IN EFI_MEMORY_TYPE    MemoryType
   1030   )
   1031 {
   1032   UINT64 TestBit;
   1033 
   1034   if (MemoryType != EfiRuntimeServicesCode &&
   1035       MemoryType != EfiRuntimeServicesData) {
   1036     return FALSE;
   1037   }
   1038 
   1039   TestBit = LShiftU64 (1, MemoryType);
   1040 
   1041   if ((PcdGet64 (PcdMemoryProfileMemoryType) & TestBit) != 0) {
   1042     return TRUE;
   1043   } else {
   1044     return FALSE;
   1045   }
   1046 }
   1047 
   1048 /**
   1049   Convert EFI memory type to profile memory index. The rule is:
   1050   If BIOS memory type (0 ~ EfiMaxMemoryType - 1), ProfileMemoryIndex = MemoryType.
   1051   As SMRAM profile is only to record EfiRuntimeServicesCode and EfiRuntimeServicesData,
   1052   so return input memory type directly.
   1053 
   1054   @param MemoryType     Memory type.
   1055 
   1056   @return EFI memory type as profile memory index.
   1057 
   1058 **/
   1059 EFI_MEMORY_TYPE
   1060 GetProfileMemoryIndex (
   1061   IN EFI_MEMORY_TYPE    MemoryType
   1062   )
   1063 {
   1064   return MemoryType;
   1065 }
   1066 
   1067 /**
   1068   Update SMRAM profile FreeMemoryPages information
   1069 
   1070   @param ContextData    Memory profile context.
   1071 
   1072 **/
   1073 VOID
   1074 SmramProfileUpdateFreePages (
   1075   IN MEMORY_PROFILE_CONTEXT_DATA  *ContextData
   1076   )
   1077 {
   1078   LIST_ENTRY                      *Node;
   1079   FREE_PAGE_LIST                  *Pages;
   1080   LIST_ENTRY                      *FreePageList;
   1081   UINTN                           NumberOfPages;
   1082 
   1083   NumberOfPages = 0;
   1084   FreePageList = &mSmmMemoryMap;
   1085   for (Node = FreePageList->BackLink;
   1086        Node != FreePageList;
   1087        Node = Node->BackLink) {
   1088     Pages = BASE_CR (Node, FREE_PAGE_LIST, Link);
   1089     NumberOfPages += Pages->NumberOfPages;
   1090   }
   1091 
   1092   mSmramFreeMemory.TotalFreeMemoryPages = NumberOfPages;
   1093 
   1094   if (NumberOfPages <= SMRAM_INFO_DUMP_PAGE_THRESHOLD) {
   1095     DumpSmramInfo ();
   1096   }
   1097 }
   1098 
   1099 /**
   1100   Update SMRAM profile Allocate information.
   1101 
   1102   @param CallerAddress  Address of caller who call Allocate.
   1103   @param Action         This Allocate action.
   1104   @param MemoryType     Memory type.
   1105   @param Size           Buffer size.
   1106   @param Buffer         Buffer address.
   1107   @param ActionString   String for memory profile action.
   1108 
   1109   @return EFI_SUCCESS           Memory profile is updated.
   1110   @return EFI_UNSUPPORTED       Memory profile is unsupported,
   1111                                 or memory profile for the image is not required.
   1112   @return EFI_OUT_OF_RESOURCES  No enough resource to update memory profile for allocate action.
   1113 
   1114 **/
   1115 EFI_STATUS
   1116 SmmCoreUpdateProfileAllocate (
   1117   IN PHYSICAL_ADDRESS       CallerAddress,
   1118   IN MEMORY_PROFILE_ACTION  Action,
   1119   IN EFI_MEMORY_TYPE        MemoryType,
   1120   IN UINTN                  Size,
   1121   IN VOID                   *Buffer,
   1122   IN CHAR8                  *ActionString OPTIONAL
   1123   )
   1124 {
   1125   EFI_STATUS                        Status;
   1126   MEMORY_PROFILE_CONTEXT            *Context;
   1127   MEMORY_PROFILE_DRIVER_INFO        *DriverInfo;
   1128   MEMORY_PROFILE_ALLOC_INFO         *AllocInfo;
   1129   MEMORY_PROFILE_CONTEXT_DATA       *ContextData;
   1130   MEMORY_PROFILE_DRIVER_INFO_DATA   *DriverInfoData;
   1131   MEMORY_PROFILE_ALLOC_INFO_DATA    *AllocInfoData;
   1132   EFI_MEMORY_TYPE                   ProfileMemoryIndex;
   1133   MEMORY_PROFILE_ACTION             BasicAction;
   1134   UINTN                             ActionStringSize;
   1135   UINTN                             ActionStringOccupiedSize;
   1136 
   1137   BasicAction = Action & MEMORY_PROFILE_ACTION_BASIC_MASK;
   1138 
   1139   ContextData = GetSmramProfileContext ();
   1140   if (ContextData == NULL) {
   1141     return EFI_UNSUPPORTED;
   1142   }
   1143 
   1144   DriverInfoData = GetMemoryProfileDriverInfoFromAddress (ContextData, CallerAddress);
   1145   if (DriverInfoData == NULL) {
   1146     return EFI_UNSUPPORTED;
   1147   }
   1148 
   1149   ActionStringSize = 0;
   1150   ActionStringOccupiedSize = 0;
   1151   if (ActionString != NULL) {
   1152     ActionStringSize = AsciiStrSize (ActionString);
   1153     ActionStringOccupiedSize = GET_OCCUPIED_SIZE (ActionStringSize, sizeof (UINT64));
   1154   }
   1155 
   1156   //
   1157   // Use SmmInternalAllocatePool() that will not update profile for this AllocatePool action.
   1158   //
   1159   AllocInfoData = NULL;
   1160   Status = SmmInternalAllocatePool (
   1161              EfiRuntimeServicesData,
   1162              sizeof (*AllocInfoData) + ActionStringSize,
   1163              (VOID **) &AllocInfoData
   1164              );
   1165   if (EFI_ERROR (Status)) {
   1166     return EFI_OUT_OF_RESOURCES;
   1167   }
   1168   ASSERT (AllocInfoData != NULL);
   1169 
   1170   //
   1171   // Only update SequenceCount if and only if it is basic action.
   1172   //
   1173   if (Action == BasicAction) {
   1174     ContextData->Context.SequenceCount ++;
   1175   }
   1176 
   1177   AllocInfo = &AllocInfoData->AllocInfo;
   1178   AllocInfoData->Signature      = MEMORY_PROFILE_ALLOC_INFO_SIGNATURE;
   1179   AllocInfo->Header.Signature   = MEMORY_PROFILE_ALLOC_INFO_SIGNATURE;
   1180   AllocInfo->Header.Length      = (UINT16) (sizeof (MEMORY_PROFILE_ALLOC_INFO) + ActionStringOccupiedSize);
   1181   AllocInfo->Header.Revision    = MEMORY_PROFILE_ALLOC_INFO_REVISION;
   1182   AllocInfo->CallerAddress      = CallerAddress;
   1183   AllocInfo->SequenceId         = ContextData->Context.SequenceCount;
   1184   AllocInfo->Action             = Action;
   1185   AllocInfo->MemoryType         = MemoryType;
   1186   AllocInfo->Buffer             = (PHYSICAL_ADDRESS) (UINTN) Buffer;
   1187   AllocInfo->Size               = Size;
   1188   if (ActionString != NULL) {
   1189     AllocInfo->ActionStringOffset = (UINT16) sizeof (MEMORY_PROFILE_ALLOC_INFO);
   1190     AllocInfoData->ActionString = (CHAR8 *) (AllocInfoData + 1);
   1191     CopyMem (AllocInfoData->ActionString, ActionString, ActionStringSize);
   1192   } else {
   1193     AllocInfo->ActionStringOffset = 0;
   1194     AllocInfoData->ActionString = NULL;
   1195   }
   1196 
   1197   InsertTailList (DriverInfoData->AllocInfoList, &AllocInfoData->Link);
   1198 
   1199   Context = &ContextData->Context;
   1200   DriverInfo = &DriverInfoData->DriverInfo;
   1201   DriverInfo->AllocRecordCount ++;
   1202 
   1203   //
   1204   // Update summary if and only if it is basic action.
   1205   //
   1206   if (Action == BasicAction) {
   1207     ProfileMemoryIndex = GetProfileMemoryIndex (MemoryType);
   1208 
   1209     DriverInfo->CurrentUsage += Size;
   1210     if (DriverInfo->PeakUsage < DriverInfo->CurrentUsage) {
   1211       DriverInfo->PeakUsage = DriverInfo->CurrentUsage;
   1212     }
   1213     DriverInfo->CurrentUsageByType[ProfileMemoryIndex] += Size;
   1214     if (DriverInfo->PeakUsageByType[ProfileMemoryIndex] < DriverInfo->CurrentUsageByType[ProfileMemoryIndex]) {
   1215       DriverInfo->PeakUsageByType[ProfileMemoryIndex] = DriverInfo->CurrentUsageByType[ProfileMemoryIndex];
   1216     }
   1217 
   1218     Context->CurrentTotalUsage += Size;
   1219     if (Context->PeakTotalUsage < Context->CurrentTotalUsage) {
   1220       Context->PeakTotalUsage = Context->CurrentTotalUsage;
   1221     }
   1222     Context->CurrentTotalUsageByType[ProfileMemoryIndex] += Size;
   1223     if (Context->PeakTotalUsageByType[ProfileMemoryIndex] < Context->CurrentTotalUsageByType[ProfileMemoryIndex]) {
   1224       Context->PeakTotalUsageByType[ProfileMemoryIndex] = Context->CurrentTotalUsageByType[ProfileMemoryIndex];
   1225     }
   1226 
   1227     SmramProfileUpdateFreePages (ContextData);
   1228   }
   1229 
   1230   return EFI_SUCCESS;
   1231 }
   1232 
   1233 /**
   1234   Get memory profile alloc info from memory profile
   1235 
   1236   @param DriverInfoData     Driver info
   1237   @param BasicAction        This Free basic action
   1238   @param Size               Buffer size
   1239   @param Buffer             Buffer address
   1240 
   1241   @return Pointer to memory profile alloc info.
   1242 **/
   1243 MEMORY_PROFILE_ALLOC_INFO_DATA *
   1244 GetMemoryProfileAllocInfoFromAddress (
   1245   IN MEMORY_PROFILE_DRIVER_INFO_DATA    *DriverInfoData,
   1246   IN MEMORY_PROFILE_ACTION              BasicAction,
   1247   IN UINTN                              Size,
   1248   IN VOID                               *Buffer
   1249   )
   1250 {
   1251   LIST_ENTRY                        *AllocInfoList;
   1252   LIST_ENTRY                        *AllocLink;
   1253   MEMORY_PROFILE_ALLOC_INFO         *AllocInfo;
   1254   MEMORY_PROFILE_ALLOC_INFO_DATA    *AllocInfoData;
   1255 
   1256   AllocInfoList = DriverInfoData->AllocInfoList;
   1257 
   1258   for (AllocLink = AllocInfoList->ForwardLink;
   1259        AllocLink != AllocInfoList;
   1260        AllocLink = AllocLink->ForwardLink) {
   1261     AllocInfoData = CR (
   1262                       AllocLink,
   1263                       MEMORY_PROFILE_ALLOC_INFO_DATA,
   1264                       Link,
   1265                       MEMORY_PROFILE_ALLOC_INFO_SIGNATURE
   1266                       );
   1267     AllocInfo = &AllocInfoData->AllocInfo;
   1268     if ((AllocInfo->Action & MEMORY_PROFILE_ACTION_BASIC_MASK) != BasicAction) {
   1269       continue;
   1270     }
   1271     switch (BasicAction) {
   1272       case MemoryProfileActionAllocatePages:
   1273         if ((AllocInfo->Buffer <= (PHYSICAL_ADDRESS) (UINTN) Buffer) &&
   1274             ((AllocInfo->Buffer + AllocInfo->Size) >= ((PHYSICAL_ADDRESS) (UINTN) Buffer + Size))) {
   1275           return AllocInfoData;
   1276         }
   1277         break;
   1278       case MemoryProfileActionAllocatePool:
   1279         if (AllocInfo->Buffer == (PHYSICAL_ADDRESS) (UINTN) Buffer) {
   1280           return AllocInfoData;
   1281         }
   1282         break;
   1283       default:
   1284         ASSERT (FALSE);
   1285         break;
   1286     }
   1287   }
   1288 
   1289   return NULL;
   1290 }
   1291 
   1292 /**
   1293   Update SMRAM profile Free information.
   1294 
   1295   @param CallerAddress  Address of caller who call Free.
   1296   @param Action         This Free action.
   1297   @param Size           Buffer size.
   1298   @param Buffer         Buffer address.
   1299 
   1300   @return EFI_SUCCESS           Memory profile is updated.
   1301   @return EFI_UNSUPPORTED       Memory profile is unsupported.
   1302   @return EFI_NOT_FOUND         No matched allocate info found for free action.
   1303 
   1304 **/
   1305 EFI_STATUS
   1306 SmmCoreUpdateProfileFree (
   1307   IN PHYSICAL_ADDRESS       CallerAddress,
   1308   IN MEMORY_PROFILE_ACTION  Action,
   1309   IN UINTN                  Size,
   1310   IN VOID                   *Buffer
   1311   )
   1312 {
   1313   MEMORY_PROFILE_CONTEXT           *Context;
   1314   MEMORY_PROFILE_DRIVER_INFO       *DriverInfo;
   1315   MEMORY_PROFILE_ALLOC_INFO        *AllocInfo;
   1316   MEMORY_PROFILE_CONTEXT_DATA      *ContextData;
   1317   MEMORY_PROFILE_DRIVER_INFO_DATA  *DriverInfoData;
   1318   LIST_ENTRY                       *DriverLink;
   1319   LIST_ENTRY                       *DriverInfoList;
   1320   MEMORY_PROFILE_DRIVER_INFO_DATA  *ThisDriverInfoData;
   1321   MEMORY_PROFILE_ALLOC_INFO_DATA   *AllocInfoData;
   1322   EFI_MEMORY_TYPE                  ProfileMemoryIndex;
   1323   MEMORY_PROFILE_ACTION            BasicAction;
   1324   BOOLEAN                          Found;
   1325 
   1326   BasicAction = Action & MEMORY_PROFILE_ACTION_BASIC_MASK;
   1327 
   1328   ContextData = GetSmramProfileContext ();
   1329   if (ContextData == NULL) {
   1330     return EFI_UNSUPPORTED;
   1331   }
   1332 
   1333   DriverInfoData = GetMemoryProfileDriverInfoFromAddress (ContextData, CallerAddress);
   1334 
   1335   //
   1336   // Do not return if DriverInfoData == NULL here,
   1337   // because driver A might free memory allocated by driver B.
   1338   //
   1339 
   1340   //
   1341   // Need use do-while loop to find all possible record,
   1342   // because one address might be recorded multiple times.
   1343   //
   1344   Found = FALSE;
   1345   AllocInfoData = NULL;
   1346   do {
   1347     if (DriverInfoData != NULL) {
   1348       switch (BasicAction) {
   1349         case MemoryProfileActionFreePages:
   1350           AllocInfoData = GetMemoryProfileAllocInfoFromAddress (DriverInfoData, MemoryProfileActionAllocatePages, Size, Buffer);
   1351           break;
   1352         case MemoryProfileActionFreePool:
   1353           AllocInfoData = GetMemoryProfileAllocInfoFromAddress (DriverInfoData, MemoryProfileActionAllocatePool, 0, Buffer);
   1354           break;
   1355         default:
   1356           ASSERT (FALSE);
   1357           AllocInfoData = NULL;
   1358           break;
   1359       }
   1360     }
   1361     if (AllocInfoData == NULL) {
   1362       //
   1363       // Legal case, because driver A might free memory allocated by driver B, by some protocol.
   1364       //
   1365       DriverInfoList = ContextData->DriverInfoList;
   1366 
   1367       for (DriverLink = DriverInfoList->ForwardLink;
   1368            DriverLink != DriverInfoList;
   1369            DriverLink = DriverLink->ForwardLink) {
   1370         ThisDriverInfoData = CR (
   1371                                DriverLink,
   1372                                MEMORY_PROFILE_DRIVER_INFO_DATA,
   1373                                Link,
   1374                                MEMORY_PROFILE_DRIVER_INFO_SIGNATURE
   1375                                );
   1376         switch (BasicAction) {
   1377           case MemoryProfileActionFreePages:
   1378             AllocInfoData = GetMemoryProfileAllocInfoFromAddress (ThisDriverInfoData, MemoryProfileActionAllocatePages, Size, Buffer);
   1379             break;
   1380           case MemoryProfileActionFreePool:
   1381             AllocInfoData = GetMemoryProfileAllocInfoFromAddress (ThisDriverInfoData, MemoryProfileActionAllocatePool, 0, Buffer);
   1382             break;
   1383           default:
   1384             ASSERT (FALSE);
   1385             AllocInfoData = NULL;
   1386             break;
   1387         }
   1388         if (AllocInfoData != NULL) {
   1389           DriverInfoData = ThisDriverInfoData;
   1390           break;
   1391         }
   1392       }
   1393 
   1394       if (AllocInfoData == NULL) {
   1395         //
   1396         // If (!Found), no matched allocate info is found for this free action.
   1397         // It is because the specified memory type allocate actions have been filtered by
   1398         // CoreNeedRecordProfile(), but free actions have no memory type information,
   1399         // they can not be filtered by CoreNeedRecordProfile(). Then, they will be
   1400         // filtered here.
   1401         //
   1402         // If (Found), it is normal exit path.
   1403         return (Found ? EFI_SUCCESS : EFI_NOT_FOUND);
   1404       }
   1405     }
   1406 
   1407     ASSERT (DriverInfoData != NULL);
   1408     ASSERT (AllocInfoData != NULL);
   1409 
   1410     Found = TRUE;
   1411 
   1412     Context = &ContextData->Context;
   1413     DriverInfo = &DriverInfoData->DriverInfo;
   1414     AllocInfo = &AllocInfoData->AllocInfo;
   1415 
   1416     DriverInfo->AllocRecordCount --;
   1417     //
   1418     // Update summary if and only if it is basic action.
   1419     //
   1420     if (AllocInfo->Action == (AllocInfo->Action & MEMORY_PROFILE_ACTION_BASIC_MASK)) {
   1421       ProfileMemoryIndex = GetProfileMemoryIndex (AllocInfo->MemoryType);
   1422 
   1423       Context->CurrentTotalUsage -= AllocInfo->Size;
   1424       Context->CurrentTotalUsageByType[ProfileMemoryIndex] -= AllocInfo->Size;
   1425 
   1426       DriverInfo->CurrentUsage -= AllocInfo->Size;
   1427       DriverInfo->CurrentUsageByType[ProfileMemoryIndex] -= AllocInfo->Size;
   1428     }
   1429 
   1430     RemoveEntryList (&AllocInfoData->Link);
   1431 
   1432     if (BasicAction == MemoryProfileActionFreePages) {
   1433       if (AllocInfo->Buffer != (PHYSICAL_ADDRESS) (UINTN) Buffer) {
   1434         SmmCoreUpdateProfileAllocate (
   1435           AllocInfo->CallerAddress,
   1436           AllocInfo->Action,
   1437           AllocInfo->MemoryType,
   1438           (UINTN) ((PHYSICAL_ADDRESS) (UINTN) Buffer - AllocInfo->Buffer),
   1439           (VOID *) (UINTN) AllocInfo->Buffer,
   1440           AllocInfoData->ActionString
   1441           );
   1442       }
   1443       if (AllocInfo->Buffer + AllocInfo->Size != ((PHYSICAL_ADDRESS) (UINTN) Buffer + Size)) {
   1444         SmmCoreUpdateProfileAllocate (
   1445           AllocInfo->CallerAddress,
   1446           AllocInfo->Action,
   1447           AllocInfo->MemoryType,
   1448           (UINTN) ((AllocInfo->Buffer + AllocInfo->Size) - ((PHYSICAL_ADDRESS) (UINTN) Buffer + Size)),
   1449           (VOID *) ((UINTN) Buffer + Size),
   1450           AllocInfoData->ActionString
   1451           );
   1452       }
   1453     }
   1454 
   1455     //
   1456     // Use SmmInternalFreePool() that will not update profile for this FreePool action.
   1457     //
   1458     SmmInternalFreePool (AllocInfoData);
   1459   } while (TRUE);
   1460 }
   1461 
   1462 /**
   1463   Update SMRAM profile information.
   1464 
   1465   @param CallerAddress  Address of caller who call Allocate or Free.
   1466   @param Action         This Allocate or Free action.
   1467   @param MemoryType     Memory type.
   1468                         EfiMaxMemoryType means the MemoryType is unknown.
   1469   @param Size           Buffer size.
   1470   @param Buffer         Buffer address.
   1471   @param ActionString   String for memory profile action.
   1472                         Only needed for user defined allocate action.
   1473 
   1474   @return EFI_SUCCESS           Memory profile is updated.
   1475   @return EFI_UNSUPPORTED       Memory profile is unsupported,
   1476                                 or memory profile for the image is not required,
   1477                                 or memory profile for the memory type is not required.
   1478   @return EFI_ACCESS_DENIED     It is during memory profile data getting.
   1479   @return EFI_ABORTED           Memory profile recording is not enabled.
   1480   @return EFI_OUT_OF_RESOURCES  No enough resource to update memory profile for allocate action.
   1481   @return EFI_NOT_FOUND         No matched allocate info found for free action.
   1482 
   1483 **/
   1484 EFI_STATUS
   1485 EFIAPI
   1486 SmmCoreUpdateProfile (
   1487   IN PHYSICAL_ADDRESS       CallerAddress,
   1488   IN MEMORY_PROFILE_ACTION  Action,
   1489   IN EFI_MEMORY_TYPE        MemoryType, // Valid for AllocatePages/AllocatePool
   1490   IN UINTN                  Size,       // Valid for AllocatePages/FreePages/AllocatePool
   1491   IN VOID                   *Buffer,
   1492   IN CHAR8                  *ActionString OPTIONAL
   1493   )
   1494 {
   1495   EFI_STATUS                    Status;
   1496   MEMORY_PROFILE_CONTEXT_DATA   *ContextData;
   1497   MEMORY_PROFILE_ACTION         BasicAction;
   1498 
   1499   if (!IS_SMRAM_PROFILE_ENABLED) {
   1500     return EFI_UNSUPPORTED;
   1501   }
   1502 
   1503   if (mSmramProfileGettingStatus) {
   1504     return EFI_ACCESS_DENIED;
   1505   }
   1506 
   1507   if (!mSmramProfileRecordingEnable) {
   1508     return EFI_ABORTED;
   1509   }
   1510 
   1511   //
   1512   // Get the basic action to know how to process the record
   1513   //
   1514   BasicAction = Action & MEMORY_PROFILE_ACTION_BASIC_MASK;
   1515 
   1516   //
   1517   // Free operations have no memory type information, so skip the check.
   1518   //
   1519   if ((BasicAction == MemoryProfileActionAllocatePages) || (BasicAction == MemoryProfileActionAllocatePool)) {
   1520     //
   1521     // Only record limited MemoryType.
   1522     //
   1523     if (!SmmCoreNeedRecordProfile (MemoryType)) {
   1524       return EFI_UNSUPPORTED;
   1525     }
   1526   }
   1527 
   1528   ContextData = GetSmramProfileContext ();
   1529   if (ContextData == NULL) {
   1530     return EFI_UNSUPPORTED;
   1531   }
   1532 
   1533   switch (BasicAction) {
   1534     case MemoryProfileActionAllocatePages:
   1535       Status = SmmCoreUpdateProfileAllocate (CallerAddress, Action, MemoryType, Size, Buffer, ActionString);
   1536       break;
   1537     case MemoryProfileActionFreePages:
   1538       Status = SmmCoreUpdateProfileFree (CallerAddress, Action, Size, Buffer);
   1539       break;
   1540     case MemoryProfileActionAllocatePool:
   1541       Status = SmmCoreUpdateProfileAllocate (CallerAddress, Action, MemoryType, Size, Buffer, ActionString);
   1542       break;
   1543     case MemoryProfileActionFreePool:
   1544       Status = SmmCoreUpdateProfileFree (CallerAddress, Action, 0, Buffer);
   1545       break;
   1546     default:
   1547       ASSERT (FALSE);
   1548       Status = EFI_UNSUPPORTED;
   1549       break;
   1550   }
   1551 
   1552   return Status;
   1553 }
   1554 
   1555 /**
   1556   SMRAM profile ready to lock callback function.
   1557 
   1558 **/
   1559 VOID
   1560 SmramProfileReadyToLock (
   1561   VOID
   1562   )
   1563 {
   1564   if (!IS_SMRAM_PROFILE_ENABLED) {
   1565     return;
   1566   }
   1567 
   1568   DEBUG ((EFI_D_INFO, "SmramProfileReadyToLock\n"));
   1569   mSmramReadyToLock = TRUE;
   1570 }
   1571 
   1572 ////////////////////
   1573 
   1574 /**
   1575   Get SMRAM profile data size.
   1576 
   1577   @return SMRAM profile data size.
   1578 
   1579 **/
   1580 UINTN
   1581 SmramProfileGetDataSize (
   1582   VOID
   1583   )
   1584 {
   1585   MEMORY_PROFILE_CONTEXT_DATA       *ContextData;
   1586   MEMORY_PROFILE_DRIVER_INFO_DATA   *DriverInfoData;
   1587   MEMORY_PROFILE_ALLOC_INFO_DATA    *AllocInfoData;
   1588   LIST_ENTRY                        *DriverInfoList;
   1589   LIST_ENTRY                        *DriverLink;
   1590   LIST_ENTRY                        *AllocInfoList;
   1591   LIST_ENTRY                        *AllocLink;
   1592   UINTN                             TotalSize;
   1593   LIST_ENTRY                        *Node;
   1594   LIST_ENTRY                        *FreePageList;
   1595   LIST_ENTRY                        *FreePoolList;
   1596   FREE_POOL_HEADER                  *Pool;
   1597   UINTN                             PoolListIndex;
   1598   UINTN                             Index;
   1599   UINTN                             SmmPoolTypeIndex;
   1600 
   1601   ContextData = GetSmramProfileContext ();
   1602   if (ContextData == NULL) {
   1603     return 0;
   1604   }
   1605 
   1606   TotalSize = sizeof (MEMORY_PROFILE_CONTEXT);
   1607 
   1608   DriverInfoList = ContextData->DriverInfoList;
   1609   for (DriverLink = DriverInfoList->ForwardLink;
   1610        DriverLink != DriverInfoList;
   1611        DriverLink = DriverLink->ForwardLink) {
   1612     DriverInfoData = CR (
   1613                    DriverLink,
   1614                    MEMORY_PROFILE_DRIVER_INFO_DATA,
   1615                    Link,
   1616                    MEMORY_PROFILE_DRIVER_INFO_SIGNATURE
   1617                    );
   1618     TotalSize += DriverInfoData->DriverInfo.Header.Length;
   1619 
   1620     AllocInfoList = DriverInfoData->AllocInfoList;
   1621     for (AllocLink = AllocInfoList->ForwardLink;
   1622          AllocLink != AllocInfoList;
   1623          AllocLink = AllocLink->ForwardLink) {
   1624       AllocInfoData = CR (
   1625                         AllocLink,
   1626                         MEMORY_PROFILE_ALLOC_INFO_DATA,
   1627                         Link,
   1628                         MEMORY_PROFILE_ALLOC_INFO_SIGNATURE
   1629                         );
   1630       TotalSize += AllocInfoData->AllocInfo.Header.Length;
   1631     }
   1632   }
   1633 
   1634 
   1635   Index = 0;
   1636   FreePageList = &mSmmMemoryMap;
   1637   for (Node = FreePageList->BackLink;
   1638        Node != FreePageList;
   1639        Node = Node->BackLink) {
   1640     Index++;
   1641   }
   1642   for (SmmPoolTypeIndex = 0; SmmPoolTypeIndex < SmmPoolTypeMax; SmmPoolTypeIndex++) {
   1643     for (PoolListIndex = 0; PoolListIndex < MAX_POOL_INDEX; PoolListIndex++) {
   1644       FreePoolList = &mSmmPoolLists[SmmPoolTypeIndex][PoolListIndex];
   1645       for (Node = FreePoolList->BackLink;
   1646            Node != FreePoolList;
   1647            Node = Node->BackLink) {
   1648         Pool = BASE_CR (Node, FREE_POOL_HEADER, Link);
   1649         if (Pool->Header.Available) {
   1650           Index++;
   1651         }
   1652       }
   1653     }
   1654   }
   1655 
   1656   TotalSize += (sizeof (MEMORY_PROFILE_FREE_MEMORY) + Index * sizeof (MEMORY_PROFILE_DESCRIPTOR));
   1657   TotalSize += (sizeof (MEMORY_PROFILE_MEMORY_RANGE) + mFullSmramRangeCount * sizeof (MEMORY_PROFILE_DESCRIPTOR));
   1658 
   1659   return TotalSize;
   1660 }
   1661 
   1662 /**
   1663   Copy SMRAM profile data.
   1664 
   1665   @param ProfileBuffer  The buffer to hold SMRAM profile data.
   1666   @param ProfileSize    On input, profile buffer size.
   1667                         On output, actual profile data size copied.
   1668   @param ProfileOffset  On input, profile buffer offset to copy.
   1669                         On output, next time profile buffer offset to copy.
   1670 
   1671 **/
   1672 VOID
   1673 SmramProfileCopyData (
   1674   OUT VOID      *ProfileBuffer,
   1675   IN OUT UINT64 *ProfileSize,
   1676   IN OUT UINT64 *ProfileOffset
   1677   )
   1678 {
   1679   MEMORY_PROFILE_CONTEXT           *Context;
   1680   MEMORY_PROFILE_DRIVER_INFO       *DriverInfo;
   1681   MEMORY_PROFILE_ALLOC_INFO        *AllocInfo;
   1682   MEMORY_PROFILE_CONTEXT_DATA      *ContextData;
   1683   MEMORY_PROFILE_DRIVER_INFO_DATA  *DriverInfoData;
   1684   MEMORY_PROFILE_ALLOC_INFO_DATA   *AllocInfoData;
   1685   LIST_ENTRY                      *DriverInfoList;
   1686   LIST_ENTRY                      *DriverLink;
   1687   LIST_ENTRY                      *AllocInfoList;
   1688   LIST_ENTRY                      *AllocLink;
   1689   LIST_ENTRY                      *Node;
   1690   FREE_PAGE_LIST                  *Pages;
   1691   LIST_ENTRY                      *FreePageList;
   1692   LIST_ENTRY                      *FreePoolList;
   1693   FREE_POOL_HEADER                *Pool;
   1694   UINTN                           PoolListIndex;
   1695   UINT32                          Index;
   1696   MEMORY_PROFILE_FREE_MEMORY      *FreeMemory;
   1697   MEMORY_PROFILE_MEMORY_RANGE     *MemoryRange;
   1698   MEMORY_PROFILE_DESCRIPTOR       *MemoryProfileDescriptor;
   1699   UINT64                          Offset;
   1700   UINT64                          RemainingSize;
   1701   UINTN                           PdbSize;
   1702   UINTN                           ActionStringSize;
   1703   UINTN                           SmmPoolTypeIndex;
   1704 
   1705   ContextData = GetSmramProfileContext ();
   1706   if (ContextData == NULL) {
   1707     return ;
   1708   }
   1709 
   1710   RemainingSize = *ProfileSize;
   1711   Offset = 0;
   1712 
   1713   if (*ProfileOffset < sizeof (MEMORY_PROFILE_CONTEXT)) {
   1714     if (RemainingSize >= sizeof (MEMORY_PROFILE_CONTEXT)) {
   1715       Context = ProfileBuffer;
   1716       CopyMem (Context, &ContextData->Context, sizeof (MEMORY_PROFILE_CONTEXT));
   1717       RemainingSize -= sizeof (MEMORY_PROFILE_CONTEXT);
   1718       ProfileBuffer = (UINT8 *) ProfileBuffer + sizeof (MEMORY_PROFILE_CONTEXT);
   1719     } else {
   1720       goto Done;
   1721     }
   1722   }
   1723   Offset += sizeof (MEMORY_PROFILE_CONTEXT);
   1724 
   1725   DriverInfoList = ContextData->DriverInfoList;
   1726   for (DriverLink = DriverInfoList->ForwardLink;
   1727        DriverLink != DriverInfoList;
   1728        DriverLink = DriverLink->ForwardLink) {
   1729     DriverInfoData = CR (
   1730                        DriverLink,
   1731                        MEMORY_PROFILE_DRIVER_INFO_DATA,
   1732                        Link,
   1733                        MEMORY_PROFILE_DRIVER_INFO_SIGNATURE
   1734                        );
   1735     if (*ProfileOffset < (Offset + DriverInfoData->DriverInfo.Header.Length)) {
   1736       if (RemainingSize >= DriverInfoData->DriverInfo.Header.Length) {
   1737         DriverInfo = ProfileBuffer;
   1738         CopyMem (DriverInfo, &DriverInfoData->DriverInfo, sizeof (MEMORY_PROFILE_DRIVER_INFO));
   1739         if (DriverInfo->PdbStringOffset != 0) {
   1740           PdbSize = AsciiStrSize (DriverInfoData->PdbString);
   1741           CopyMem ((VOID *) ((UINTN) DriverInfo + DriverInfo->PdbStringOffset), DriverInfoData->PdbString, PdbSize);
   1742         }
   1743         RemainingSize -= DriverInfo->Header.Length;
   1744         ProfileBuffer = (UINT8 *) ProfileBuffer + DriverInfo->Header.Length;
   1745       } else {
   1746         goto Done;
   1747       }
   1748     }
   1749     Offset += DriverInfoData->DriverInfo.Header.Length;
   1750 
   1751     AllocInfoList = DriverInfoData->AllocInfoList;
   1752     for (AllocLink = AllocInfoList->ForwardLink;
   1753          AllocLink != AllocInfoList;
   1754          AllocLink = AllocLink->ForwardLink) {
   1755       AllocInfoData = CR (
   1756                         AllocLink,
   1757                         MEMORY_PROFILE_ALLOC_INFO_DATA,
   1758                         Link,
   1759                         MEMORY_PROFILE_ALLOC_INFO_SIGNATURE
   1760                         );
   1761       if (*ProfileOffset < (Offset + AllocInfoData->AllocInfo.Header.Length)) {
   1762         if (RemainingSize >= AllocInfoData->AllocInfo.Header.Length) {
   1763           AllocInfo = ProfileBuffer;
   1764           CopyMem (AllocInfo, &AllocInfoData->AllocInfo, sizeof (MEMORY_PROFILE_ALLOC_INFO));
   1765           if (AllocInfo->ActionStringOffset) {
   1766             ActionStringSize = AsciiStrSize (AllocInfoData->ActionString);
   1767             CopyMem ((VOID *) ((UINTN) AllocInfo + AllocInfo->ActionStringOffset), AllocInfoData->ActionString, ActionStringSize);
   1768           }
   1769           RemainingSize -= AllocInfo->Header.Length;
   1770           ProfileBuffer = (UINT8 *) ProfileBuffer + AllocInfo->Header.Length;
   1771         } else {
   1772           goto Done;
   1773         }
   1774       }
   1775       Offset += AllocInfoData->AllocInfo.Header.Length;
   1776     }
   1777   }
   1778 
   1779 
   1780   if (*ProfileOffset < (Offset + sizeof (MEMORY_PROFILE_FREE_MEMORY))) {
   1781     if (RemainingSize >= sizeof (MEMORY_PROFILE_FREE_MEMORY)) {
   1782       FreeMemory = ProfileBuffer;
   1783       CopyMem (FreeMemory, &mSmramFreeMemory, sizeof (MEMORY_PROFILE_FREE_MEMORY));
   1784       Index = 0;
   1785       FreePageList = &mSmmMemoryMap;
   1786       for (Node = FreePageList->BackLink;
   1787            Node != FreePageList;
   1788            Node = Node->BackLink) {
   1789         Index++;
   1790       }
   1791       for (SmmPoolTypeIndex = 0; SmmPoolTypeIndex < SmmPoolTypeMax; SmmPoolTypeIndex++) {
   1792         for (PoolListIndex = 0; PoolListIndex < MAX_POOL_INDEX; PoolListIndex++) {
   1793           FreePoolList = &mSmmPoolLists[SmmPoolTypeIndex][MAX_POOL_INDEX - PoolListIndex - 1];
   1794           for (Node = FreePoolList->BackLink;
   1795                Node != FreePoolList;
   1796                Node = Node->BackLink) {
   1797             Pool = BASE_CR (Node, FREE_POOL_HEADER, Link);
   1798             if (Pool->Header.Available) {
   1799               Index++;
   1800             }
   1801           }
   1802         }
   1803       }
   1804       FreeMemory->FreeMemoryEntryCount = Index;
   1805 
   1806       RemainingSize -= sizeof (MEMORY_PROFILE_FREE_MEMORY);
   1807       ProfileBuffer = (UINT8 *) ProfileBuffer + sizeof (MEMORY_PROFILE_FREE_MEMORY);
   1808     } else {
   1809       goto Done;
   1810     }
   1811   }
   1812   Offset += sizeof (MEMORY_PROFILE_FREE_MEMORY);
   1813   FreePageList = &mSmmMemoryMap;
   1814   for (Node = FreePageList->BackLink;
   1815        Node != FreePageList;
   1816        Node = Node->BackLink) {
   1817     if (*ProfileOffset < (Offset + sizeof (MEMORY_PROFILE_DESCRIPTOR))) {
   1818       if (RemainingSize >= sizeof (MEMORY_PROFILE_DESCRIPTOR)) {
   1819         Pages = BASE_CR (Node, FREE_PAGE_LIST, Link);
   1820         MemoryProfileDescriptor = ProfileBuffer;
   1821         MemoryProfileDescriptor->Header.Signature = MEMORY_PROFILE_DESCRIPTOR_SIGNATURE;
   1822         MemoryProfileDescriptor->Header.Length = sizeof (MEMORY_PROFILE_DESCRIPTOR);
   1823         MemoryProfileDescriptor->Header.Revision = MEMORY_PROFILE_DESCRIPTOR_REVISION;
   1824         MemoryProfileDescriptor->Address = (PHYSICAL_ADDRESS) (UINTN) Pages;
   1825         MemoryProfileDescriptor->Size = EFI_PAGES_TO_SIZE (Pages->NumberOfPages);
   1826 
   1827         RemainingSize -= sizeof (MEMORY_PROFILE_DESCRIPTOR);
   1828         ProfileBuffer = (UINT8 *) ProfileBuffer + sizeof (MEMORY_PROFILE_DESCRIPTOR);
   1829       } else {
   1830         goto Done;
   1831       }
   1832     }
   1833     Offset += sizeof (MEMORY_PROFILE_DESCRIPTOR);
   1834   }
   1835   for (SmmPoolTypeIndex = 0; SmmPoolTypeIndex < SmmPoolTypeMax; SmmPoolTypeIndex++) {
   1836     for (PoolListIndex = 0; PoolListIndex < MAX_POOL_INDEX; PoolListIndex++) {
   1837       FreePoolList = &mSmmPoolLists[SmmPoolTypeIndex][MAX_POOL_INDEX - PoolListIndex - 1];
   1838       for (Node = FreePoolList->BackLink;
   1839            Node != FreePoolList;
   1840            Node = Node->BackLink) {
   1841         Pool = BASE_CR (Node, FREE_POOL_HEADER, Link);
   1842         if (Pool->Header.Available) {
   1843           if (*ProfileOffset < (Offset + sizeof (MEMORY_PROFILE_DESCRIPTOR))) {
   1844             if (RemainingSize >= sizeof (MEMORY_PROFILE_DESCRIPTOR)) {
   1845               MemoryProfileDescriptor = ProfileBuffer;
   1846               MemoryProfileDescriptor->Header.Signature = MEMORY_PROFILE_DESCRIPTOR_SIGNATURE;
   1847               MemoryProfileDescriptor->Header.Length = sizeof (MEMORY_PROFILE_DESCRIPTOR);
   1848               MemoryProfileDescriptor->Header.Revision = MEMORY_PROFILE_DESCRIPTOR_REVISION;
   1849               MemoryProfileDescriptor->Address = (PHYSICAL_ADDRESS) (UINTN) Pool;
   1850               MemoryProfileDescriptor->Size = Pool->Header.Size;
   1851 
   1852               RemainingSize -= sizeof (MEMORY_PROFILE_DESCRIPTOR);
   1853               ProfileBuffer = (UINT8 *) ProfileBuffer + sizeof (MEMORY_PROFILE_DESCRIPTOR);
   1854             } else {
   1855               goto Done;
   1856             }
   1857           }
   1858           Offset += sizeof (MEMORY_PROFILE_DESCRIPTOR);
   1859         }
   1860       }
   1861     }
   1862   }
   1863 
   1864   if (*ProfileOffset < (Offset + sizeof (MEMORY_PROFILE_MEMORY_RANGE))) {
   1865     if (RemainingSize >= sizeof (MEMORY_PROFILE_MEMORY_RANGE)) {
   1866       MemoryRange = ProfileBuffer;
   1867       MemoryRange->Header.Signature = MEMORY_PROFILE_MEMORY_RANGE_SIGNATURE;
   1868       MemoryRange->Header.Length = sizeof (MEMORY_PROFILE_MEMORY_RANGE);
   1869       MemoryRange->Header.Revision = MEMORY_PROFILE_MEMORY_RANGE_REVISION;
   1870       MemoryRange->MemoryRangeCount = (UINT32) mFullSmramRangeCount;
   1871 
   1872       RemainingSize -= sizeof (MEMORY_PROFILE_MEMORY_RANGE);
   1873       ProfileBuffer = (UINT8 *) ProfileBuffer + sizeof (MEMORY_PROFILE_MEMORY_RANGE);
   1874     } else {
   1875       goto Done;
   1876     }
   1877   }
   1878   Offset += sizeof (MEMORY_PROFILE_MEMORY_RANGE);
   1879   for (Index = 0; Index < mFullSmramRangeCount; Index++) {
   1880     if (*ProfileOffset < (Offset + sizeof (MEMORY_PROFILE_DESCRIPTOR))) {
   1881       if (RemainingSize >= sizeof (MEMORY_PROFILE_DESCRIPTOR)) {
   1882         MemoryProfileDescriptor = ProfileBuffer;
   1883         MemoryProfileDescriptor->Header.Signature = MEMORY_PROFILE_DESCRIPTOR_SIGNATURE;
   1884         MemoryProfileDescriptor->Header.Length = sizeof (MEMORY_PROFILE_DESCRIPTOR);
   1885         MemoryProfileDescriptor->Header.Revision = MEMORY_PROFILE_DESCRIPTOR_REVISION;
   1886         MemoryProfileDescriptor->Address = mFullSmramRanges[Index].PhysicalStart;
   1887         MemoryProfileDescriptor->Size = mFullSmramRanges[Index].PhysicalSize;
   1888 
   1889         RemainingSize -= sizeof (MEMORY_PROFILE_DESCRIPTOR);
   1890         ProfileBuffer = (UINT8 *) ProfileBuffer + sizeof (MEMORY_PROFILE_DESCRIPTOR);
   1891       } else {
   1892         goto Done;
   1893       }
   1894     }
   1895     Offset += sizeof (MEMORY_PROFILE_DESCRIPTOR);
   1896   }
   1897 
   1898 Done:
   1899   //
   1900   // On output, actual profile data size copied.
   1901   //
   1902   *ProfileSize -= RemainingSize;
   1903   //
   1904   // On output, next time profile buffer offset to copy.
   1905   //
   1906   *ProfileOffset = Offset;
   1907 }
   1908 
   1909 /**
   1910   Get memory profile data.
   1911 
   1912   @param[in]      This              The EDKII_SMM_MEMORY_PROFILE_PROTOCOL instance.
   1913   @param[in, out] ProfileSize       On entry, points to the size in bytes of the ProfileBuffer.
   1914                                     On return, points to the size of the data returned in ProfileBuffer.
   1915   @param[out]     ProfileBuffer     Profile buffer.
   1916 
   1917   @return EFI_SUCCESS               Get the memory profile data successfully.
   1918   @return EFI_UNSUPPORTED           Memory profile is unsupported.
   1919   @return EFI_BUFFER_TO_SMALL       The ProfileSize is too small for the resulting data.
   1920                                     ProfileSize is updated with the size required.
   1921 
   1922 **/
   1923 EFI_STATUS
   1924 EFIAPI
   1925 SmramProfileProtocolGetData (
   1926   IN     EDKII_SMM_MEMORY_PROFILE_PROTOCOL  *This,
   1927   IN OUT UINT64                             *ProfileSize,
   1928      OUT VOID                               *ProfileBuffer
   1929   )
   1930 {
   1931   UINT64                                Size;
   1932   UINT64                                Offset;
   1933   MEMORY_PROFILE_CONTEXT_DATA           *ContextData;
   1934   BOOLEAN                               SmramProfileGettingStatus;
   1935 
   1936   ContextData = GetSmramProfileContext ();
   1937   if (ContextData == NULL) {
   1938     return EFI_UNSUPPORTED;
   1939   }
   1940 
   1941   SmramProfileGettingStatus = mSmramProfileGettingStatus;
   1942   mSmramProfileGettingStatus = TRUE;
   1943 
   1944   Size = SmramProfileGetDataSize ();
   1945 
   1946   if (*ProfileSize < Size) {
   1947     *ProfileSize = Size;
   1948     mSmramProfileGettingStatus = SmramProfileGettingStatus;
   1949     return EFI_BUFFER_TOO_SMALL;
   1950   }
   1951 
   1952   Offset = 0;
   1953   SmramProfileCopyData (ProfileBuffer, &Size, &Offset);
   1954   *ProfileSize = Size;
   1955 
   1956   mSmramProfileGettingStatus = SmramProfileGettingStatus;
   1957   return EFI_SUCCESS;
   1958 }
   1959 
   1960 /**
   1961   Register image to memory profile.
   1962 
   1963   @param[in] This               The EDKII_SMM_MEMORY_PROFILE_PROTOCOL instance.
   1964   @param[in] FilePath           File path of the image.
   1965   @param[in] ImageBase          Image base address.
   1966   @param[in] ImageSize          Image size.
   1967   @param[in] FileType           File type of the image.
   1968 
   1969   @return EFI_SUCCESS           Register successfully.
   1970   @return EFI_UNSUPPORTED       Memory profile is unsupported,
   1971                                 or memory profile for the image is not required.
   1972   @return EFI_OUT_OF_RESOURCES  No enough resource for this register.
   1973 
   1974 **/
   1975 EFI_STATUS
   1976 EFIAPI
   1977 SmramProfileProtocolRegisterImage (
   1978   IN EDKII_SMM_MEMORY_PROFILE_PROTOCOL  *This,
   1979   IN EFI_DEVICE_PATH_PROTOCOL           *FilePath,
   1980   IN PHYSICAL_ADDRESS                   ImageBase,
   1981   IN UINT64                             ImageSize,
   1982   IN EFI_FV_FILETYPE                    FileType
   1983   )
   1984 {
   1985   EFI_STATUS                        Status;
   1986   EFI_SMM_DRIVER_ENTRY              DriverEntry;
   1987   VOID                              *EntryPointInImage;
   1988   EFI_GUID                          *Name;
   1989 
   1990   ZeroMem (&DriverEntry, sizeof (DriverEntry));
   1991   Name = GetFileNameFromFilePath (FilePath);
   1992   if (Name != NULL) {
   1993     CopyMem (&DriverEntry.FileName, Name, sizeof (EFI_GUID));
   1994   }
   1995   DriverEntry.ImageBuffer = ImageBase;
   1996   DriverEntry.NumberOfPage = EFI_SIZE_TO_PAGES ((UINTN) ImageSize);
   1997   Status = InternalPeCoffGetEntryPoint ((VOID *) (UINTN) DriverEntry.ImageBuffer, &EntryPointInImage);
   1998   ASSERT_EFI_ERROR (Status);
   1999   DriverEntry.ImageEntryPoint = (PHYSICAL_ADDRESS) (UINTN) EntryPointInImage;
   2000 
   2001   return RegisterSmramProfileImage (&DriverEntry, FALSE);
   2002 }
   2003 
   2004 /**
   2005   Unregister image from memory profile.
   2006 
   2007   @param[in] This               The EDKII_SMM_MEMORY_PROFILE_PROTOCOL instance.
   2008   @param[in] FilePath           File path of the image.
   2009   @param[in] ImageBase          Image base address.
   2010   @param[in] ImageSize          Image size.
   2011 
   2012   @return EFI_SUCCESS           Unregister successfully.
   2013   @return EFI_UNSUPPORTED       Memory profile is unsupported,
   2014                                 or memory profile for the image is not required.
   2015   @return EFI_NOT_FOUND         The image is not found.
   2016 
   2017 **/
   2018 EFI_STATUS
   2019 EFIAPI
   2020 SmramProfileProtocolUnregisterImage (
   2021   IN EDKII_SMM_MEMORY_PROFILE_PROTOCOL  *This,
   2022   IN EFI_DEVICE_PATH_PROTOCOL           *FilePath,
   2023   IN PHYSICAL_ADDRESS                   ImageBase,
   2024   IN UINT64                             ImageSize
   2025   )
   2026 {
   2027   EFI_STATUS                        Status;
   2028   EFI_SMM_DRIVER_ENTRY              DriverEntry;
   2029   VOID                              *EntryPointInImage;
   2030   EFI_GUID                          *Name;
   2031 
   2032   ZeroMem (&DriverEntry, sizeof (DriverEntry));
   2033   Name = GetFileNameFromFilePath (FilePath);
   2034   if (Name != NULL) {
   2035     CopyMem (&DriverEntry.FileName, Name, sizeof (EFI_GUID));
   2036   }
   2037   DriverEntry.ImageBuffer = ImageBase;
   2038   DriverEntry.NumberOfPage = EFI_SIZE_TO_PAGES ((UINTN) ImageSize);
   2039   Status = InternalPeCoffGetEntryPoint ((VOID *) (UINTN) DriverEntry.ImageBuffer, &EntryPointInImage);
   2040   ASSERT_EFI_ERROR (Status);
   2041   DriverEntry.ImageEntryPoint = (PHYSICAL_ADDRESS) (UINTN) EntryPointInImage;
   2042 
   2043   return UnregisterSmramProfileImage (&DriverEntry, FALSE);
   2044 }
   2045 
   2046 /**
   2047   Get memory profile recording state.
   2048 
   2049   @param[in]  This              The EDKII_SMM_MEMORY_PROFILE_PROTOCOL instance.
   2050   @param[out] RecordingState    Recording state.
   2051 
   2052   @return EFI_SUCCESS           Memory profile recording state is returned.
   2053   @return EFI_UNSUPPORTED       Memory profile is unsupported.
   2054   @return EFI_INVALID_PARAMETER RecordingState is NULL.
   2055 
   2056 **/
   2057 EFI_STATUS
   2058 EFIAPI
   2059 SmramProfileProtocolGetRecordingState (
   2060   IN EDKII_SMM_MEMORY_PROFILE_PROTOCOL  *This,
   2061   OUT BOOLEAN                           *RecordingState
   2062   )
   2063 {
   2064   MEMORY_PROFILE_CONTEXT_DATA           *ContextData;
   2065 
   2066   ContextData = GetSmramProfileContext ();
   2067   if (ContextData == NULL) {
   2068     return EFI_UNSUPPORTED;
   2069   }
   2070 
   2071   if (RecordingState == NULL) {
   2072     return EFI_INVALID_PARAMETER;
   2073   }
   2074   *RecordingState = mSmramProfileRecordingEnable;
   2075   return EFI_SUCCESS;
   2076 }
   2077 
   2078 /**
   2079   Set memory profile recording state.
   2080 
   2081   @param[in] This               The EDKII_SMM_MEMORY_PROFILE_PROTOCOL instance.
   2082   @param[in] RecordingState     Recording state.
   2083 
   2084   @return EFI_SUCCESS           Set memory profile recording state successfully.
   2085   @return EFI_UNSUPPORTED       Memory profile is unsupported.
   2086 
   2087 **/
   2088 EFI_STATUS
   2089 EFIAPI
   2090 SmramProfileProtocolSetRecordingState (
   2091   IN EDKII_SMM_MEMORY_PROFILE_PROTOCOL  *This,
   2092   IN BOOLEAN                            RecordingState
   2093   )
   2094 {
   2095   MEMORY_PROFILE_CONTEXT_DATA           *ContextData;
   2096 
   2097   ContextData = GetSmramProfileContext ();
   2098   if (ContextData == NULL) {
   2099     return EFI_UNSUPPORTED;
   2100   }
   2101 
   2102   mSmramProfileRecordingEnable = RecordingState;
   2103   return EFI_SUCCESS;
   2104 }
   2105 
   2106 /**
   2107   Record memory profile of multilevel caller.
   2108 
   2109   @param[in] This               The EDKII_SMM_MEMORY_PROFILE_PROTOCOL instance.
   2110   @param[in] CallerAddress      Address of caller.
   2111   @param[in] Action             Memory profile action.
   2112   @param[in] MemoryType         Memory type.
   2113                                 EfiMaxMemoryType means the MemoryType is unknown.
   2114   @param[in] Buffer             Buffer address.
   2115   @param[in] Size               Buffer size.
   2116   @param[in] ActionString       String for memory profile action.
   2117                                 Only needed for user defined allocate action.
   2118 
   2119   @return EFI_SUCCESS           Memory profile is updated.
   2120   @return EFI_UNSUPPORTED       Memory profile is unsupported,
   2121                                 or memory profile for the image is not required,
   2122                                 or memory profile for the memory type is not required.
   2123   @return EFI_ACCESS_DENIED     It is during memory profile data getting.
   2124   @return EFI_ABORTED           Memory profile recording is not enabled.
   2125   @return EFI_OUT_OF_RESOURCES  No enough resource to update memory profile for allocate action.
   2126   @return EFI_NOT_FOUND         No matched allocate info found for free action.
   2127 
   2128 **/
   2129 EFI_STATUS
   2130 EFIAPI
   2131 SmramProfileProtocolRecord (
   2132   IN EDKII_SMM_MEMORY_PROFILE_PROTOCOL  *This,
   2133   IN PHYSICAL_ADDRESS                   CallerAddress,
   2134   IN MEMORY_PROFILE_ACTION              Action,
   2135   IN EFI_MEMORY_TYPE                    MemoryType,
   2136   IN VOID                               *Buffer,
   2137   IN UINTN                              Size,
   2138   IN CHAR8                              *ActionString OPTIONAL
   2139   )
   2140 {
   2141   return SmmCoreUpdateProfile (CallerAddress, Action, MemoryType, Size, Buffer, ActionString);
   2142 }
   2143 
   2144 /**
   2145   SMRAM profile handler to get profile info.
   2146 
   2147   @param SmramProfileParameterGetInfo The parameter of SMM profile get size.
   2148 
   2149 **/
   2150 VOID
   2151 SmramProfileHandlerGetInfo (
   2152   IN SMRAM_PROFILE_PARAMETER_GET_PROFILE_INFO   *SmramProfileParameterGetInfo
   2153   )
   2154 {
   2155   MEMORY_PROFILE_CONTEXT_DATA   *ContextData;
   2156   BOOLEAN                       SmramProfileGettingStatus;
   2157 
   2158   ContextData = GetSmramProfileContext ();
   2159   if (ContextData == NULL) {
   2160     return ;
   2161   }
   2162 
   2163   SmramProfileGettingStatus = mSmramProfileGettingStatus;
   2164   mSmramProfileGettingStatus = TRUE;
   2165 
   2166   SmramProfileParameterGetInfo->ProfileSize = SmramProfileGetDataSize();
   2167   SmramProfileParameterGetInfo->Header.ReturnStatus = 0;
   2168 
   2169   mSmramProfileGettingStatus = SmramProfileGettingStatus;
   2170 }
   2171 
   2172 /**
   2173   SMRAM profile handler to get profile data.
   2174 
   2175   @param SmramProfileParameterGetData The parameter of SMM profile get data.
   2176 
   2177 **/
   2178 VOID
   2179 SmramProfileHandlerGetData (
   2180   IN SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA   *SmramProfileParameterGetData
   2181   )
   2182 {
   2183   UINT64                                    ProfileSize;
   2184   UINT64                                    ProfileOffset;
   2185   SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA  SmramProfileGetData;
   2186   MEMORY_PROFILE_CONTEXT_DATA               *ContextData;
   2187   BOOLEAN                                   SmramProfileGettingStatus;
   2188 
   2189   ContextData = GetSmramProfileContext ();
   2190   if (ContextData == NULL) {
   2191     return ;
   2192   }
   2193 
   2194   SmramProfileGettingStatus = mSmramProfileGettingStatus;
   2195   mSmramProfileGettingStatus = TRUE;
   2196 
   2197 
   2198   CopyMem (&SmramProfileGetData, SmramProfileParameterGetData, sizeof (SmramProfileGetData));
   2199 
   2200   ProfileSize = SmramProfileGetDataSize();
   2201 
   2202   //
   2203   // Sanity check
   2204   //
   2205   if (!SmmIsBufferOutsideSmmValid ((UINTN) SmramProfileGetData.ProfileBuffer, (UINTN) ProfileSize)) {
   2206     DEBUG ((EFI_D_ERROR, "SmramProfileHandlerGetData: SMM ProfileBuffer in SMRAM or overflow!\n"));
   2207     SmramProfileParameterGetData->ProfileSize = ProfileSize;
   2208     SmramProfileParameterGetData->Header.ReturnStatus = (UINT64) (INT64) (INTN) EFI_ACCESS_DENIED;
   2209     goto Done;
   2210   }
   2211 
   2212   if (SmramProfileGetData.ProfileSize < ProfileSize) {
   2213     SmramProfileParameterGetData->ProfileSize = ProfileSize;
   2214     SmramProfileParameterGetData->Header.ReturnStatus = (UINT64) (INT64) (INTN) EFI_BUFFER_TOO_SMALL;
   2215     goto Done;
   2216   }
   2217 
   2218   ProfileOffset = 0;
   2219   SmramProfileCopyData ((VOID *) (UINTN) SmramProfileGetData.ProfileBuffer, &ProfileSize, &ProfileOffset);
   2220   SmramProfileParameterGetData->ProfileSize = ProfileSize;
   2221   SmramProfileParameterGetData->Header.ReturnStatus = 0;
   2222 
   2223 Done:
   2224   mSmramProfileGettingStatus = SmramProfileGettingStatus;
   2225 }
   2226 
   2227 /**
   2228   SMRAM profile handler to get profile data by offset.
   2229 
   2230   @param SmramProfileParameterGetDataByOffset   The parameter of SMM profile get data by offset.
   2231 
   2232 **/
   2233 VOID
   2234 SmramProfileHandlerGetDataByOffset (
   2235   IN SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA_BY_OFFSET     *SmramProfileParameterGetDataByOffset
   2236   )
   2237 {
   2238   SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA_BY_OFFSET    SmramProfileGetDataByOffset;
   2239   MEMORY_PROFILE_CONTEXT_DATA                           *ContextData;
   2240   BOOLEAN                                               SmramProfileGettingStatus;
   2241 
   2242   ContextData = GetSmramProfileContext ();
   2243   if (ContextData == NULL) {
   2244     return ;
   2245   }
   2246 
   2247   SmramProfileGettingStatus = mSmramProfileGettingStatus;
   2248   mSmramProfileGettingStatus = TRUE;
   2249 
   2250 
   2251   CopyMem (&SmramProfileGetDataByOffset, SmramProfileParameterGetDataByOffset, sizeof (SmramProfileGetDataByOffset));
   2252 
   2253   //
   2254   // Sanity check
   2255   //
   2256   if (!SmmIsBufferOutsideSmmValid ((UINTN) SmramProfileGetDataByOffset.ProfileBuffer, (UINTN) SmramProfileGetDataByOffset.ProfileSize)) {
   2257     DEBUG ((EFI_D_ERROR, "SmramProfileHandlerGetDataByOffset: SMM ProfileBuffer in SMRAM or overflow!\n"));
   2258     SmramProfileParameterGetDataByOffset->Header.ReturnStatus = (UINT64) (INT64) (INTN) EFI_ACCESS_DENIED;
   2259     goto Done;
   2260   }
   2261 
   2262   SmramProfileCopyData ((VOID *) (UINTN) SmramProfileGetDataByOffset.ProfileBuffer, &SmramProfileGetDataByOffset.ProfileSize, &SmramProfileGetDataByOffset.ProfileOffset);
   2263   CopyMem (SmramProfileParameterGetDataByOffset, &SmramProfileGetDataByOffset, sizeof (SmramProfileGetDataByOffset));
   2264   SmramProfileParameterGetDataByOffset->Header.ReturnStatus = 0;
   2265 
   2266 Done:
   2267   mSmramProfileGettingStatus = SmramProfileGettingStatus;
   2268 }
   2269 
   2270 /**
   2271   SMRAM profile handler to register SMM image.
   2272 
   2273   @param SmramProfileParameterRegisterImage The parameter of SMM profile register image.
   2274 
   2275 **/
   2276 VOID
   2277 SmramProfileHandlerRegisterImage (
   2278   IN SMRAM_PROFILE_PARAMETER_REGISTER_IMAGE *SmramProfileParameterRegisterImage
   2279   )
   2280 {
   2281   EFI_STATUS                        Status;
   2282   EFI_SMM_DRIVER_ENTRY              DriverEntry;
   2283   VOID                              *EntryPointInImage;
   2284 
   2285   ZeroMem (&DriverEntry, sizeof (DriverEntry));
   2286   CopyMem (&DriverEntry.FileName, &SmramProfileParameterRegisterImage->FileName, sizeof(EFI_GUID));
   2287   DriverEntry.ImageBuffer = SmramProfileParameterRegisterImage->ImageBuffer;
   2288   DriverEntry.NumberOfPage = (UINTN) SmramProfileParameterRegisterImage->NumberOfPage;
   2289   Status = InternalPeCoffGetEntryPoint ((VOID *) (UINTN) DriverEntry.ImageBuffer, &EntryPointInImage);
   2290   ASSERT_EFI_ERROR (Status);
   2291   DriverEntry.ImageEntryPoint = (PHYSICAL_ADDRESS) (UINTN) EntryPointInImage;
   2292 
   2293   Status = RegisterSmramProfileImage (&DriverEntry, FALSE);
   2294   if (!EFI_ERROR (Status)) {
   2295     SmramProfileParameterRegisterImage->Header.ReturnStatus = 0;
   2296   }
   2297 }
   2298 
   2299 /**
   2300   SMRAM profile handler to unregister SMM image.
   2301 
   2302   @param SmramProfileParameterUnregisterImage The parameter of SMM profile unregister image.
   2303 
   2304 **/
   2305 VOID
   2306 SmramProfileHandlerUnregisterImage (
   2307   IN SMRAM_PROFILE_PARAMETER_UNREGISTER_IMAGE *SmramProfileParameterUnregisterImage
   2308   )
   2309 {
   2310   EFI_STATUS                        Status;
   2311   EFI_SMM_DRIVER_ENTRY              DriverEntry;
   2312   VOID                              *EntryPointInImage;
   2313 
   2314   ZeroMem (&DriverEntry, sizeof (DriverEntry));
   2315   CopyMem (&DriverEntry.FileName, &SmramProfileParameterUnregisterImage->FileName, sizeof (EFI_GUID));
   2316   DriverEntry.ImageBuffer = SmramProfileParameterUnregisterImage->ImageBuffer;
   2317   DriverEntry.NumberOfPage = (UINTN) SmramProfileParameterUnregisterImage->NumberOfPage;
   2318   Status = InternalPeCoffGetEntryPoint ((VOID *) (UINTN) DriverEntry.ImageBuffer, &EntryPointInImage);
   2319   ASSERT_EFI_ERROR (Status);
   2320   DriverEntry.ImageEntryPoint = (PHYSICAL_ADDRESS) (UINTN) EntryPointInImage;
   2321 
   2322   Status = UnregisterSmramProfileImage (&DriverEntry, FALSE);
   2323   if (!EFI_ERROR (Status)) {
   2324     SmramProfileParameterUnregisterImage->Header.ReturnStatus = 0;
   2325   }
   2326 }
   2327 
   2328 /**
   2329   Dispatch function for a Software SMI handler.
   2330 
   2331   Caution: This function may receive untrusted input.
   2332   Communicate buffer and buffer size are external input, so this function will do basic validation.
   2333 
   2334   @param DispatchHandle  The unique handle assigned to this handler by SmiHandlerRegister().
   2335   @param Context         Points to an optional handler context which was specified when the
   2336                          handler was registered.
   2337   @param CommBuffer      A pointer to a collection of data in memory that will
   2338                          be conveyed from a non-SMM environment into an SMM environment.
   2339   @param CommBufferSize  The size of the CommBuffer.
   2340 
   2341   @retval EFI_SUCCESS Command is handled successfully.
   2342 
   2343 **/
   2344 EFI_STATUS
   2345 EFIAPI
   2346 SmramProfileHandler (
   2347   IN EFI_HANDLE  DispatchHandle,
   2348   IN CONST VOID  *Context         OPTIONAL,
   2349   IN OUT VOID    *CommBuffer      OPTIONAL,
   2350   IN OUT UINTN   *CommBufferSize  OPTIONAL
   2351   )
   2352 {
   2353   SMRAM_PROFILE_PARAMETER_HEADER           *SmramProfileParameterHeader;
   2354   UINTN                                    TempCommBufferSize;
   2355   SMRAM_PROFILE_PARAMETER_RECORDING_STATE  *ParameterRecordingState;
   2356 
   2357   DEBUG ((EFI_D_ERROR, "SmramProfileHandler Enter\n"));
   2358 
   2359   //
   2360   // If input is invalid, stop processing this SMI
   2361   //
   2362   if (CommBuffer == NULL || CommBufferSize == NULL) {
   2363     return EFI_SUCCESS;
   2364   }
   2365 
   2366   TempCommBufferSize = *CommBufferSize;
   2367 
   2368   if (TempCommBufferSize < sizeof (SMRAM_PROFILE_PARAMETER_HEADER)) {
   2369     DEBUG ((EFI_D_ERROR, "SmramProfileHandler: SMM communication buffer size invalid!\n"));
   2370     return EFI_SUCCESS;
   2371   }
   2372 
   2373   if (mSmramReadyToLock && !SmmIsBufferOutsideSmmValid ((UINTN)CommBuffer, TempCommBufferSize)) {
   2374     DEBUG ((EFI_D_ERROR, "SmramProfileHandler: SMM communication buffer in SMRAM or overflow!\n"));
   2375     return EFI_SUCCESS;
   2376   }
   2377 
   2378   SmramProfileParameterHeader = (SMRAM_PROFILE_PARAMETER_HEADER *) ((UINTN) CommBuffer);
   2379 
   2380   SmramProfileParameterHeader->ReturnStatus = (UINT64)-1;
   2381 
   2382   if (GetSmramProfileContext () == NULL) {
   2383     SmramProfileParameterHeader->ReturnStatus = (UINT64) (INT64) (INTN) EFI_UNSUPPORTED;
   2384     return EFI_SUCCESS;
   2385   }
   2386 
   2387   switch (SmramProfileParameterHeader->Command) {
   2388   case SMRAM_PROFILE_COMMAND_GET_PROFILE_INFO:
   2389     DEBUG ((EFI_D_ERROR, "SmramProfileHandlerGetInfo\n"));
   2390     if (TempCommBufferSize != sizeof (SMRAM_PROFILE_PARAMETER_GET_PROFILE_INFO)) {
   2391       DEBUG ((EFI_D_ERROR, "SmramProfileHandler: SMM communication buffer size invalid!\n"));
   2392       return EFI_SUCCESS;
   2393     }
   2394     SmramProfileHandlerGetInfo ((SMRAM_PROFILE_PARAMETER_GET_PROFILE_INFO *) (UINTN) CommBuffer);
   2395     break;
   2396   case SMRAM_PROFILE_COMMAND_GET_PROFILE_DATA:
   2397     DEBUG ((EFI_D_ERROR, "SmramProfileHandlerGetData\n"));
   2398     if (TempCommBufferSize != sizeof (SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA)) {
   2399       DEBUG ((EFI_D_ERROR, "SmramProfileHandler: SMM communication buffer size invalid!\n"));
   2400       return EFI_SUCCESS;
   2401     }
   2402     SmramProfileHandlerGetData ((SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA *) (UINTN) CommBuffer);
   2403     break;
   2404   case SMRAM_PROFILE_COMMAND_GET_PROFILE_DATA_BY_OFFSET:
   2405     DEBUG ((EFI_D_ERROR, "SmramProfileHandlerGetDataByOffset\n"));
   2406     if (TempCommBufferSize != sizeof (SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA_BY_OFFSET)) {
   2407       DEBUG ((EFI_D_ERROR, "SmramProfileHandler: SMM communication buffer size invalid!\n"));
   2408       return EFI_SUCCESS;
   2409     }
   2410     SmramProfileHandlerGetDataByOffset ((SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA_BY_OFFSET *) (UINTN) CommBuffer);
   2411     break;
   2412   case SMRAM_PROFILE_COMMAND_REGISTER_IMAGE:
   2413     DEBUG ((EFI_D_ERROR, "SmramProfileHandlerRegisterImage\n"));
   2414     if (TempCommBufferSize != sizeof (SMRAM_PROFILE_PARAMETER_REGISTER_IMAGE)) {
   2415       DEBUG ((EFI_D_ERROR, "SmramProfileHandler: SMM communication buffer size invalid!\n"));
   2416       return EFI_SUCCESS;
   2417     }
   2418     if (mSmramReadyToLock) {
   2419       return EFI_SUCCESS;
   2420     }
   2421     SmramProfileHandlerRegisterImage ((SMRAM_PROFILE_PARAMETER_REGISTER_IMAGE *) (UINTN) CommBuffer);
   2422     break;
   2423   case SMRAM_PROFILE_COMMAND_UNREGISTER_IMAGE:
   2424     DEBUG ((EFI_D_ERROR, "SmramProfileHandlerUnregisterImage\n"));
   2425     if (TempCommBufferSize != sizeof (SMRAM_PROFILE_PARAMETER_UNREGISTER_IMAGE)) {
   2426       DEBUG ((EFI_D_ERROR, "SmramProfileHandler: SMM communication buffer size invalid!\n"));
   2427       return EFI_SUCCESS;
   2428     }
   2429     if (mSmramReadyToLock) {
   2430       return EFI_SUCCESS;
   2431     }
   2432     SmramProfileHandlerUnregisterImage ((SMRAM_PROFILE_PARAMETER_UNREGISTER_IMAGE *) (UINTN) CommBuffer);
   2433     break;
   2434   case SMRAM_PROFILE_COMMAND_GET_RECORDING_STATE:
   2435     DEBUG ((EFI_D_ERROR, "SmramProfileHandlerGetRecordingState\n"));
   2436     if (TempCommBufferSize != sizeof (SMRAM_PROFILE_PARAMETER_RECORDING_STATE)) {
   2437       DEBUG ((EFI_D_ERROR, "SmramProfileHandler: SMM communication buffer size invalid!\n"));
   2438       return EFI_SUCCESS;
   2439     }
   2440     ParameterRecordingState = (SMRAM_PROFILE_PARAMETER_RECORDING_STATE *) (UINTN) CommBuffer;
   2441     ParameterRecordingState->RecordingState = mSmramProfileRecordingEnable;
   2442     ParameterRecordingState->Header.ReturnStatus = 0;
   2443     break;
   2444   case SMRAM_PROFILE_COMMAND_SET_RECORDING_STATE:
   2445     DEBUG ((EFI_D_ERROR, "SmramProfileHandlerSetRecordingState\n"));
   2446     if (TempCommBufferSize != sizeof (SMRAM_PROFILE_PARAMETER_RECORDING_STATE)) {
   2447       DEBUG ((EFI_D_ERROR, "SmramProfileHandler: SMM communication buffer size invalid!\n"));
   2448       return EFI_SUCCESS;
   2449     }
   2450     ParameterRecordingState = (SMRAM_PROFILE_PARAMETER_RECORDING_STATE *) (UINTN) CommBuffer;
   2451     mSmramProfileRecordingEnable = ParameterRecordingState->RecordingState;
   2452     ParameterRecordingState->Header.ReturnStatus = 0;
   2453     break;
   2454 
   2455   default:
   2456     break;
   2457   }
   2458 
   2459   DEBUG ((EFI_D_ERROR, "SmramProfileHandler Exit\n"));
   2460 
   2461   return EFI_SUCCESS;
   2462 }
   2463 
   2464 /**
   2465   Register SMRAM profile handler.
   2466 
   2467 **/
   2468 VOID
   2469 RegisterSmramProfileHandler (
   2470   VOID
   2471   )
   2472 {
   2473   EFI_STATUS    Status;
   2474   EFI_HANDLE    DispatchHandle;
   2475 
   2476   if (!IS_SMRAM_PROFILE_ENABLED) {
   2477     return;
   2478   }
   2479 
   2480   Status = SmiHandlerRegister (
   2481              SmramProfileHandler,
   2482              &gEdkiiMemoryProfileGuid,
   2483              &DispatchHandle
   2484              );
   2485   ASSERT_EFI_ERROR (Status);
   2486 }
   2487 
   2488 ////////////////////
   2489 
   2490 /**
   2491   Dump SMRAM range.
   2492 
   2493 **/
   2494 VOID
   2495 DumpSmramRange (
   2496   VOID
   2497   )
   2498 {
   2499   UINTN                         Index;
   2500   MEMORY_PROFILE_CONTEXT_DATA   *ContextData;
   2501   BOOLEAN                       SmramProfileGettingStatus;
   2502 
   2503   ContextData = GetSmramProfileContext ();
   2504   if (ContextData == NULL) {
   2505     return ;
   2506   }
   2507 
   2508   SmramProfileGettingStatus = mSmramProfileGettingStatus;
   2509   mSmramProfileGettingStatus = TRUE;
   2510 
   2511   DEBUG ((EFI_D_INFO, "FullSmramRange address - 0x%08x\n", mFullSmramRanges));
   2512 
   2513   DEBUG ((EFI_D_INFO, "======= SmramProfile begin =======\n"));
   2514 
   2515   DEBUG ((EFI_D_INFO, "FullSmramRange:\n"));
   2516   for (Index = 0; Index < mFullSmramRangeCount; Index++) {
   2517     DEBUG ((EFI_D_INFO, "  FullSmramRange (0x%x)\n", Index));
   2518     DEBUG ((EFI_D_INFO, "    PhysicalStart      - 0x%016lx\n", mFullSmramRanges[Index].PhysicalStart));
   2519     DEBUG ((EFI_D_INFO, "    CpuStart           - 0x%016lx\n", mFullSmramRanges[Index].CpuStart));
   2520     DEBUG ((EFI_D_INFO, "    PhysicalSize       - 0x%016lx\n", mFullSmramRanges[Index].PhysicalSize));
   2521     DEBUG ((EFI_D_INFO, "    RegionState        - 0x%016lx\n", mFullSmramRanges[Index].RegionState));
   2522   }
   2523 
   2524   DEBUG ((EFI_D_INFO, "======= SmramProfile end =======\n"));
   2525 
   2526   mSmramProfileGettingStatus = SmramProfileGettingStatus;
   2527 }
   2528 
   2529 /**
   2530   Dump SMRAM free page list.
   2531 
   2532 **/
   2533 VOID
   2534 DumpFreePagesList (
   2535   VOID
   2536   )
   2537 {
   2538   LIST_ENTRY                    *FreePageList;
   2539   LIST_ENTRY                    *Node;
   2540   FREE_PAGE_LIST                *Pages;
   2541   UINTN                         Index;
   2542   MEMORY_PROFILE_CONTEXT_DATA   *ContextData;
   2543   BOOLEAN                       SmramProfileGettingStatus;
   2544 
   2545   ContextData = GetSmramProfileContext ();
   2546   if (ContextData == NULL) {
   2547     return ;
   2548   }
   2549 
   2550   SmramProfileGettingStatus = mSmramProfileGettingStatus;
   2551   mSmramProfileGettingStatus = TRUE;
   2552 
   2553   DEBUG ((EFI_D_INFO, "======= SmramProfile begin =======\n"));
   2554 
   2555   DEBUG ((EFI_D_INFO, "FreePagesList:\n"));
   2556   FreePageList = &mSmmMemoryMap;
   2557   for (Node = FreePageList->BackLink, Index = 0;
   2558        Node != FreePageList;
   2559        Node = Node->BackLink, Index++) {
   2560     Pages = BASE_CR (Node, FREE_PAGE_LIST, Link);
   2561     DEBUG ((EFI_D_INFO, "  Index - 0x%x\n", Index));
   2562     DEBUG ((EFI_D_INFO, "    PhysicalStart - 0x%016lx\n", (PHYSICAL_ADDRESS) (UINTN) Pages));
   2563     DEBUG ((EFI_D_INFO, "    NumberOfPages - 0x%08x\n", Pages->NumberOfPages));
   2564   }
   2565 
   2566   DEBUG ((EFI_D_INFO, "======= SmramProfile end =======\n"));
   2567 
   2568   mSmramProfileGettingStatus = SmramProfileGettingStatus;
   2569 }
   2570 
   2571 /**
   2572   Dump SMRAM free pool list.
   2573 
   2574 **/
   2575 VOID
   2576 DumpFreePoolList (
   2577   VOID
   2578   )
   2579 {
   2580   LIST_ENTRY                    *FreePoolList;
   2581   LIST_ENTRY                    *Node;
   2582   FREE_POOL_HEADER              *Pool;
   2583   UINTN                         Index;
   2584   UINTN                         PoolListIndex;
   2585   MEMORY_PROFILE_CONTEXT_DATA   *ContextData;
   2586   BOOLEAN                       SmramProfileGettingStatus;
   2587   UINTN                         SmmPoolTypeIndex;
   2588 
   2589   ContextData = GetSmramProfileContext ();
   2590   if (ContextData == NULL) {
   2591     return ;
   2592   }
   2593 
   2594   SmramProfileGettingStatus = mSmramProfileGettingStatus;
   2595   mSmramProfileGettingStatus = TRUE;
   2596 
   2597   DEBUG ((DEBUG_INFO, "======= SmramProfile begin =======\n"));
   2598 
   2599   for (SmmPoolTypeIndex = 0; SmmPoolTypeIndex < SmmPoolTypeMax; SmmPoolTypeIndex++) {
   2600     for (PoolListIndex = 0; PoolListIndex < MAX_POOL_INDEX; PoolListIndex++) {
   2601       DEBUG ((DEBUG_INFO, "FreePoolList(%d)(%d):\n", SmmPoolTypeIndex, PoolListIndex));
   2602       FreePoolList = &mSmmPoolLists[SmmPoolTypeIndex][PoolListIndex];
   2603       for (Node = FreePoolList->BackLink, Index = 0;
   2604            Node != FreePoolList;
   2605            Node = Node->BackLink, Index++) {
   2606         Pool = BASE_CR (Node, FREE_POOL_HEADER, Link);
   2607         DEBUG ((DEBUG_INFO, "  Index - 0x%x\n", Index));
   2608         DEBUG ((DEBUG_INFO, "    PhysicalStart - 0x%016lx\n", (PHYSICAL_ADDRESS) (UINTN) Pool));
   2609         DEBUG ((DEBUG_INFO, "    Size          - 0x%08x\n", Pool->Header.Size));
   2610         DEBUG ((DEBUG_INFO, "    Available     - 0x%02x\n", Pool->Header.Available));
   2611       }
   2612     }
   2613   }
   2614 
   2615   DEBUG ((DEBUG_INFO, "======= SmramProfile end =======\n"));
   2616 
   2617   mSmramProfileGettingStatus = SmramProfileGettingStatus;
   2618 }
   2619 
   2620 GLOBAL_REMOVE_IF_UNREFERENCED CHAR8 *mSmmActionString[] = {
   2621   "SmmUnknown",
   2622   "gSmst->SmmAllocatePages",
   2623   "gSmst->SmmFreePages",
   2624   "gSmst->SmmAllocatePool",
   2625   "gSmst->SmmFreePool",
   2626 };
   2627 
   2628 typedef struct {
   2629   MEMORY_PROFILE_ACTION  Action;
   2630   CHAR8                 *String;
   2631 } ACTION_STRING;
   2632 
   2633 ACTION_STRING mExtActionString[] = {
   2634   {MEMORY_PROFILE_ACTION_LIB_ALLOCATE_PAGES,                    "Lib:AllocatePages"},
   2635   {MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RUNTIME_PAGES,            "Lib:AllocateRuntimePages"},
   2636   {MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RESERVED_PAGES,           "Lib:AllocateReservedPages"},
   2637   {MEMORY_PROFILE_ACTION_LIB_FREE_PAGES,                        "Lib:FreePages"},
   2638   {MEMORY_PROFILE_ACTION_LIB_ALLOCATE_ALIGNED_PAGES,            "Lib:AllocateAlignedPages"},
   2639   {MEMORY_PROFILE_ACTION_LIB_ALLOCATE_ALIGNED_RUNTIME_PAGES,    "Lib:AllocateAlignedRuntimePages"},
   2640   {MEMORY_PROFILE_ACTION_LIB_ALLOCATE_ALIGNED_RESERVED_PAGES,   "Lib:AllocateAlignedReservedPages"},
   2641   {MEMORY_PROFILE_ACTION_LIB_FREE_ALIGNED_PAGES,                "Lib:FreeAlignedPages"},
   2642   {MEMORY_PROFILE_ACTION_LIB_ALLOCATE_POOL,                     "Lib:AllocatePool"},
   2643   {MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RUNTIME_POOL,             "Lib:AllocateRuntimePool"},
   2644   {MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RESERVED_POOL,            "Lib:AllocateReservedPool"},
   2645   {MEMORY_PROFILE_ACTION_LIB_FREE_POOL,                         "Lib:FreePool"},
   2646   {MEMORY_PROFILE_ACTION_LIB_ALLOCATE_ZERO_POOL,                "Lib:AllocateZeroPool"},
   2647   {MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RUNTIME_ZERO_POOL,        "Lib:AllocateRuntimeZeroPool"},
   2648   {MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RESERVED_ZERO_POOL,       "Lib:AllocateReservedZeroPool"},
   2649   {MEMORY_PROFILE_ACTION_LIB_ALLOCATE_COPY_POOL,                "Lib:AllocateCopyPool"},
   2650   {MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RUNTIME_COPY_POOL,        "Lib:AllocateRuntimeCopyPool"},
   2651   {MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RESERVED_COPY_POOL,       "Lib:AllocateReservedCopyPool"},
   2652   {MEMORY_PROFILE_ACTION_LIB_REALLOCATE_POOL,                   "Lib:ReallocatePool"},
   2653   {MEMORY_PROFILE_ACTION_LIB_REALLOCATE_RUNTIME_POOL,           "Lib:ReallocateRuntimePool"},
   2654   {MEMORY_PROFILE_ACTION_LIB_REALLOCATE_RESERVED_POOL,          "Lib:ReallocateReservedPool"},
   2655 };
   2656 
   2657 GLOBAL_REMOVE_IF_UNREFERENCED CHAR8 mUserDefinedActionString[] = {"UserDefined-0x80000000"};
   2658 
   2659 typedef struct {
   2660   EFI_MEMORY_TYPE   MemoryType;
   2661   CHAR8             *MemoryTypeStr;
   2662 } PROFILE_MEMORY_TYPE_STRING;
   2663 
   2664 GLOBAL_REMOVE_IF_UNREFERENCED PROFILE_MEMORY_TYPE_STRING mMemoryTypeString[] = {
   2665   {EfiRuntimeServicesCode, "EfiRuntimeServicesCode"},
   2666   {EfiRuntimeServicesData, "EfiRuntimeServicesData"}
   2667 };
   2668 
   2669 /**
   2670   Memory type to string.
   2671 
   2672   @param[in] MemoryType Memory type.
   2673 
   2674   @return Pointer to string.
   2675 
   2676 **/
   2677 CHAR8 *
   2678 ProfileMemoryTypeToStr (
   2679   IN EFI_MEMORY_TYPE    MemoryType
   2680   )
   2681 {
   2682   UINTN     Index;
   2683   for (Index = 0; Index < ARRAY_SIZE (mMemoryTypeString); Index++) {
   2684     if (mMemoryTypeString[Index].MemoryType == MemoryType) {
   2685       return mMemoryTypeString[Index].MemoryTypeStr;
   2686     }
   2687   }
   2688 
   2689   return "UnexpectedMemoryType";
   2690 }
   2691 
   2692 /**
   2693   Action to string.
   2694 
   2695   @param[in] Action                     Profile action.
   2696 
   2697   @return Pointer to string.
   2698 
   2699 **/
   2700 CHAR8 *
   2701 ProfileActionToStr (
   2702   IN MEMORY_PROFILE_ACTION  Action
   2703   )
   2704 {
   2705   UINTN     Index;
   2706   UINTN     ActionStringCount;
   2707   CHAR8     **ActionString;
   2708 
   2709   ActionString = mSmmActionString;
   2710   ActionStringCount = ARRAY_SIZE (mSmmActionString);
   2711 
   2712   if ((UINTN) (UINT32) Action < ActionStringCount) {
   2713     return ActionString[Action];
   2714   }
   2715   for (Index = 0; Index < ARRAY_SIZE (mExtActionString); Index++) {
   2716     if (mExtActionString[Index].Action == Action) {
   2717       return mExtActionString[Index].String;
   2718     }
   2719   }
   2720 
   2721   return ActionString[0];
   2722 }
   2723 
   2724 /**
   2725   Dump SMRAM profile.
   2726 
   2727 **/
   2728 VOID
   2729 DumpSmramProfile (
   2730   VOID
   2731   )
   2732 {
   2733   MEMORY_PROFILE_CONTEXT            *Context;
   2734   MEMORY_PROFILE_DRIVER_INFO        *DriverInfo;
   2735   MEMORY_PROFILE_ALLOC_INFO         *AllocInfo;
   2736   MEMORY_PROFILE_CONTEXT_DATA       *ContextData;
   2737   MEMORY_PROFILE_DRIVER_INFO_DATA   *DriverInfoData;
   2738   MEMORY_PROFILE_ALLOC_INFO_DATA    *AllocInfoData;
   2739   LIST_ENTRY                        *SmramDriverInfoList;
   2740   UINTN                             DriverIndex;
   2741   LIST_ENTRY                        *DriverLink;
   2742   LIST_ENTRY                        *AllocInfoList;
   2743   UINTN                             AllocIndex;
   2744   LIST_ENTRY                        *AllocLink;
   2745   BOOLEAN                           SmramProfileGettingStatus;
   2746   UINTN                             TypeIndex;
   2747 
   2748   ContextData = GetSmramProfileContext ();
   2749   if (ContextData == NULL) {
   2750     return ;
   2751   }
   2752 
   2753   SmramProfileGettingStatus = mSmramProfileGettingStatus;
   2754   mSmramProfileGettingStatus = TRUE;
   2755 
   2756   Context = &ContextData->Context;
   2757   DEBUG ((EFI_D_INFO, "======= SmramProfile begin =======\n"));
   2758   DEBUG ((EFI_D_INFO, "MEMORY_PROFILE_CONTEXT\n"));
   2759 
   2760   DEBUG ((EFI_D_INFO, "  CurrentTotalUsage     - 0x%016lx\n", Context->CurrentTotalUsage));
   2761   DEBUG ((EFI_D_INFO, "  PeakTotalUsage        - 0x%016lx\n", Context->PeakTotalUsage));
   2762   for (TypeIndex = 0; TypeIndex < sizeof (Context->CurrentTotalUsageByType) / sizeof (Context->CurrentTotalUsageByType[0]); TypeIndex++) {
   2763     if ((Context->CurrentTotalUsageByType[TypeIndex] != 0) ||
   2764         (Context->PeakTotalUsageByType[TypeIndex] != 0)) {
   2765       DEBUG ((EFI_D_INFO, "  CurrentTotalUsage[0x%02x]  - 0x%016lx (%a)\n", TypeIndex, Context->CurrentTotalUsageByType[TypeIndex], ProfileMemoryTypeToStr (TypeIndex)));
   2766       DEBUG ((EFI_D_INFO, "  PeakTotalUsage[0x%02x]     - 0x%016lx (%a)\n", TypeIndex, Context->PeakTotalUsageByType[TypeIndex], ProfileMemoryTypeToStr (TypeIndex)));
   2767     }
   2768   }
   2769   DEBUG ((EFI_D_INFO, "  TotalImageSize        - 0x%016lx\n", Context->TotalImageSize));
   2770   DEBUG ((EFI_D_INFO, "  ImageCount            - 0x%08x\n", Context->ImageCount));
   2771   DEBUG ((EFI_D_INFO, "  SequenceCount         - 0x%08x\n", Context->SequenceCount));
   2772 
   2773   SmramDriverInfoList = ContextData->DriverInfoList;
   2774   for (DriverLink = SmramDriverInfoList->ForwardLink, DriverIndex = 0;
   2775        DriverLink != SmramDriverInfoList;
   2776        DriverLink = DriverLink->ForwardLink, DriverIndex++) {
   2777     DriverInfoData = CR (
   2778                    DriverLink,
   2779                    MEMORY_PROFILE_DRIVER_INFO_DATA,
   2780                    Link,
   2781                    MEMORY_PROFILE_DRIVER_INFO_SIGNATURE
   2782                    );
   2783     DriverInfo = &DriverInfoData->DriverInfo;
   2784     DEBUG ((EFI_D_INFO, "  MEMORY_PROFILE_DRIVER_INFO (0x%x)\n", DriverIndex));
   2785     DEBUG ((EFI_D_INFO, "    FileName            - %g\n", &DriverInfo->FileName));
   2786     DEBUG ((EFI_D_INFO, "    ImageBase           - 0x%016lx\n", DriverInfo->ImageBase));
   2787     DEBUG ((EFI_D_INFO, "    ImageSize           - 0x%016lx\n", DriverInfo->ImageSize));
   2788     DEBUG ((EFI_D_INFO, "    EntryPoint          - 0x%016lx\n", DriverInfo->EntryPoint));
   2789     DEBUG ((EFI_D_INFO, "    ImageSubsystem      - 0x%04x\n", DriverInfo->ImageSubsystem));
   2790     DEBUG ((EFI_D_INFO, "    FileType            - 0x%02x\n", DriverInfo->FileType));
   2791     DEBUG ((EFI_D_INFO, "    CurrentUsage        - 0x%016lx\n", DriverInfo->CurrentUsage));
   2792     DEBUG ((EFI_D_INFO, "    PeakUsage           - 0x%016lx\n", DriverInfo->PeakUsage));
   2793     for (TypeIndex = 0; TypeIndex < sizeof (DriverInfo->CurrentUsageByType) / sizeof (DriverInfo->CurrentUsageByType[0]); TypeIndex++) {
   2794       if ((DriverInfo->CurrentUsageByType[TypeIndex] != 0) ||
   2795           (DriverInfo->PeakUsageByType[TypeIndex] != 0)) {
   2796         DEBUG ((EFI_D_INFO, "    CurrentUsage[0x%02x]     - 0x%016lx (%a)\n", TypeIndex, DriverInfo->CurrentUsageByType[TypeIndex], ProfileMemoryTypeToStr (TypeIndex)));
   2797         DEBUG ((EFI_D_INFO, "    PeakUsage[0x%02x]        - 0x%016lx (%a)\n", TypeIndex, DriverInfo->PeakUsageByType[TypeIndex], ProfileMemoryTypeToStr (TypeIndex)));
   2798       }
   2799     }
   2800     DEBUG ((EFI_D_INFO, "    AllocRecordCount    - 0x%08x\n", DriverInfo->AllocRecordCount));
   2801 
   2802     AllocInfoList = DriverInfoData->AllocInfoList;
   2803     for (AllocLink = AllocInfoList->ForwardLink, AllocIndex = 0;
   2804          AllocLink != AllocInfoList;
   2805          AllocLink = AllocLink->ForwardLink, AllocIndex++) {
   2806       AllocInfoData = CR (
   2807                      AllocLink,
   2808                      MEMORY_PROFILE_ALLOC_INFO_DATA,
   2809                      Link,
   2810                      MEMORY_PROFILE_ALLOC_INFO_SIGNATURE
   2811                      );
   2812       AllocInfo = &AllocInfoData->AllocInfo;
   2813       DEBUG ((EFI_D_INFO, "    MEMORY_PROFILE_ALLOC_INFO (0x%x)\n", AllocIndex));
   2814       DEBUG ((EFI_D_INFO, "      CallerAddress  - 0x%016lx (Offset: 0x%08x)\n", AllocInfo->CallerAddress, AllocInfo->CallerAddress - DriverInfo->ImageBase));
   2815       DEBUG ((EFI_D_INFO, "      SequenceId     - 0x%08x\n", AllocInfo->SequenceId));
   2816       if ((AllocInfo->Action & MEMORY_PROFILE_ACTION_USER_DEFINED_MASK) != 0) {
   2817         if (AllocInfoData->ActionString != NULL) {
   2818           DEBUG ((EFI_D_INFO, "      Action         - 0x%08x (%a)\n", AllocInfo->Action, AllocInfoData->ActionString));
   2819         } else {
   2820           DEBUG ((EFI_D_INFO, "      Action         - 0x%08x (UserDefined-0x%08x)\n", AllocInfo->Action, AllocInfo->Action));
   2821         }
   2822       } else {
   2823         DEBUG ((EFI_D_INFO, "      Action         - 0x%08x (%a)\n", AllocInfo->Action, ProfileActionToStr (AllocInfo->Action)));
   2824       }
   2825       DEBUG ((EFI_D_INFO, "      MemoryType     - 0x%08x (%a)\n", AllocInfo->MemoryType, ProfileMemoryTypeToStr (AllocInfo->MemoryType)));
   2826       DEBUG ((EFI_D_INFO, "      Buffer         - 0x%016lx\n", AllocInfo->Buffer));
   2827       DEBUG ((EFI_D_INFO, "      Size           - 0x%016lx\n", AllocInfo->Size));
   2828     }
   2829   }
   2830 
   2831   DEBUG ((EFI_D_INFO, "======= SmramProfile end =======\n"));
   2832 
   2833   mSmramProfileGettingStatus = SmramProfileGettingStatus;
   2834 }
   2835 
   2836 /**
   2837   Dump SMRAM infromation.
   2838 
   2839 **/
   2840 VOID
   2841 DumpSmramInfo (
   2842   VOID
   2843   )
   2844 {
   2845   DEBUG_CODE (
   2846     if (IS_SMRAM_PROFILE_ENABLED) {
   2847       DumpSmramProfile ();
   2848       DumpFreePagesList ();
   2849       DumpFreePoolList ();
   2850       DumpSmramRange ();
   2851     }
   2852   );
   2853 }
   2854 
   2855