X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=blobdiff_plain;f=ShellPkg%2FDynamicCommand%2FDpDynamicCommand%2FDp.c;fp=ShellPkg%2FDynamicCommand%2FDpDynamicCommand%2FDp.c;h=fafc64fe2d950902936f91e396798e8ece8e9922;hp=3ecc753d0cf7313c8b5fb79fcfcadc42848eea38;hb=115eae650bfd2be2c2bc37360f4a755065e774c4;hpb=718a937ed963697527b24b4949d716cb694eda75 diff --git a/ShellPkg/DynamicCommand/DpDynamicCommand/Dp.c b/ShellPkg/DynamicCommand/DpDynamicCommand/Dp.c index 3ecc753d0c..fafc64fe2d 100644 --- a/ShellPkg/DynamicCommand/DpDynamicCommand/Dp.c +++ b/ShellPkg/DynamicCommand/DpDynamicCommand/Dp.c @@ -13,7 +13,7 @@ Dp uses this information to group records in different ways. It also uses timer information to calculate elapsed time for each measurement. - Copyright (c) 2009 - 2017, Intel Corporation. All rights reserved. + Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved. (C) Copyright 2015-2016 Hewlett Packard Enterprise Development LP
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License @@ -24,13 +24,34 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. **/ -#include "PerformanceTokens.h" #include "Dp.h" #include "Literals.h" #include "DpInternal.h" +#pragma pack(1) + +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 Entry; +} RSDT_TABLE; + +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT64 Entry; +} XSDT_TABLE; + +#pragma pack() + EFI_HANDLE mDpHiiHandle; +typedef struct { + EFI_HANDLE Handle; + EFI_GUID ModuleGuid; +} HANDLE_GUID_MAP; + +HANDLE_GUID_MAP *mCacheHandleGuidTable; +UINTN mCachePairCount = 0; + // /// Module-Global Variables ///@{ @@ -38,11 +59,14 @@ CHAR16 mGaugeString[DP_GAUGE_STRING_LENGTH + 1]; CHAR16 mUnicodeToken[DXE_PERFORMANCE_STRING_SIZE]; UINT64 mInterestThreshold; BOOLEAN mShowId = FALSE; +UINT8 *mBootPerformanceTable; +UINTN mBootPerformanceTableSize; +BOOLEAN mPeiPhase = FALSE; +BOOLEAN mDxePhase = FALSE; PERF_SUMMARY_DATA SummaryData = { 0 }; ///< Create the SummaryData structure and init. to ZERO. - -/// Timer Specific Information. -TIMER_INFO TimerInfo; +MEASUREMENT_RECORD *mMeasurementList = NULL; +UINTN mMeasurementNum = 0; /// Items for which to gather cumulative statistics. PERF_CUM_DATA CumData[] = { @@ -99,6 +123,536 @@ DumpStatistics( void ) SHELL_FREE_NON_NULL (StringPtrUnknown); } +/** + This function scan ACPI table in RSDT. + + @param Rsdt ACPI RSDT + @param Signature ACPI table signature + + @return ACPI table +**/ +VOID * +ScanTableInRSDT ( + IN RSDT_TABLE *Rsdt, + IN UINT32 Signature + ) +{ + UINTN Index; + UINT32 EntryCount; + UINT32 *EntryPtr; + EFI_ACPI_DESCRIPTION_HEADER *Table; + + EntryCount = (Rsdt->Header.Length - sizeof (EFI_ACPI_DESCRIPTION_HEADER)) / sizeof(UINT32); + + EntryPtr = &Rsdt->Entry; + for (Index = 0; Index < EntryCount; Index ++, EntryPtr ++) { + Table = (EFI_ACPI_DESCRIPTION_HEADER*)((UINTN)(*EntryPtr)); + if (Table->Signature == Signature) { + return Table; + } + } + + return NULL; +} + +/** + This function scan ACPI table in XSDT. + + @param Xsdt ACPI XSDT + @param Signature ACPI table signature + + @return ACPI table +**/ +VOID * +ScanTableInXSDT ( + IN XSDT_TABLE *Xsdt, + IN UINT32 Signature + ) +{ + UINTN Index; + UINT32 EntryCount; + UINT64 EntryPtr; + UINTN BasePtr; + EFI_ACPI_DESCRIPTION_HEADER *Table; + + EntryCount = (Xsdt->Header.Length - sizeof (EFI_ACPI_DESCRIPTION_HEADER)) / sizeof(UINT64); + + BasePtr = (UINTN)(&(Xsdt->Entry)); + for (Index = 0; Index < EntryCount; Index ++) { + CopyMem (&EntryPtr, (VOID *)(BasePtr + Index * sizeof(UINT64)), sizeof(UINT64)); + Table = (EFI_ACPI_DESCRIPTION_HEADER*)((UINTN)(EntryPtr)); + if (Table->Signature == Signature) { + return Table; + } + } + + return NULL; +} + +/** + This function scan ACPI table in RSDP. + + @param Rsdp ACPI RSDP + @param Signature ACPI table signature + + @return ACPI table +**/ +VOID * +FindAcpiPtr ( + IN EFI_ACPI_5_0_ROOT_SYSTEM_DESCRIPTION_POINTER *Rsdp, + IN UINT32 Signature + ) +{ + EFI_ACPI_DESCRIPTION_HEADER *AcpiTable; + RSDT_TABLE *Rsdt; + XSDT_TABLE *Xsdt; + + AcpiTable = NULL; + + // + // Check ACPI2.0 table + // + Rsdt = (RSDT_TABLE *)(UINTN)Rsdp->RsdtAddress; + Xsdt = NULL; + if ((Rsdp->Revision >= 2) && (Rsdp->XsdtAddress < (UINT64)(UINTN)-1)) { + Xsdt = (XSDT_TABLE *)(UINTN)Rsdp->XsdtAddress; + } + // + // Check Xsdt + // + if (Xsdt != NULL) { + AcpiTable = ScanTableInXSDT (Xsdt, Signature); + } + // + // Check Rsdt + // + if ((AcpiTable == NULL) && (Rsdt != NULL)) { + AcpiTable = ScanTableInRSDT (Rsdt, Signature); + } + + return AcpiTable; +} + +/** + Get Boot performance table form Acpi table. + +**/ +EFI_STATUS +GetBootPerformanceTable ( + ) +{ + EFI_STATUS Status; + VOID *AcpiTable; + FIRMWARE_PERFORMANCE_TABLE *FirmwarePerformanceTable; + + AcpiTable = NULL; + + Status = EfiGetSystemConfigurationTable ( + &gEfiAcpi20TableGuid, + &AcpiTable + ); + if (EFI_ERROR (Status)) { + Status = EfiGetSystemConfigurationTable ( + &gEfiAcpi10TableGuid, + &AcpiTable + ); + } + if (EFI_ERROR(Status)) { + return Status; + } + + FirmwarePerformanceTable = FindAcpiPtr ( + (EFI_ACPI_5_0_ROOT_SYSTEM_DESCRIPTION_POINTER *)AcpiTable, + EFI_ACPI_5_0_FIRMWARE_PERFORMANCE_DATA_TABLE_SIGNATURE + ); + if (FirmwarePerformanceTable == NULL) { + return EFI_NOT_FOUND; + } + + mBootPerformanceTable = (UINT8*) (UINTN)FirmwarePerformanceTable->BootPointerRecord.BootPerformanceTablePointer; + mBootPerformanceTableSize = ((BOOT_PERFORMANCE_TABLE *) mBootPerformanceTable)->Header.Length; + + return EFI_SUCCESS; +} + +/** + Get Handle form Module Guid. + + @param ModuleGuid Module Guid. + @param Handle The handle to be returned. + +**/ +VOID +GetHandleFormModuleGuid ( + IN EFI_GUID *ModuleGuid, + IN OUT EFI_HANDLE *Handle + ) +{ + UINTN Index; + + if (IsZeroGuid (ModuleGuid)) { + *Handle = NULL; + } + // + // Try to get the Handle form the caached array. + // + for (Index = 0; Index < mCachePairCount; Index++) { + if (CompareGuid (ModuleGuid, &mCacheHandleGuidTable[Index].ModuleGuid)) { + *Handle = mCacheHandleGuidTable[Index].Handle; + break; + } + } + if (Index >= mCachePairCount) { + *Handle = NULL; + } +} + +/** +Cache the GUID and handle mapping pairs. In order to save time for searching. + +**/ +EFI_STATUS +BuildCachedGuidHandleTable ( + VOID + ) +{ + EFI_STATUS Status; + EFI_HANDLE *HandleBuffer; + UINTN HandleCount; + UINTN Index; + EFI_LOADED_IMAGE_PROTOCOL *LoadedImage; + EFI_DRIVER_BINDING_PROTOCOL *DriverBinding; + EFI_GUID *TempGuid; + MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FvFilePath; + + Status = gBS->LocateHandleBuffer (AllHandles, NULL, NULL, &HandleCount, &HandleBuffer); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_HANDLES_ERROR), mDpHiiHandle, Status); + return Status; + } + + mCacheHandleGuidTable = AllocateZeroPool (HandleCount * sizeof (HANDLE_GUID_MAP)); + if (mCacheHandleGuidTable == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + for (Index = 0; Index < HandleCount; Index++) { + // + // Try Handle as ImageHandle. + // + Status = gBS->HandleProtocol ( + HandleBuffer[Index], + &gEfiLoadedImageProtocolGuid, + (VOID**) &LoadedImage + ); + if (EFI_ERROR (Status)) { + // + // Try Handle as Controller Handle + // + Status = gBS->OpenProtocol ( + HandleBuffer[Index], + &gEfiDriverBindingProtocolGuid, + (VOID **) &DriverBinding, + NULL, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (!EFI_ERROR (Status)) { + // + // Get Image protocol from ImageHandle + // + Status = gBS->HandleProtocol ( + DriverBinding->ImageHandle, + &gEfiLoadedImageProtocolGuid, + (VOID**) &LoadedImage + ); + } + } + + if (!EFI_ERROR (Status) && LoadedImage != NULL) { + // + // Get Module Guid from DevicePath. + // + if (LoadedImage->FilePath != NULL && + LoadedImage->FilePath->Type == MEDIA_DEVICE_PATH && + LoadedImage->FilePath->SubType == MEDIA_PIWG_FW_FILE_DP + ) { + FvFilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) LoadedImage->FilePath; + TempGuid = &FvFilePath->FvFileName; + + mCacheHandleGuidTable[mCachePairCount].Handle = HandleBuffer[Index]; + CopyGuid (&mCacheHandleGuidTable[mCachePairCount].ModuleGuid, TempGuid); + mCachePairCount ++; + } + } + } + if (HandleBuffer != NULL) { + FreePool (HandleBuffer); + HandleBuffer = NULL; + } + return Status; +} + +/** + Get Measurement form Fpdt records. + + @param RecordHeader Pointer to the start record. + @param IsStart Is start record or End record. + @param Measurement Pointer to the measurement which need to be filled. + +**/ +VOID +GetMeasurementInfo ( + IN EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *RecordHeader, + IN BOOLEAN IsStart, + IN OUT MEASUREMENT_RECORD *Measurement + ) +{ + VOID *ModuleGuid; + EFI_HANDLE StartHandle; + + switch (RecordHeader->Type) { + case FPDT_GUID_EVENT_TYPE: + ModuleGuid = &(((FPDT_GUID_EVENT_RECORD *)RecordHeader)->Guid); + Measurement->Identifier = ((UINT32)((FPDT_GUID_EVENT_RECORD *)RecordHeader)->ProgressID); + if (IsStart) { + Measurement->StartTimeStamp = ((FPDT_GUID_EVENT_RECORD *)RecordHeader)->Timestamp; + } else { + Measurement->EndTimeStamp = ((FPDT_GUID_EVENT_RECORD *)RecordHeader)->Timestamp; + } + switch (Measurement->Identifier) { + case MODULE_START_ID: + case MODULE_END_ID: + if (mPeiPhase) { + Measurement->Token = ALit_PEIM; + Measurement->Module = ALit_PEIM; + } else if (mDxePhase) { + Measurement->Token = ALit_START_IMAGE; + Measurement->Module = ALit_START_IMAGE; + } + break; + default: + ASSERT(FALSE); + } + + if (AsciiStrCmp (Measurement->Token, ALit_PEIM) == 0) { + Measurement->Handle = &(((FPDT_GUID_EVENT_RECORD *)RecordHeader)->Guid); + } else { + GetHandleFormModuleGuid(ModuleGuid, &StartHandle); + Measurement->Handle = StartHandle; + } + break; + + case FPDT_DYNAMIC_STRING_EVENT_TYPE: + ModuleGuid = &(((FPDT_DYNAMIC_STRING_EVENT_RECORD *)RecordHeader)->Guid); + Measurement->Identifier = ((UINT32)((FPDT_DYNAMIC_STRING_EVENT_RECORD *)RecordHeader)->ProgressID); + if (IsStart) { + Measurement->StartTimeStamp = ((FPDT_DYNAMIC_STRING_EVENT_RECORD *)RecordHeader)->Timestamp; + } else { + Measurement->EndTimeStamp = ((FPDT_DYNAMIC_STRING_EVENT_RECORD *)RecordHeader)->Timestamp; + } + switch (Measurement->Identifier) { + case MODULE_START_ID: + case MODULE_END_ID: + if (mPeiPhase) { + Measurement->Token = ALit_PEIM; + } else if (mDxePhase) { + Measurement->Token = ALit_START_IMAGE; + } + break; + + case MODULE_LOADIMAGE_START_ID: + case MODULE_LOADIMAGE_END_ID: + Measurement->Token = ALit_LOAD_IMAGE; + break; + + case MODULE_DB_START_ID: + case MODULE_DB_END_ID: + Measurement->Token = ALit_DB_START; + break; + + case MODULE_DB_SUPPORT_START_ID: + case MODULE_DB_SUPPORT_END_ID: + Measurement->Token = ALit_DB_SUPPORT; + break; + + case MODULE_DB_STOP_START_ID: + case MODULE_DB_STOP_END_ID: + Measurement->Token = ALit_DB_STOP; + break; + + default: + Measurement->Token = ((FPDT_DYNAMIC_STRING_EVENT_RECORD *)RecordHeader)->String; + break; + } + + Measurement->Module = ((FPDT_DYNAMIC_STRING_EVENT_RECORD *)RecordHeader)->String; + + if (AsciiStrCmp (Measurement->Token, ALit_PEIM) == 0) { + Measurement->Handle = &(((FPDT_DYNAMIC_STRING_EVENT_RECORD *)RecordHeader)->Guid); + } else { + GetHandleFormModuleGuid(ModuleGuid, &StartHandle); + Measurement->Handle = StartHandle; + } + break; + + case FPDT_GUID_QWORD_EVENT_TYPE: + ModuleGuid = &(((FPDT_GUID_QWORD_EVENT_RECORD *)RecordHeader)->Guid); + Measurement->Identifier = ((UINT32)((FPDT_GUID_QWORD_EVENT_RECORD *)RecordHeader)->ProgressID); + if (IsStart) { + Measurement->StartTimeStamp = ((FPDT_GUID_QWORD_EVENT_RECORD *)RecordHeader)->Timestamp; + } else { + Measurement->EndTimeStamp = ((FPDT_GUID_QWORD_EVENT_RECORD *)RecordHeader)->Timestamp; + } + switch (Measurement->Identifier) { + case MODULE_DB_START_ID: + Measurement->Token = ALit_DB_START; + Measurement->Module = ALit_DB_START; + break; + + case MODULE_DB_SUPPORT_START_ID: + case MODULE_DB_SUPPORT_END_ID: + Measurement->Token = ALit_DB_SUPPORT; + Measurement->Module = ALit_DB_SUPPORT; + break; + + case MODULE_DB_STOP_START_ID: + case MODULE_DB_STOP_END_ID: + Measurement->Token = ALit_DB_STOP; + Measurement->Module = ALit_DB_STOP; + break; + + case MODULE_LOADIMAGE_START_ID: + case MODULE_LOADIMAGE_END_ID: + Measurement->Token = ALit_LOAD_IMAGE; + Measurement->Module = ALit_LOAD_IMAGE; + break; + + default: + ASSERT(FALSE); + } + GetHandleFormModuleGuid(ModuleGuid, &StartHandle); + Measurement->Handle = StartHandle; + break; + + case FPDT_GUID_QWORD_STRING_EVENT_TYPE: + ModuleGuid = &(((FPDT_GUID_QWORD_STRING_EVENT_RECORD *)RecordHeader)->Guid); + Measurement->Identifier = ((UINT32)((FPDT_GUID_QWORD_STRING_EVENT_RECORD *)RecordHeader)->ProgressID); + if (IsStart) { + Measurement->StartTimeStamp = ((FPDT_GUID_QWORD_STRING_EVENT_RECORD*)RecordHeader)->Timestamp; + } else { + Measurement->EndTimeStamp = ((FPDT_GUID_QWORD_STRING_EVENT_RECORD *)RecordHeader)->Timestamp; + } + // + // Currently only "DB:Start:" end record with FPDT_GUID_QWORD_STRING_EVENT_TYPE. + // + switch (Measurement->Identifier) { + case MODULE_DB_END_ID: + Measurement->Token = ALit_DB_START; + Measurement->Module = ALit_DB_START; + break; + default: + ASSERT(FALSE); + } + GetHandleFormModuleGuid(ModuleGuid, &StartHandle); + Measurement->Handle = StartHandle; + break; + + default: + break; + } +} + +/** + Search the start measurement in the mMeasurementList for the end measurement. + + @param EndMeasureMent Measurement for end record. + +**/ +VOID +SearchMeasurement ( + IN MEASUREMENT_RECORD *EndMeasureMent + ) +{ + INTN Index; + + for (Index = mMeasurementNum - 1; Index >= 0; Index--) { + if (AsciiStrCmp (EndMeasureMent->Token, ALit_PEIM) == 0) { + if (mMeasurementList[Index].EndTimeStamp == 0 && EndMeasureMent->Handle!= NULL && mMeasurementList[Index].Handle != NULL&& + CompareGuid(mMeasurementList[Index].Handle, EndMeasureMent->Handle) && + (AsciiStrCmp (mMeasurementList[Index].Token, EndMeasureMent->Token) == 0) && + (AsciiStrCmp (mMeasurementList[Index].Module, EndMeasureMent->Module) == 0)) { + mMeasurementList[Index].EndTimeStamp = EndMeasureMent->EndTimeStamp; + break; + } + } else { + if (mMeasurementList[Index].EndTimeStamp == 0 && mMeasurementList[Index].Handle == EndMeasureMent->Handle && + (AsciiStrCmp (mMeasurementList[Index].Token, EndMeasureMent->Token) == 0) && + (AsciiStrCmp (mMeasurementList[Index].Module, EndMeasureMent->Module) == 0)) { + mMeasurementList[Index].EndTimeStamp = EndMeasureMent->EndTimeStamp; + break; + } + } + } +} + +/** + Generate the measure record array. + +**/ +EFI_STATUS +BuildMeasurementList ( + ) +{ + EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *RecordHeader; + UINT8 *PerformanceTablePtr; + UINT16 StartProgressId; + UINTN TableLength; + UINT8 *StartRecordEvent; + MEASUREMENT_RECORD MeasureMent; + + mMeasurementList = AllocateZeroPool (mBootPerformanceTableSize); + if (mMeasurementList == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + TableLength = sizeof (BOOT_PERFORMANCE_TABLE); + PerformanceTablePtr = (mBootPerformanceTable + TableLength); + + while (TableLength < mBootPerformanceTableSize) { + RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER*) PerformanceTablePtr; + StartRecordEvent = (UINT8 *)RecordHeader; + StartProgressId = ((FPDT_GUID_EVENT_RECORD *)StartRecordEvent)->ProgressID; + + // + // If the record is the start record, fill the info to the measurement in the mMeasurementList. + // If the record is the end record, find the related start measurement in the mMeasurementList and fill the EndTimeStamp. + // + if (((StartProgressId >= PERF_EVENTSIGNAL_START_ID && ((StartProgressId & 0x000F) == 0)) || + (StartProgressId < PERF_EVENTSIGNAL_START_ID && ((StartProgressId & 0x0001) != 0)))) { + // + // Since PEIM and StartImage has same Type and ID when PCD PcdEdkiiFpdtStringRecordEnableOnly = FALSE + // So we need to identify these two kinds of record through different phase. + // + if (AsciiStrCmp (((FPDT_DYNAMIC_STRING_EVENT_RECORD *)StartRecordEvent)->String, ALit_PEI) == 0) { + mPeiPhase = TRUE; + } else if (AsciiStrCmp (((FPDT_DYNAMIC_STRING_EVENT_RECORD *)StartRecordEvent)->String, ALit_DXE) == 0) { + mDxePhase = TRUE; + mPeiPhase = FALSE; + } + // Get measurement info form the start record to the mMeasurementList. + GetMeasurementInfo (RecordHeader, TRUE, &(mMeasurementList[mMeasurementNum])); + mMeasurementNum ++; + } else { + GetMeasurementInfo (RecordHeader, FALSE, &MeasureMent); + SearchMeasurement (&MeasureMent); + } + TableLength += RecordHeader->Length; + PerformanceTablePtr += RecordHeader->Length; + } + return EFI_SUCCESS; +} + /** Initialize the cumulative data. @@ -155,6 +709,7 @@ RunDp ( PERF_CUM_DATA *CustomCumulativeData; UINTN NameSize; SHELL_STATUS ShellStatus; + TIMER_INFO TimerInfo; StringPtr = NULL; SummaryMode = FALSE; @@ -174,6 +729,36 @@ RunDp ( Status = ShellInitialize(); ASSERT_EFI_ERROR(Status); + // + // DP dump performance data by parsing FPDT table in ACPI table. + // Folloing 3 steps are to get the measurement form the FPDT table. + // + + // + //1. Get FPDT from ACPI table. + // + Status = GetBootPerformanceTable (); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_GET_BOOT_PERFORMANCE_TABLE_FAIL), mDpHiiHandle); + return Status; + } + + // + //2. Cache the ModuleGuid and hanlde mapping table. + // + Status = BuildCachedGuidHandleTable(); + if (EFI_ERROR (Status)) { + return Status; + } + + // + //3. Build the measurement array form the FPDT records. + // + Status = BuildMeasurementList (); + if (EFI_ERROR(Status)) { + return Status; + } + // // Process Command Line arguments // @@ -267,11 +852,9 @@ RunDp ( } TimerInfo.Frequency = (UINT32)DivU64x32 (PerformanceProperty->Frequency, 1000); - TimerInfo.StartCount = PerformanceProperty->TimerStartValue; - TimerInfo.EndCount = PerformanceProperty->TimerEndValue; - - // Determine in which direction the performance counter counts. - TimerInfo.CountUp = (BOOLEAN) (TimerInfo.EndCount >= TimerInfo.StartCount); + TimerInfo.StartCount = 0; + TimerInfo.EndCount = 0xFFFF; + TimerInfo.CountUp = TRUE; // // Print header @@ -385,6 +968,12 @@ Done: } SHELL_FREE_NON_NULL (CustomCumulativeData); + SHELL_FREE_NON_NULL (mMeasurementList); + + SHELL_FREE_NON_NULL (mCacheHandleGuidTable); + + mMeasurementNum = 0; + mCachePairCount = 0; return ShellStatus; }