summaryrefslogtreecommitdiffstats
path: root/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand')
-rw-r--r--src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/Dp.c966
-rw-r--r--src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/Dp.h140
-rw-r--r--src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/Dp.uni128
-rw-r--r--src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/DpApp.c47
-rw-r--r--src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/DpApp.inf64
-rw-r--r--src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/DpDynamicCommand.c125
-rw-r--r--src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/DpDynamicCommand.inf68
-rw-r--r--src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/DpInternal.h315
-rw-r--r--src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/DpTrace.c904
-rw-r--r--src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/DpUtilities.c422
-rw-r--r--src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/Literals.c22
-rw-r--r--src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/Literals.h26
12 files changed, 3227 insertions, 0 deletions
diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/Dp.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/Dp.c
new file mode 100644
index 00000000..8ebe5183
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/Dp.c
@@ -0,0 +1,966 @@
+/** @file
+ Shell command for Displaying Performance Metrics.
+
+ The Dp command reads performance data and presents it in several
+ different formats depending upon the needs of the user. Both
+ Trace and Measured Profiling information is processed and presented.
+
+ Dp uses the "PerformanceLib" to read the measurement records.
+ The "TimerLib" provides information about the timer, such as frequency,
+ beginning, and ending counter values.
+ Measurement records contain identifying information (Handle, Token, Module)
+ and start and end time values.
+ 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 - 2018, Intel Corporation. All rights reserved.
+ (C) Copyright 2015-2016 Hewlett Packard Enterprise Development LP<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#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_HII_HANDLE mDpHiiHandle;
+
+typedef struct {
+ EFI_HANDLE Handle;
+ EFI_GUID ModuleGuid;
+} HANDLE_GUID_MAP;
+
+HANDLE_GUID_MAP *mCacheHandleGuidTable;
+UINTN mCachePairCount = 0;
+
+//
+/// Module-Global Variables
+///@{
+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.
+MEASUREMENT_RECORD *mMeasurementList = NULL;
+UINTN mMeasurementNum = 0;
+
+/// Items for which to gather cumulative statistics.
+PERF_CUM_DATA CumData[] = {
+ PERF_INIT_CUM_DATA (LOAD_IMAGE_TOK),
+ PERF_INIT_CUM_DATA (START_IMAGE_TOK),
+ PERF_INIT_CUM_DATA (DRIVERBINDING_START_TOK),
+ PERF_INIT_CUM_DATA (DRIVERBINDING_SUPPORT_TOK),
+ PERF_INIT_CUM_DATA (DRIVERBINDING_STOP_TOK)
+};
+
+/// Number of items for which we are gathering cumulative statistics.
+UINT32 const NumCum = sizeof(CumData) / sizeof(PERF_CUM_DATA);
+
+STATIC CONST SHELL_PARAM_ITEM ParamList[] = {
+ {L"-v", TypeFlag}, // -v Verbose Mode
+ {L"-A", TypeFlag}, // -A All, Cooked
+ {L"-R", TypeFlag}, // -R RAW All
+ {L"-s", TypeFlag}, // -s Summary
+ {L"-x", TypeFlag}, // -x eXclude Cumulative Items
+ {L"-i", TypeFlag}, // -i Display Identifier
+ {L"-c", TypeValue}, // -c Display cumulative data.
+ {L"-n", TypeValue}, // -n # Number of records to display for A and R
+ {L"-t", TypeValue}, // -t # Threshold of interest
+ {NULL, TypeMax}
+ };
+
+///@}
+
+/**
+ Display the trailing Verbose information.
+**/
+VOID
+DumpStatistics( void )
+{
+ EFI_STRING StringPtr;
+ EFI_STRING StringPtrUnknown;
+ StringPtr = HiiGetString (mDpHiiHandle, STRING_TOKEN (STR_DP_SECTION_STATISTICS), NULL);
+ StringPtrUnknown = HiiGetString (mDpHiiHandle, STRING_TOKEN (STR_ALIT_UNKNOWN), NULL);
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_SECTION_HEADER), mDpHiiHandle,
+ (StringPtr == NULL) ? StringPtrUnknown : StringPtr);
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_STATS_NUMTRACE), mDpHiiHandle, SummaryData.NumTrace);
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_STATS_NUMINCOMPLETE), mDpHiiHandle, SummaryData.NumIncomplete);
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_STATS_NUMPHASES), mDpHiiHandle, SummaryData.NumSummary);
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_STATS_NUMHANDLES), mDpHiiHandle, SummaryData.NumHandles, SummaryData.NumTrace - SummaryData.NumHandles);
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_STATS_NUMPEIMS), mDpHiiHandle, SummaryData.NumPEIMs);
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_STATS_NUMGLOBALS), mDpHiiHandle, SummaryData.NumGlobal);
+ SHELL_FREE_NON_NULL (StringPtr);
+ SHELL_FREE_NON_NULL (StringPtrUnknown);
+}
+
+/**
+ Get Boot performance table form Acpi table.
+
+**/
+EFI_STATUS
+GetBootPerformanceTable (
+ )
+{
+ FIRMWARE_PERFORMANCE_TABLE *FirmwarePerformanceTable;
+
+ FirmwarePerformanceTable = (FIRMWARE_PERFORMANCE_TABLE *) EfiLocateFirstAcpiTable (
+ EFI_ACPI_5_0_FIRMWARE_PERFORMANCE_DATA_TABLE_SIGNATURE
+ );
+ if (FirmwarePerformanceTable == NULL) {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_GET_ACPI_FPDT_FAIL), mDpHiiHandle);
+ 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 from the cached 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 EFI_SUCCESS;
+}
+
+/**
+ 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 (Measurement->Token != NULL && AsciiStrCmp (Measurement->Token, ALit_PEIM) == 0) {
+ Measurement->Handle = &(((FPDT_DYNAMIC_STRING_EVENT_RECORD *)RecordHeader)->Guid);
+ } else {
+ GetHandleFormModuleGuid(ModuleGuid, &StartHandle);
+ Measurement->Handle = StartHandle;
+ //
+ // When no perf entry to record the PEI and DXE phase,
+ // For start image, we need detect the PEIM and non PEIM here.
+ //
+ if (Measurement->Token == NULL) {
+ if (StartHandle == NULL && !IsZeroGuid (ModuleGuid)) {
+ Measurement->Token = ALit_PEIM;
+ Measurement->Module = ALit_PEIM;
+ Measurement->Handle = ModuleGuid;
+ } else {
+ Measurement->Token = ALit_START_IMAGE;
+ Measurement->Module = ALit_START_IMAGE;
+ }
+ }
+ }
+ 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 (Measurement->Token != NULL && AsciiStrCmp (Measurement->Token, ALit_PEIM) == 0) {
+ Measurement->Handle = &(((FPDT_DYNAMIC_STRING_EVENT_RECORD *)RecordHeader)->Guid);
+ } else {
+ GetHandleFormModuleGuid(ModuleGuid, &StartHandle);
+ Measurement->Handle = StartHandle;
+ //
+ // When no perf entry to record the PEI and DXE phase,
+ // For start image, we need detect the PEIM and non PEIM here.
+ //
+ if (Measurement->Token == NULL && (Measurement->Identifier == MODULE_START_ID || Measurement->Identifier == MODULE_END_ID)) {
+ if (StartHandle == NULL && !IsZeroGuid (ModuleGuid)) {
+ Measurement->Token = ALit_PEIM;
+ Measurement->Handle = ModuleGuid;
+ } else {
+ Measurement->Token = ALit_START_IMAGE;
+ }
+ }
+ }
+ 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;
+
+ case FPDT_DUAL_GUID_STRING_EVENT_TYPE:
+ ModuleGuid = &(((FPDT_DUAL_GUID_STRING_EVENT_RECORD *)RecordHeader)->Guid1);
+ Measurement->Identifier = ((UINT32)((FPDT_DUAL_GUID_STRING_EVENT_RECORD *)RecordHeader)->ProgressID);
+ if (IsStart) {
+ Measurement->StartTimeStamp = ((FPDT_DUAL_GUID_STRING_EVENT_RECORD *)RecordHeader)->Timestamp;
+ } else {
+ Measurement->EndTimeStamp = ((FPDT_DUAL_GUID_STRING_EVENT_RECORD *)RecordHeader)->Timestamp;
+ }
+ Measurement->Token = ((FPDT_DUAL_GUID_STRING_EVENT_RECORD *)RecordHeader)->String;
+ Measurement->Module = ((FPDT_DUAL_GUID_STRING_EVENT_RECORD *)RecordHeader)->String;
+ 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 (EndMeasureMent->Identifier == PERF_CROSSMODULE_END_ID) {
+ if (mMeasurementList[Index].EndTimeStamp == 0 &&
+ (AsciiStrCmp (mMeasurementList[Index].Token, EndMeasureMent->Token) == 0) &&
+ (AsciiStrCmp (mMeasurementList[Index].Module, EndMeasureMent->Module) == 0) &&
+ mMeasurementList[Index].Identifier == PERF_CROSSMODULE_START_ID) {
+ 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 with ProgressId 0, the record doesn't appear in pairs. The timestamp in the record is the EndTimeStamp, its StartTimeStamp is 0.
+ // 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 == 0) {
+ GetMeasurementInfo (RecordHeader, FALSE, &(mMeasurementList[mMeasurementNum]));
+ mMeasurementNum ++;
+ } else 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(StartProgressId == PERF_CROSSMODULE_START_ID ){
+ 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 {
+ ZeroMem(&MeasureMent, sizeof(MEASUREMENT_RECORD));
+ GetMeasurementInfo (RecordHeader, FALSE, &MeasureMent);
+ SearchMeasurement (&MeasureMent);
+ }
+ TableLength += RecordHeader->Length;
+ PerformanceTablePtr += RecordHeader->Length;
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Initialize the cumulative data.
+
+**/
+VOID
+InitCumulativeData (
+ VOID
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; Index < NumCum; ++Index) {
+ CumData[Index].Count = 0;
+ CumData[Index].MinDur = PERF_MAXDUR;
+ CumData[Index].MaxDur = 0;
+ CumData[Index].Duration = 0;
+ }
+}
+
+/**
+ Initialize the Summary data.
+
+**/
+VOID
+InitSummaryData (
+ VOID
+ )
+{
+ SummaryData.NumTrace = 0;
+ SummaryData.NumIncomplete = 0;
+ SummaryData.NumSummary = 0;
+ SummaryData.NumHandles = 0;
+ SummaryData.NumPEIMs = 0;
+ SummaryData.NumGlobal = 0;
+}
+
+/**
+ Dump performance data.
+
+ @param[in] ImageHandle The image handle.
+ @param[in] SystemTable The system table.
+
+ @retval SHELL_SUCCESS Command completed successfully.
+ @retval SHELL_INVALID_PARAMETER Command usage error.
+ @retval SHELL_ABORTED The user aborts the operation.
+ @retval value Unknown error.
+**/
+SHELL_STATUS
+RunDp (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ LIST_ENTRY *ParamPackage;
+ CONST CHAR16 *CmdLineArg;
+ EFI_STATUS Status;
+
+ PERFORMANCE_PROPERTY *PerformanceProperty;
+ UINTN Number2Display;
+
+ EFI_STRING StringPtr;
+ BOOLEAN SummaryMode;
+ BOOLEAN VerboseMode;
+ BOOLEAN AllMode;
+ BOOLEAN RawMode;
+ BOOLEAN ExcludeMode;
+ BOOLEAN CumulativeMode;
+ CONST CHAR16 *CustomCumulativeToken;
+ PERF_CUM_DATA *CustomCumulativeData;
+ UINTN NameSize;
+ SHELL_STATUS ShellStatus;
+ TIMER_INFO TimerInfo;
+ UINT64 Intermediate;
+
+ StringPtr = NULL;
+ SummaryMode = FALSE;
+ VerboseMode = FALSE;
+ AllMode = FALSE;
+ RawMode = FALSE;
+ ExcludeMode = FALSE;
+ CumulativeMode = FALSE;
+ CustomCumulativeData = NULL;
+ ShellStatus = SHELL_SUCCESS;
+
+ //
+ // initialize the shell lib (we must be in non-auto-init...)
+ //
+ Status = ShellInitialize();
+ ASSERT_EFI_ERROR(Status);
+
+ //
+ // Process Command Line arguments
+ //
+ Status = ShellCommandLineParse (ParamList, &ParamPackage, NULL, TRUE);
+ if (EFI_ERROR(Status)) {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_INVALID_ARG), mDpHiiHandle);
+ return SHELL_INVALID_PARAMETER;
+ } else if (ShellCommandLineGetCount(ParamPackage) > 1){
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_TOO_MANY), mDpHiiHandle);
+ return SHELL_INVALID_PARAMETER;
+ }
+
+ //
+ // Boolean options
+ //
+ VerboseMode = ShellCommandLineGetFlag (ParamPackage, L"-v");
+ SummaryMode = (BOOLEAN) (ShellCommandLineGetFlag (ParamPackage, L"-S") || ShellCommandLineGetFlag (ParamPackage, L"-s"));
+ AllMode = ShellCommandLineGetFlag (ParamPackage, L"-A");
+ RawMode = ShellCommandLineGetFlag (ParamPackage, L"-R");
+ ExcludeMode = ShellCommandLineGetFlag (ParamPackage, L"-x");
+ mShowId = ShellCommandLineGetFlag (ParamPackage, L"-i");
+ CumulativeMode = ShellCommandLineGetFlag (ParamPackage, L"-c");
+
+ if (AllMode && RawMode) {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_CONFLICT_ARG), mDpHiiHandle, L"-A", L"-R");
+ return SHELL_INVALID_PARAMETER;
+ }
+
+ // Options with Values
+ if (ShellCommandLineGetFlag (ParamPackage, L"-n")) {
+ CmdLineArg = ShellCommandLineGetValue (ParamPackage, L"-n");
+ if (CmdLineArg == NULL) {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_TOO_FEW), mDpHiiHandle);
+ return SHELL_INVALID_PARAMETER;
+ } else {
+ if (!(RawMode || AllMode)) {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_NO_RAW_ALL), mDpHiiHandle);
+ return SHELL_INVALID_PARAMETER;
+ }
+ Status = ShellConvertStringToUint64(CmdLineArg, &Intermediate, FALSE, TRUE);
+ if (EFI_ERROR (Status)) {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_INVALID_NUM_ARG), mDpHiiHandle, L"-n");
+ return SHELL_INVALID_PARAMETER;
+ } else {
+ Number2Display = (UINTN)Intermediate;
+ if (Number2Display == 0 || Number2Display > MAXIMUM_DISPLAYCOUNT) {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_INVALID_RANGE), mDpHiiHandle, L"-n", 0, MAXIMUM_DISPLAYCOUNT);
+ return SHELL_INVALID_PARAMETER;
+ }
+ }
+ }
+ } else {
+ Number2Display = DEFAULT_DISPLAYCOUNT;
+ }
+
+ if (ShellCommandLineGetFlag (ParamPackage, L"-t")) {
+ CmdLineArg = ShellCommandLineGetValue (ParamPackage, L"-t");
+ if (CmdLineArg == NULL) {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_TOO_FEW), mDpHiiHandle);
+ return SHELL_INVALID_PARAMETER;
+ } else {
+ Status = ShellConvertStringToUint64(CmdLineArg, &Intermediate, FALSE, TRUE);
+ if (EFI_ERROR (Status)) {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_INVALID_NUM_ARG), mDpHiiHandle, L"-t");
+ return SHELL_INVALID_PARAMETER;
+ } else {
+ mInterestThreshold = Intermediate;
+ }
+ }
+ } else {
+ mInterestThreshold = DEFAULT_THRESHOLD; // 1ms := 1,000 us
+ }
+
+ if (ShellCommandLineGetFlag (ParamPackage, L"-c")) {
+ CustomCumulativeToken = ShellCommandLineGetValue (ParamPackage, L"-c");
+ if (CustomCumulativeToken == NULL) {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_TOO_FEW), mDpHiiHandle);
+ return SHELL_INVALID_PARAMETER;
+ } else {
+ CustomCumulativeData = AllocateZeroPool (sizeof (PERF_CUM_DATA));
+ if (CustomCumulativeData == NULL) {
+ ShellStatus = SHELL_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ CustomCumulativeData->MinDur = PERF_MAXDUR;
+ CustomCumulativeData->MaxDur = 0;
+ CustomCumulativeData->Count = 0;
+ CustomCumulativeData->Duration = 0;
+ NameSize = StrLen (CustomCumulativeToken) + 1;
+ CustomCumulativeData->Name = AllocateZeroPool (NameSize);
+ if (CustomCumulativeData->Name == NULL) {
+ ShellStatus = SHELL_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ UnicodeStrToAsciiStrS (CustomCumulativeToken, CustomCumulativeData->Name, NameSize);
+ }
+ }
+
+ //
+ // 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)) {
+ ShellStatus = Status;
+ goto Done;
+ }
+
+ //
+ //2. Cache the ModuleGuid and hanlde mapping table.
+ //
+ Status = BuildCachedGuidHandleTable();
+ if (EFI_ERROR (Status)) {
+ ShellStatus = Status;
+ goto Done;
+ }
+
+ //
+ //3. Build the measurement array form the FPDT records.
+ //
+ Status = BuildMeasurementList ();
+ if (EFI_ERROR (Status)) {
+ ShellStatus = SHELL_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ //
+ // Initialize the pre-defined cumulative data.
+ //
+ InitCumulativeData ();
+
+ //
+ // Initialize the Summary data.
+ //
+ InitSummaryData ();
+
+ //
+ // Timer specific processing
+ //
+ // Get the Performance counter characteristics:
+ // Freq = Frequency in Hz
+ // StartCount = Value loaded into the counter when it starts counting
+ // EndCount = Value counter counts to before it needs to be reset
+ //
+ Status = EfiGetSystemConfigurationTable (&gPerformanceProtocolGuid, (VOID **) &PerformanceProperty);
+ if (EFI_ERROR (Status) || (PerformanceProperty == NULL)) {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PERF_PROPERTY_NOT_FOUND), mDpHiiHandle);
+ goto Done;
+ }
+
+ TimerInfo.Frequency = (UINT32)DivU64x32 (PerformanceProperty->Frequency, 1000);
+ TimerInfo.StartCount = 0;
+ TimerInfo.EndCount = 0xFFFF;
+ TimerInfo.CountUp = TRUE;
+
+ //
+ // Print header
+ //
+ // print DP's build version
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_BUILD_REVISION), mDpHiiHandle, DP_MAJOR_VERSION, DP_MINOR_VERSION);
+
+ // print performance timer characteristics
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_KHZ), mDpHiiHandle, TimerInfo.Frequency);
+
+ if (VerboseMode && !RawMode) {
+ StringPtr = HiiGetString (mDpHiiHandle,
+ (EFI_STRING_ID) (TimerInfo.CountUp ? STRING_TOKEN (STR_DP_UP) : STRING_TOKEN (STR_DP_DOWN)), NULL);
+ ASSERT (StringPtr != NULL);
+ // Print Timer count range and direction
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_TIMER_PROPERTIES), mDpHiiHandle,
+ StringPtr,
+ TimerInfo.StartCount,
+ TimerInfo.EndCount
+ );
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_VERBOSE_THRESHOLD), mDpHiiHandle, mInterestThreshold);
+ }
+
+/****************************************************************************
+**** Print Sections based on command line options
+****
+**** Option modes have the following priority:
+**** v Verbose -- Valid in combination with any other options
+**** t Threshold -- Modifies All, Raw, and Cooked output
+**** Default is 0 for All and Raw mode
+**** Default is DEFAULT_THRESHOLD for "Cooked" mode
+**** n Number2Display Used by All and Raw mode. Otherwise ignored.
+**** A All -- R and S options are ignored
+**** R Raw -- S option is ignored
+**** s Summary -- Modifies "Cooked" output only
+**** Cooked (Default)
+****************************************************************************/
+ GatherStatistics (CustomCumulativeData);
+ if (CumulativeMode) {
+ ProcessCumulative (CustomCumulativeData);
+ } else if (AllMode) {
+ Status = DumpAllTrace( Number2Display, ExcludeMode);
+ if (Status == EFI_ABORTED) {
+ ShellStatus = SHELL_ABORTED;
+ goto Done;
+ }
+ } else if (RawMode) {
+ Status = DumpRawTrace( Number2Display, ExcludeMode);
+ if (Status == EFI_ABORTED) {
+ ShellStatus = SHELL_ABORTED;
+ goto Done;
+ }
+ } else {
+ //------------- Begin Cooked Mode Processing
+ ProcessPhases ();
+ if ( ! SummaryMode) {
+ Status = ProcessHandles ( ExcludeMode);
+ if (Status == EFI_ABORTED) {
+ ShellStatus = SHELL_ABORTED;
+ goto Done;
+ }
+
+ Status = ProcessPeims ();
+ if (Status == EFI_ABORTED) {
+ ShellStatus = SHELL_ABORTED;
+ goto Done;
+ }
+
+ Status = ProcessGlobal ();
+ if (Status == EFI_ABORTED) {
+ ShellStatus = SHELL_ABORTED;
+ goto Done;
+ }
+
+ ProcessCumulative (NULL);
+ }
+ } //------------- End of Cooked Mode Processing
+ if ( VerboseMode || SummaryMode) {
+ DumpStatistics();
+ }
+
+Done:
+ if (ParamPackage != NULL) {
+ ShellCommandLineFreeVarList (ParamPackage);
+ }
+ SHELL_FREE_NON_NULL (StringPtr);
+ if (CustomCumulativeData != NULL) {
+ SHELL_FREE_NON_NULL (CustomCumulativeData->Name);
+ }
+ SHELL_FREE_NON_NULL (CustomCumulativeData);
+
+ SHELL_FREE_NON_NULL (mMeasurementList);
+
+ SHELL_FREE_NON_NULL (mCacheHandleGuidTable);
+
+ mMeasurementNum = 0;
+ mCachePairCount = 0;
+ return ShellStatus;
+}
+
+
+/**
+ Retrieve HII package list from ImageHandle and publish to HII database.
+
+ @param ImageHandle The image handle of the process.
+
+ @return HII handle.
+**/
+EFI_HII_HANDLE
+InitializeHiiPackage (
+ EFI_HANDLE ImageHandle
+ )
+{
+ EFI_STATUS Status;
+ EFI_HII_PACKAGE_LIST_HEADER *PackageList;
+ EFI_HII_HANDLE HiiHandle;
+
+ //
+ // Retrieve HII package list from ImageHandle
+ //
+ Status = gBS->OpenProtocol (
+ ImageHandle,
+ &gEfiHiiPackageListProtocolGuid,
+ (VOID **)&PackageList,
+ ImageHandle,
+ NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+
+ //
+ // Publish HII package list to HII Database.
+ //
+ Status = gHiiDatabase->NewPackageList (
+ gHiiDatabase,
+ PackageList,
+ NULL,
+ &HiiHandle
+ );
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+ return HiiHandle;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/Dp.h b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/Dp.h
new file mode 100644
index 00000000..ca6bd2f4
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/Dp.h
@@ -0,0 +1,140 @@
+/** @file
+ Header file for 'dp' command functions.
+
+ Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _DP_H_
+#define _DP_H_
+
+
+#include <Uefi.h>
+
+#include <Guid/Performance.h>
+#include <Guid/ExtendedFirmwarePerformance.h>
+#include <Guid/FirmwarePerformance.h>
+
+#include <Protocol/HiiPackageList.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/LoadedImage.h>
+#include <Protocol/UnicodeCollation.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/ShellLib.h>
+#include <Library/UefiLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/PcdLib.h>
+#include <Library/SortLib.h>
+#include <Library/HiiLib.h>
+#include <Library/FileHandleLib.h>
+#include <Library/UefiHiiServicesLib.h>
+#include <Library/PerformanceLib.h>
+
+extern EFI_HII_HANDLE mDpHiiHandle;
+
+#define DP_MAJOR_VERSION 2
+#define DP_MINOR_VERSION 5
+
+/**
+ * The value assigned to DP_DEBUG controls which debug output
+ * is generated. Set it to ZERO to disable.
+**/
+#define DP_DEBUG 0
+
+#define DEFAULT_THRESHOLD 1000 ///< One millisecond.
+#define DEFAULT_DISPLAYCOUNT 50
+#define MAXIMUM_DISPLAYCOUNT 999999 ///< Arbitrary maximum reasonable number.
+
+#define PERF_MAXDUR 0xFFFFFFFFFFFFFFFFULL
+
+/// Determine whether 0 <= C < L. If L == 0, return true regardless of C.
+#define WITHIN_LIMIT( C, L) ( ((L) == 0) || ((C) < (L)) )
+
+/// Structure for storing Timer specific information.
+typedef struct {
+ UINT64 StartCount; ///< Value timer is initialized with.
+ UINT64 EndCount; ///< Value timer has just before it wraps.
+ UINT32 Frequency; ///< Timer count frequency in KHz.
+ BOOLEAN CountUp; ///< TRUE if the counter counts up.
+} TIMER_INFO;
+
+/** Initialize one PERF_CUM_DATA structure instance for token t.
+ *
+ * This parameterized macro takes a single argument, t, which is expected
+ * to resolve to a pointer to an ASCII string literal. This parameter may
+ * take any one of the following forms:
+ * - PERF_INIT_CUM_DATA("Token") A string literal
+ * - PERF_INIT_CUM_DATA(pointer) A pointer -- CHAR8 *pointer;
+ * - PERF_INIT_CUM_DATA(array) Address of an array -- CHAR8 array[N];
+**/
+#define PERF_INIT_CUM_DATA(t) { 0ULL, PERF_MAXDUR, 0ULL, (t), 0U }
+
+typedef struct {
+ UINT64 Duration; ///< Cumulative duration for this item.
+ UINT64 MinDur; ///< Smallest duration encountered.
+ UINT64 MaxDur; ///< Largest duration encountered.
+ CHAR8 *Name; ///< ASCII name of this item.
+ UINT32 Count; ///< Total number of measurements accumulated.
+} PERF_CUM_DATA;
+
+typedef struct {
+ UINT32 NumTrace; ///< Number of recorded TRACE performance measurements.
+ UINT32 NumIncomplete; ///< Number of measurements with no END value.
+ UINT32 NumSummary; ///< Number of summary section measurements.
+ UINT32 NumHandles; ///< Number of measurements with handles.
+ UINT32 NumPEIMs; ///< Number of measurements of PEIMs.
+ UINT32 NumGlobal; ///< Number of measurements with END value and NULL handle.
+} PERF_SUMMARY_DATA;
+
+typedef struct {
+ CONST VOID *Handle;
+ CONST CHAR8 *Token; ///< Measured token string name.
+ CONST CHAR8 *Module; ///< Module string name.
+ UINT64 StartTimeStamp; ///< Start time point.
+ UINT64 EndTimeStamp; ///< End time point.
+ UINT32 Identifier; ///< Identifier.
+} MEASUREMENT_RECORD;
+
+typedef struct {
+ CHAR8 *Name; ///< Measured token string name.
+ UINT64 CumulativeTime; ///< Accumulated Elapsed Time.
+ UINT64 MinTime; ///< Minimum Elapsed Time.
+ UINT64 MaxTime; ///< Maximum Elapsed Time.
+ UINT32 Count; ///< Number of measurements accumulated.
+} PROFILE_RECORD;
+
+/**
+ Dump performance data.
+
+ @param[in] ImageHandle The image handle.
+ @param[in] SystemTable The system table.
+
+ @retval SHELL_SUCCESS Command completed successfully.
+ @retval SHELL_INVALID_PARAMETER Command usage error.
+ @retval SHELL_ABORTED The user aborts the operation.
+ @retval value Unknown error.
+**/
+SHELL_STATUS
+RunDp (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ );
+
+/**
+ Retrieve HII package list from ImageHandle and publish to HII database.
+
+ @param ImageHandle The image handle of the process.
+
+ @return HII handle.
+**/
+EFI_HII_HANDLE
+InitializeHiiPackage (
+ EFI_HANDLE ImageHandle
+ );
+#endif // _DP_H_
diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/Dp.uni b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/Dp.uni
new file mode 100644
index 00000000..8d870057
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/Dp.uni
@@ -0,0 +1,128 @@
+// *++
+//
+// (C) Copyright 2014-2015 Hewlett-Packard Development Company, L.P.<BR>
+// Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+// (C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+//
+// Module Name:
+//
+// DpStrings.uni
+//
+// Abstract:
+//
+// String definitions for the Shell dp command
+//
+// Revision History:
+//
+// --*/
+
+/=#
+
+#langdef en-US "English"
+
+#string STR_DP_UP #language en-US "UP"
+#string STR_DP_DOWN #language en-US "DOWN"
+#string STR_DP_DASHES #language en-US "-------------------------------------------------------------------------------\n"
+#string STR_DP_SECTION_HEADER #language en-US "\n==[ %s ]========\n"
+#string STR_DP_INVALID_ARG #language en-US "Invalid argument(s)\n"
+#string STR_DP_TOO_MANY #language en-US "Too many arguments\n"
+#string STR_DP_TOO_FEW #language en-US "Too few arguments\n"
+#string STR_DP_INVALID_NUM_ARG #language en-US "Invalid argument(s), the value of %H%s%N must be numbers\n"
+#string STR_DP_INVALID_RANGE #language en-US "Invalid argument(s), the value of %H%s%N must be between %H%d%N and %H%d%N\n"
+#string STR_DP_CONFLICT_ARG #language en-US "Invalid argument(s), %H%s%N can not be used together with %H%s%N\n"
+#string STR_DP_NO_RAW_ALL #language en-US "Invalid argument(s), -n flag must use with -A or -R\n"
+#string STR_DP_HANDLES_ERROR #language en-US "Locate all handles error - %r\n"
+#string STR_DP_ERROR_NAME #language en-US "Unknown driver name"
+#string STR_PERF_PROPERTY_NOT_FOUND #language en-US "Performance property not found\n"
+#string STR_DP_BUILD_REVISION #language en-US "\nDP Build Version: %d.%d\n"
+#string STR_DP_KHZ #language en-US "System Performance Timer Frequency: %,8d (KHz)\n"
+#string STR_DP_TIMER_PROPERTIES #language en-US "System Performance Timer counts %s from 0x%Lx to 0x%Lx\n"
+#string STR_DP_VERBOSE_THRESHOLD #language en-US "Measurements less than %,Ld microseconds are not displayed.\n"
+#string STR_DP_SECTION_PHASES #language en-US "Major Phases"
+#string STR_DP_SEC_PHASE #language en-US " SEC Phase Duration: %L8d (us)\n"
+#string STR_DP_PHASE_BDSTO #language en-US " BDS Timeout: %L8d (ms) included in BDS Duration\n"
+#string STR_DP_PHASE_DURATION #language en-US "%5a Phase Duration: %L8d (ms)\n"
+#string STR_DP_TOTAL_DURATION #language en-US "Total Duration: %L8d (ms)\n"
+#string STR_DP_SECTION_DRIVERS #language en-US "Drivers by Handle"
+#string STR_DP_HANDLE_SECTION #language en-US "Index: Handle Driver Name Description Time(us)\n"
+#string STR_DP_HANDLE_VARS #language en-US "%5d: [%3x] %36s %11s %L8d\n"
+#string STR_DP_HANDLE_SECTION2 #language en-US "Index: Handle Driver Name Description Time(us) ID\n"
+#string STR_DP_HANDLE_VARS2 #language en-US "%5d: [%3x] %36s %11s %L8d %5d\n"
+#string STR_DP_SECTION_PEIMS #language en-US "PEIMs"
+#string STR_DP_PEIM_SECTION #language en-US "Index: Instance GUID Token Time(us)\n"
+#string STR_DP_PEIM_VARS #language en-US "%5d: %g PEIM %L8d\n"
+#string STR_DP_PEIM_SECTION2 #language en-US "Index: Instance GUID Token Time(us) ID\n"
+#string STR_DP_PEIM_VARS2 #language en-US "%5d: %g PEIM %L8d %5d\n"
+#string STR_DP_SECTION_GENERAL #language en-US "General"
+#string STR_DP_GLOBAL_SECTION #language en-US "Index Name Description Time(us)\n"
+#string STR_DP_GLOBAL_VARS #language en-US "%5d:%25s %31s %L8d\n"
+#string STR_DP_GLOBAL_SECTION2 #language en-US "Index Name Description Time(us) ID\n"
+#string STR_DP_GLOBAL_VARS2 #language en-US "%5d:%25s %31s %L8d %5d\n"
+#string STR_DP_SECTION_CUMULATIVE #language en-US "Cumulative"
+#string STR_DP_CUMULATIVE_SECT_1 #language en-US "(Times in microsec.) Cumulative Average Shortest Longest\n"
+#string STR_DP_CUMULATIVE_SECT_2 #language en-US " Name Count Duration Duration Duration Duration\n"
+#string STR_DP_CUMULATIVE_STATS #language en-US "%11a %8d %L10d %L10d %L10d %L10d\n"
+#string STR_DP_SECTION_STATISTICS #language en-US "Statistics"
+#string STR_DP_STATS_NUMTRACE #language en-US "There were %d measurements taken, of which:\n"
+#string STR_DP_STATS_NUMINCOMPLETE #language en-US "%,8d are incomplete.\n"
+#string STR_DP_STATS_NUMPHASES #language en-US "%,8d are major execution phases.\n"
+#string STR_DP_STATS_NUMHANDLES #language en-US "%,8d have non-NULL handles, %d are NULL.\n"
+#string STR_DP_STATS_NUMPEIMS #language en-US "%,8d are PEIMs.\n"
+#string STR_DP_STATS_NUMGLOBALS #language en-US "%,8d are general measurements.\n"
+#string STR_DP_STATS_NUMPROFILE #language en-US "%,8d are profiling records.\n"
+#string STR_DP_SECTION_ALL #language en-US "Sequential Trace Records"
+#string STR_DP_ALL_HEADR #language en-US "\nIndex Handle Module Token Time(us)\n"
+#string STR_DP_ALL_VARS #language en-US "%5d:%3s0x%08p %36s %13s %L8d\n"
+#string STR_DP_ALL_DASHES2 #language en-US "-------------------------------------------------------------------------------------\n"
+#string STR_DP_ALL_HEADR2 #language en-US "\nIndex Handle Module Token Time(us) ID\n"
+#string STR_DP_ALL_VARS2 #language en-US "%5d:%3s0x%08p %36s %13s %L8d %5d\n"
+#string STR_DP_SECTION_RAWTRACE #language en-US "RAW Trace"
+#string STR_DP_RAW_DASHES #language en-US "---------------------------------------------------------------------------------------------------------------------------\n"
+#string STR_DP_RAW_VARS #language en-US "%5d: %16LX %16LX %16LX %31a %31a\n"
+#string STR_DP_RAW_HEADR #language en-US "\nIndex Handle Start Count End Count Token Module\n"
+#string STR_DP_RAW_DASHES2 #language en-US "---------------------------------------------------------------------------------------------------------------------------------\n"
+#string STR_DP_RAW_VARS2 #language en-US "%5d: %16LX %16LX %16LX %31a %31a %5d\n"
+#string STR_DP_RAW_HEADR2 #language en-US "\nIndex Handle Start Count End Count Token Module ID\n"
+#string STR_DP_INCOMPLETE #language en-US " I "
+#string STR_DP_COMPLETE #language en-US " "
+#string STR_ALIT_UNKNOWN #language en-US "Unknown"
+#string STR_DP_GET_ACPI_FPDT_FAIL #language en-US "Fail to get Firmware Performance Data Table (FPDT) in ACPI Table\n"
+
+#string STR_GET_HELP_DP #language en-US ""
+".TH dp 0 "Display performance metrics"\r\n"
+".SH NAME\r\n"
+"Displays performance metrics that are stored in memory.\r\n"
+".SH SYNOPSIS\r\n"
+"DP [-b] [-v] [-x] [-s | -A | -R] [-t value] [-n count] [-c [token]][-i] [-?]\r\n"
+".SH OPTIONS\r\n"
+" \r\n"
+" -b - Displays on multiple pages\r\n"
+" -v - Displays additional information\r\n"
+" -x - Prevents display of individual measurements for cumulative items\r\n"
+" -s - Displays summary information only\r\n"
+" -A - Displays all measurements in a list\r\n"
+" -R - Displays all measurements in raw format\r\n"
+" -t VALUE - Sets display threshold to VALUE microseconds\r\n"
+" -n COUNT - Limits display to COUNT lines in All and Raw modes\r\n"
+" -i - Displays identifier\r\n"
+" -c TOKEN - Display pre-defined and custom cumulative data\r\n"
+" Pre-defined cumulative token are:\r\n"
+" 1. LoadImage:\r\n"
+" 2. StartImage:\r\n"
+" 3. DB:Start:\r\n"
+" 4. DB:Support:\r\n"
+" -? - Displays DP help information\r\n"
+".SH DESCRIPTION\r\n"
+" \r\n"
+"NOTES:\r\n"
+" 1. Displays Performance metrics that are stored in memory.\r\n"
+".SH RETURNVALUES\r\n"
+" \r\n"
+"RETURN VALUES:\r\n"
+" SHELL_SUCCESS The action was completed as requested.\r\n"
+" SHELL_NOT_FOUND The requested option was not found.\r\n"
+" SHELL_INVALID_PARAMETER One of the passed in parameters was incorrectly formatted or its value was out of bounds.\r\n"
+" SHELL_UNSUPPORTED The action as requested was unsupported.\r\n"
+" SHELL_OUT_OF_RESOURCES There was insufficient free space for the request to be completed.\r\n"
diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/DpApp.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/DpApp.c
new file mode 100644
index 00000000..b77d644d
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/DpApp.c
@@ -0,0 +1,47 @@
+/** @file
+ Entrypoint of "dp" shell standalone application.
+
+ Copyright (c) 2017, Intel Corporation. All rights reserved. <BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#include "Dp.h"
+
+//
+// String token ID of help message text.
+// Shell supports to find help message in the resource section of an application image if
+// .MAN file is not found. This global variable is added to make build tool recognizes
+// that the help string is consumed by user and then build tool will add the string into
+// the resource section. Thus the application can use '-?' option to show help message in
+// Shell.
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_STRING_ID mStringHelpTokenId = STRING_TOKEN (STR_GET_HELP_DP);
+
+/**
+ Entry point of Tftp standalone application.
+
+ @param ImageHandle The image handle of the process.
+ @param SystemTable The EFI System Table pointer.
+
+ @retval EFI_SUCCESS Tftp command is executed successfully.
+ @retval EFI_ABORTED HII package was failed to initialize.
+ @retval others Other errors when executing tftp command.
+**/
+EFI_STATUS
+EFIAPI
+DpAppInitialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ mDpHiiHandle = InitializeHiiPackage (ImageHandle);
+ if (mDpHiiHandle == NULL) {
+ return EFI_ABORTED;
+ }
+
+ Status = (EFI_STATUS)RunDp (ImageHandle, SystemTable);
+ HiiRemovePackages (mDpHiiHandle);
+ return Status;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/DpApp.inf b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/DpApp.inf
new file mode 100644
index 00000000..25d053a3
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/DpApp.inf
@@ -0,0 +1,64 @@
+## @file
+# Provides Shell 'dp' standalone application.
+#
+# Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010006
+ BASE_NAME = dp
+ FILE_GUID = 1831A379-2D48-45BD-9744-D4059D93815D
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 1.0
+ ENTRY_POINT = DpAppInitialize
+#
+# This flag specifies whether HII resource section is generated into PE image.
+#
+ UEFI_HII_RESOURCE_SECTION = TRUE
+
+[Sources.common]
+ Dp.uni
+ Dp.c
+ Dp.h
+ Literals.h
+ Literals.c
+ DpInternal.h
+ DpUtilities.c
+ DpTrace.c
+ DpApp.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ ShellPkg/ShellPkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ MemoryAllocationLib
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ ShellLib
+ UefiLib
+ UefiRuntimeServicesTableLib
+ UefiBootServicesTableLib
+ UefiApplicationEntryPoint
+ SortLib
+ PrintLib
+ DevicePathLib
+ PerformanceLib
+ DxeServicesLib
+ PeCoffGetEntryPointLib
+
+[Guids]
+ gPerformanceProtocolGuid ## CONSUMES ## SystemTable
+
+[Protocols]
+ gEfiLoadedImageProtocolGuid ## CONSUMES
+ gEfiDriverBindingProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiComponentName2ProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiLoadedImageDevicePathProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiHiiPackageListProtocolGuid ## CONSUMES
+
diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/DpDynamicCommand.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/DpDynamicCommand.c
new file mode 100644
index 00000000..ca8dec0a
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/DpDynamicCommand.c
@@ -0,0 +1,125 @@
+/** @file
+ Produce "dp" shell dynamic command.
+
+ Copyright (c) 2017, Intel Corporation. All rights reserved. <BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#include "Dp.h"
+#include <Protocol/ShellDynamicCommand.h>
+
+/**
+ This is the shell command handler function pointer callback type. This
+ function handles the command when it is invoked in the shell.
+
+ @param[in] This The instance of the EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL.
+ @param[in] SystemTable The pointer to the system table.
+ @param[in] ShellParameters The parameters associated with the command.
+ @param[in] Shell The instance of the shell protocol used in the context
+ of processing this command.
+
+ @return EFI_SUCCESS the operation was successful
+ @return other the operation failed.
+**/
+SHELL_STATUS
+EFIAPI
+DpCommandHandler (
+ IN EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *This,
+ IN EFI_SYSTEM_TABLE *SystemTable,
+ IN EFI_SHELL_PARAMETERS_PROTOCOL *ShellParameters,
+ IN EFI_SHELL_PROTOCOL *Shell
+ )
+{
+ gEfiShellParametersProtocol = ShellParameters;
+ gEfiShellProtocol = Shell;
+ return RunDp (gImageHandle, SystemTable);
+}
+
+/**
+ This is the command help handler function pointer callback type. This
+ function is responsible for displaying help information for the associated
+ command.
+
+ @param[in] This The instance of the EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL.
+ @param[in] Language The pointer to the language string to use.
+
+ @return string Pool allocated help string, must be freed by caller
+**/
+CHAR16 *
+EFIAPI
+DpCommandGetHelp (
+ IN EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *This,
+ IN CONST CHAR8 *Language
+ )
+{
+ return HiiGetString (mDpHiiHandle, STRING_TOKEN (STR_GET_HELP_DP), Language);
+}
+
+EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL mDpDynamicCommand = {
+ L"dp",
+ DpCommandHandler,
+ DpCommandGetHelp
+};
+
+/**
+ Entry point of Tftp Dynamic Command.
+
+ Produce the DynamicCommand protocol to handle "tftp" command.
+
+ @param ImageHandle The image handle of the process.
+ @param SystemTable The EFI System Table pointer.
+
+ @retval EFI_SUCCESS Tftp command is executed successfully.
+ @retval EFI_ABORTED HII package was failed to initialize.
+ @retval others Other errors when executing tftp command.
+**/
+EFI_STATUS
+EFIAPI
+DpCommandInitialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ mDpHiiHandle = InitializeHiiPackage (ImageHandle);
+ if (mDpHiiHandle == NULL) {
+ return EFI_ABORTED;
+ }
+
+ Status = gBS->InstallProtocolInterface (
+ &ImageHandle,
+ &gEfiShellDynamicCommandProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &mDpDynamicCommand
+ );
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+}
+
+/**
+ Tftp driver unload handler.
+
+ @param ImageHandle The image handle of the process.
+
+ @retval EFI_SUCCESS The image is unloaded.
+ @retval Others Failed to unload the image.
+**/
+EFI_STATUS
+EFIAPI
+DpUnload (
+ IN EFI_HANDLE ImageHandle
+)
+{
+ EFI_STATUS Status;
+ Status = gBS->UninstallProtocolInterface (
+ ImageHandle,
+ &gEfiShellDynamicCommandProtocolGuid,
+ &mDpDynamicCommand
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ HiiRemovePackages (mDpHiiHandle);
+ return EFI_SUCCESS;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/DpDynamicCommand.inf b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/DpDynamicCommand.inf
new file mode 100644
index 00000000..159632a3
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/DpDynamicCommand.inf
@@ -0,0 +1,68 @@
+## @file
+# Provides Shell 'dp' dynamic command.
+#
+# Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010006
+ BASE_NAME = dpDynamicCommand
+ FILE_GUID = 0253F9FA-129A-4A8D-B12E-7DC2B6376302
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = DpCommandInitialize
+ UNLOAD_IMAGE = DpUnload
+#
+# This flag specifies whether HII resource section is generated into PE image.
+#
+ UEFI_HII_RESOURCE_SECTION = TRUE
+
+[Sources.common]
+ Dp.uni
+ Dp.c
+ Dp.h
+ Literals.h
+ Literals.c
+ DpInternal.h
+ DpUtilities.c
+ DpTrace.c
+ DpDynamicCommand.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ ShellPkg/ShellPkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ MemoryAllocationLib
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ ShellLib
+ UefiLib
+ UefiRuntimeServicesTableLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ SortLib
+ PrintLib
+ DevicePathLib
+ PerformanceLib
+ DxeServicesLib
+ PeCoffGetEntryPointLib
+
+[Guids]
+ gPerformanceProtocolGuid ## CONSUMES ## SystemTable
+
+[Protocols]
+ gEfiLoadedImageProtocolGuid ## CONSUMES
+ gEfiDriverBindingProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiComponentName2ProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiLoadedImageDevicePathProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiHiiPackageListProtocolGuid ## CONSUMES
+ gEfiShellDynamicCommandProtocolGuid ## PRODUCES
+
+[DEPEX]
+ TRUE
diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/DpInternal.h b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/DpInternal.h
new file mode 100644
index 00000000..d6d30c54
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/DpInternal.h
@@ -0,0 +1,315 @@
+/** @file
+ Declarations of objects defined internally to the Dp Application.
+
+ Declarations of data and functions which are private to the Dp application.
+ This file should never be referenced by anything other than components of the
+ Dp application. In addition to global data, function declarations for
+ DpUtilities.c, DpTrace.c, and DpProfile.c are included here.
+
+ Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+ (C) Copyright 2015-2016 Hewlett Packard Enterprise Development LP<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+#ifndef _DP_INTELNAL_H_
+#define _DP_INTELNAL_H_
+
+#define DP_GAUGE_STRING_LENGTH 36
+
+//
+/// Module-Global Variables
+///@{
+extern EFI_HII_HANDLE mDpHiiHandle;
+extern CHAR16 mGaugeString[DP_GAUGE_STRING_LENGTH + 1];
+extern CHAR16 mUnicodeToken[DXE_PERFORMANCE_STRING_SIZE];
+extern UINT64 mInterestThreshold;
+extern BOOLEAN mShowId;
+extern UINT8 *mBootPerformanceTable;
+extern UINTN mBootPerformanceTableLength;
+extern MEASUREMENT_RECORD *mMeasurementList;
+extern UINTN mMeasurementNum;
+
+extern PERF_SUMMARY_DATA SummaryData; ///< Create the SummaryData structure and init. to ZERO.
+
+/// Items for which to gather cumulative statistics.
+extern PERF_CUM_DATA CumData[];
+
+/// Number of items for which we are gathering cumulative statistics.
+extern UINT32 const NumCum;
+
+///@}
+
+/**
+ Calculate an event's duration in timer ticks.
+
+ Given the count direction and the event's start and end timer values,
+ calculate the duration of the event in timer ticks. Information for
+ the current measurement is pointed to by the parameter.
+
+ If the measurement's start time is 1, it indicates that the developer
+ is indicating that the measurement began at the release of reset.
+ The start time is adjusted to the timer's starting count before performing
+ the elapsed time calculation.
+
+ The calculated duration, in ticks, is the absolute difference between
+ the measurement's ending and starting counts.
+
+ @param Measurement Pointer to a MEASUREMENT_RECORD structure containing
+ data for the current measurement.
+
+ @return The 64-bit duration of the event.
+**/
+UINT64
+GetDuration (
+ IN OUT MEASUREMENT_RECORD *Measurement
+ );
+
+/**
+ Determine whether the Measurement record is for an EFI Phase.
+
+ The Token and Module members of the measurement record are checked.
+ Module must be empty and Token must be one of SEC, PEI, DXE, BDS, or SHELL.
+
+ @param[in] Measurement A pointer to the Measurement record to test.
+
+ @retval TRUE The measurement record is for an EFI Phase.
+ @retval FALSE The measurement record is NOT for an EFI Phase.
+**/
+BOOLEAN
+IsPhase(
+ IN MEASUREMENT_RECORD *Measurement
+ );
+
+/**
+ Determine whether the Measurement record is for core code.
+
+ @param[in] Measurement A pointer to the Measurement record to test.
+
+ @retval TRUE The measurement record is used for core.
+ @retval FALSE The measurement record is NOT used for core.
+
+**/
+BOOLEAN
+IsCorePerf(
+ IN MEASUREMENT_RECORD *Measurement
+ );
+
+/**
+ 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 converted
+ to Unicode and copied into UnicodeBuffer. The name is truncated,
+ if necessary, to ensure that UnicodeBuffer is not overrun.
+
+ @param[in] PdbFileName Pdb file name.
+ @param[out] UnicodeBuffer The resultant Unicode File Name.
+
+**/
+VOID
+DpGetShortPdbFileName (
+ IN CHAR8 *PdbFileName,
+ OUT CHAR16 *UnicodeBuffer
+ );
+
+/**
+ Get a human readable name for an image handle.
+ The following methods will be tried orderly:
+ 1. Image PDB
+ 2. ComponentName2 protocol
+ 3. FFS UI section
+ 4. Image GUID
+ 5. Image DevicePath
+ 6. Unknown Driver Name
+
+ @param[in] Handle
+
+ @post The resulting Unicode name string is stored in the
+ mGaugeString global array.
+
+**/
+VOID
+DpGetNameFromHandle (
+ IN EFI_HANDLE Handle
+ );
+
+/**
+ Calculate the Duration in microseconds.
+
+ Duration is multiplied by 1000, instead of Frequency being divided by 1000 or
+ multiplying the result by 1000, in order to maintain precision. Since Duration is
+ a 64-bit value, multiplying it by 1000 is unlikely to produce an overflow.
+
+ The time is calculated as (Duration * 1000) / Timer_Frequency.
+
+ @param[in] Duration The event duration in timer ticks.
+
+ @return A 64-bit value which is the Elapsed time in microseconds.
+**/
+UINT64
+DurationInMicroSeconds (
+ IN UINT64 Duration
+ );
+
+/**
+ Get index of Measurement Record's match in the CumData array.
+
+ If the Measurement's Token value matches a Token in one of the CumData
+ records, the index of the matching record is returned. The returned
+ index is a signed value so that negative values can indicate that
+ the Measurement didn't match any entry in the CumData array.
+
+ @param[in] Measurement A pointer to a Measurement Record to match against the CumData array.
+
+ @retval <0 Token is not in the CumData array.
+ @retval >=0 Return value is the index into CumData where Token is found.
+**/
+INTN
+GetCumulativeItem(
+ IN MEASUREMENT_RECORD *Measurement
+ );
+
+/**
+ Collect verbose statistics about the logged performance measurements.
+
+ General Summary information for all Trace measurements is gathered and
+ stored within the SummaryData structure. This information is both
+ used internally by subsequent reporting functions, and displayed
+ at the end of verbose reports.
+
+ @pre The SummaryData and CumData structures must be initialized
+ prior to calling this function.
+
+ @post The SummaryData and CumData structures contain statistics for the
+ current performance logs.
+
+ @param[in, out] CustomCumulativeData The pointer to the custom cumulative data.
+
+**/
+VOID
+GatherStatistics(
+ IN OUT PERF_CUM_DATA *CustomCumulativeData OPTIONAL
+ );
+
+/**
+ Gather and print ALL Trace Records.
+
+ Displays all "interesting" Trace measurements in order.<BR>
+ The number of records displayed is controlled by:
+ - records with a duration less than mInterestThreshold microseconds are not displayed.
+ - No more than Limit records are displayed. A Limit of zero will not limit the output.
+ - If the ExcludeFlag is TRUE, records matching entries in the CumData array are not
+ displayed.
+
+ @pre The mInterestThreshold global variable is set to the shortest duration to be printed.
+ The mGaugeString and mUnicodeToken global arrays are used for temporary string storage.
+ They must not be in use by a calling function.
+
+ @param[in] Limit The number of records to print. Zero is ALL.
+ @param[in] ExcludeFlag TRUE to exclude individual Cumulative items from display.
+
+ @retval EFI_SUCCESS The operation was successful.
+ @retval EFI_ABORTED The user aborts the operation.
+ @return Others from a call to gBS->LocateHandleBuffer().
+**/
+EFI_STATUS
+DumpAllTrace(
+ IN UINTN Limit,
+ IN BOOLEAN ExcludeFlag
+ );
+
+/**
+ Gather and print Raw Trace Records.
+
+ All Trace measurements with a duration greater than or equal to
+ mInterestThreshold are printed without interpretation.
+
+ The number of records displayed is controlled by:
+ - records with a duration less than mInterestThreshold microseconds are not displayed.
+ - No more than Limit records are displayed. A Limit of zero will not limit the output.
+ - If the ExcludeFlag is TRUE, records matching entries in the CumData array are not
+ displayed.
+
+ @pre The mInterestThreshold global variable is set to the shortest duration to be printed.
+
+ @param[in] Limit The number of records to print. Zero is ALL.
+ @param[in] ExcludeFlag TRUE to exclude individual Cumulative items from display.
+ @retval EFI_SUCCESS The operation was successful.
+ @retval EFI_ABORTED The user aborts the operation.
+**/
+EFI_STATUS
+DumpRawTrace(
+ IN UINTN Limit,
+ IN BOOLEAN ExcludeFlag
+ );
+
+/**
+ Gather and print Major Phase metrics.
+
+**/
+VOID
+ProcessPhases(
+ VOID
+ );
+
+
+/**
+ Gather and print Handle data.
+
+ @param[in] ExcludeFlag TRUE to exclude individual Cumulative items from display.
+
+ @retval EFI_SUCCESS The operation was successful.
+ @retval EFI_ABORTED The user aborts the operation.
+ @return Others from a call to gBS->LocateHandleBuffer().
+**/
+EFI_STATUS
+ProcessHandles(
+ IN BOOLEAN ExcludeFlag
+ );
+
+
+/**
+ Gather and print PEIM data.
+
+ Only prints complete PEIM records
+
+ @retval EFI_SUCCESS The operation was successful.
+ @retval EFI_ABORTED The user aborts the operation.
+**/
+EFI_STATUS
+ProcessPeims(
+ VOID
+ );
+
+/**
+ Gather and print global data.
+
+ Strips out incomplete or "Execution Phase" records
+ Only prints records where Handle is NULL
+ Increment TIndex for every record, even skipped ones, so that we have an
+ indication of every measurement record taken.
+
+ @retval EFI_SUCCESS The operation was successful.
+ @retval EFI_ABORTED The user aborts the operation.
+**/
+EFI_STATUS
+ProcessGlobal(
+ VOID
+ );
+
+/**
+ Gather and print cumulative data.
+
+ Traverse the measurement records and:<BR>
+ For each record with a Token listed in the CumData array:<BR>
+ - Update the instance count and the total, minimum, and maximum durations.
+ Finally, print the gathered cumulative statistics.
+
+ @param[in] CustomCumulativeData The pointer to the custom cumulative data.
+
+**/
+VOID
+ProcessCumulative(
+ IN PERF_CUM_DATA *CustomCumulativeData OPTIONAL
+ );
+
+#endif
diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/DpTrace.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/DpTrace.c
new file mode 100644
index 00000000..d66f4bd6
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/DpTrace.c
@@ -0,0 +1,904 @@
+/** @file
+ Trace reporting for the Dp utility.
+
+ Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+ (C) Copyright 2015-2016 Hewlett Packard Enterprise Development LP<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/PeCoffGetEntryPointLib.h>
+#include <Library/PerformanceLib.h>
+#include <Library/PrintLib.h>
+#include <Library/HiiLib.h>
+#include <Library/PcdLib.h>
+
+#include "Dp.h"
+#include "Literals.h"
+#include "DpInternal.h"
+
+/**
+ Attempts to retrieve a performance measurement log entry from the performance measurement log.
+
+
+ @param LogEntryKey On entry, the key of the performance measurement log entry to retrieve.
+ 0, then the first performance measurement log entry is retrieved.
+ On exit, the key of the next performance log entry.
+ @param Handle Pointer to environment specific context used to identify the component
+ being measured.
+ @param Token Pointer to a Null-terminated ASCII string that identifies the component
+ being measured.
+ @param Module Pointer to a Null-terminated ASCII string that identifies the module
+ being measured.
+ @param StartTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
+ was started.
+ @param EndTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
+ was ended.
+ @param Identifier Pointer to the 32-bit identifier that was recorded when the measurement
+ was ended.
+
+ @return The key for the next performance log entry (in general case).
+
+**/
+UINTN
+GetPerformanceMeasurementRecord (
+ IN UINTN LogEntryKey,
+ OUT CONST VOID **Handle,
+ OUT CONST CHAR8 **Token,
+ OUT CONST CHAR8 **Module,
+ OUT UINT64 *StartTimeStamp,
+ OUT UINT64 *EndTimeStamp,
+ OUT UINT32 *Identifier
+ )
+{
+ if (LogEntryKey == mMeasurementNum) {
+ return 0;
+ }
+
+ *Handle = (VOID *) (UINTN) mMeasurementList[LogEntryKey].Handle;
+ *Token = mMeasurementList[LogEntryKey].Token;
+ *Module = mMeasurementList[LogEntryKey].Module;
+ *StartTimeStamp = mMeasurementList[LogEntryKey].StartTimeStamp;
+ *EndTimeStamp = mMeasurementList[LogEntryKey].EndTimeStamp;
+ *Identifier = mMeasurementList[LogEntryKey].Identifier;
+
+ LogEntryKey ++;
+
+ return LogEntryKey;
+}
+
+/**
+ Collect verbose statistics about the logged performance measurements.
+
+ General Summary information for all Trace measurements is gathered and
+ stored within the SummaryData structure. This information is both
+ used internally by subsequent reporting functions, and displayed
+ at the end of verbose reports.
+
+ @pre The SummaryData and CumData structures must be initialized
+ prior to calling this function.
+
+ @post The SummaryData and CumData structures contain statistics for the
+ current performance logs.
+
+ @param[in, out] CustomCumulativeData A pointer to the custom cumulative data.
+
+**/
+VOID
+GatherStatistics(
+ IN OUT PERF_CUM_DATA *CustomCumulativeData OPTIONAL
+ )
+{
+ MEASUREMENT_RECORD Measurement;
+ UINT64 Duration;
+ UINTN LogEntryKey;
+ INTN TIndex;
+
+ LogEntryKey = 0;
+ while ((LogEntryKey = GetPerformanceMeasurementRecord (
+ LogEntryKey,
+ &Measurement.Handle,
+ &Measurement.Token,
+ &Measurement.Module,
+ &Measurement.StartTimeStamp,
+ &Measurement.EndTimeStamp,
+ &Measurement.Identifier)) != 0)
+ {
+ ++SummaryData.NumTrace; // Count the number of TRACE Measurement records
+ if (Measurement.EndTimeStamp == 0) {
+ ++SummaryData.NumIncomplete; // Count the incomplete records
+ continue;
+ }
+
+ if (Measurement.Handle != NULL) {
+ ++SummaryData.NumHandles; // Count the number of measurements with non-NULL handles
+ }
+
+ if (IsPhase( &Measurement)) {
+ ++SummaryData.NumSummary; // Count the number of major phases
+ }
+ else { // !IsPhase
+ if(Measurement.Handle == NULL) {
+ ++SummaryData.NumGlobal;
+ }
+ }
+
+ if (AsciiStrCmp (Measurement.Token, ALit_PEIM) == 0) {
+ ++SummaryData.NumPEIMs; // Count PEIM measurements
+ }
+
+ Duration = GetDuration (&Measurement);
+ TIndex = GetCumulativeItem (&Measurement);
+ if (TIndex >= 0) {
+ CumData[TIndex].Duration += Duration;
+ CumData[TIndex].Count++;
+ if ( Duration < CumData[TIndex].MinDur ) {
+ CumData[TIndex].MinDur = Duration;
+ }
+ if ( Duration > CumData[TIndex].MaxDur ) {
+ CumData[TIndex].MaxDur = Duration;
+ }
+ }
+
+ //
+ // Collect the data for custom cumulative data.
+ //
+ if ((CustomCumulativeData != NULL) && (AsciiStrCmp (Measurement.Token, CustomCumulativeData->Name) == 0)) {
+ CustomCumulativeData->Duration += Duration;
+ CustomCumulativeData->Count++;
+ if (Duration < CustomCumulativeData->MinDur) {
+ CustomCumulativeData->MinDur = Duration;
+ }
+ if (Duration > CustomCumulativeData->MaxDur) {
+ CustomCumulativeData->MaxDur = Duration;
+ }
+ }
+ }
+}
+
+/**
+ Gather and print ALL Trace Records.
+
+ Displays all "interesting" Trace measurements in order.<BR>
+ The number of records displayed is controlled by:
+ - records with a duration less than mInterestThreshold microseconds are not displayed.
+ - No more than Limit records are displayed. A Limit of zero will not limit the output.
+ - If the ExcludeFlag is TRUE, records matching entries in the CumData array are not
+ displayed.
+
+ @pre The mInterestThreshold global variable is set to the shortest duration to be printed.
+ The mGaugeString and mUnicodeToken global arrays are used for temporary string storage.
+ They must not be in use by a calling function.
+
+ @param[in] Limit The number of records to print. Zero is ALL.
+ @param[in] ExcludeFlag TRUE to exclude individual Cumulative items from display.
+
+ @retval EFI_SUCCESS The operation was successful.
+ @retval EFI_ABORTED The user aborts the operation.
+ @return Others from a call to gBS->LocateHandleBuffer().
+**/
+EFI_STATUS
+DumpAllTrace(
+ IN UINTN Limit,
+ IN BOOLEAN ExcludeFlag
+ )
+{
+ MEASUREMENT_RECORD Measurement;
+ UINT64 ElapsedTime;
+ UINT64 Duration;
+ CHAR16 *IncFlag;
+ UINTN LogEntryKey;
+ UINTN Count;
+ UINTN Index;
+ UINTN TIndex;
+
+ EFI_HANDLE *HandleBuffer;
+ UINTN HandleCount;
+ EFI_STATUS Status;
+ EFI_STRING StringPtrUnknown;
+
+ StringPtrUnknown = HiiGetString (mDpHiiHandle, STRING_TOKEN (STR_ALIT_UNKNOWN), NULL);
+ IncFlag = HiiGetString (mDpHiiHandle, STRING_TOKEN (STR_DP_SECTION_ALL), NULL);
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_SECTION_HEADER), mDpHiiHandle,
+ (IncFlag == NULL) ? StringPtrUnknown : IncFlag);
+ FreePool (StringPtrUnknown);
+
+ // Get Handle information
+ //
+ Status = gBS->LocateHandleBuffer (AllHandles, NULL, NULL, &HandleCount, &HandleBuffer);
+ if (EFI_ERROR (Status)) {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_HANDLES_ERROR), mDpHiiHandle, Status);
+ }
+ else {
+ // We have successfully populated the HandleBuffer
+ // Display ALL Measurement Records
+ // Up to Limit lines displayed
+ // Display only records with Elapsed times >= mInterestThreshold
+ // Display driver names in Module field for records with Handles.
+ //
+ if (mShowId) {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_ALL_HEADR2), mDpHiiHandle);
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_ALL_DASHES2), mDpHiiHandle);
+ } else {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_ALL_HEADR), mDpHiiHandle);
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_DASHES), mDpHiiHandle);
+ }
+
+ LogEntryKey = 0;
+ Count = 0;
+ Index = 0;
+ while ( WITHIN_LIMIT(Count, Limit) &&
+ ((LogEntryKey = GetPerformanceMeasurementRecord (
+ LogEntryKey,
+ &Measurement.Handle,
+ &Measurement.Token,
+ &Measurement.Module,
+ &Measurement.StartTimeStamp,
+ &Measurement.EndTimeStamp,
+ &Measurement.Identifier)) != 0)
+ )
+ {
+ ++Index; // Count every record. First record is 1.
+ ElapsedTime = 0;
+ SHELL_FREE_NON_NULL (IncFlag);
+ if (Measurement.EndTimeStamp != 0) {
+ Duration = GetDuration (&Measurement);
+ ElapsedTime = DurationInMicroSeconds ( Duration );
+ IncFlag = HiiGetString (mDpHiiHandle, STRING_TOKEN (STR_DP_COMPLETE), NULL);
+ }
+ else {
+ IncFlag = HiiGetString (mDpHiiHandle, STRING_TOKEN (STR_DP_INCOMPLETE), NULL); // Mark incomplete records
+ }
+ if (((Measurement.EndTimeStamp != 0) && (ElapsedTime < mInterestThreshold)) ||
+ ((ExcludeFlag) && (GetCumulativeItem(&Measurement) >= 0))
+ ) { // Ignore "uninteresting" or excluded records
+ continue;
+ }
+ ++Count; // Count the number of records printed
+
+ // If Handle is non-zero, see if we can determine a name for the driver
+ AsciiStrToUnicodeStrS (Measurement.Module, mGaugeString, ARRAY_SIZE (mGaugeString)); // Use Module by default
+ AsciiStrToUnicodeStrS (Measurement.Token, mUnicodeToken, ARRAY_SIZE (mUnicodeToken));
+ if (Measurement.Handle != NULL) {
+ // See if the Handle is in the HandleBuffer
+ for (TIndex = 0; TIndex < HandleCount; TIndex++) {
+ if (Measurement.Handle == HandleBuffer[TIndex]) {
+ DpGetNameFromHandle (HandleBuffer[TIndex]);
+ break;
+ }
+ }
+ }
+
+ if (AsciiStrCmp (Measurement.Token, ALit_PEIM) == 0) {
+ UnicodeSPrint (mGaugeString, sizeof (mGaugeString), L"%g", Measurement.Handle);
+ }
+
+ // Ensure that the argument strings are not too long.
+ mGaugeString[DP_GAUGE_STRING_LENGTH] = 0;
+ mUnicodeToken[13] = 0;
+
+ if (mShowId) {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_ALL_VARS2), mDpHiiHandle,
+ Index, // 1 based, Which measurement record is being printed
+ IncFlag,
+ Measurement.Handle,
+ mGaugeString,
+ mUnicodeToken,
+ ElapsedTime,
+ Measurement.Identifier
+ );
+ } else {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_ALL_VARS), mDpHiiHandle,
+ Index, // 1 based, Which measurement record is being printed
+ IncFlag,
+ Measurement.Handle,
+ mGaugeString,
+ mUnicodeToken,
+ ElapsedTime
+ );
+ }
+ if (ShellGetExecutionBreakFlag ()) {
+ Status = EFI_ABORTED;
+ break;
+ }
+ }
+ }
+ if (HandleBuffer != NULL) {
+ FreePool (HandleBuffer);
+ }
+ SHELL_FREE_NON_NULL (IncFlag);
+
+ return Status;
+}
+
+/**
+ Gather and print Raw Trace Records.
+
+ All Trace measurements with a duration greater than or equal to
+ mInterestThreshold are printed without interpretation.
+
+ The number of records displayed is controlled by:
+ - records with a duration less than mInterestThreshold microseconds are not displayed.
+ - No more than Limit records are displayed. A Limit of zero will not limit the output.
+ - If the ExcludeFlag is TRUE, records matching entries in the CumData array are not
+ displayed.
+
+ @pre The mInterestThreshold global variable is set to the shortest duration to be printed.
+
+ @param[in] Limit The number of records to print. Zero is ALL.
+ @param[in] ExcludeFlag TRUE to exclude individual Cumulative items from display.
+
+ @retval EFI_SUCCESS The operation was successful.
+ @retval EFI_ABORTED The user aborts the operation.
+**/
+EFI_STATUS
+DumpRawTrace(
+ IN UINTN Limit,
+ IN BOOLEAN ExcludeFlag
+ )
+{
+ MEASUREMENT_RECORD Measurement;
+ UINT64 ElapsedTime;
+ UINT64 Duration;
+ UINTN LogEntryKey;
+ UINTN Count;
+ UINTN Index;
+
+ EFI_STRING StringPtr;
+ EFI_STRING StringPtrUnknown;
+ EFI_STATUS Status;
+
+ Status = EFI_SUCCESS;
+
+ StringPtrUnknown = HiiGetString (mDpHiiHandle, STRING_TOKEN (STR_ALIT_UNKNOWN), NULL);
+ StringPtr = HiiGetString (mDpHiiHandle, STRING_TOKEN (STR_DP_SECTION_RAWTRACE), NULL);
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_SECTION_HEADER), mDpHiiHandle,
+ (StringPtr == NULL) ? StringPtrUnknown : StringPtr);
+ FreePool (StringPtr);
+ FreePool (StringPtrUnknown);
+
+ if (mShowId) {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_RAW_HEADR2), mDpHiiHandle);
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_RAW_DASHES2), mDpHiiHandle);
+ } else {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_RAW_HEADR), mDpHiiHandle);
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_RAW_DASHES), mDpHiiHandle);
+ }
+
+ LogEntryKey = 0;
+ Count = 0;
+ Index = 0;
+ while ( WITHIN_LIMIT(Count, Limit) &&
+ ((LogEntryKey = GetPerformanceMeasurementRecord (
+ LogEntryKey,
+ &Measurement.Handle,
+ &Measurement.Token,
+ &Measurement.Module,
+ &Measurement.StartTimeStamp,
+ &Measurement.EndTimeStamp,
+ &Measurement.Identifier)) != 0)
+ )
+ {
+ ++Index; // Count every record. First record is 1.
+ ElapsedTime = 0;
+ if (Measurement.EndTimeStamp != 0) {
+ Duration = GetDuration (&Measurement);
+ ElapsedTime = DurationInMicroSeconds ( Duration );
+ }
+ if ((ElapsedTime < mInterestThreshold) ||
+ ((ExcludeFlag) && (GetCumulativeItem(&Measurement) >= 0))
+ ) { // Ignore "uninteresting" or Excluded records
+ continue;
+ }
+ ++Count; // Count the number of records printed
+
+ if (mShowId) {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_RAW_VARS2), mDpHiiHandle,
+ Index, // 1 based, Which measurement record is being printed
+ Measurement.Handle,
+ Measurement.StartTimeStamp,
+ Measurement.EndTimeStamp,
+ Measurement.Token,
+ Measurement.Module,
+ Measurement.Identifier
+ );
+ } else {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_RAW_VARS), mDpHiiHandle,
+ Index, // 1 based, Which measurement record is being printed
+ Measurement.Handle,
+ Measurement.StartTimeStamp,
+ Measurement.EndTimeStamp,
+ Measurement.Token,
+ Measurement.Module
+ );
+ }
+ if (ShellGetExecutionBreakFlag ()) {
+ Status = EFI_ABORTED;
+ break;
+ }
+ }
+ return Status;
+}
+
+/**
+ Gather and print Major Phase metrics.
+
+**/
+VOID
+ProcessPhases(
+ VOID
+ )
+{
+ MEASUREMENT_RECORD Measurement;
+ UINT64 BdsTimeoutValue;
+ UINT64 SecTime;
+ UINT64 PeiTime;
+ UINT64 DxeTime;
+ UINT64 BdsTime;
+ UINT64 ElapsedTime;
+ UINT64 Duration;
+ UINT64 Total;
+ EFI_STRING StringPtr;
+ UINTN LogEntryKey;
+ EFI_STRING StringPtrUnknown;
+
+ BdsTimeoutValue = 0;
+ SecTime = 0;
+ PeiTime = 0;
+ DxeTime = 0;
+ BdsTime = 0;
+ //
+ // Get Execution Phase Statistics
+ //
+ StringPtrUnknown = HiiGetString (mDpHiiHandle, STRING_TOKEN (STR_ALIT_UNKNOWN), NULL);
+ StringPtr = HiiGetString (mDpHiiHandle, STRING_TOKEN (STR_DP_SECTION_PHASES), NULL);
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_SECTION_HEADER), mDpHiiHandle,
+ (StringPtr == NULL) ? StringPtrUnknown : StringPtr);
+ FreePool (StringPtr);
+ FreePool (StringPtrUnknown);
+
+ LogEntryKey = 0;
+ while ((LogEntryKey = GetPerformanceMeasurementRecord (
+ LogEntryKey,
+ &Measurement.Handle,
+ &Measurement.Token,
+ &Measurement.Module,
+ &Measurement.StartTimeStamp,
+ &Measurement.EndTimeStamp,
+ &Measurement.Identifier)) != 0)
+ {
+ if (Measurement.EndTimeStamp == 0) { // Skip "incomplete" records
+ continue;
+ }
+ Duration = GetDuration (&Measurement);
+ if ( Measurement.Handle != NULL
+ && (AsciiStrCmp (Measurement.Token, ALit_BdsTO) == 0)
+ )
+ {
+ BdsTimeoutValue = Duration;
+ } else if (AsciiStrCmp (Measurement.Token, ALit_SEC) == 0) {
+ SecTime = Duration;
+ } else if (AsciiStrCmp (Measurement.Token, ALit_PEI) == 0) {
+ PeiTime = Duration;
+ } else if (AsciiStrCmp (Measurement.Token, ALit_DXE) == 0) {
+ DxeTime = Duration;
+ } else if (AsciiStrCmp (Measurement.Token, ALit_BDS) == 0) {
+ BdsTime = Duration;
+ }
+ }
+
+ Total = 0;
+
+ // print SEC phase duration time
+ //
+ if (SecTime > 0) {
+ ElapsedTime = DurationInMicroSeconds ( SecTime ); // Calculate elapsed time in microseconds
+ Total += DivU64x32 (ElapsedTime, 1000); // Accumulate time in milliseconds
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_SEC_PHASE), mDpHiiHandle, ElapsedTime);
+ }
+
+ // print PEI phase duration time
+ //
+ if (PeiTime > 0) {
+ ElapsedTime = DivU64x32 (PeiTime, 1000000);
+ Total += ElapsedTime;
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_PHASE_DURATION), mDpHiiHandle, ALit_PEI, ElapsedTime);
+ }
+
+ // print DXE phase duration time
+ //
+ if (DxeTime > 0) {
+ ElapsedTime = DivU64x32 (DxeTime, 1000000);
+ Total += ElapsedTime;
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_PHASE_DURATION), mDpHiiHandle, ALit_DXE, ElapsedTime);
+ }
+
+ // print BDS phase duration time
+ //
+ if (BdsTime > 0) {
+ ElapsedTime = DivU64x32 (BdsTime, 1000000);
+ Total += ElapsedTime;
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_PHASE_DURATION), mDpHiiHandle, ALit_BDS, ElapsedTime);
+ }
+
+ if (BdsTimeoutValue > 0) {
+ ElapsedTime = DivU64x32 (BdsTimeoutValue, 1000000);
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_PHASE_BDSTO), mDpHiiHandle, ALit_BdsTO, ElapsedTime);
+ }
+
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_TOTAL_DURATION), mDpHiiHandle, Total);
+}
+
+/**
+ Gather and print Handle data.
+
+ @param[in] ExcludeFlag TRUE to exclude individual Cumulative items from display.
+
+ @retval EFI_SUCCESS The operation was successful.
+ @retval EFI_ABORTED The user aborts the operation.
+ @return Others from a call to gBS->LocateHandleBuffer().
+**/
+EFI_STATUS
+ProcessHandles(
+ IN BOOLEAN ExcludeFlag
+ )
+{
+ MEASUREMENT_RECORD Measurement;
+ UINT64 ElapsedTime;
+ UINT64 Duration;
+ EFI_HANDLE *HandleBuffer;
+ EFI_STRING StringPtr;
+ UINTN Index;
+ UINTN LogEntryKey;
+ UINTN Count;
+ UINTN HandleCount;
+ EFI_STATUS Status;
+ EFI_STRING StringPtrUnknown;
+
+ StringPtrUnknown = HiiGetString (mDpHiiHandle, STRING_TOKEN (STR_ALIT_UNKNOWN), NULL);
+ StringPtr = HiiGetString (mDpHiiHandle, STRING_TOKEN (STR_DP_SECTION_DRIVERS), NULL);
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_SECTION_HEADER), mDpHiiHandle,
+ (StringPtr == NULL) ? StringPtrUnknown : StringPtr);
+ FreePool (StringPtr);
+ FreePool (StringPtrUnknown);
+
+ Status = gBS->LocateHandleBuffer (AllHandles, NULL, NULL, &HandleCount, &HandleBuffer);
+ if (EFI_ERROR (Status)) {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_HANDLES_ERROR), mDpHiiHandle, Status);
+ }
+ else {
+#if DP_DEBUG == 2
+ Print (L"There are %,d Handles defined.\n", (Size / sizeof(HandleBuffer[0])));
+#endif
+
+ if (mShowId) {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_HANDLE_SECTION2), mDpHiiHandle);
+ } else {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_HANDLE_SECTION), mDpHiiHandle);
+ }
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_DASHES), mDpHiiHandle);
+
+ LogEntryKey = 0;
+ Count = 0;
+ while ((LogEntryKey = GetPerformanceMeasurementRecord (
+ LogEntryKey,
+ &Measurement.Handle,
+ &Measurement.Token,
+ &Measurement.Module,
+ &Measurement.StartTimeStamp,
+ &Measurement.EndTimeStamp,
+ &Measurement.Identifier)) != 0)
+ {
+ Count++;
+ Duration = GetDuration (&Measurement);
+ ElapsedTime = DurationInMicroSeconds ( Duration );
+ if ((ElapsedTime < mInterestThreshold) ||
+ (Measurement.EndTimeStamp == 0) ||
+ (!IsCorePerf (&Measurement)) ||
+ ((ExcludeFlag) && (GetCumulativeItem(&Measurement) >= 0))
+ ) { // Ignore "uninteresting" or excluded records
+ continue;
+ }
+ mGaugeString[0] = 0; // Empty driver name by default
+ AsciiStrToUnicodeStrS (Measurement.Token, mUnicodeToken, ARRAY_SIZE (mUnicodeToken));
+ // See if the Handle is in the HandleBuffer
+ for (Index = 0; Index < HandleCount; Index++) {
+ if (Measurement.Handle == HandleBuffer[Index]) {
+ DpGetNameFromHandle (HandleBuffer[Index]); // Name is put into mGaugeString
+ break;
+ }
+ }
+ // Ensure that the argument strings are not too long.
+ mGaugeString[DP_GAUGE_STRING_LENGTH] = 0;
+ mUnicodeToken[11] = 0;
+ if (mGaugeString[0] != 0) {
+ // Display the record if it has a valid handle.
+ if (mShowId) {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_HANDLE_VARS2), mDpHiiHandle,
+ Count, // 1 based, Which measurement record is being printed
+ Index + 1, // 1 based, Which handle is being printed
+ mGaugeString,
+ mUnicodeToken,
+ ElapsedTime,
+ Measurement.Identifier
+ );
+ } else {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_HANDLE_VARS), mDpHiiHandle,
+ Count, // 1 based, Which measurement record is being printed
+ Index + 1, // 1 based, Which handle is being printed
+ mGaugeString,
+ mUnicodeToken,
+ ElapsedTime
+ );
+ }
+ }
+ if (ShellGetExecutionBreakFlag ()) {
+ Status = EFI_ABORTED;
+ break;
+ }
+ }
+ }
+ if (HandleBuffer != NULL) {
+ FreePool (HandleBuffer);
+ }
+ return Status;
+}
+
+/**
+ Gather and print PEIM data.
+
+ Only prints complete PEIM records
+
+ @retval EFI_SUCCESS The operation was successful.
+ @retval EFI_ABORTED The user aborts the operation.
+**/
+EFI_STATUS
+ProcessPeims(
+ VOID
+)
+{
+ MEASUREMENT_RECORD Measurement;
+ UINT64 Duration;
+ UINT64 ElapsedTime;
+ EFI_STRING StringPtr;
+ UINTN LogEntryKey;
+ UINTN TIndex;
+ EFI_STRING StringPtrUnknown;
+ EFI_STATUS Status;
+
+ Status = EFI_SUCCESS;
+
+ StringPtrUnknown = HiiGetString (mDpHiiHandle, STRING_TOKEN (STR_ALIT_UNKNOWN), NULL);
+ StringPtr = HiiGetString (mDpHiiHandle, STRING_TOKEN (STR_DP_SECTION_PEIMS), NULL);
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_SECTION_HEADER), mDpHiiHandle,
+ (StringPtr == NULL) ? StringPtrUnknown : StringPtr);
+ FreePool (StringPtr);
+ FreePool (StringPtrUnknown);
+
+ if (mShowId) {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_PEIM_SECTION2), mDpHiiHandle);
+ } else {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_PEIM_SECTION), mDpHiiHandle);
+ }
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_DASHES), mDpHiiHandle);
+ TIndex = 0;
+ LogEntryKey = 0;
+ while ((LogEntryKey = GetPerformanceMeasurementRecord (
+ LogEntryKey,
+ &Measurement.Handle,
+ &Measurement.Token,
+ &Measurement.Module,
+ &Measurement.StartTimeStamp,
+ &Measurement.EndTimeStamp,
+ &Measurement.Identifier)) != 0)
+ {
+ TIndex++;
+ if ((Measurement.EndTimeStamp == 0) ||
+ (AsciiStrCmp (Measurement.Token, ALit_PEIM) != 0)
+ ) {
+ continue;
+ }
+
+ Duration = GetDuration (&Measurement);
+ ElapsedTime = DurationInMicroSeconds ( Duration ); // Calculate elapsed time in microseconds
+ if (ElapsedTime >= mInterestThreshold) {
+ // PEIM FILE Handle is the start address of its FFS file that contains its file guid.
+ if (mShowId) {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_PEIM_VARS2), mDpHiiHandle,
+ TIndex, // 1 based, Which measurement record is being printed
+ Measurement.Handle, // file guid
+ ElapsedTime,
+ Measurement.Identifier
+ );
+ } else {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_PEIM_VARS), mDpHiiHandle,
+ TIndex, // 1 based, Which measurement record is being printed
+ Measurement.Handle, // file guid
+ ElapsedTime
+ );
+ }
+ }
+ if (ShellGetExecutionBreakFlag ()) {
+ Status = EFI_ABORTED;
+ break;
+ }
+ }
+ return Status;
+}
+
+/**
+ Gather and print global data.
+
+ Strips out incomplete or "Execution Phase" records
+ Only prints records where Handle is NULL
+ Increment TIndex for every record, even skipped ones, so that we have an
+ indication of every measurement record taken.
+
+ @retval EFI_SUCCESS The operation was successful.
+ @retval EFI_ABORTED The user aborts the operation.
+**/
+EFI_STATUS
+ProcessGlobal(
+ VOID
+)
+{
+ MEASUREMENT_RECORD Measurement;
+ UINT64 Duration;
+ UINT64 ElapsedTime;
+ EFI_STRING StringPtr;
+ UINTN LogEntryKey;
+ UINTN Index; // Index, or number, of the measurement record being processed
+ EFI_STRING StringPtrUnknown;
+ EFI_STATUS Status;
+
+ Status = EFI_SUCCESS;
+
+ StringPtrUnknown = HiiGetString (mDpHiiHandle, STRING_TOKEN (STR_ALIT_UNKNOWN), NULL);
+ StringPtr = HiiGetString (mDpHiiHandle, STRING_TOKEN (STR_DP_SECTION_GENERAL), NULL);
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_SECTION_HEADER), mDpHiiHandle,
+ (StringPtr == NULL) ? StringPtrUnknown: StringPtr);
+ FreePool (StringPtr);
+ FreePool (StringPtrUnknown);
+
+ if (mShowId) {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_GLOBAL_SECTION2), mDpHiiHandle);
+ } else {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_GLOBAL_SECTION), mDpHiiHandle);
+ }
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_DASHES), mDpHiiHandle);
+
+ Index = 1;
+ LogEntryKey = 0;
+
+ while ((LogEntryKey = GetPerformanceMeasurementRecord (
+ LogEntryKey,
+ &Measurement.Handle,
+ &Measurement.Token,
+ &Measurement.Module,
+ &Measurement.StartTimeStamp,
+ &Measurement.EndTimeStamp,
+ &Measurement.Identifier)) != 0)
+ {
+ AsciiStrToUnicodeStrS (Measurement.Module, mGaugeString, ARRAY_SIZE (mGaugeString));
+ AsciiStrToUnicodeStrS (Measurement.Token, mUnicodeToken, ARRAY_SIZE (mUnicodeToken));
+ mGaugeString[25] = 0;
+ mUnicodeToken[31] = 0;
+ if ( ! ( IsPhase( &Measurement) ||
+ IsCorePerf (&Measurement) ||
+ (Measurement.EndTimeStamp == 0)
+ ))
+ {
+ Duration = GetDuration (&Measurement);
+ ElapsedTime = DurationInMicroSeconds ( Duration );
+ if (ElapsedTime >= mInterestThreshold) {
+ if (mShowId) {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_GLOBAL_VARS2), mDpHiiHandle,
+ Index,
+ mGaugeString,
+ mUnicodeToken,
+ ElapsedTime,
+ Measurement.Identifier
+ );
+ } else {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_GLOBAL_VARS), mDpHiiHandle,
+ Index,
+ mGaugeString,
+ mUnicodeToken,
+ ElapsedTime
+ );
+ }
+ }
+ }
+ if (ShellGetExecutionBreakFlag ()) {
+ Status = EFI_ABORTED;
+ break;
+ }
+ Index++;
+ }
+ return Status;
+}
+
+/**
+ Gather and print cumulative data.
+
+ Traverse the measurement records and:<BR>
+ For each record with a Token listed in the CumData array:<BR>
+ - Update the instance count and the total, minimum, and maximum durations.
+ Finally, print the gathered cumulative statistics.
+
+ @param[in] CustomCumulativeData A pointer to the custom cumulative data.
+
+**/
+VOID
+ProcessCumulative(
+ IN PERF_CUM_DATA *CustomCumulativeData OPTIONAL
+ )
+{
+ UINT64 AvgDur; // the computed average duration
+ UINT64 Dur;
+ UINT64 MinDur;
+ UINT64 MaxDur;
+ EFI_STRING StringPtr;
+ UINTN TIndex;
+ EFI_STRING StringPtrUnknown;
+
+ StringPtrUnknown = HiiGetString (mDpHiiHandle, STRING_TOKEN (STR_ALIT_UNKNOWN), NULL);
+ StringPtr = HiiGetString (mDpHiiHandle, STRING_TOKEN (STR_DP_SECTION_CUMULATIVE), NULL);
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_SECTION_HEADER), mDpHiiHandle,
+ (StringPtr == NULL) ? StringPtrUnknown: StringPtr);
+ FreePool (StringPtr);
+ FreePool (StringPtrUnknown);
+
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_CUMULATIVE_SECT_1), mDpHiiHandle);
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_CUMULATIVE_SECT_2), mDpHiiHandle);
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_DASHES), mDpHiiHandle);
+
+ for ( TIndex = 0; TIndex < NumCum; ++TIndex) {
+ if (CumData[TIndex].Count != 0) {
+ AvgDur = DivU64x32 (CumData[TIndex].Duration, CumData[TIndex].Count);
+ AvgDur = DurationInMicroSeconds(AvgDur);
+ Dur = DurationInMicroSeconds(CumData[TIndex].Duration);
+ MaxDur = DurationInMicroSeconds(CumData[TIndex].MaxDur);
+ MinDur = DurationInMicroSeconds(CumData[TIndex].MinDur);
+
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_CUMULATIVE_STATS), mDpHiiHandle,
+ CumData[TIndex].Name,
+ CumData[TIndex].Count,
+ Dur,
+ AvgDur,
+ MinDur,
+ MaxDur
+ );
+ }
+ }
+
+ //
+ // Print the custom cumulative data.
+ //
+ if (CustomCumulativeData != NULL) {
+ if (CustomCumulativeData->Count != 0) {
+ AvgDur = DivU64x32 (CustomCumulativeData->Duration, CustomCumulativeData->Count);
+ AvgDur = DurationInMicroSeconds (AvgDur);
+ Dur = DurationInMicroSeconds (CustomCumulativeData->Duration);
+ MaxDur = DurationInMicroSeconds (CustomCumulativeData->MaxDur);
+ MinDur = DurationInMicroSeconds (CustomCumulativeData->MinDur);
+ } else {
+ AvgDur = 0;
+ Dur = 0;
+ MaxDur = 0;
+ MinDur = 0;
+ }
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_CUMULATIVE_STATS), mDpHiiHandle,
+ CustomCumulativeData->Name,
+ CustomCumulativeData->Count,
+ Dur,
+ AvgDur,
+ MinDur,
+ MaxDur
+ );
+ }
+}
diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/DpUtilities.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/DpUtilities.c
new file mode 100644
index 00000000..8d84e69b
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/DpUtilities.c
@@ -0,0 +1,422 @@
+/** @file
+ Utility functions used by the Dp application.
+
+ Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+ (C) Copyright 2015-2016 Hewlett Packard Enterprise Development LP<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/PeCoffGetEntryPointLib.h>
+#include <Library/PrintLib.h>
+#include <Library/HiiLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/HandleParsingLib.h>
+
+#include <Pi/PiFirmwareFile.h>
+#include <Library/DxeServicesLib.h>
+
+#include <Protocol/LoadedImage.h>
+#include <Protocol/DriverBinding.h>
+#include <Protocol/ComponentName2.h>
+#include <Protocol/DevicePath.h>
+
+#include <Guid/Performance.h>
+
+#include "Dp.h"
+#include "Literals.h"
+#include "DpInternal.h"
+
+/**
+ Calculate an event's duration in timer ticks.
+
+ Given the count direction and the event's start and end timer values,
+ calculate the duration of the event in timer ticks. Information for
+ the current measurement is pointed to by the parameter.
+
+ If the measurement's start time is 1, it indicates that the developer
+ is indicating that the measurement began at the release of reset.
+ The start time is adjusted to the timer's starting count before performing
+ the elapsed time calculation.
+
+ The calculated duration, in ticks, is the absolute difference between
+ the measurement's ending and starting counts.
+
+ @param Measurement Pointer to a MEASUREMENT_RECORD structure containing
+ data for the current measurement.
+
+ @return The 64-bit duration of the event.
+**/
+UINT64
+GetDuration (
+ IN OUT MEASUREMENT_RECORD *Measurement
+ )
+{
+ UINT64 Duration;
+ BOOLEAN Error;
+
+ if (Measurement->EndTimeStamp == 0) {
+ return 0;
+ }
+
+ Duration = Measurement->EndTimeStamp - Measurement->StartTimeStamp;
+ Error = (BOOLEAN)(Duration > Measurement->EndTimeStamp);
+
+ if (Error) {
+ DEBUG ((EFI_D_ERROR, ALit_TimerLibError));
+ Duration = 0;
+ }
+ return Duration;
+}
+
+/**
+ Determine whether the Measurement record is for an EFI Phase.
+
+ The Token and Module members of the measurement record are checked.
+ Module must be empty and Token must be one of SEC, PEI, DXE, BDS, or SHELL.
+
+ @param[in] Measurement A pointer to the Measurement record to test.
+
+ @retval TRUE The measurement record is for an EFI Phase.
+ @retval FALSE The measurement record is NOT for an EFI Phase.
+**/
+BOOLEAN
+IsPhase(
+ IN MEASUREMENT_RECORD *Measurement
+ )
+{
+ BOOLEAN RetVal;
+
+ RetVal = (BOOLEAN)(
+ ((AsciiStrCmp (Measurement->Token, ALit_SEC) == 0) ||
+ (AsciiStrCmp (Measurement->Token, ALit_PEI) == 0) ||
+ (AsciiStrCmp (Measurement->Token, ALit_DXE) == 0) ||
+ (AsciiStrCmp (Measurement->Token, ALit_BDS) == 0))
+ );
+ return RetVal;
+}
+
+/**
+ Determine whether the Measurement record is for core code.
+
+ @param[in] Measurement A pointer to the Measurement record to test.
+
+ @retval TRUE The measurement record is used for core.
+ @retval FALSE The measurement record is NOT used for core.
+
+**/
+BOOLEAN
+IsCorePerf(
+ IN MEASUREMENT_RECORD *Measurement
+ )
+{
+ BOOLEAN RetVal;
+
+ RetVal = (BOOLEAN)(
+ ((Measurement->Identifier == MODULE_START_ID) ||
+ (Measurement->Identifier == MODULE_END_ID) ||
+ (Measurement->Identifier == MODULE_LOADIMAGE_START_ID) ||
+ (Measurement->Identifier == MODULE_LOADIMAGE_END_ID) ||
+ (Measurement->Identifier == MODULE_DB_START_ID) ||
+ (Measurement->Identifier == MODULE_DB_END_ID) ||
+ (Measurement->Identifier == MODULE_DB_SUPPORT_START_ID) ||
+ (Measurement->Identifier == MODULE_DB_SUPPORT_END_ID) ||
+ (Measurement->Identifier == MODULE_DB_STOP_START_ID) ||
+ (Measurement->Identifier == MODULE_DB_STOP_START_ID))
+ );
+ return RetVal;
+}
+
+/**
+ 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 converted
+ to Unicode and copied into UnicodeBuffer. The name is truncated,
+ if necessary, to ensure that UnicodeBuffer is not overrun.
+
+ @param[in] PdbFileName Pdb file name.
+ @param[out] UnicodeBuffer The resultant Unicode File Name.
+
+**/
+VOID
+DpGetShortPdbFileName (
+ IN CHAR8 *PdbFileName,
+ OUT CHAR16 *UnicodeBuffer
+ )
+{
+ UINTN IndexA; // Current work location within an ASCII string.
+ UINTN IndexU; // Current work location within a Unicode string.
+ UINTN StartIndex;
+ UINTN EndIndex;
+
+ ZeroMem (UnicodeBuffer, (DP_GAUGE_STRING_LENGTH + 1) * sizeof (CHAR16));
+
+ if (PdbFileName == NULL) {
+ StrnCpyS (UnicodeBuffer, DP_GAUGE_STRING_LENGTH + 1, L" ", 1);
+ } else {
+ StartIndex = 0;
+ for (EndIndex = 0; PdbFileName[EndIndex] != 0; EndIndex++)
+ ;
+ for (IndexA = 0; PdbFileName[IndexA] != 0; IndexA++) {
+ if ((PdbFileName[IndexA] == '\\') || (PdbFileName[IndexA] == '/')) {
+ StartIndex = IndexA + 1;
+ }
+
+ if (PdbFileName[IndexA] == '.') {
+ EndIndex = IndexA;
+ }
+ }
+
+ IndexU = 0;
+ for (IndexA = StartIndex; IndexA < EndIndex; IndexA++) {
+ UnicodeBuffer[IndexU] = (CHAR16) PdbFileName[IndexA];
+ IndexU++;
+ if (IndexU >= DP_GAUGE_STRING_LENGTH) {
+ UnicodeBuffer[DP_GAUGE_STRING_LENGTH] = 0;
+ break;
+ }
+ }
+ }
+}
+
+/**
+ Get a human readable name for an image handle.
+ The following methods will be tried orderly:
+ 1. Image PDB
+ 2. ComponentName2 protocol
+ 3. FFS UI section
+ 4. Image GUID
+ 5. Image DevicePath
+ 6. Unknown Driver Name
+
+ @param[in] Handle
+
+ @post The resulting Unicode name string is stored in the
+ mGaugeString global array.
+
+**/
+VOID
+DpGetNameFromHandle (
+ IN EFI_HANDLE Handle
+ )
+{
+ EFI_STATUS Status;
+ EFI_LOADED_IMAGE_PROTOCOL *Image;
+ CHAR8 *PdbFileName;
+ EFI_DRIVER_BINDING_PROTOCOL *DriverBinding;
+ EFI_STRING StringPtr;
+ EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_GUID *NameGuid;
+ CHAR16 *NameString;
+ UINTN StringSize;
+ CHAR8 *PlatformLanguage;
+ CHAR8 *BestLanguage;
+ EFI_COMPONENT_NAME2_PROTOCOL *ComponentName2;
+
+ Image = NULL;
+ LoadedImageDevicePath = NULL;
+ DevicePath = NULL;
+
+ //
+ // Method 1: Get the name string from image PDB
+ //
+ Status = gBS->HandleProtocol (
+ Handle,
+ &gEfiLoadedImageProtocolGuid,
+ (VOID **) &Image
+ );
+
+ if (EFI_ERROR (Status)) {
+ Status = gBS->OpenProtocol (
+ Handle,
+ &gEfiDriverBindingProtocolGuid,
+ (VOID **) &DriverBinding,
+ NULL,
+ NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = gBS->HandleProtocol (
+ DriverBinding->ImageHandle,
+ &gEfiLoadedImageProtocolGuid,
+ (VOID **) &Image
+ );
+ }
+ }
+
+ if (!EFI_ERROR (Status)) {
+ PdbFileName = PeCoffLoaderGetPdbPointer (Image->ImageBase);
+
+ if (PdbFileName != NULL) {
+ DpGetShortPdbFileName (PdbFileName, mGaugeString);
+ return;
+ }
+ }
+
+ //
+ // Method 2: Get the name string from ComponentName2 protocol
+ //
+ Status = gBS->HandleProtocol (
+ Handle,
+ &gEfiComponentName2ProtocolGuid,
+ (VOID **) &ComponentName2
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Firstly use platform language setting, secondly use driver's first supported language.
+ //
+ GetVariable2 (L"PlatformLang", &gEfiGlobalVariableGuid, (VOID**)&PlatformLanguage, NULL);
+ BestLanguage = GetBestLanguage(
+ ComponentName2->SupportedLanguages,
+ FALSE,
+ (PlatformLanguage != NULL) ? PlatformLanguage : "",
+ ComponentName2->SupportedLanguages,
+ NULL
+ );
+ SHELL_FREE_NON_NULL (PlatformLanguage);
+
+ Status = ComponentName2->GetDriverName (
+ ComponentName2,
+ BestLanguage != NULL ? BestLanguage : "en-US",
+ &StringPtr
+ );
+ if (!EFI_ERROR (Status)) {
+ SHELL_FREE_NON_NULL (BestLanguage);
+ StrnCpyS (mGaugeString, DP_GAUGE_STRING_LENGTH + 1, StringPtr, DP_GAUGE_STRING_LENGTH);
+ mGaugeString[DP_GAUGE_STRING_LENGTH] = 0;
+ return;
+ }
+ }
+
+ Status = gBS->HandleProtocol (
+ Handle,
+ &gEfiLoadedImageDevicePathProtocolGuid,
+ (VOID **) &LoadedImageDevicePath
+ );
+ if (!EFI_ERROR (Status) && (LoadedImageDevicePath != NULL)) {
+ DevicePath = LoadedImageDevicePath;
+ } else if (Image != NULL) {
+ DevicePath = Image->FilePath;
+ }
+
+ if (DevicePath != NULL) {
+ //
+ // Try to get image GUID from image DevicePath
+ //
+ NameGuid = NULL;
+ while (!IsDevicePathEndType (DevicePath)) {
+ NameGuid = EfiGetNameGuidFromFwVolDevicePathNode ((MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) DevicePath);
+ if (NameGuid != NULL) {
+ break;
+ }
+ DevicePath = NextDevicePathNode (DevicePath);
+ }
+
+ if (NameGuid != NULL) {
+ //
+ // Try to get the image's FFS UI section by image GUID
+ //
+ NameString = NULL;
+ StringSize = 0;
+ Status = GetSectionFromAnyFv (
+ NameGuid,
+ EFI_SECTION_USER_INTERFACE,
+ 0,
+ (VOID **) &NameString,
+ &StringSize
+ );
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // Method 3. Get the name string from FFS UI section
+ //
+ StrnCpyS (mGaugeString, DP_GAUGE_STRING_LENGTH + 1, NameString, DP_GAUGE_STRING_LENGTH);
+ mGaugeString[DP_GAUGE_STRING_LENGTH] = 0;
+ FreePool (NameString);
+ } else {
+ //
+ // Method 4: Get the name string from image GUID
+ //
+ UnicodeSPrint (mGaugeString, sizeof (mGaugeString), L"%g", NameGuid);
+ }
+ return;
+ } else {
+ //
+ // Method 5: Get the name string from image DevicePath
+ //
+ NameString = ConvertDevicePathToText (DevicePath, TRUE, FALSE);
+ if (NameString != NULL) {
+ StrnCpyS (mGaugeString, DP_GAUGE_STRING_LENGTH + 1, NameString, DP_GAUGE_STRING_LENGTH);
+ mGaugeString[DP_GAUGE_STRING_LENGTH] = 0;
+ FreePool (NameString);
+ return;
+ }
+ }
+ }
+
+ //
+ // Method 6: Unknown Driver Name
+ //
+ StringPtr = HiiGetString (mDpHiiHandle, STRING_TOKEN (STR_DP_ERROR_NAME), NULL);
+ ASSERT (StringPtr != NULL);
+ StrnCpyS (mGaugeString, DP_GAUGE_STRING_LENGTH + 1, StringPtr, DP_GAUGE_STRING_LENGTH);
+ FreePool (StringPtr);
+}
+
+/**
+ Calculate the Duration in microseconds.
+
+ Duration is multiplied by 1000, instead of Frequency being divided by 1000 or
+ multiplying the result by 1000, in order to maintain precision. Since Duration is
+ a 64-bit value, multiplying it by 1000 is unlikely to produce an overflow.
+
+ The time is calculated as (Duration * 1000) / Timer_Frequency.
+
+ @param[in] Duration The event duration in timer ticks.
+
+ @return A 64-bit value which is the Elapsed time in microseconds.
+**/
+UINT64
+DurationInMicroSeconds (
+ IN UINT64 Duration
+ )
+{
+ return DivU64x32 (Duration, 1000);
+}
+
+/**
+ Get index of Measurement Record's match in the CumData array.
+
+ If the Measurement's Token value matches a Token in one of the CumData
+ records, the index of the matching record is returned. The returned
+ index is a signed value so that negative values can indicate that
+ the Measurement didn't match any entry in the CumData array.
+
+ @param[in] Measurement A pointer to a Measurement Record to match against the CumData array.
+
+ @retval <0 Token is not in the CumData array.
+ @retval >=0 Return value is the index into CumData where Token is found.
+**/
+INTN
+GetCumulativeItem(
+ IN MEASUREMENT_RECORD *Measurement
+ )
+{
+ INTN Index;
+
+ for( Index = 0; Index < (INTN)NumCum; ++Index) {
+ if (AsciiStrCmp (Measurement->Token, CumData[Index].Name) == 0) {
+ return Index; // Exit, we found a match
+ }
+ }
+ // If the for loop exits, Token was not found.
+ return -1; // Indicate failure
+}
diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/Literals.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/Literals.c
new file mode 100644
index 00000000..ec99fe4b
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/Literals.c
@@ -0,0 +1,22 @@
+/** @file
+ Definitions of ASCII string literals used by DP.
+
+ Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+#include <Guid/ExtendedFirmwarePerformance.h>
+
+// ASCII String literals which probably don't need translation
+CHAR8 const ALit_TimerLibError[] = "Timer library instance error!\n";
+CHAR8 const ALit_SEC[] = SEC_TOK;
+CHAR8 const ALit_DXE[] = DXE_TOK;
+CHAR8 const ALit_PEI[] = PEI_TOK;
+CHAR8 const ALit_BDS[] = BDS_TOK;
+CHAR8 const ALit_START_IMAGE[] = START_IMAGE_TOK;
+CHAR8 const ALit_LOAD_IMAGE[] = LOAD_IMAGE_TOK;
+CHAR8 const ALit_DB_START[] = DRIVERBINDING_START_TOK;
+CHAR8 const ALit_DB_SUPPORT[] = DRIVERBINDING_SUPPORT_TOK;
+CHAR8 const ALit_DB_STOP[] = DRIVERBINDING_STOP_TOK;
+
+CHAR8 const ALit_BdsTO[] = "BdsTimeOut";
+CHAR8 const ALit_PEIM[] = "PEIM";
diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/Literals.h b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/Literals.h
new file mode 100644
index 00000000..c0ef8791
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/Literals.h
@@ -0,0 +1,26 @@
+/** @file
+ Declarations of ASCII string literals used by DP.
+
+ Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+#ifndef _LITERALS_H_
+#define _LITERALS_H_
+
+// ASCII String literals which probably don't need translation
+extern CHAR8 const ALit_TimerLibError[];
+extern CHAR8 const ALit_SEC[];
+extern CHAR8 const ALit_DXE[];
+extern CHAR8 const ALit_SHELL[];
+extern CHAR8 const ALit_PEI[];
+extern CHAR8 const ALit_BDS[];
+extern CHAR8 const ALit_PEIM[];
+extern CHAR8 const ALit_START_IMAGE[];
+extern CHAR8 const ALit_LOAD_IMAGE[];
+extern CHAR8 const ALit_DB_START[];
+extern CHAR8 const ALit_DB_SUPPORT[];
+extern CHAR8 const ALit_DB_STOP[];
+extern CHAR8 const ALit_BdsTO[];
+extern CHAR8 const ALit_PEIM[];
+
+#endif // _LITERALS_H_