diff options
Diffstat (limited to 'roms/edk2/MdeModulePkg/Core/PiSmmCore/SmiHandlerProfile.c')
-rw-r--r-- | roms/edk2/MdeModulePkg/Core/PiSmmCore/SmiHandlerProfile.c | 1367 |
1 files changed, 1367 insertions, 0 deletions
diff --git a/roms/edk2/MdeModulePkg/Core/PiSmmCore/SmiHandlerProfile.c b/roms/edk2/MdeModulePkg/Core/PiSmmCore/SmiHandlerProfile.c new file mode 100644 index 000000000..0323617dc --- /dev/null +++ b/roms/edk2/MdeModulePkg/Core/PiSmmCore/SmiHandlerProfile.c @@ -0,0 +1,1367 @@ +/** @file
+ SMI handler profile support.
+
+Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiSmm.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/SmmServicesTableLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PrintLib.h>
+#include <Library/UefiLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/PeCoffGetEntryPointLib.h>
+#include <Protocol/LoadedImage.h>
+#include <Protocol/SmmAccess2.h>
+#include <Protocol/SmmReadyToLock.h>
+#include <Protocol/SmmEndOfDxe.h>
+
+#include <Guid/SmiHandlerProfile.h>
+
+#include "PiSmmCore.h"
+
+#define GET_OCCUPIED_SIZE(ActualSize, Alignment) \
+ ((ActualSize) + (((Alignment) - ((ActualSize) & ((Alignment) - 1))) & ((Alignment) - 1)))
+
+typedef struct {
+ EFI_GUID FileGuid;
+ PHYSICAL_ADDRESS EntryPoint;
+ PHYSICAL_ADDRESS ImageBase;
+ UINT64 ImageSize;
+ UINT32 ImageRef;
+ UINT16 PdbStringSize;
+ CHAR8 *PdbString;
+} IMAGE_STRUCT;
+
+/**
+ Register SMI handler profile handler.
+**/
+VOID
+RegisterSmiHandlerProfileHandler(
+ VOID
+ );
+
+/**
+ Retrieves and returns a pointer to the entry point to a PE/COFF image that has been loaded
+ into system memory with the PE/COFF Loader Library functions.
+
+ Retrieves the entry point to the PE/COFF image specified by Pe32Data and returns this entry
+ point in EntryPoint. If the entry point could not be retrieved from the PE/COFF image, then
+ return RETURN_INVALID_PARAMETER. Otherwise return RETURN_SUCCESS.
+ If Pe32Data is NULL, then ASSERT().
+ If EntryPoint is NULL, then ASSERT().
+
+ @param Pe32Data The pointer to the PE/COFF image that is loaded in system memory.
+ @param EntryPoint The pointer to entry point to the PE/COFF image to return.
+
+ @retval RETURN_SUCCESS EntryPoint was returned.
+ @retval RETURN_INVALID_PARAMETER The entry point could not be found in the PE/COFF image.
+
+**/
+RETURN_STATUS
+InternalPeCoffGetEntryPoint (
+ IN VOID *Pe32Data,
+ OUT VOID **EntryPoint
+ );
+
+extern LIST_ENTRY mSmiEntryList;
+extern LIST_ENTRY mHardwareSmiEntryList;
+extern SMI_ENTRY mRootSmiEntry;
+
+extern SMI_HANDLER_PROFILE_PROTOCOL mSmiHandlerProfile;
+
+GLOBAL_REMOVE_IF_UNREFERENCED LIST_ENTRY mHardwareSmiEntryList = INITIALIZE_LIST_HEAD_VARIABLE (mHardwareSmiEntryList);
+
+GLOBAL_REMOVE_IF_UNREFERENCED LIST_ENTRY mRootSmiEntryList = INITIALIZE_LIST_HEAD_VARIABLE (mRootSmiEntryList);
+
+GLOBAL_REMOVE_IF_UNREFERENCED LIST_ENTRY *mSmmCoreRootSmiEntryList = &mRootSmiEntryList;
+GLOBAL_REMOVE_IF_UNREFERENCED LIST_ENTRY *mSmmCoreSmiEntryList = &mSmiEntryList;
+GLOBAL_REMOVE_IF_UNREFERENCED LIST_ENTRY *mSmmCoreHardwareSmiEntryList = &mHardwareSmiEntryList;
+
+GLOBAL_REMOVE_IF_UNREFERENCED IMAGE_STRUCT *mImageStruct;
+GLOBAL_REMOVE_IF_UNREFERENCED UINT32 mImageStructCountMax;
+GLOBAL_REMOVE_IF_UNREFERENCED UINT32 mImageStructCount;
+
+GLOBAL_REMOVE_IF_UNREFERENCED VOID *mSmiHandlerProfileDatabase;
+GLOBAL_REMOVE_IF_UNREFERENCED UINTN mSmiHandlerProfileDatabaseSize;
+
+GLOBAL_REMOVE_IF_UNREFERENCED UINTN mSmmImageDatabaseSize;
+GLOBAL_REMOVE_IF_UNREFERENCED UINTN mSmmRootSmiDatabaseSize;
+GLOBAL_REMOVE_IF_UNREFERENCED UINTN mSmmSmiDatabaseSize;
+GLOBAL_REMOVE_IF_UNREFERENCED UINTN mSmmHardwareSmiDatabaseSize;
+
+GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mSmiHandlerProfileRecordingStatus;
+
+GLOBAL_REMOVE_IF_UNREFERENCED SMI_HANDLER_PROFILE_PROTOCOL mSmiHandlerProfile = {
+ SmiHandlerProfileRegisterHandler,
+ SmiHandlerProfileUnregisterHandler,
+};
+
+/**
+ This function dump raw data.
+
+ @param Data raw data
+ @param Size raw data size
+**/
+VOID
+InternalDumpData (
+ IN UINT8 *Data,
+ IN UINTN Size
+ )
+{
+ UINTN Index;
+ for (Index = 0; Index < Size; Index++) {
+ DEBUG ((DEBUG_INFO, "%02x ", (UINTN)Data[Index]));
+ }
+}
+
+/**
+ Get GUID name for an image.
+
+ @param[in] LoadedImage LoadedImage protocol.
+ @param[out] Guid Guid of the FFS
+**/
+VOID
+GetDriverGuid (
+ IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage,
+ OUT EFI_GUID *Guid
+ )
+{
+ EFI_GUID *FileName;
+
+ FileName = NULL;
+ if ((DevicePathType(LoadedImage->FilePath) == MEDIA_DEVICE_PATH) &&
+ (DevicePathSubType(LoadedImage->FilePath) == MEDIA_PIWG_FW_FILE_DP)) {
+ FileName = &((MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)LoadedImage->FilePath)->FvFileName;
+ }
+ if (FileName != NULL) {
+ CopyGuid(Guid, FileName);
+ } else {
+ ZeroMem(Guid, sizeof(EFI_GUID));
+ }
+}
+
+/**
+ Add image structure.
+
+ @param ImageBase image base
+ @param ImageSize image size
+ @param EntryPoint image entry point
+ @param Guid FFS GUID of the image
+ @param PdbString image PDB string
+**/
+VOID
+AddImageStruct(
+ IN PHYSICAL_ADDRESS ImageBase,
+ IN UINT64 ImageSize,
+ IN PHYSICAL_ADDRESS EntryPoint,
+ IN EFI_GUID *Guid,
+ IN CHAR8 *PdbString
+ )
+{
+ UINTN PdbStringSize;
+
+ if (mImageStructCount >= mImageStructCountMax) {
+ ASSERT(FALSE);
+ return;
+ }
+
+ CopyGuid(&mImageStruct[mImageStructCount].FileGuid, Guid);
+ mImageStruct[mImageStructCount].ImageRef = mImageStructCount;
+ mImageStruct[mImageStructCount].ImageBase = ImageBase;
+ mImageStruct[mImageStructCount].ImageSize = ImageSize;
+ mImageStruct[mImageStructCount].EntryPoint = EntryPoint;
+ if (PdbString != NULL) {
+ PdbStringSize = AsciiStrSize(PdbString);
+ mImageStruct[mImageStructCount].PdbString = AllocateCopyPool (PdbStringSize, PdbString);
+ if (mImageStruct[mImageStructCount].PdbString != NULL) {
+ mImageStruct[mImageStructCount].PdbStringSize = (UINT16) PdbStringSize;
+ }
+ }
+
+ mImageStructCount++;
+}
+
+/**
+ return an image structure based upon image address.
+
+ @param Address image address
+
+ @return image structure
+**/
+IMAGE_STRUCT *
+AddressToImageStruct(
+ IN UINTN Address
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; Index < mImageStructCount; Index++) {
+ if ((Address >= mImageStruct[Index].ImageBase) &&
+ (Address < mImageStruct[Index].ImageBase + mImageStruct[Index].ImageSize)) {
+ return &mImageStruct[Index];
+ }
+ }
+ return NULL;
+}
+
+/**
+ return an image reference index based upon image address.
+
+ @param Address image address
+
+ @return image reference index
+**/
+UINT32
+AddressToImageRef(
+ IN UINTN Address
+ )
+{
+ IMAGE_STRUCT *ImageStruct;
+
+ ImageStruct = AddressToImageStruct(Address);
+ if (ImageStruct != NULL) {
+ return ImageStruct->ImageRef;
+ }
+ return (UINT32)-1;
+}
+
+/**
+ Collect SMM image information based upon loaded image protocol.
+**/
+VOID
+GetSmmLoadedImage(
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN NoHandles;
+ UINTN HandleBufferSize;
+ EFI_HANDLE *HandleBuffer;
+ UINTN Index;
+ EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
+ CHAR16 *PathStr;
+ EFI_SMM_DRIVER_ENTRY *LoadedImagePrivate;
+ PHYSICAL_ADDRESS EntryPoint;
+ VOID *EntryPointInImage;
+ EFI_GUID Guid;
+ CHAR8 *PdbString;
+ PHYSICAL_ADDRESS RealImageBase;
+
+ HandleBufferSize = 0;
+ HandleBuffer = NULL;
+ Status = gSmst->SmmLocateHandle(
+ ByProtocol,
+ &gEfiLoadedImageProtocolGuid,
+ NULL,
+ &HandleBufferSize,
+ HandleBuffer
+ );
+ if (Status != EFI_BUFFER_TOO_SMALL) {
+ return;
+ }
+ HandleBuffer = AllocateZeroPool (HandleBufferSize);
+ if (HandleBuffer == NULL) {
+ return;
+ }
+ Status = gSmst->SmmLocateHandle(
+ ByProtocol,
+ &gEfiLoadedImageProtocolGuid,
+ NULL,
+ &HandleBufferSize,
+ HandleBuffer
+ );
+ if (EFI_ERROR(Status)) {
+ return;
+ }
+
+ NoHandles = HandleBufferSize/sizeof(EFI_HANDLE);
+ mImageStructCountMax = (UINT32) NoHandles;
+ mImageStruct = AllocateZeroPool(mImageStructCountMax * sizeof(IMAGE_STRUCT));
+ if (mImageStruct == NULL) {
+ goto Done;
+ }
+
+ for (Index = 0; Index < NoHandles; Index++) {
+ Status = gSmst->SmmHandleProtocol(
+ HandleBuffer[Index],
+ &gEfiLoadedImageProtocolGuid,
+ (VOID **)&LoadedImage
+ );
+ if (EFI_ERROR(Status)) {
+ continue;
+ }
+ PathStr = ConvertDevicePathToText(LoadedImage->FilePath, TRUE, TRUE);
+ GetDriverGuid(LoadedImage, &Guid);
+ DEBUG ((DEBUG_INFO, "Image: %g ", &Guid));
+
+ EntryPoint = 0;
+ LoadedImagePrivate = BASE_CR(LoadedImage, EFI_SMM_DRIVER_ENTRY, SmmLoadedImage);
+ RealImageBase = (UINTN)LoadedImage->ImageBase;
+ if (LoadedImagePrivate->Signature == EFI_SMM_DRIVER_ENTRY_SIGNATURE) {
+ EntryPoint = LoadedImagePrivate->ImageEntryPoint;
+ if ((EntryPoint != 0) && ((EntryPoint < (UINTN)LoadedImage->ImageBase) || (EntryPoint >= ((UINTN)LoadedImage->ImageBase + LoadedImage->ImageSize)))) {
+ //
+ // If the EntryPoint is not in the range of image buffer, it should come from emulation environment.
+ // So patch ImageBuffer here to align the EntryPoint.
+ //
+ Status = InternalPeCoffGetEntryPoint(LoadedImage->ImageBase, &EntryPointInImage);
+ ASSERT_EFI_ERROR(Status);
+ RealImageBase = (UINTN)LoadedImage->ImageBase + EntryPoint - (UINTN)EntryPointInImage;
+ }
+ }
+ DEBUG ((DEBUG_INFO, "(0x%lx - 0x%lx", RealImageBase, LoadedImage->ImageSize));
+ if (EntryPoint != 0) {
+ DEBUG ((DEBUG_INFO, ", EntryPoint:0x%lx", EntryPoint));
+ }
+ DEBUG ((DEBUG_INFO, ")\n"));
+
+ if (RealImageBase != 0) {
+ PdbString = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) RealImageBase);
+ DEBUG ((DEBUG_INFO, " pdb - %a\n", PdbString));
+ } else {
+ PdbString = NULL;
+ }
+ DEBUG ((DEBUG_INFO, " (%s)\n", PathStr));
+
+ AddImageStruct(RealImageBase, LoadedImage->ImageSize, EntryPoint, &Guid, PdbString);
+ }
+
+Done:
+ FreePool(HandleBuffer);
+ return;
+}
+
+/**
+ Dump SMI child context.
+
+ @param HandlerType the handler type
+ @param Context the handler context
+ @param ContextSize the handler context size
+**/
+VOID
+DumpSmiChildContext (
+ IN EFI_GUID *HandlerType,
+ IN VOID *Context,
+ IN UINTN ContextSize
+ )
+{
+ CHAR16 *Str;
+
+ if (CompareGuid (HandlerType, &gEfiSmmSwDispatch2ProtocolGuid)) {
+ DEBUG ((DEBUG_INFO, " SwSmi - 0x%lx\n", ((SMI_HANDLER_PROFILE_SW_REGISTER_CONTEXT *)Context)->SwSmiInputValue));
+ } else if (CompareGuid (HandlerType, &gEfiSmmSxDispatch2ProtocolGuid)) {
+ DEBUG ((DEBUG_INFO, " SxType - 0x%x\n", ((EFI_SMM_SX_REGISTER_CONTEXT *)Context)->Type));
+ DEBUG ((DEBUG_INFO, " SxPhase - 0x%x\n", ((EFI_SMM_SX_REGISTER_CONTEXT *)Context)->Phase));
+ } else if (CompareGuid (HandlerType, &gEfiSmmPowerButtonDispatch2ProtocolGuid)) {
+ DEBUG ((DEBUG_INFO, " PowerButtonPhase - 0x%x\n", ((EFI_SMM_POWER_BUTTON_REGISTER_CONTEXT *)Context)->Phase));
+ } else if (CompareGuid (HandlerType, &gEfiSmmStandbyButtonDispatch2ProtocolGuid)) {
+ DEBUG ((DEBUG_INFO, " StandbyButtonPhase - 0x%x\n", ((EFI_SMM_STANDBY_BUTTON_REGISTER_CONTEXT *)Context)->Phase));
+ } else if (CompareGuid (HandlerType, &gEfiSmmPeriodicTimerDispatch2ProtocolGuid)) {
+ DEBUG ((DEBUG_INFO, " PeriodicTimerPeriod - %ld\n", ((EFI_SMM_PERIODIC_TIMER_REGISTER_CONTEXT *)Context)->Period));
+ DEBUG ((DEBUG_INFO, " PeriodicTimerSmiTickInterval - %ld\n", ((EFI_SMM_PERIODIC_TIMER_REGISTER_CONTEXT *)Context)->SmiTickInterval));
+ } else if (CompareGuid (HandlerType, &gEfiSmmGpiDispatch2ProtocolGuid)) {
+ DEBUG ((DEBUG_INFO, " GpiNum - 0x%lx\n", ((EFI_SMM_GPI_REGISTER_CONTEXT *)Context)->GpiNum));
+ } else if (CompareGuid (HandlerType, &gEfiSmmIoTrapDispatch2ProtocolGuid)) {
+ DEBUG ((DEBUG_INFO, " IoTrapAddress - 0x%x\n", ((EFI_SMM_IO_TRAP_REGISTER_CONTEXT *)Context)->Address));
+ DEBUG ((DEBUG_INFO, " IoTrapLength - 0x%x\n", ((EFI_SMM_IO_TRAP_REGISTER_CONTEXT *)Context)->Length));
+ DEBUG ((DEBUG_INFO, " IoTrapType - 0x%x\n", ((EFI_SMM_IO_TRAP_REGISTER_CONTEXT *)Context)->Type));
+ } else if (CompareGuid (HandlerType, &gEfiSmmUsbDispatch2ProtocolGuid)) {
+ DEBUG ((DEBUG_INFO, " UsbType - 0x%x\n", ((SMI_HANDLER_PROFILE_USB_REGISTER_CONTEXT *)Context)->Type));
+ Str = ConvertDevicePathToText((EFI_DEVICE_PATH_PROTOCOL *)(((SMI_HANDLER_PROFILE_USB_REGISTER_CONTEXT *)Context) + 1), TRUE, TRUE);
+ DEBUG ((DEBUG_INFO, " UsbDevicePath - %s\n", Str));
+ if (Str != NULL) {
+ FreePool (Str);
+ }
+ } else {
+ DEBUG ((DEBUG_INFO, " Context - "));
+ InternalDumpData (Context, ContextSize);
+ DEBUG ((DEBUG_INFO, "\n"));
+ }
+}
+
+/**
+ Dump all SMI handlers associated with SmiEntry.
+
+ @param SmiEntry SMI entry.
+**/
+VOID
+DumpSmiHandlerOnSmiEntry(
+ IN SMI_ENTRY *SmiEntry
+ )
+{
+ LIST_ENTRY *ListEntry;
+ SMI_HANDLER *SmiHandler;
+ IMAGE_STRUCT *ImageStruct;
+
+ ListEntry = &SmiEntry->SmiHandlers;
+ for (ListEntry = ListEntry->ForwardLink;
+ ListEntry != &SmiEntry->SmiHandlers;
+ ListEntry = ListEntry->ForwardLink) {
+ SmiHandler = CR(ListEntry, SMI_HANDLER, Link, SMI_HANDLER_SIGNATURE);
+ ImageStruct = AddressToImageStruct((UINTN)SmiHandler->Handler);
+ if (ImageStruct != NULL) {
+ DEBUG ((DEBUG_INFO, " Module - %g", &ImageStruct->FileGuid));
+ }
+ if ((ImageStruct != NULL) && (ImageStruct->PdbString[0] != 0)) {
+ DEBUG ((DEBUG_INFO, " (Pdb - %a)", ImageStruct->PdbString));
+ }
+ DEBUG ((DEBUG_INFO, "\n"));
+ if (SmiHandler->ContextSize != 0) {
+ DumpSmiChildContext (&SmiEntry->HandlerType, SmiHandler->Context, SmiHandler->ContextSize);
+ }
+ DEBUG ((DEBUG_INFO, " Handler - 0x%x", SmiHandler->Handler));
+ if (ImageStruct != NULL) {
+ DEBUG ((DEBUG_INFO, " <== RVA - 0x%x", (UINTN)SmiHandler->Handler - (UINTN) ImageStruct->ImageBase));
+ }
+ DEBUG ((DEBUG_INFO, "\n"));
+ DEBUG ((DEBUG_INFO, " CallerAddr - 0x%x", SmiHandler->CallerAddr));
+ if (ImageStruct != NULL) {
+ DEBUG ((DEBUG_INFO, " <== RVA - 0x%x", SmiHandler->CallerAddr - (UINTN) ImageStruct->ImageBase));
+ }
+ DEBUG ((DEBUG_INFO, "\n"));
+ }
+
+ return;
+}
+
+/**
+ Dump all SMI entry on the list.
+
+ @param SmiEntryList a list of SMI entry.
+**/
+VOID
+DumpSmiEntryList(
+ IN LIST_ENTRY *SmiEntryList
+ )
+{
+ LIST_ENTRY *ListEntry;
+ SMI_ENTRY *SmiEntry;
+
+ ListEntry = SmiEntryList;
+ for (ListEntry = ListEntry->ForwardLink;
+ ListEntry != SmiEntryList;
+ ListEntry = ListEntry->ForwardLink) {
+ SmiEntry = CR(ListEntry, SMI_ENTRY, AllEntries, SMI_ENTRY_SIGNATURE);
+ DEBUG ((DEBUG_INFO, "SmiEntry - %g\n", &SmiEntry->HandlerType));
+ DumpSmiHandlerOnSmiEntry(SmiEntry);
+ }
+
+ return;
+}
+
+/**
+ SMM Ready To Lock event notification handler.
+
+ This function collects all SMM image information and build SmiHandleProfile database,
+ and register SmiHandlerProfile SMI handler.
+
+ @param[in] Protocol Points to the protocol's unique identifier.
+ @param[in] Interface Points to the interface instance.
+ @param[in] Handle The handle on which the interface was installed.
+
+ @retval EFI_SUCCESS Notification handler runs successfully.
+**/
+EFI_STATUS
+EFIAPI
+SmmReadyToLockInSmiHandlerProfile (
+ IN CONST EFI_GUID *Protocol,
+ IN VOID *Interface,
+ IN EFI_HANDLE Handle
+ )
+{
+ //
+ // Dump all image
+ //
+ DEBUG ((DEBUG_INFO, "##################\n"));
+ DEBUG ((DEBUG_INFO, "# IMAGE DATABASE #\n"));
+ DEBUG ((DEBUG_INFO, "##################\n"));
+ GetSmmLoadedImage ();
+ DEBUG ((DEBUG_INFO, "\n"));
+
+ //
+ // Dump SMI Handler
+ //
+ DEBUG ((DEBUG_INFO, "########################\n"));
+ DEBUG ((DEBUG_INFO, "# SMI Handler DATABASE #\n"));
+ DEBUG ((DEBUG_INFO, "########################\n"));
+
+ DEBUG ((DEBUG_INFO, "# 1. ROOT SMI Handler #\n"));
+ DEBUG_CODE (
+ DumpSmiEntryList(mSmmCoreRootSmiEntryList);
+ );
+
+ DEBUG ((DEBUG_INFO, "# 2. GUID SMI Handler #\n"));
+ DEBUG_CODE (
+ DumpSmiEntryList(mSmmCoreSmiEntryList);
+ );
+
+ DEBUG ((DEBUG_INFO, "# 3. Hardware SMI Handler #\n"));
+ DEBUG_CODE (
+ DumpSmiEntryList(mSmmCoreHardwareSmiEntryList);
+ );
+
+ DEBUG ((DEBUG_INFO, "\n"));
+
+ RegisterSmiHandlerProfileHandler();
+
+ if (mImageStruct != NULL) {
+ FreePool(mImageStruct);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ returns SMM image data base size.
+
+ @return SMM image data base size.
+**/
+UINTN
+GetSmmImageDatabaseSize(
+ VOID
+ )
+{
+ UINTN Size;
+ UINT32 Index;
+
+ Size = 0;
+ for (Index = 0; Index < mImageStructCount; Index++) {
+ Size += sizeof(SMM_CORE_IMAGE_DATABASE_STRUCTURE) + GET_OCCUPIED_SIZE (mImageStruct[Index].PdbStringSize, sizeof (UINT64));
+ }
+ return Size;
+}
+
+/**
+ returns all SMI handlers' size associated with SmiEntry.
+
+ @param SmiEntry SMI entry.
+
+ @return all SMI handlers' size associated with SmiEntry.
+**/
+UINTN
+GetSmmSmiHandlerSizeOnSmiEntry(
+ IN SMI_ENTRY *SmiEntry
+ )
+{
+ LIST_ENTRY *ListEntry;
+ SMI_HANDLER *SmiHandler;
+ UINTN Size;
+
+ Size = 0;
+ ListEntry = &SmiEntry->SmiHandlers;
+ for (ListEntry = ListEntry->ForwardLink;
+ ListEntry != &SmiEntry->SmiHandlers;
+ ListEntry = ListEntry->ForwardLink) {
+ SmiHandler = CR(ListEntry, SMI_HANDLER, Link, SMI_HANDLER_SIGNATURE);
+ Size += sizeof(SMM_CORE_SMI_HANDLER_STRUCTURE) + GET_OCCUPIED_SIZE (SmiHandler->ContextSize, sizeof (UINT64));
+ }
+
+ return Size;
+}
+
+/**
+ return all SMI handler database size on the SMI entry list.
+
+ @param SmiEntryList a list of SMI entry.
+
+ @return all SMI handler database size on the SMI entry list.
+**/
+UINTN
+GetSmmSmiDatabaseSize(
+ IN LIST_ENTRY *SmiEntryList
+ )
+{
+ LIST_ENTRY *ListEntry;
+ SMI_ENTRY *SmiEntry;
+ UINTN Size;
+
+ Size = 0;
+ ListEntry = SmiEntryList;
+ for (ListEntry = ListEntry->ForwardLink;
+ ListEntry != SmiEntryList;
+ ListEntry = ListEntry->ForwardLink) {
+ SmiEntry = CR(ListEntry, SMI_ENTRY, AllEntries, SMI_ENTRY_SIGNATURE);
+ Size += sizeof(SMM_CORE_SMI_DATABASE_STRUCTURE);
+ Size += GetSmmSmiHandlerSizeOnSmiEntry(SmiEntry);
+ }
+ return Size;
+}
+
+/**
+ return SMI handler profile database size.
+
+ @return SMI handler profile database size.
+**/
+UINTN
+GetSmiHandlerProfileDatabaseSize (
+ VOID
+ )
+{
+ mSmmImageDatabaseSize = GetSmmImageDatabaseSize();
+ mSmmRootSmiDatabaseSize = GetSmmSmiDatabaseSize(mSmmCoreRootSmiEntryList);
+ mSmmSmiDatabaseSize = GetSmmSmiDatabaseSize(mSmmCoreSmiEntryList);
+ mSmmHardwareSmiDatabaseSize = GetSmmSmiDatabaseSize(mSmmCoreHardwareSmiEntryList);
+
+ return mSmmImageDatabaseSize + mSmmSmiDatabaseSize + mSmmRootSmiDatabaseSize + mSmmHardwareSmiDatabaseSize;
+}
+
+/**
+ get SMM image database.
+
+ @param Data The buffer to hold SMM image database
+ @param ExpectedSize The expected size of the SMM image database
+
+ @return SMM image data base size.
+**/
+UINTN
+GetSmmImageDatabaseData (
+ IN OUT VOID *Data,
+ IN UINTN ExpectedSize
+ )
+{
+ SMM_CORE_IMAGE_DATABASE_STRUCTURE *ImageStruct;
+ UINTN Size;
+ UINTN Index;
+
+ ImageStruct = Data;
+ Size = 0;
+ for (Index = 0; Index < mImageStructCount; Index++) {
+ if (Size >= ExpectedSize) {
+ return 0;
+ }
+ if (sizeof(SMM_CORE_IMAGE_DATABASE_STRUCTURE) + GET_OCCUPIED_SIZE (mImageStruct[Index].PdbStringSize, sizeof (UINT64)) > ExpectedSize - Size) {
+ return 0;
+ }
+ ImageStruct->Header.Signature = SMM_CORE_IMAGE_DATABASE_SIGNATURE;
+ ImageStruct->Header.Length = (UINT32)(sizeof(SMM_CORE_IMAGE_DATABASE_STRUCTURE) + GET_OCCUPIED_SIZE (mImageStruct[Index].PdbStringSize, sizeof (UINT64)));
+ ImageStruct->Header.Revision = SMM_CORE_IMAGE_DATABASE_REVISION;
+ CopyGuid(&ImageStruct->FileGuid, &mImageStruct[Index].FileGuid);
+ ImageStruct->ImageRef = mImageStruct[Index].ImageRef;
+ ImageStruct->EntryPoint = mImageStruct[Index].EntryPoint;
+ ImageStruct->ImageBase = mImageStruct[Index].ImageBase;
+ ImageStruct->ImageSize = mImageStruct[Index].ImageSize;
+ if (mImageStruct[Index].PdbStringSize != 0) {
+ ImageStruct->PdbStringOffset = sizeof(SMM_CORE_IMAGE_DATABASE_STRUCTURE);
+ CopyMem ((VOID *)((UINTN)ImageStruct + ImageStruct->PdbStringOffset), mImageStruct[Index].PdbString, mImageStruct[Index].PdbStringSize);
+ } else {
+ ImageStruct->PdbStringOffset = 0;
+ }
+ ImageStruct = (SMM_CORE_IMAGE_DATABASE_STRUCTURE *)((UINTN)ImageStruct + ImageStruct->Header.Length);
+ Size += sizeof(SMM_CORE_IMAGE_DATABASE_STRUCTURE) + GET_OCCUPIED_SIZE (mImageStruct[Index].PdbStringSize, sizeof (UINT64));
+ }
+
+ if (ExpectedSize != Size) {
+ return 0;
+ }
+ return Size;
+}
+
+/**
+ get all SMI handler data associated with SmiEntry.
+
+ @param SmiEntry SMI entry.
+ @param Data The buffer to hold all SMI handler data
+ @param MaxSize The max size of the SMM image database
+ @param Count The count of the SMI handler.
+
+ @return SMM image data base size.
+**/
+UINTN
+GetSmmSmiHandlerDataOnSmiEntry(
+ IN SMI_ENTRY *SmiEntry,
+ IN OUT VOID *Data,
+ IN UINTN MaxSize,
+ OUT UINT32 *Count
+ )
+{
+ SMM_CORE_SMI_HANDLER_STRUCTURE *SmiHandlerStruct;
+ LIST_ENTRY *ListEntry;
+ SMI_HANDLER *SmiHandler;
+ UINTN Size;
+
+ SmiHandlerStruct = Data;
+ Size = 0;
+ *Count = 0;
+ ListEntry = &SmiEntry->SmiHandlers;
+ for (ListEntry = ListEntry->ForwardLink;
+ ListEntry != &SmiEntry->SmiHandlers;
+ ListEntry = ListEntry->ForwardLink) {
+ SmiHandler = CR(ListEntry, SMI_HANDLER, Link, SMI_HANDLER_SIGNATURE);
+ if (Size >= MaxSize) {
+ *Count = 0;
+ return 0;
+ }
+ if (sizeof(SMM_CORE_SMI_HANDLER_STRUCTURE) + GET_OCCUPIED_SIZE (SmiHandler->ContextSize, sizeof (UINT64)) > MaxSize - Size) {
+ *Count = 0;
+ return 0;
+ }
+ SmiHandlerStruct->Length = (UINT32)(sizeof(SMM_CORE_SMI_HANDLER_STRUCTURE) + GET_OCCUPIED_SIZE (SmiHandler->ContextSize, sizeof (UINT64)));
+ SmiHandlerStruct->CallerAddr = (UINTN)SmiHandler->CallerAddr;
+ SmiHandlerStruct->Handler = (UINTN)SmiHandler->Handler;
+ SmiHandlerStruct->ImageRef = AddressToImageRef((UINTN)SmiHandler->Handler);
+ SmiHandlerStruct->ContextBufferSize = (UINT32)SmiHandler->ContextSize;
+ if (SmiHandler->ContextSize != 0) {
+ SmiHandlerStruct->ContextBufferOffset = sizeof(SMM_CORE_SMI_HANDLER_STRUCTURE);
+ CopyMem ((UINT8 *)SmiHandlerStruct + SmiHandlerStruct->ContextBufferOffset, SmiHandler->Context, SmiHandler->ContextSize);
+ } else {
+ SmiHandlerStruct->ContextBufferOffset = 0;
+ }
+ Size += sizeof(SMM_CORE_SMI_HANDLER_STRUCTURE) + GET_OCCUPIED_SIZE (SmiHandler->ContextSize, sizeof (UINT64));
+ SmiHandlerStruct = (SMM_CORE_SMI_HANDLER_STRUCTURE *)((UINTN)SmiHandlerStruct + SmiHandlerStruct->Length);
+ *Count = *Count + 1;
+ }
+
+ return Size;
+}
+
+/**
+ get all SMI handler database on the SMI entry list.
+
+ @param SmiEntryList a list of SMI entry.
+ @param HandlerCategory The handler category
+ @param Data The buffer to hold all SMI handler database
+ @param ExpectedSize The expected size of the SMM image database
+
+ @return all SMI database size on the SMI entry list.
+**/
+UINTN
+GetSmmSmiDatabaseData(
+ IN LIST_ENTRY *SmiEntryList,
+ IN UINT32 HandlerCategory,
+ IN OUT VOID *Data,
+ IN UINTN ExpectedSize
+ )
+{
+ SMM_CORE_SMI_DATABASE_STRUCTURE *SmiStruct;
+ LIST_ENTRY *ListEntry;
+ SMI_ENTRY *SmiEntry;
+ UINTN Size;
+ UINTN SmiHandlerSize;
+ UINT32 SmiHandlerCount;
+
+ SmiStruct = Data;
+ Size = 0;
+ ListEntry = SmiEntryList;
+ for (ListEntry = ListEntry->ForwardLink;
+ ListEntry != SmiEntryList;
+ ListEntry = ListEntry->ForwardLink) {
+ SmiEntry = CR(ListEntry, SMI_ENTRY, AllEntries, SMI_ENTRY_SIGNATURE);
+ if (Size >= ExpectedSize) {
+ return 0;
+ }
+ if (sizeof(SMM_CORE_SMI_DATABASE_STRUCTURE) > ExpectedSize - Size) {
+ return 0;
+ }
+
+ SmiStruct->Header.Signature = SMM_CORE_SMI_DATABASE_SIGNATURE;
+ SmiStruct->Header.Length = sizeof(SMM_CORE_SMI_DATABASE_STRUCTURE);
+ SmiStruct->Header.Revision = SMM_CORE_SMI_DATABASE_REVISION;
+ SmiStruct->HandlerCategory = HandlerCategory;
+ CopyGuid(&SmiStruct->HandlerType, &SmiEntry->HandlerType);
+ Size += sizeof(SMM_CORE_SMI_DATABASE_STRUCTURE);
+ SmiHandlerSize = GetSmmSmiHandlerDataOnSmiEntry(SmiEntry, (UINT8 *)SmiStruct + SmiStruct->Header.Length, ExpectedSize - Size, &SmiHandlerCount);
+ SmiStruct->HandlerCount = SmiHandlerCount;
+ Size += SmiHandlerSize;
+ SmiStruct->Header.Length += (UINT32)SmiHandlerSize;
+ SmiStruct = (VOID *)((UINTN)SmiStruct + SmiStruct->Header.Length);
+ }
+ if (ExpectedSize != Size) {
+ return 0;
+ }
+ return Size;
+}
+
+/**
+ Get SMI handler profile database.
+
+ @param Data the buffer to hold SMI handler profile database
+
+ @retval EFI_SUCCESS the database is got.
+ @retval EFI_INVALID_PARAMETER the database size mismatch.
+**/
+EFI_STATUS
+GetSmiHandlerProfileDatabaseData(
+ IN OUT VOID *Data
+ )
+{
+ UINTN SmmImageDatabaseSize;
+ UINTN SmmSmiDatabaseSize;
+ UINTN SmmRootSmiDatabaseSize;
+ UINTN SmmHardwareSmiDatabaseSize;
+
+ DEBUG((DEBUG_VERBOSE, "GetSmiHandlerProfileDatabaseData\n"));
+ SmmImageDatabaseSize = GetSmmImageDatabaseData(Data, mSmmImageDatabaseSize);
+ if (SmmImageDatabaseSize != mSmmImageDatabaseSize) {
+ DEBUG((DEBUG_ERROR, "GetSmiHandlerProfileDatabaseData - SmmImageDatabaseSize mismatch!\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+ SmmRootSmiDatabaseSize = GetSmmSmiDatabaseData(mSmmCoreRootSmiEntryList, SmmCoreSmiHandlerCategoryRootHandler, (UINT8 *)Data + SmmImageDatabaseSize, mSmmRootSmiDatabaseSize);
+ if (SmmRootSmiDatabaseSize != mSmmRootSmiDatabaseSize) {
+ DEBUG((DEBUG_ERROR, "GetSmiHandlerProfileDatabaseData - SmmRootSmiDatabaseSize mismatch!\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+ SmmSmiDatabaseSize = GetSmmSmiDatabaseData(mSmmCoreSmiEntryList, SmmCoreSmiHandlerCategoryGuidHandler, (UINT8 *)Data + SmmImageDatabaseSize + mSmmRootSmiDatabaseSize, mSmmSmiDatabaseSize);
+ if (SmmSmiDatabaseSize != mSmmSmiDatabaseSize) {
+ DEBUG((DEBUG_ERROR, "GetSmiHandlerProfileDatabaseData - SmmSmiDatabaseSize mismatch!\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+ SmmHardwareSmiDatabaseSize = GetSmmSmiDatabaseData(mSmmCoreHardwareSmiEntryList, SmmCoreSmiHandlerCategoryHardwareHandler, (UINT8 *)Data + SmmImageDatabaseSize + SmmRootSmiDatabaseSize + SmmSmiDatabaseSize, mSmmHardwareSmiDatabaseSize);
+ if (SmmHardwareSmiDatabaseSize != mSmmHardwareSmiDatabaseSize) {
+ DEBUG((DEBUG_ERROR, "GetSmiHandlerProfileDatabaseData - SmmHardwareSmiDatabaseSize mismatch!\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ build SMI handler profile database.
+**/
+VOID
+BuildSmiHandlerProfileDatabase(
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ mSmiHandlerProfileDatabaseSize = GetSmiHandlerProfileDatabaseSize();
+ mSmiHandlerProfileDatabase = AllocatePool(mSmiHandlerProfileDatabaseSize);
+ if (mSmiHandlerProfileDatabase == NULL) {
+ return;
+ }
+ Status = GetSmiHandlerProfileDatabaseData(mSmiHandlerProfileDatabase);
+ if (EFI_ERROR(Status)) {
+ FreePool(mSmiHandlerProfileDatabase);
+ mSmiHandlerProfileDatabase = NULL;
+ }
+}
+
+/**
+ Copy SMI handler profile data.
+
+ @param DataBuffer The buffer to hold SMI handler profile data.
+ @param DataSize On input, data buffer size.
+ On output, actual data buffer size copied.
+ @param DataOffset On input, data buffer offset to copy.
+ On output, next time data buffer offset to copy.
+
+**/
+VOID
+SmiHandlerProfileCopyData(
+ OUT VOID *DataBuffer,
+ IN OUT UINT64 *DataSize,
+ IN OUT UINT64 *DataOffset
+ )
+{
+ if (*DataOffset >= mSmiHandlerProfileDatabaseSize) {
+ *DataOffset = mSmiHandlerProfileDatabaseSize;
+ return;
+ }
+ if (mSmiHandlerProfileDatabaseSize - *DataOffset < *DataSize) {
+ *DataSize = mSmiHandlerProfileDatabaseSize - *DataOffset;
+ }
+
+ CopyMem(
+ DataBuffer,
+ (UINT8 *)mSmiHandlerProfileDatabase + *DataOffset,
+ (UINTN)*DataSize
+ );
+ *DataOffset = *DataOffset + *DataSize;
+}
+
+/**
+ SMI handler profile handler to get info.
+
+ @param SmiHandlerProfileParameterGetInfo The parameter of SMI handler profile get info.
+
+**/
+VOID
+SmiHandlerProfileHandlerGetInfo(
+ IN SMI_HANDLER_PROFILE_PARAMETER_GET_INFO *SmiHandlerProfileParameterGetInfo
+ )
+{
+ BOOLEAN SmiHandlerProfileRecordingStatus;
+
+ SmiHandlerProfileRecordingStatus = mSmiHandlerProfileRecordingStatus;
+ mSmiHandlerProfileRecordingStatus = FALSE;
+
+ SmiHandlerProfileParameterGetInfo->DataSize = mSmiHandlerProfileDatabaseSize;
+ SmiHandlerProfileParameterGetInfo->Header.ReturnStatus = 0;
+
+ mSmiHandlerProfileRecordingStatus = SmiHandlerProfileRecordingStatus;
+}
+
+/**
+ SMI handler profile handler to get data by offset.
+
+ @param SmiHandlerProfileParameterGetDataByOffset The parameter of SMI handler profile get data by offset.
+
+**/
+VOID
+SmiHandlerProfileHandlerGetDataByOffset(
+ IN SMI_HANDLER_PROFILE_PARAMETER_GET_DATA_BY_OFFSET *SmiHandlerProfileParameterGetDataByOffset
+ )
+{
+ SMI_HANDLER_PROFILE_PARAMETER_GET_DATA_BY_OFFSET SmiHandlerProfileGetDataByOffset;
+ BOOLEAN SmiHandlerProfileRecordingStatus;
+
+ SmiHandlerProfileRecordingStatus = mSmiHandlerProfileRecordingStatus;
+ mSmiHandlerProfileRecordingStatus = FALSE;
+
+ CopyMem(&SmiHandlerProfileGetDataByOffset, SmiHandlerProfileParameterGetDataByOffset, sizeof(SmiHandlerProfileGetDataByOffset));
+
+ //
+ // Sanity check
+ //
+ if (!SmmIsBufferOutsideSmmValid((UINTN)SmiHandlerProfileGetDataByOffset.DataBuffer, (UINTN)SmiHandlerProfileGetDataByOffset.DataSize)) {
+ DEBUG((DEBUG_ERROR, "SmiHandlerProfileHandlerGetDataByOffset: SMI handler profile get data in SMRAM or overflow!\n"));
+ SmiHandlerProfileParameterGetDataByOffset->Header.ReturnStatus = (UINT64)(INT64)(INTN)EFI_ACCESS_DENIED;
+ goto Done;
+ }
+
+ SmiHandlerProfileCopyData((VOID *)(UINTN)SmiHandlerProfileGetDataByOffset.DataBuffer, &SmiHandlerProfileGetDataByOffset.DataSize, &SmiHandlerProfileGetDataByOffset.DataOffset);
+ CopyMem(SmiHandlerProfileParameterGetDataByOffset, &SmiHandlerProfileGetDataByOffset, sizeof(SmiHandlerProfileGetDataByOffset));
+ SmiHandlerProfileParameterGetDataByOffset->Header.ReturnStatus = 0;
+
+Done:
+ mSmiHandlerProfileRecordingStatus = SmiHandlerProfileRecordingStatus;
+}
+
+/**
+ Dispatch function for a Software SMI handler.
+
+ Caution: This function may receive untrusted input.
+ Communicate buffer and buffer size are external input, so this function will do basic validation.
+
+ @param DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
+ @param Context Points to an optional handler context which was specified when the
+ handler was registered.
+ @param CommBuffer A pointer to a collection of data in memory that will
+ be conveyed from a non-SMM environment into an SMM environment.
+ @param CommBufferSize The size of the CommBuffer.
+
+ @retval EFI_SUCCESS Command is handled successfully.
+**/
+EFI_STATUS
+EFIAPI
+SmiHandlerProfileHandler(
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *Context OPTIONAL,
+ IN OUT VOID *CommBuffer OPTIONAL,
+ IN OUT UINTN *CommBufferSize OPTIONAL
+ )
+{
+ SMI_HANDLER_PROFILE_PARAMETER_HEADER *SmiHandlerProfileParameterHeader;
+ UINTN TempCommBufferSize;
+
+ DEBUG((DEBUG_ERROR, "SmiHandlerProfileHandler Enter\n"));
+
+ if (mSmiHandlerProfileDatabase == NULL) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // If input is invalid, stop processing this SMI
+ //
+ if (CommBuffer == NULL || CommBufferSize == NULL) {
+ return EFI_SUCCESS;
+ }
+
+ TempCommBufferSize = *CommBufferSize;
+
+ if (TempCommBufferSize < sizeof(SMI_HANDLER_PROFILE_PARAMETER_HEADER)) {
+ DEBUG((DEBUG_ERROR, "SmiHandlerProfileHandler: SMM communication buffer size invalid!\n"));
+ return EFI_SUCCESS;
+ }
+
+ if (!SmmIsBufferOutsideSmmValid((UINTN)CommBuffer, TempCommBufferSize)) {
+ DEBUG((DEBUG_ERROR, "SmiHandlerProfileHandler: SMM communication buffer in SMRAM or overflow!\n"));
+ return EFI_SUCCESS;
+ }
+
+ SmiHandlerProfileParameterHeader = (SMI_HANDLER_PROFILE_PARAMETER_HEADER *)((UINTN)CommBuffer);
+ SmiHandlerProfileParameterHeader->ReturnStatus = (UINT64)-1;
+
+ switch (SmiHandlerProfileParameterHeader->Command) {
+ case SMI_HANDLER_PROFILE_COMMAND_GET_INFO:
+ DEBUG((DEBUG_ERROR, "SmiHandlerProfileHandlerGetInfo\n"));
+ if (TempCommBufferSize != sizeof(SMI_HANDLER_PROFILE_PARAMETER_GET_INFO)) {
+ DEBUG((DEBUG_ERROR, "SmiHandlerProfileHandler: SMM communication buffer size invalid!\n"));
+ return EFI_SUCCESS;
+ }
+ SmiHandlerProfileHandlerGetInfo((SMI_HANDLER_PROFILE_PARAMETER_GET_INFO *)(UINTN)CommBuffer);
+ break;
+ case SMI_HANDLER_PROFILE_COMMAND_GET_DATA_BY_OFFSET:
+ DEBUG((DEBUG_ERROR, "SmiHandlerProfileHandlerGetDataByOffset\n"));
+ if (TempCommBufferSize != sizeof(SMI_HANDLER_PROFILE_PARAMETER_GET_DATA_BY_OFFSET)) {
+ DEBUG((DEBUG_ERROR, "SmiHandlerProfileHandler: SMM communication buffer size invalid!\n"));
+ return EFI_SUCCESS;
+ }
+ SmiHandlerProfileHandlerGetDataByOffset((SMI_HANDLER_PROFILE_PARAMETER_GET_DATA_BY_OFFSET *)(UINTN)CommBuffer);
+ break;
+ default:
+ break;
+ }
+
+ DEBUG((DEBUG_ERROR, "SmiHandlerProfileHandler Exit\n"));
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Register SMI handler profile handler.
+**/
+VOID
+RegisterSmiHandlerProfileHandler (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE DispatchHandle;
+
+ Status = gSmst->SmiHandlerRegister (
+ SmiHandlerProfileHandler,
+ &gSmiHandlerProfileGuid,
+ &DispatchHandle
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ BuildSmiHandlerProfileDatabase();
+}
+
+/**
+ Finds the SMI entry for the requested handler type.
+
+ @param HandlerType The type of the interrupt
+ @param Create Create a new entry if not found
+
+ @return SMI entry
+**/
+SMI_ENTRY *
+SmmCoreFindHardwareSmiEntry (
+ IN EFI_GUID *HandlerType,
+ IN BOOLEAN Create
+ )
+{
+ LIST_ENTRY *Link;
+ SMI_ENTRY *Item;
+ SMI_ENTRY *SmiEntry;
+
+ //
+ // Search the SMI entry list for the matching GUID
+ //
+ SmiEntry = NULL;
+ for (Link = mHardwareSmiEntryList.ForwardLink;
+ Link != &mHardwareSmiEntryList;
+ Link = Link->ForwardLink) {
+
+ Item = CR (Link, SMI_ENTRY, AllEntries, SMI_ENTRY_SIGNATURE);
+ if (CompareGuid (&Item->HandlerType, HandlerType)) {
+ //
+ // This is the SMI entry
+ //
+ SmiEntry = Item;
+ break;
+ }
+ }
+
+ //
+ // If the protocol entry was not found and Create is TRUE, then
+ // allocate a new entry
+ //
+ if ((SmiEntry == NULL) && Create) {
+ SmiEntry = AllocatePool (sizeof(SMI_ENTRY));
+ if (SmiEntry != NULL) {
+ //
+ // Initialize new SMI entry structure
+ //
+ SmiEntry->Signature = SMI_ENTRY_SIGNATURE;
+ CopyGuid ((VOID *)&SmiEntry->HandlerType, HandlerType);
+ InitializeListHead (&SmiEntry->SmiHandlers);
+
+ //
+ // Add it to SMI entry list
+ //
+ InsertTailList (&mHardwareSmiEntryList, &SmiEntry->AllEntries);
+ }
+ }
+ return SmiEntry;
+}
+
+/**
+ Convert EFI_SMM_USB_REGISTER_CONTEXT to SMI_HANDLER_PROFILE_USB_REGISTER_CONTEXT.
+
+ @param UsbContext A pointer to EFI_SMM_USB_REGISTER_CONTEXT
+ @param UsbContextSize The size of EFI_SMM_USB_REGISTER_CONTEXT in bytes
+ @param SmiHandlerUsbContextSize The size of SMI_HANDLER_PROFILE_USB_REGISTER_CONTEXT in bytes
+
+ @return SmiHandlerUsbContext A pointer to SMI_HANDLER_PROFILE_USB_REGISTER_CONTEXT
+**/
+SMI_HANDLER_PROFILE_USB_REGISTER_CONTEXT *
+ConvertSmiHandlerUsbContext (
+ IN EFI_SMM_USB_REGISTER_CONTEXT *UsbContext,
+ IN UINTN UsbContextSize,
+ OUT UINTN *SmiHandlerUsbContextSize
+ )
+{
+ UINTN DevicePathSize;
+ SMI_HANDLER_PROFILE_USB_REGISTER_CONTEXT *SmiHandlerUsbContext;
+
+ ASSERT (UsbContextSize == sizeof(EFI_SMM_USB_REGISTER_CONTEXT));
+
+ DevicePathSize = GetDevicePathSize (UsbContext->Device);
+ SmiHandlerUsbContext = AllocatePool (sizeof (SMI_HANDLER_PROFILE_USB_REGISTER_CONTEXT) + DevicePathSize);
+ if (SmiHandlerUsbContext == NULL) {
+ *SmiHandlerUsbContextSize = 0;
+ return NULL;
+ }
+ SmiHandlerUsbContext->Type = UsbContext->Type;
+ SmiHandlerUsbContext->DevicePathSize = (UINT32)DevicePathSize;
+ CopyMem (SmiHandlerUsbContext + 1, UsbContext->Device, DevicePathSize);
+ *SmiHandlerUsbContextSize = sizeof (SMI_HANDLER_PROFILE_USB_REGISTER_CONTEXT) + DevicePathSize;
+ return SmiHandlerUsbContext;
+}
+
+/**
+ Convert EFI_SMM_SW_REGISTER_CONTEXT to SMI_HANDLER_PROFILE_SW_REGISTER_CONTEXT.
+
+ @param SwContext A pointer to EFI_SMM_SW_REGISTER_CONTEXT
+ @param SwContextSize The size of EFI_SMM_SW_REGISTER_CONTEXT in bytes
+ @param SmiHandlerSwContextSize The size of SMI_HANDLER_PROFILE_SW_REGISTER_CONTEXT in bytes
+
+ @return SmiHandlerSwContext A pointer to SMI_HANDLER_PROFILE_SW_REGISTER_CONTEXT
+**/
+SMI_HANDLER_PROFILE_SW_REGISTER_CONTEXT *
+ConvertSmiHandlerSwContext (
+ IN EFI_SMM_SW_REGISTER_CONTEXT *SwContext,
+ IN UINTN SwContextSize,
+ OUT UINTN *SmiHandlerSwContextSize
+ )
+{
+ SMI_HANDLER_PROFILE_SW_REGISTER_CONTEXT *SmiHandlerSwContext;
+
+ ASSERT (SwContextSize == sizeof(EFI_SMM_SW_REGISTER_CONTEXT));
+
+ SmiHandlerSwContext = AllocatePool (sizeof (SMI_HANDLER_PROFILE_SW_REGISTER_CONTEXT));
+ if (SmiHandlerSwContext == NULL) {
+ *SmiHandlerSwContextSize = 0;
+ return NULL;
+ }
+ SmiHandlerSwContext->SwSmiInputValue = SwContext->SwSmiInputValue;
+ *SmiHandlerSwContextSize = sizeof (SMI_HANDLER_PROFILE_SW_REGISTER_CONTEXT);
+ return SmiHandlerSwContext;
+}
+
+/**
+ This function is called by SmmChildDispatcher module to report
+ a new SMI handler is registered, to SmmCore.
+
+ @param This The protocol instance
+ @param HandlerGuid The GUID to identify the type of the handler.
+ For the SmmChildDispatch protocol, the HandlerGuid
+ must be the GUID of SmmChildDispatch protocol.
+ @param Handler The SMI handler.
+ @param CallerAddress The address of the module who registers the SMI handler.
+ @param Context The context of the SMI handler.
+ For the SmmChildDispatch protocol, the Context
+ must match the one defined for SmmChildDispatch protocol.
+ @param ContextSize The size of the context in bytes.
+ For the SmmChildDispatch protocol, the Context
+ must match the one defined for SmmChildDispatch protocol.
+
+ @retval EFI_SUCCESS The information is recorded.
+ @retval EFI_OUT_OF_RESOURCES There is no enough resource to record the information.
+**/
+EFI_STATUS
+EFIAPI
+SmiHandlerProfileRegisterHandler (
+ IN SMI_HANDLER_PROFILE_PROTOCOL *This,
+ IN EFI_GUID *HandlerGuid,
+ IN EFI_SMM_HANDLER_ENTRY_POINT2 Handler,
+ IN PHYSICAL_ADDRESS CallerAddress,
+ IN VOID *Context, OPTIONAL
+ IN UINTN ContextSize OPTIONAL
+ )
+{
+ SMI_HANDLER *SmiHandler;
+ SMI_ENTRY *SmiEntry;
+ LIST_ENTRY *List;
+
+ if (((ContextSize == 0) && (Context != NULL)) ||
+ ((ContextSize != 0) && (Context == NULL))) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ SmiHandler = AllocateZeroPool (sizeof (SMI_HANDLER));
+ if (SmiHandler == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ SmiHandler->Signature = SMI_HANDLER_SIGNATURE;
+ SmiHandler->Handler = Handler;
+ SmiHandler->CallerAddr = (UINTN)CallerAddress;
+ SmiHandler->Context = Context;
+ SmiHandler->ContextSize = ContextSize;
+
+ if (Context != NULL) {
+ if (CompareGuid (HandlerGuid, &gEfiSmmUsbDispatch2ProtocolGuid)) {
+ SmiHandler->Context = ConvertSmiHandlerUsbContext (Context, ContextSize, &SmiHandler->ContextSize);
+ } else if (CompareGuid (HandlerGuid, &gEfiSmmSwDispatch2ProtocolGuid)) {
+ SmiHandler->Context = ConvertSmiHandlerSwContext (Context, ContextSize, &SmiHandler->ContextSize);
+ } else {
+ SmiHandler->Context = AllocateCopyPool (ContextSize, Context);
+ }
+ }
+ if (SmiHandler->Context == NULL) {
+ SmiHandler->ContextSize = 0;
+ }
+
+ SmiEntry = SmmCoreFindHardwareSmiEntry (HandlerGuid, TRUE);
+ if (SmiEntry == NULL) {
+ if (SmiHandler->Context != NULL) {
+ FreePool (SmiHandler->Context);
+ }
+ FreePool (SmiHandler);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ List = &SmiEntry->SmiHandlers;
+
+ SmiHandler->SmiEntry = SmiEntry;
+ InsertTailList (List, &SmiHandler->Link);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function is called by SmmChildDispatcher module to report
+ an existing SMI handler is unregistered, to SmmCore.
+
+ @param This The protocol instance
+ @param HandlerGuid The GUID to identify the type of the handler.
+ For the SmmChildDispatch protocol, the HandlerGuid
+ must be the GUID of SmmChildDispatch protocol.
+ @param Handler The SMI handler.
+ @param Context The context of the SMI handler.
+ If it is NOT NULL, it will be used to check what is registered.
+ @param ContextSize The size of the context in bytes.
+ If Context is NOT NULL, it will be used to check what is registered.
+
+ @retval EFI_SUCCESS The original record is removed.
+ @retval EFI_NOT_FOUND There is no record for the HandlerGuid and handler.
+**/
+EFI_STATUS
+EFIAPI
+SmiHandlerProfileUnregisterHandler (
+ IN SMI_HANDLER_PROFILE_PROTOCOL *This,
+ IN EFI_GUID *HandlerGuid,
+ IN EFI_SMM_HANDLER_ENTRY_POINT2 Handler,
+ IN VOID *Context, OPTIONAL
+ IN UINTN ContextSize OPTIONAL
+ )
+{
+ LIST_ENTRY *Link;
+ LIST_ENTRY *Head;
+ SMI_HANDLER *SmiHandler;
+ SMI_ENTRY *SmiEntry;
+ SMI_HANDLER *TargetSmiHandler;
+ VOID *SearchContext;
+ UINTN SearchContextSize;
+
+ if (((ContextSize == 0) && (Context != NULL)) ||
+ ((ContextSize != 0) && (Context == NULL))) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ SmiEntry = SmmCoreFindHardwareSmiEntry (HandlerGuid, FALSE);
+ if (SmiEntry == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ SearchContext = Context;
+ SearchContextSize = ContextSize;
+ if (Context != NULL) {
+ if (CompareGuid (HandlerGuid, &gEfiSmmUsbDispatch2ProtocolGuid)) {
+ SearchContext = ConvertSmiHandlerUsbContext (Context, ContextSize, &SearchContextSize);
+ } else if (CompareGuid (HandlerGuid, &gEfiSmmSwDispatch2ProtocolGuid)) {
+ SearchContext = ConvertSmiHandlerSwContext (Context, ContextSize, &SearchContextSize);
+ }
+ }
+
+ TargetSmiHandler = NULL;
+ Head = &SmiEntry->SmiHandlers;
+ for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) {
+ SmiHandler = CR (Link, SMI_HANDLER, Link, SMI_HANDLER_SIGNATURE);
+ if (SmiHandler->Handler == Handler) {
+ if ((SearchContext == NULL) ||
+ ((SearchContextSize == SmiHandler->ContextSize) && (CompareMem (SearchContext, SmiHandler->Context, SearchContextSize) == 0))) {
+ TargetSmiHandler = SmiHandler;
+ break;
+ }
+ }
+ }
+
+ if (SearchContext != NULL) {
+ if (CompareGuid (HandlerGuid, &gEfiSmmUsbDispatch2ProtocolGuid)) {
+ FreePool (SearchContext);
+ }
+ }
+
+ if (TargetSmiHandler == NULL) {
+ return EFI_NOT_FOUND;
+ }
+ SmiHandler = TargetSmiHandler;
+
+ RemoveEntryList (&SmiHandler->Link);
+ if (SmiHandler->Context != NULL) {
+ FreePool (SmiHandler->Context);
+ }
+ FreePool (SmiHandler);
+
+ if (IsListEmpty (&SmiEntry->SmiHandlers)) {
+ RemoveEntryList (&SmiEntry->AllEntries);
+ FreePool (SmiEntry);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Initialize SmiHandler profile feature.
+**/
+VOID
+SmmCoreInitializeSmiHandlerProfile (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ VOID *Registration;
+ EFI_HANDLE Handle;
+
+ if ((PcdGet8 (PcdSmiHandlerProfilePropertyMask) & 0x1) != 0) {
+ InsertTailList (&mRootSmiEntryList, &mRootSmiEntry.AllEntries);
+
+ Status = gSmst->SmmRegisterProtocolNotify (
+ &gEfiSmmReadyToLockProtocolGuid,
+ SmmReadyToLockInSmiHandlerProfile,
+ &Registration
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Handle = NULL;
+ Status = gSmst->SmmInstallProtocolInterface (
+ &Handle,
+ &gSmiHandlerProfileGuid,
+ EFI_NATIVE_INTERFACE,
+ &mSmiHandlerProfile
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+}
+
|