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