/** @file Shell application to dump SMI handler profile information. Copyright (c) 2017, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at http://opensource.org/licenses/bsd-license.php THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. **/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define PROFILE_NAME_STRING_LENGTH 64 CHAR8 mNameString[PROFILE_NAME_STRING_LENGTH + 1]; VOID *mSmiHandlerProfileDatabase; UINTN mSmiHandlerProfileDatabaseSize; /** 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++) { Print (L"%02x", (UINTN)Data[Index]); if ((Index + 1) != Size) { Print (L" "); } } } /** Get SMI handler profile database. **/ VOID GetSmiHandlerProfileDatabase( VOID ) { EFI_STATUS Status; UINTN CommSize; UINT8 *CommBuffer; EFI_SMM_COMMUNICATE_HEADER *CommHeader; SMI_HANDLER_PROFILE_PARAMETER_GET_INFO *CommGetInfo; SMI_HANDLER_PROFILE_PARAMETER_GET_DATA_BY_OFFSET *CommGetData; EFI_SMM_COMMUNICATION_PROTOCOL *SmmCommunication; UINTN MinimalSizeNeeded; EDKII_PI_SMM_COMMUNICATION_REGION_TABLE *PiSmmCommunicationRegionTable; UINT32 Index; EFI_MEMORY_DESCRIPTOR *Entry; VOID *Buffer; UINTN Size; UINTN Offset; Status = gBS->LocateProtocol(&gEfiSmmCommunicationProtocolGuid, NULL, (VOID **)&SmmCommunication); if (EFI_ERROR(Status)) { Print(L"SmiHandlerProfile: Locate SmmCommunication protocol - %r\n", Status); return ; } MinimalSizeNeeded = EFI_PAGE_SIZE; Status = EfiGetSystemConfigurationTable( &gEdkiiPiSmmCommunicationRegionTableGuid, (VOID **)&PiSmmCommunicationRegionTable ); if (EFI_ERROR(Status)) { Print(L"SmiHandlerProfile: Get PiSmmCommunicationRegionTable - %r\n", Status); return ; } ASSERT(PiSmmCommunicationRegionTable != NULL); Entry = (EFI_MEMORY_DESCRIPTOR *)(PiSmmCommunicationRegionTable + 1); Size = 0; for (Index = 0; Index < PiSmmCommunicationRegionTable->NumberOfEntries; Index++) { if (Entry->Type == EfiConventionalMemory) { Size = EFI_PAGES_TO_SIZE((UINTN)Entry->NumberOfPages); if (Size >= MinimalSizeNeeded) { break; } } Entry = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)Entry + PiSmmCommunicationRegionTable->DescriptorSize); } ASSERT(Index < PiSmmCommunicationRegionTable->NumberOfEntries); CommBuffer = (UINT8 *)(UINTN)Entry->PhysicalStart; // // Get Size // CommHeader = (EFI_SMM_COMMUNICATE_HEADER *)&CommBuffer[0]; CopyMem(&CommHeader->HeaderGuid, &gSmiHandlerProfileGuid, sizeof(gSmiHandlerProfileGuid)); CommHeader->MessageLength = sizeof(SMI_HANDLER_PROFILE_PARAMETER_GET_INFO); CommGetInfo = (SMI_HANDLER_PROFILE_PARAMETER_GET_INFO *)&CommBuffer[OFFSET_OF(EFI_SMM_COMMUNICATE_HEADER, Data)]; CommGetInfo->Header.Command = SMI_HANDLER_PROFILE_COMMAND_GET_INFO; CommGetInfo->Header.DataLength = sizeof(*CommGetInfo); CommGetInfo->Header.ReturnStatus = (UINT64)-1; CommGetInfo->DataSize = 0; CommSize = sizeof(EFI_GUID) + sizeof(UINTN) + CommHeader->MessageLength; Status = SmmCommunication->Communicate(SmmCommunication, CommBuffer, &CommSize); if (EFI_ERROR(Status)) { Print(L"SmiHandlerProfile: SmmCommunication - %r\n", Status); return ; } if (CommGetInfo->Header.ReturnStatus != 0) { Print(L"SmiHandlerProfile: GetInfo - 0x%0x\n", CommGetInfo->Header.ReturnStatus); return ; } mSmiHandlerProfileDatabaseSize = (UINTN)CommGetInfo->DataSize; // // Get Data // mSmiHandlerProfileDatabase = AllocateZeroPool(mSmiHandlerProfileDatabaseSize); if (mSmiHandlerProfileDatabase == NULL) { Status = EFI_OUT_OF_RESOURCES; Print(L"SmiHandlerProfile: AllocateZeroPool (0x%x) for dump buffer - %r\n", mSmiHandlerProfileDatabaseSize, Status); return ; } CommHeader = (EFI_SMM_COMMUNICATE_HEADER *)&CommBuffer[0]; CopyMem(&CommHeader->HeaderGuid, &gSmiHandlerProfileGuid, sizeof(gSmiHandlerProfileGuid)); CommHeader->MessageLength = sizeof(SMI_HANDLER_PROFILE_PARAMETER_GET_DATA_BY_OFFSET); CommGetData = (SMI_HANDLER_PROFILE_PARAMETER_GET_DATA_BY_OFFSET *)&CommBuffer[OFFSET_OF(EFI_SMM_COMMUNICATE_HEADER, Data)]; CommGetData->Header.Command = SMI_HANDLER_PROFILE_COMMAND_GET_DATA_BY_OFFSET; CommGetData->Header.DataLength = sizeof(*CommGetData); CommGetData->Header.ReturnStatus = (UINT64)-1; CommSize = sizeof(EFI_GUID) + sizeof(UINTN) + CommHeader->MessageLength; Buffer = (UINT8 *)CommHeader + CommSize; Size -= CommSize; CommGetData->DataBuffer = (PHYSICAL_ADDRESS)(UINTN)Buffer; CommGetData->DataOffset = 0; while (CommGetData->DataOffset < mSmiHandlerProfileDatabaseSize) { Offset = (UINTN)CommGetData->DataOffset; if (Size <= (mSmiHandlerProfileDatabaseSize - CommGetData->DataOffset)) { CommGetData->DataSize = (UINT64)Size; } else { CommGetData->DataSize = (UINT64)(mSmiHandlerProfileDatabaseSize - CommGetData->DataOffset); } Status = SmmCommunication->Communicate(SmmCommunication, CommBuffer, &CommSize); ASSERT_EFI_ERROR(Status); if (CommGetData->Header.ReturnStatus != 0) { FreePool(mSmiHandlerProfileDatabase); mSmiHandlerProfileDatabase = NULL; Print(L"SmiHandlerProfile: GetData - 0x%x\n", CommGetData->Header.ReturnStatus); return ; } CopyMem((UINT8 *)mSmiHandlerProfileDatabase + Offset, (VOID *)(UINTN)CommGetData->DataBuffer, (UINTN)CommGetData->DataSize); } DEBUG ((DEBUG_INFO, "SmiHandlerProfileSize - 0x%x\n", mSmiHandlerProfileDatabaseSize)); return ; } /** Get the file name portion of the Pdb File Name. The portion of the Pdb File Name between the last backslash and either a following period or the end of the string is copied into AsciiBuffer. The name is truncated, if necessary, to ensure that AsciiBuffer is not overrun. @param[in] PdbFileName Pdb file name. @param[out] AsciiBuffer The resultant Ascii File Name. **/ VOID GetShortPdbFileName ( IN CHAR8 *PdbFileName, OUT CHAR8 *AsciiBuffer ) { UINTN IndexPdb; // Current work location within a Pdb string. UINTN IndexBuffer; // Current work location within a Buffer string. UINTN StartIndex; UINTN EndIndex; ZeroMem (AsciiBuffer, PROFILE_NAME_STRING_LENGTH + 1); if (PdbFileName == NULL) { AsciiStrnCpyS (AsciiBuffer, PROFILE_NAME_STRING_LENGTH + 1, " ", 1); } else { StartIndex = 0; for (EndIndex = 0; PdbFileName[EndIndex] != 0; EndIndex++); for (IndexPdb = 0; PdbFileName[IndexPdb] != 0; IndexPdb++) { if ((PdbFileName[IndexPdb] == '\\') || (PdbFileName[IndexPdb] == '/')) { StartIndex = IndexPdb + 1; } if (PdbFileName[IndexPdb] == '.') { EndIndex = IndexPdb; } } IndexBuffer = 0; for (IndexPdb = StartIndex; IndexPdb < EndIndex; IndexPdb++) { AsciiBuffer[IndexBuffer] = PdbFileName[IndexPdb]; IndexBuffer++; if (IndexBuffer >= PROFILE_NAME_STRING_LENGTH) { AsciiBuffer[PROFILE_NAME_STRING_LENGTH] = 0; break; } } } } /** Get a human readable name for an image. The following methods will be tried orderly: 1. Image PDB 2. FFS UI section 3. Image GUID @param[in] ImageStruct Point to the image structure. @return The resulting Ascii name string is stored in the mNameString global array. **/ CHAR8 * GetDriverNameString ( IN SMM_CORE_IMAGE_DATABASE_STRUCTURE *ImageStruct ) { EFI_STATUS Status; CHAR16 *NameString; UINTN StringSize; if (ImageStruct == NULL) { return "???"; } // // Method 1: Get the name string from image PDB // if (ImageStruct->PdbStringOffset != 0) { GetShortPdbFileName ((CHAR8 *) ((UINTN) ImageStruct + ImageStruct->PdbStringOffset), mNameString); return mNameString; } if (!IsZeroGuid (&ImageStruct->FileGuid)) { // // Try to get the image's FFS UI section by image GUID // NameString = NULL; StringSize = 0; Status = GetSectionFromAnyFv ( &ImageStruct->FileGuid, EFI_SECTION_USER_INTERFACE, 0, (VOID **) &NameString, &StringSize ); if (!EFI_ERROR (Status)) { // // Method 2: Get the name string from FFS UI section // if (StrLen (NameString) > PROFILE_NAME_STRING_LENGTH) { NameString[PROFILE_NAME_STRING_LENGTH] = 0; } UnicodeStrToAsciiStrS (NameString, mNameString, sizeof (mNameString)); FreePool (NameString); return mNameString; } } // // Method 3: Get the name string from image GUID // AsciiSPrint (mNameString, sizeof (mNameString), "%g", &ImageStruct->FileGuid); return mNameString; } /** Get image structure from reference index. @param ImageRef the image reference index @return image structure **/ SMM_CORE_IMAGE_DATABASE_STRUCTURE * GetImageFromRef ( IN UINTN ImageRef ) { SMM_CORE_IMAGE_DATABASE_STRUCTURE *ImageStruct; ImageStruct = (VOID *)mSmiHandlerProfileDatabase; while ((UINTN)ImageStruct < (UINTN)mSmiHandlerProfileDatabase + mSmiHandlerProfileDatabaseSize) { if (ImageStruct->Header.Signature == SMM_CORE_IMAGE_DATABASE_SIGNATURE) { if (ImageStruct->ImageRef == ImageRef) { return ImageStruct; } } ImageStruct = (VOID *)((UINTN)ImageStruct + ImageStruct->Header.Length); } return NULL; } /** Dump SMM loaded image information. **/ VOID DumpSmmLoadedImage( VOID ) { SMM_CORE_IMAGE_DATABASE_STRUCTURE *ImageStruct; CHAR8 *PdbString; CHAR8 *NameString; ImageStruct = (VOID *)mSmiHandlerProfileDatabase; while ((UINTN)ImageStruct < (UINTN)mSmiHandlerProfileDatabase + mSmiHandlerProfileDatabaseSize) { if (ImageStruct->Header.Signature == SMM_CORE_IMAGE_DATABASE_SIGNATURE) { NameString = GetDriverNameString (ImageStruct); Print(L" ImageBase, ImageStruct->ImageSize); if (ImageStruct->EntryPoint != 0) { Print(L" EntryPoint=\"0x%lx\"", ImageStruct->EntryPoint); } Print(L" FvFile=\"%g\"", &ImageStruct->FileGuid); Print(L" RefId=\"0x%x\"", ImageStruct->ImageRef); Print(L">\n"); if (ImageStruct->PdbStringOffset != 0) { PdbString = (CHAR8 *)((UINTN)ImageStruct + ImageStruct->PdbStringOffset); Print(L" %a\n", PdbString); } Print(L" \n"); } ImageStruct = (VOID *)((UINTN)ImageStruct + ImageStruct->Header.Length); } return; } CHAR8 *mSxTypeString[] = { "SxS0", "SxS1", "SxS2", "SxS3", "SxS4", "SxS5", }; /** Convert SxType to a string. @param Type SxType @return SxType string **/ CHAR8 * SxTypeToString ( IN EFI_SLEEP_TYPE Type ) { if (Type >= 0 && Type <= ARRAY_SIZE(mSxTypeString)) { return mSxTypeString[Type]; } else { AsciiSPrint (mNameString, sizeof(mNameString), "0x%x", Type); return mNameString; } } CHAR8 *mSxPhaseString[] = { "SxEntry", "SxExit", }; /** Convert SxPhase to a string. @param Phase SxPhase @return SxPhase string **/ CHAR8 * SxPhaseToString ( IN EFI_SLEEP_PHASE Phase ) { if (Phase >= 0 && Phase <= ARRAY_SIZE(mSxPhaseString)) { return mSxPhaseString[Phase]; } else { AsciiSPrint (mNameString, sizeof(mNameString), "0x%x", Phase); return mNameString; } } CHAR8 *mPowerButtonPhaseString[] = { "PowerButtonEntry", "PowerButtonExit", }; /** Convert PowerButtonPhase to a string. @param Phase PowerButtonPhase @return PowerButtonPhase string **/ CHAR8 * PowerButtonPhaseToString ( IN EFI_POWER_BUTTON_PHASE Phase ) { if (Phase >= 0 && Phase <= ARRAY_SIZE(mPowerButtonPhaseString)) { return mPowerButtonPhaseString[Phase]; } else { AsciiSPrint (mNameString, sizeof(mNameString), "0x%x", Phase); return mNameString; } } CHAR8 *mStandbyButtonPhaseString[] = { "StandbyButtonEntry", "StandbyButtonExit", }; /** Convert StandbyButtonPhase to a string. @param Phase StandbyButtonPhase @return StandbyButtonPhase string **/ CHAR8 * StandbyButtonPhaseToString ( IN EFI_STANDBY_BUTTON_PHASE Phase ) { if (Phase >= 0 && Phase <= ARRAY_SIZE(mStandbyButtonPhaseString)) { return mStandbyButtonPhaseString[Phase]; } else { AsciiSPrint (mNameString, sizeof(mNameString), "0x%x", Phase); return mNameString; } } CHAR8 *mIoTrapTypeString[] = { "WriteTrap", "ReadTrap", "ReadWriteTrap", }; /** Convert IoTrapType to a string. @param Type IoTrapType @return IoTrapType string **/ CHAR8 * IoTrapTypeToString ( IN EFI_SMM_IO_TRAP_DISPATCH_TYPE Type ) { if (Type >= 0 && Type <= ARRAY_SIZE(mIoTrapTypeString)) { return mIoTrapTypeString[Type]; } else { AsciiSPrint (mNameString, sizeof(mNameString), "0x%x", Type); return mNameString; } } CHAR8 *mUsbTypeString[] = { "UsbLegacy", "UsbWake", }; /** Convert UsbType to a string. @param Type UsbType @return UsbType string **/ CHAR8 * UsbTypeToString ( IN EFI_USB_SMI_TYPE Type ) { if (Type >= 0 && Type <= ARRAY_SIZE(mUsbTypeString)) { return mUsbTypeString[Type]; } else { AsciiSPrint (mNameString, sizeof(mNameString), "0x%x", Type); return mNameString; } } /** 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)) { Print(L" SwSmi=\"0x%lx\"", ((SMI_HANDLER_PROFILE_SW_REGISTER_CONTEXT *)Context)->SwSmiInputValue); } else if (CompareGuid (HandlerType, &gEfiSmmSxDispatch2ProtocolGuid)) { Print(L" SxType=\"%a\"", SxTypeToString(((EFI_SMM_SX_REGISTER_CONTEXT *)Context)->Type)); Print(L" SxPhase=\"%a\"", SxPhaseToString(((EFI_SMM_SX_REGISTER_CONTEXT *)Context)->Phase)); } else if (CompareGuid (HandlerType, &gEfiSmmPowerButtonDispatch2ProtocolGuid)) { Print(L" PowerButtonPhase=\"%a\"", PowerButtonPhaseToString(((EFI_SMM_POWER_BUTTON_REGISTER_CONTEXT *)Context)->Phase)); } else if (CompareGuid (HandlerType, &gEfiSmmStandbyButtonDispatch2ProtocolGuid)) { Print(L" StandbyButtonPhase=\"%a\"", StandbyButtonPhaseToString(((EFI_SMM_STANDBY_BUTTON_REGISTER_CONTEXT *)Context)->Phase)); } else if (CompareGuid (HandlerType, &gEfiSmmPeriodicTimerDispatch2ProtocolGuid)) { Print(L" PeriodicTimerPeriod=\"%ld\"", ((EFI_SMM_PERIODIC_TIMER_REGISTER_CONTEXT *)Context)->Period); Print(L" PeriodicTimerSmiTickInterval=\"%ld\"", ((EFI_SMM_PERIODIC_TIMER_REGISTER_CONTEXT *)Context)->SmiTickInterval); } else if (CompareGuid (HandlerType, &gEfiSmmGpiDispatch2ProtocolGuid)) { Print(L" GpiNum=\"0x%lx\"", ((EFI_SMM_GPI_REGISTER_CONTEXT *)Context)->GpiNum); } else if (CompareGuid (HandlerType, &gEfiSmmIoTrapDispatch2ProtocolGuid)) { Print(L" IoTrapAddress=\"0x%x\"", ((EFI_SMM_IO_TRAP_REGISTER_CONTEXT *)Context)->Address); Print(L" IoTrapLength=\"0x%x\"", ((EFI_SMM_IO_TRAP_REGISTER_CONTEXT *)Context)->Length); Print(L" IoTrapType=\"%a\"", IoTrapTypeToString(((EFI_SMM_IO_TRAP_REGISTER_CONTEXT *)Context)->Type)); } else if (CompareGuid (HandlerType, &gEfiSmmUsbDispatch2ProtocolGuid)) { Print(L" UsbType=\"0x%x\"", UsbTypeToString(((SMI_HANDLER_PROFILE_USB_REGISTER_CONTEXT *)Context)->Type)); Str = ConvertDevicePathToText((EFI_DEVICE_PATH_PROTOCOL *)(((SMI_HANDLER_PROFILE_USB_REGISTER_CONTEXT *)Context) + 1), TRUE, TRUE); Print(L" UsbDevicePath=\"%s\"", Str); if (Str != NULL) { FreePool (Str); } } else { Print(L" Context=\""); InternalDumpData (Context, ContextSize); Print(L"\""); } } /** Dump SMI handler in HandlerCategory. @param HandlerCategory SMI handler category **/ VOID DumpSmiHandler( IN UINT32 HandlerCategory ) { SMM_CORE_SMI_DATABASE_STRUCTURE *SmiStruct; SMM_CORE_SMI_HANDLER_STRUCTURE *SmiHandlerStruct; UINTN Index; SMM_CORE_IMAGE_DATABASE_STRUCTURE *ImageStruct; CHAR8 *NameString; SmiStruct = (VOID *)mSmiHandlerProfileDatabase; while ((UINTN)SmiStruct < (UINTN)mSmiHandlerProfileDatabase + mSmiHandlerProfileDatabaseSize) { if ((SmiStruct->Header.Signature == SMM_CORE_SMI_DATABASE_SIGNATURE) && (SmiStruct->HandlerCategory == HandlerCategory)) { SmiHandlerStruct = (VOID *)(SmiStruct + 1); Print(L" HandlerType)) { Print(L" HandlerType=\"%g\"", &SmiStruct->HandlerType); } Print(L">\n"); for (Index = 0; Index < SmiStruct->HandlerCount; Index++) { Print(L" ContextBufferSize != 0) { DumpSmiChildContext (&SmiStruct->HandlerType, (UINT8 *)SmiHandlerStruct + SmiHandlerStruct->ContextBufferOffset, SmiHandlerStruct->ContextBufferSize); } Print(L">\n"); ImageStruct = GetImageFromRef((UINTN)SmiHandlerStruct->ImageRef); NameString = GetDriverNameString (ImageStruct); Print(L" \n", SmiHandlerStruct->ImageRef, NameString); if ((ImageStruct != NULL) && (ImageStruct->PdbStringOffset != 0)) { Print(L" %a\n", (UINT8 *)ImageStruct + ImageStruct->PdbStringOffset); } Print(L" \n"); Print(L" \n", SmiHandlerStruct->Handler); if (ImageStruct != NULL) { Print(L" 0x%x\n", (UINTN) (SmiHandlerStruct->Handler - ImageStruct->ImageBase)); } Print(L" \n", SmiHandlerStruct->Handler); Print(L" \n", SmiHandlerStruct->CallerAddr); if (ImageStruct != NULL) { Print(L" 0x%x\n", (UINTN) (SmiHandlerStruct->CallerAddr - ImageStruct->ImageBase)); } Print(L" \n", SmiHandlerStruct->Handler); SmiHandlerStruct = (VOID *)((UINTN)SmiHandlerStruct + SmiHandlerStruct->Length); Print(L" \n"); } Print(L" \n"); } SmiStruct = (VOID *)((UINTN)SmiStruct + SmiStruct->Header.Length); } return; } /** The Entry Point for SMI handler profile info application. @param ImageHandle The firmware allocated handle for the EFI image. @param SystemTable A pointer to the EFI System Table. @retval EFI_SUCCESS The entry point is executed successfully. @retval Other Some error occurred when executing this entry point. **/ EFI_STATUS EFIAPI SmiHandlerProfileInfoEntrypoint ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { GetSmiHandlerProfileDatabase(); if (mSmiHandlerProfileDatabase == NULL) { return EFI_SUCCESS; } // // Dump all image // Print(L"\n"); Print(L"\n"); Print(L"\n"); Print(L" \n"); DumpSmmLoadedImage(); Print(L"\n\n"); // // Dump SMI Handler // Print(L"\n"); Print(L" \n\n"); Print(L" \n"); Print(L" \n"); DumpSmiHandler(SmmCoreSmiHandlerCategoryRootHandler); Print(L" \n\n"); Print(L" \n"); Print(L" \n"); DumpSmiHandler(SmmCoreSmiHandlerCategoryGuidHandler); Print(L" \n\n"); Print(L" \n"); Print(L" \n"); DumpSmiHandler(SmmCoreSmiHandlerCategoryHardwareHandler); Print(L" \n\n"); Print(L"\n"); Print(L"\n"); if (mSmiHandlerProfileDatabase != NULL) { FreePool(mSmiHandlerProfileDatabase); } return EFI_SUCCESS; }