| /** @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); | |
| } | |
| } |