From f215e02bf85f68d3a6106c2a1f4f7f063f819064 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Thu, 11 Apr 2024 10:17:27 +0200 Subject: Adding upstream version 7.0.14-dfsg. Signed-off-by: Daniel Baumann --- .../ShellPkg/DynamicCommand/DpDynamicCommand/Dp.c | 966 ++++++++++ .../ShellPkg/DynamicCommand/DpDynamicCommand/Dp.h | 140 ++ .../DynamicCommand/DpDynamicCommand/Dp.uni | 128 ++ .../DynamicCommand/DpDynamicCommand/DpApp.c | 47 + .../DynamicCommand/DpDynamicCommand/DpApp.inf | 64 + .../DpDynamicCommand/DpDynamicCommand.c | 125 ++ .../DpDynamicCommand/DpDynamicCommand.inf | 68 + .../DynamicCommand/DpDynamicCommand/DpInternal.h | 315 ++++ .../DynamicCommand/DpDynamicCommand/DpTrace.c | 904 ++++++++++ .../DynamicCommand/DpDynamicCommand/DpUtilities.c | 422 +++++ .../DynamicCommand/DpDynamicCommand/Literals.c | 22 + .../DynamicCommand/DpDynamicCommand/Literals.h | 26 + .../DynamicCommand/HttpDynamicCommand/Http.c | 1905 ++++++++++++++++++++ .../DynamicCommand/HttpDynamicCommand/Http.h | 92 + .../DynamicCommand/HttpDynamicCommand/Http.uni | 117 ++ .../DynamicCommand/HttpDynamicCommand/HttpApp.c | 61 + .../DynamicCommand/HttpDynamicCommand/HttpApp.inf | 57 + .../HttpDynamicCommand/HttpDynamicCommand.c | 137 ++ .../HttpDynamicCommand/HttpDynamicCommand.inf | 62 + .../DynamicCommand/TftpDynamicCommand/Tftp.c | 1129 ++++++++++++ .../DynamicCommand/TftpDynamicCommand/Tftp.h | 69 + .../DynamicCommand/TftpDynamicCommand/Tftp.uni | 94 + .../DynamicCommand/TftpDynamicCommand/TftpApp.c | 48 + .../DynamicCommand/TftpDynamicCommand/TftpApp.inf | 55 + .../TftpDynamicCommand/TftpDynamicCommand.c | 126 ++ .../TftpDynamicCommand/TftpDynamicCommand.inf | 60 + 26 files changed, 7239 insertions(+) create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/Dp.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/Dp.h create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/Dp.uni create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/DpApp.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/DpApp.inf create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/DpDynamicCommand.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/DpDynamicCommand.inf create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/DpInternal.h create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/DpTrace.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/DpUtilities.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/Literals.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/DpDynamicCommand/Literals.h create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/HttpDynamicCommand/Http.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/HttpDynamicCommand/Http.h create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/HttpDynamicCommand/Http.uni create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/HttpDynamicCommand/HttpApp.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/HttpDynamicCommand/HttpApp.inf create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/HttpDynamicCommand/HttpDynamicCommand.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/HttpDynamicCommand/HttpDynamicCommand.inf create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/TftpDynamicCommand/Tftp.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/TftpDynamicCommand/Tftp.h create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/TftpDynamicCommand/Tftp.uni create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/TftpDynamicCommand/TftpApp.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/TftpDynamicCommand/TftpApp.inf create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/TftpDynamicCommand/TftpDynamicCommand.c create mode 100644 src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/TftpDynamicCommand/TftpDynamicCommand.inf (limited to 'src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand') 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
+ 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 + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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.
+// Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+// (C) Copyright 2015 Hewlett Packard Enterprise Development LP
+// 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.
+ + 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.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ +#include "Dp.h" +#include + +/** + 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
+ 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.
+ 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:
+ For each record with a Token listed in the CumData array:
+ - 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
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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.
+ 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:
+ For each record with a Token listed in the CumData array:
+ - 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
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include + +#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.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#include + +// 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.
+ 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_ diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/HttpDynamicCommand/Http.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/HttpDynamicCommand/Http.c new file mode 100644 index 00000000..5173ac1e --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/HttpDynamicCommand/Http.c @@ -0,0 +1,1905 @@ +/** @file + The implementation for the 'http' Shell command. + + Copyright (c) 2015, ARM Ltd. All rights reserved.
+ Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.
+ (C) Copyright 2015 Hewlett Packard Enterprise Development LP
+ Copyright (c) 2020, Broadcom. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include "Http.h" + +#define IP4_CONFIG2_INTERFACE_INFO_NAME_LENGTH 32 + +// +// Constant strings and definitions related to the message +// indicating the amount of progress in the dowloading of a HTTP file. +// + +// +// Number of steps in the progression slider. +// +#define HTTP_PROGRESS_SLIDER_STEPS \ + ((sizeof (HTTP_PROGR_FRAME) / sizeof (CHAR16)) - 3) + +// +// Size in number of characters plus one (final zero) of the message to +// indicate the progress of an HTTP download. The format is "[(progress slider: +// 40 characters)] (nb of KBytes downloaded so far: 7 characters) Kb". There +// are thus the number of characters in HTTP_PROGR_FRAME[] plus 11 characters +// (2 // spaces, "Kb" and seven characters for the number of KBytes). +// +#define HTTP_PROGRESS_MESSAGE_SIZE \ + ((sizeof (HTTP_PROGR_FRAME) / sizeof (CHAR16)) + 12) + +// +// Buffer size. Note that larger buffer does not mean better speed. +// +#define DEFAULT_BUF_SIZE SIZE_32KB +#define MAX_BUF_SIZE SIZE_4MB + +#define MIN_PARAM_COUNT 2 +#define MAX_PARAM_COUNT 4 +#define NEED_REDIRECTION(Code) \ + (((Code >= HTTP_STATUS_300_MULTIPLE_CHOICES) \ + && (Code <= HTTP_STATUS_307_TEMPORARY_REDIRECT)) \ + || (Code == HTTP_STATUS_308_PERMANENT_REDIRECT)) + +#define CLOSE_HTTP_HANDLE(ControllerHandle,HttpChildHandle) \ + do { \ + if (HttpChildHandle) { \ + CloseProtocolAndDestroyServiceChild ( \ + ControllerHandle, \ + &gEfiHttpServiceBindingProtocolGuid, \ + &gEfiHttpProtocolGuid, \ + HttpChildHandle \ + ); \ + HttpChildHandle = NULL; \ + } \ + } while (0) + +typedef enum { + HdrHost, + HdrConn, + HdrAgent, + HdrMax +} HDR_TYPE; + +#define USER_AGENT_HDR "Mozilla/5.0 (EDK2; Linux) Gecko/20100101 Firefox/79.0" + +#define TIMER_MAX_TIMEOUT_S 10 + +// +// File name to use when Uri ends with "/". +// +#define DEFAULT_HTML_FILE L"index.html" +#define DEFAULT_HTTP_PROTO L"http" + +// +// String to delete the HTTP progress message to be able to update it : +// (HTTP_PROGRESS_MESSAGE_SIZE-1) '\b'. +// +#define HTTP_PROGRESS_DEL \ + L"\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\ +\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b" + +#define HTTP_KB L"\b\b\b\b\b\b\b\b\b\b" +// +// Frame for the progression slider. +// +#define HTTP_PROGR_FRAME L"[ ]" + +// +// Improve readability by using these macros. +// +#define PRINT_HII(token,...) \ + ShellPrintHiiEx (\ + -1, -1, NULL, token, mHttpHiiHandle, __VA_ARGS__) + +#define PRINT_HII_APP(token,value) \ + PRINT_HII (token, HTTP_APP_NAME, value) + +// +// TimeBaseLib.h constants. +// These will be removed once the library gets fixed. +// + +// +// Define EPOCH (1970-JANUARY-01) in the Julian Date representation. +// +#define EPOCH_JULIAN_DATE 2440588 + +// +// Seconds per unit. +// +#define SEC_PER_MIN ((UINTN) 60) +#define SEC_PER_HOUR ((UINTN) 3600) +#define SEC_PER_DAY ((UINTN) 86400) + +// +// String descriptions for server errors. +// +STATIC CONST CHAR16 *ErrStatusDesc[] = +{ + L"400 Bad Request", + L"401 Unauthorized", + L"402 Payment required", + L"403 Forbidden", + L"404 Not Found", + L"405 Method not allowed", + L"406 Not acceptable", + L"407 Proxy authentication required", + L"408 Request time out", + L"409 Conflict", + L"410 Gone", + L"411 Length required", + L"412 Precondition failed", + L"413 Request entity too large", + L"414 Request URI to large", + L"415 Unsupported media type", + L"416 Requested range not satisfied", + L"417 Expectation failed", + L"500 Internal server error", + L"501 Not implemented", + L"502 Bad gateway", + L"503 Service unavailable", + L"504 Gateway timeout", + L"505 HTTP version not supported" +}; + +STATIC CONST SHELL_PARAM_ITEM ParamList[] = { + {L"-i", TypeValue}, + {L"-k", TypeFlag}, + {L"-l", TypeValue}, + {L"-m", TypeFlag}, + {L"-s", TypeValue}, + {L"-t", TypeValue}, + {NULL , TypeMax} +}; + +// +// Local File Handle. +// +STATIC SHELL_FILE_HANDLE mFileHandle = NULL; + +// +// Path of the local file, Unicode encoded. +// +STATIC CONST CHAR16 *mLocalFilePath; + +STATIC BOOLEAN gRequestCallbackComplete = FALSE; +STATIC BOOLEAN gResponseCallbackComplete = FALSE; + +STATIC BOOLEAN gHttpError; + +EFI_HII_HANDLE mHttpHiiHandle; + +// +// Functions declarations. +// + +/** + Check and convert the UINT16 option values of the 'http' command. + + @param[in] ValueStr Value as an Unicode encoded string. + @param[out] Value UINT16 value. + + @retval TRUE The value was returned. + @retval FALSE A parsing error occured. +**/ +STATIC +BOOLEAN +StringToUint16 ( + IN CONST CHAR16 *ValueStr, + OUT UINT16 *Value + ); + +/** + Get the name of the NIC. + + @param[in] ControllerHandle The network physical device handle. + @param[in] NicNumber The network physical device number. + @param[out] NicName Address where to store the NIC name. + The memory area has to be at least + IP4_CONFIG2_INTERFACE_INFO_NAME_LENGTH + double byte wide. + + @retval EFI_SUCCESS The name of the NIC was returned. + @retval Others The creation of the child for the Managed + Network Service failed or the opening of + the Managed Network Protocol failed or + the operational parameters for the + Managed Network Protocol could not be + read. +**/ +STATIC +EFI_STATUS +GetNicName ( + IN EFI_HANDLE ControllerHandle, + IN UINTN NicNumber, + OUT CHAR16 *NicName + ); + +/** + Create a child for the service identified by its service binding protocol GUID + and get from the child the interface of the protocol identified by its GUID. + + @param[in] ControllerHandle Controller handle. + @param[in] ServiceBindingProtocolGuid Service binding protocol GUID of the + service to be created. + @param[in] ProtocolGuid GUID of the protocol to be open. + @param[out] ChildHandle Address where the handler of the + created child is returned. NULL is + returned in case of error. + @param[out] Interface Address where a pointer to the + protocol interface is returned in + case of success. + + @retval EFI_SUCCESS The child was created and the protocol opened. + @retval Others Either the creation of the child or the opening + of the protocol failed. +**/ +STATIC +EFI_STATUS +CreateServiceChildAndOpenProtocol ( + IN EFI_HANDLE ControllerHandle, + IN EFI_GUID *ServiceBindingProtocolGuid, + IN EFI_GUID *ProtocolGuid, + OUT EFI_HANDLE *ChildHandle, + OUT VOID **Interface + ); + +/** + Close the protocol identified by its GUID on the child handle of the service + identified by its service binding protocol GUID, then destroy the child + handle. + + @param[in] ControllerHandle Controller handle. + @param[in] ServiceBindingProtocolGuid Service binding protocol GUID of the + service to be destroyed. + @param[in] ProtocolGuid GUID of the protocol to be closed. + @param[in] ChildHandle Handle of the child to be destroyed. + +**/ +STATIC +VOID +CloseProtocolAndDestroyServiceChild ( + IN EFI_HANDLE ControllerHandle, + IN EFI_GUID *ServiceBindingProtocolGuid, + IN EFI_GUID *ProtocolGuid, + IN EFI_HANDLE ChildHandle + ); + +/** + Worker function that download the data of a file from an HTTP server given + the path of the file and its size. + + @param[in] Context A pointer to the download context. + + @retval EFI_SUCCESS The file was downloaded. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. + @retval Others The downloading of the file + from the server failed. +**/ +STATIC +EFI_STATUS +DownloadFile ( + IN HTTP_DOWNLOAD_CONTEXT *Context, + IN EFI_HANDLE ControllerHandle, + IN CHAR16 *NicName + ); + +/** + Cleans off leading and trailing spaces and tabs. + + @param[in] String pointer to the string to trim them off. + + @retval EFI_SUCCESS No errors. + @retval EFI_INVALID_PARAMETER String pointer is NULL. +**/ +STATIC +EFI_STATUS +TrimSpaces ( + IN CHAR16 *String + ) +{ + CHAR16 *Str; + UINTN Len; + + ASSERT (String != NULL); + + if (String == NULL) { + return EFI_INVALID_PARAMETER; + } + + Str = String; + + // + // Remove any whitespace at the beginning of the Str. + // + while (*Str == L' ' || *Str == L'\t') { + Str++; + } + + // + // Remove any whitespace at the end of the Str. + // + do { + Len = StrLen (Str); + if (!Len || (Str[Len - 1] != L' ' && Str[Len - 1] != '\t')) { + break; + } + + Str[Len - 1] = CHAR_NULL; + } while (Len); + + CopyMem (String, Str, StrSize (Str)); + + return EFI_SUCCESS; +} + +// +// Callbacks for request and response. +// We just acknowledge that operation has completed here. +// + +/** + Callback to set the request completion flag. + + @param[in] Event: The event. + @param[in] Context: pointer to Notification Context. + **/ +STATIC +VOID +EFIAPI +RequestCallback ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + gRequestCallbackComplete = TRUE; +} + +/** + Callback to set the response completion flag. + @param[in] Event: The event. + @param[in] Context: pointer to Notification Context. + **/ +STATIC +VOID +EFIAPI +ResponseCallback ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + gResponseCallbackComplete = TRUE; +} + +// +// Set of functions from TimeBaseLib. +// This will be removed once TimeBaseLib is enabled for ShellPkg. +// + +/** + Calculate Epoch days. + + @param[in] Time - a pointer to the EFI_TIME abstraction. + + @retval Number of days elapsed since EPOCH_JULIAN_DAY. + **/ +STATIC +UINTN +EfiGetEpochDays ( + IN EFI_TIME *Time + ) +{ + UINTN a; + UINTN y; + UINTN m; + // + // Absolute Julian Date representation of the supplied Time. + // + UINTN JulianDate; + // + // Number of days elapsed since EPOCH_JULIAN_DAY. + // + UINTN EpochDays; + + a = (14 - Time->Month) / 12 ; + y = Time->Year + 4800 - a; + m = Time->Month + (12 * a) - 3; + + JulianDate = Time->Day + ((153 * m + 2) / 5) + (365 * y) + (y / 4) - + (y / 100) + (y / 400) - 32045; + + ASSERT (JulianDate >= EPOCH_JULIAN_DATE); + EpochDays = JulianDate - EPOCH_JULIAN_DATE; + + return EpochDays; +} + +/** + Converts EFI_TIME to Epoch seconds + (elapsed since 1970 JANUARY 01, 00:00:00 UTC). + + @param[in] Time: a pointer to EFI_TIME abstraction. + **/ +STATIC +UINTN +EFIAPI +EfiTimeToEpoch ( + IN EFI_TIME *Time + ) +{ + // + // Number of days elapsed since EPOCH_JULIAN_DAY. + // + UINTN EpochDays; + UINTN EpochSeconds; + + EpochDays = EfiGetEpochDays (Time); + + EpochSeconds = (EpochDays * SEC_PER_DAY) + + ((UINTN)Time->Hour * SEC_PER_HOUR) + + (Time->Minute * SEC_PER_MIN) + Time->Second; + + return EpochSeconds; +} + +/** + Function for 'http' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). + + @retval SHELL_SUCCESS The 'http' command completed successfully. + @retval SHELL_ABORTED The Shell Library initialization failed. + @retval SHELL_INVALID_PARAMETER At least one of the command's arguments is + not valid. + @retval SHELL_OUT_OF_RESOURCES A memory allocation failed. + @retval SHELL_NOT_FOUND Network Interface Card not found. + @retval SHELL_UNSUPPORTED Command was valid, but the server returned + a status code indicating some error. + Examine the file requested for error body. +**/ +SHELL_STATUS +RunHttp ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LIST_ENTRY *CheckPackage; + UINTN ParamCount; + UINTN HandleCount; + UINTN NicNumber; + UINTN InitialSize; + UINTN ParamOffset; + UINTN StartSize; + CHAR16 *ProblemParam; + CHAR16 NicName[IP4_CONFIG2_INTERFACE_INFO_NAME_LENGTH]; + CHAR16 *Walker1; + CHAR16 *VStr; + CONST CHAR16 *UserNicName; + CONST CHAR16 *ValueStr; + CONST CHAR16 *RemoteFilePath; + CONST CHAR16 *Walker; + EFI_HTTPv4_ACCESS_POINT IPv4Node; + EFI_HANDLE *Handles; + EFI_HANDLE ControllerHandle; + HTTP_DOWNLOAD_CONTEXT Context; + BOOLEAN NicFound; + + ProblemParam = NULL; + RemoteFilePath = NULL; + NicFound = FALSE; + Handles = NULL; + + // + // Initialize the Shell library (we must be in non-auto-init...). + // + ParamOffset = 0; + gHttpError = FALSE; + + Status = ShellInitialize (); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return SHELL_ABORTED; + } + + ZeroMem (&Context, sizeof (Context)); + + // + // Parse the command line. + // + Status = ShellCommandLineParse ( + ParamList, + &CheckPackage, + &ProblemParam, + TRUE + ); + if (EFI_ERROR (Status)) { + if ((Status == EFI_VOLUME_CORRUPTED) + && (ProblemParam != NULL)) + { + PRINT_HII_APP (STRING_TOKEN (STR_GEN_PROBLEM), ProblemParam); + SHELL_FREE_NON_NULL (ProblemParam); + } else { + ASSERT (FALSE); + } + + goto Error; + } + + // + // Check the number of parameters. + // + Status = EFI_INVALID_PARAMETER; + + ParamCount = ShellCommandLineGetCount (CheckPackage); + if (ParamCount > MAX_PARAM_COUNT) { + PRINT_HII_APP (STRING_TOKEN (STR_GEN_TOO_MANY), NULL); + goto Error; + } + + if (ParamCount < MIN_PARAM_COUNT) { + PRINT_HII_APP (STRING_TOKEN (STR_GEN_TOO_FEW), NULL); + goto Error; + } + + ZeroMem (&Context.HttpConfigData, sizeof (Context.HttpConfigData)); + ZeroMem (&IPv4Node, sizeof (IPv4Node)); + IPv4Node.UseDefaultAddress = TRUE; + + Context.HttpConfigData.HttpVersion = HttpVersion11; + Context.HttpConfigData.AccessPoint.IPv4Node = &IPv4Node; + + // + // Get the host address (not necessarily IPv4 format). + // + ValueStr = ShellCommandLineGetRawValue (CheckPackage, 1); + if (!ValueStr) { + PRINT_HII_APP (STRING_TOKEN (STR_GEN_PARAM_INV), ValueStr); + goto Error; + } else { + StartSize = 0; + TrimSpaces ((CHAR16 *)ValueStr); + if (!StrStr (ValueStr, L"://")) { + Context.ServerAddrAndProto = StrnCatGrow ( + &Context.ServerAddrAndProto, + &StartSize, + DEFAULT_HTTP_PROTO, + StrLen (DEFAULT_HTTP_PROTO) + ); + Context.ServerAddrAndProto = StrnCatGrow ( + &Context.ServerAddrAndProto, + &StartSize, + L"://", + StrLen (L"://") + ); + VStr = (CHAR16 *)ValueStr; + } else { + VStr = StrStr (ValueStr, L"://") + StrLen (L"://"); + } + + for (Walker1 = VStr; *Walker1; Walker1++) { + if (*Walker1 == L'/') { + break; + } + } + + if (*Walker1 == L'/') { + ParamOffset = 1; + RemoteFilePath = Walker1; + } + + Context.ServerAddrAndProto = StrnCatGrow ( + &Context.ServerAddrAndProto, + &StartSize, + ValueStr, + StrLen (ValueStr) - StrLen (Walker1) + ); + if (!Context.ServerAddrAndProto) { + Status = EFI_OUT_OF_RESOURCES; + goto Error; + } + } + + if (!RemoteFilePath) { + RemoteFilePath = ShellCommandLineGetRawValue (CheckPackage, 2); + if (!RemoteFilePath) { + // + // If no path given, assume just "/". + // + RemoteFilePath = L"/"; + } + } + + TrimSpaces ((CHAR16 *)RemoteFilePath); + + if (ParamCount == MAX_PARAM_COUNT - ParamOffset) { + mLocalFilePath = ShellCommandLineGetRawValue ( + CheckPackage, + MAX_PARAM_COUNT - 1 - ParamOffset + ); + } else { + Walker = RemoteFilePath + StrLen (RemoteFilePath); + while ((--Walker) >= RemoteFilePath) { + if ((*Walker == L'\\') || + (*Walker == L'/' ) ) { + break; + } + } + + mLocalFilePath = Walker + 1; + } + + if (!StrLen (mLocalFilePath)) { + mLocalFilePath = DEFAULT_HTML_FILE; + } + + InitialSize = 0; + Context.Uri = StrnCatGrow ( + &Context.Uri, + &InitialSize, + RemoteFilePath, + StrLen (RemoteFilePath) + ); + if (!Context.Uri) { + Status = EFI_OUT_OF_RESOURCES; + goto Error; + } + + // + // Get the name of the Network Interface Card to be used if any. + // + UserNicName = ShellCommandLineGetValue (CheckPackage, L"-i"); + + ValueStr = ShellCommandLineGetValue (CheckPackage, L"-l"); + if ((ValueStr != NULL) + && (!StringToUint16 ( + ValueStr, + &Context.HttpConfigData.AccessPoint.IPv4Node->LocalPort + ) + )) + { + goto Error; + } + + Context.BufferSize = DEFAULT_BUF_SIZE; + + ValueStr = ShellCommandLineGetValue (CheckPackage, L"-s"); + if (ValueStr != NULL) { + Context.BufferSize = ShellStrToUintn (ValueStr); + if (!Context.BufferSize || Context.BufferSize > MAX_BUF_SIZE) { + PRINT_HII_APP (STRING_TOKEN (STR_GEN_PARAM_INV), ValueStr); + goto Error; + } + } + + ValueStr = ShellCommandLineGetValue (CheckPackage, L"-t"); + if (ValueStr != NULL) { + Context.HttpConfigData.TimeOutMillisec = (UINT32)ShellStrToUintn (ValueStr); + } + + // + // Locate all HTTP Service Binding protocols. + // + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiManagedNetworkServiceBindingProtocolGuid, + NULL, + &HandleCount, + &Handles + ); + if (EFI_ERROR (Status) || (HandleCount == 0)) { + PRINT_HII (STRING_TOKEN (STR_HTTP_ERR_NO_NIC), NULL); + if (!EFI_ERROR (Status)) { + Status = EFI_NOT_FOUND; + } + + goto Error; + } + + Status = EFI_NOT_FOUND; + + Context.Flags = 0; + if (ShellCommandLineGetFlag (CheckPackage, L"-m")) { + Context.Flags |= DL_FLAG_TIME; + } + + if (ShellCommandLineGetFlag (CheckPackage, L"-k")) { + Context.Flags |= DL_FLAG_KEEP_BAD; + } + + for (NicNumber = 0; + (NicNumber < HandleCount) && (Status != EFI_SUCCESS); + NicNumber++) + { + ControllerHandle = Handles[NicNumber]; + + Status = GetNicName (ControllerHandle, NicNumber, NicName); + if (EFI_ERROR (Status)) { + PRINT_HII (STRING_TOKEN (STR_HTTP_ERR_NIC_NAME), NicNumber, Status); + continue; + } + + if (UserNicName != NULL) { + if (StrCmp (NicName, UserNicName) != 0) { + Status = EFI_NOT_FOUND; + continue; + } + + NicFound = TRUE; + } + + Status = DownloadFile (&Context, ControllerHandle, NicName); + PRINT_HII (STRING_TOKEN (STR_GEN_CRLF), NULL); + + if (EFI_ERROR (Status)) { + PRINT_HII ( + STRING_TOKEN (STR_HTTP_ERR_DOWNLOAD), + RemoteFilePath, + NicName, + Status + ); + // + // If a user aborted the operation, + // do not try another controller. + // + if (Status == EFI_ABORTED) { + goto Error; + } + } + + if (gHttpError) { + // + // This is not related to connection, so no need to repeat with + // another interface. + // + break; + } + } + + if ((UserNicName != NULL) && (!NicFound)) { + PRINT_HII (STRING_TOKEN (STR_HTTP_ERR_NIC_NOT_FOUND), UserNicName); + } + +Error: + ShellCommandLineFreeVarList (CheckPackage); + SHELL_FREE_NON_NULL (Handles); + SHELL_FREE_NON_NULL (Context.ServerAddrAndProto); + SHELL_FREE_NON_NULL (Context.Uri); + + return Status & ~MAX_BIT; +} + +/** + Check and convert the UINT16 option values of the 'http' command + + @param[in] ValueStr Value as an Unicode encoded string + @param[out] Value UINT16 value + + @retval TRUE The value was returned. + @retval FALSE A parsing error occured. +**/ +STATIC +BOOLEAN +StringToUint16 ( + IN CONST CHAR16 *ValueStr, + OUT UINT16 *Value + ) +{ + UINTN Val; + + Val = ShellStrToUintn (ValueStr); + if (Val > MAX_UINT16) { + PRINT_HII_APP (STRING_TOKEN (STR_GEN_PARAM_INV), ValueStr); + return FALSE; + } + + *Value = (UINT16)Val; + return TRUE; +} + +/** + Get the name of the NIC. + + @param[in] ControllerHandle The network physical device handle. + @param[in] NicNumber The network physical device number. + @param[out] NicName Address where to store the NIC name. + The memory area has to be at least + IP4_CONFIG2_INTERFACE_INFO_NAME_LENGTH + double byte wide. + + @retval EFI_SUCCESS The name of the NIC was returned. + @retval Others The creation of the child for the Managed + Network Service failed or the opening of + the Managed Network Protocol failed or + the operational parameters for the + Managed Network Protocol could not be + read. +**/ +STATIC +EFI_STATUS +GetNicName ( + IN EFI_HANDLE ControllerHandle, + IN UINTN NicNumber, + OUT CHAR16 *NicName + ) +{ + EFI_STATUS Status; + EFI_HANDLE MnpHandle; + EFI_MANAGED_NETWORK_PROTOCOL *Mnp; + EFI_SIMPLE_NETWORK_MODE SnpMode; + + Status = CreateServiceChildAndOpenProtocol ( + ControllerHandle, + &gEfiManagedNetworkServiceBindingProtocolGuid, + &gEfiManagedNetworkProtocolGuid, + &MnpHandle, + (VOID**)&Mnp + ); + if (EFI_ERROR (Status)) { + goto Error; + } + + Status = Mnp->GetModeData (Mnp, NULL, &SnpMode); + if (EFI_ERROR (Status) && (Status != EFI_NOT_STARTED)) { + goto Error; + } + + UnicodeSPrint ( + NicName, + IP4_CONFIG2_INTERFACE_INFO_NAME_LENGTH, + SnpMode.IfType == NET_IFTYPE_ETHERNET ? L"eth%d" : L"unk%d", + NicNumber + ); + + Status = EFI_SUCCESS; + +Error: + + if (MnpHandle != NULL) { + CloseProtocolAndDestroyServiceChild ( + ControllerHandle, + &gEfiManagedNetworkServiceBindingProtocolGuid, + &gEfiManagedNetworkProtocolGuid, + MnpHandle + ); + } + + return Status; +} + +/** + Create a child for the service identified by its service binding protocol GUID + and get from the child the interface of the protocol identified by its GUID. + + @param[in] ControllerHandle Controller handle. + @param[in] ServiceBindingProtocolGuid Service binding protocol GUID of the + service to be created. + @param[in] ProtocolGuid GUID of the protocol to be open. + @param[out] ChildHandle Address where the handler of the + created child is returned. NULL is + returned in case of error. + @param[out] Interface Address where a pointer to the + protocol interface is returned in + case of success. + + @retval EFI_SUCCESS The child was created and the protocol opened. + @retval Others Either the creation of the child or the opening + of the protocol failed. +**/ +STATIC +EFI_STATUS +CreateServiceChildAndOpenProtocol ( + IN EFI_HANDLE ControllerHandle, + IN EFI_GUID *ServiceBindingProtocolGuid, + IN EFI_GUID *ProtocolGuid, + OUT EFI_HANDLE *ChildHandle, + OUT VOID **Interface + ) +{ + EFI_STATUS Status; + + *ChildHandle = NULL; + Status = NetLibCreateServiceChild ( + ControllerHandle, + gImageHandle, + ServiceBindingProtocolGuid, + ChildHandle + ); + if (!EFI_ERROR (Status)) { + Status = gBS->OpenProtocol ( + *ChildHandle, + ProtocolGuid, + Interface, + gImageHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + NetLibDestroyServiceChild ( + ControllerHandle, + gImageHandle, + ServiceBindingProtocolGuid, + *ChildHandle + ); + *ChildHandle = NULL; + } + } + + return Status; +} + +/** + Close the protocol identified by its GUID on the child handle of the service + identified by its service binding protocol GUID, then destroy the child + handle. + + @param[in] ControllerHandle Controller handle. + @param[in] ServiceBindingProtocolGuid Service binding protocol GUID of the + service to be destroyed. + @param[in] ProtocolGuid GUID of the protocol to be closed. + @param[in] ChildHandle Handle of the child to be destroyed. +**/ +STATIC +VOID +CloseProtocolAndDestroyServiceChild ( + IN EFI_HANDLE ControllerHandle, + IN EFI_GUID *ServiceBindingProtocolGuid, + IN EFI_GUID *ProtocolGuid, + IN EFI_HANDLE ChildHandle + ) +{ + gBS->CloseProtocol ( + ChildHandle, + ProtocolGuid, + gImageHandle, + ControllerHandle + ); + + NetLibDestroyServiceChild ( + ControllerHandle, + gImageHandle, + ServiceBindingProtocolGuid, + ChildHandle + ); +} + +/** + Wait until operation completes. Completion is indicated by + setting of an appropriate variable. + + @param[in] Context A pointer to the HTTP download context. + @param[in, out] CallBackComplete A pointer to the callback completion + variable set by the callback. + + @retval EFI_SUCCESS Callback signalled completion. + @retval EFI_TIMEOUT Timed out waiting for completion. + @retval Others Error waiting for completion. +**/ +STATIC +EFI_STATUS +WaitForCompletion ( + IN HTTP_DOWNLOAD_CONTEXT *Context, + IN OUT BOOLEAN *CallBackComplete + ) +{ + EFI_STATUS Status; + EFI_EVENT WaitEvt; + + Status = EFI_SUCCESS; + + // + // Use a timer to measure timeout. Cannot use Stall here! + // + Status = gBS->CreateEvent ( + EVT_TIMER, + TPL_CALLBACK, + NULL, + NULL, + &WaitEvt + ); + ASSERT_EFI_ERROR (Status); + + if (!EFI_ERROR (Status)) { + Status = gBS->SetTimer ( + WaitEvt, + TimerRelative, + EFI_TIMER_PERIOD_SECONDS (TIMER_MAX_TIMEOUT_S) + ); + + ASSERT_EFI_ERROR (Status); + } + + while (! *CallBackComplete + && (!EFI_ERROR (Status)) + && EFI_ERROR (gBS->CheckEvent (WaitEvt))) + { + Status = Context->Http->Poll (Context->Http); + if (!Context->ContentDownloaded + && CallBackComplete == &gResponseCallbackComplete) + { + // + // An HTTP server may just send a response redirection header. + // In this case, don't wait for the event as + // it might never happen and we waste 10s waiting. + // Note that at this point Response may not has been populated, + // so it needs to be checked first. + // + if (Context->ResponseToken.Message + && Context->ResponseToken.Message->Data.Response + && (NEED_REDIRECTION ( + Context->ResponseToken.Message->Data.Response->StatusCode + ) + )) + { + break; + } + } + } + + gBS->SetTimer (WaitEvt, TimerCancel, 0); + gBS->CloseEvent (WaitEvt); + + if (*CallBackComplete) { + return EFI_SUCCESS; + } + + if (!EFI_ERROR (Status)) { + Status = EFI_TIMEOUT; + } + + return Status; +} + +/** + Generate and send a request to the http server. + + @param[in] Context HTTP download context. + @param[in] DownloadUrl Fully qualified URL to be downloaded. + + @retval EFI_SUCCESS Request has been sent successfully. + @retval EFI_INVALID_PARAMETER Invalid URL. + @retval EFI_OUT_OF_RESOURCES Out of memory. + @retval EFI_DEVICE_ERROR If HTTPS is used, this probably + means that TLS support either was not + installed or not configured. + @retval Others Error sending the request. +**/ +STATIC +EFI_STATUS +SendRequest ( + IN HTTP_DOWNLOAD_CONTEXT *Context, + IN CHAR16 *DownloadUrl + ) +{ + EFI_HTTP_REQUEST_DATA RequestData; + EFI_HTTP_HEADER RequestHeader[HdrMax]; + EFI_HTTP_MESSAGE RequestMessage; + EFI_STATUS Status; + CHAR16 *Host; + UINTN StringSize; + + ZeroMem (&RequestData, sizeof (RequestData)); + ZeroMem (&RequestHeader, sizeof (RequestHeader)); + ZeroMem (&RequestMessage, sizeof (RequestMessage)); + ZeroMem (&Context->RequestToken, sizeof (Context->RequestToken)); + + RequestHeader[HdrHost].FieldName = "Host"; + RequestHeader[HdrConn].FieldName = "Connection"; + RequestHeader[HdrAgent].FieldName = "User-Agent"; + + Host = (CHAR16 *)Context->ServerAddrAndProto; + while (*Host != CHAR_NULL && *Host != L'/') { + Host++; + } + + if (*Host == CHAR_NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Get the next slash. + // + Host++; + // + // And now the host name. + // + Host++; + + StringSize = StrLen (Host) + 1; + RequestHeader[HdrHost].FieldValue = AllocatePool (StringSize); + if (!RequestHeader[HdrHost].FieldValue) { + return EFI_OUT_OF_RESOURCES; + } + + UnicodeStrToAsciiStrS ( + Host, + RequestHeader[HdrHost].FieldValue, + StringSize + ); + + RequestHeader[HdrConn].FieldValue = "close"; + RequestHeader[HdrAgent].FieldValue = USER_AGENT_HDR; + RequestMessage.HeaderCount = HdrMax; + + RequestData.Method = HttpMethodGet; + RequestData.Url = DownloadUrl; + + RequestMessage.Data.Request = &RequestData; + RequestMessage.Headers = RequestHeader; + RequestMessage.BodyLength = 0; + RequestMessage.Body = NULL; + Context->RequestToken.Event = NULL; + + // + // Completion callback event to be set when Request completes. + // + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + RequestCallback, + Context, + &Context->RequestToken.Event + ); + ASSERT_EFI_ERROR (Status); + + Context->RequestToken.Status = EFI_SUCCESS; + Context->RequestToken.Message = &RequestMessage; + gRequestCallbackComplete = FALSE; + Status = Context->Http->Request (Context->Http, &Context->RequestToken); + if (EFI_ERROR (Status)) { + goto Error; + } + + Status = WaitForCompletion (Context, &gRequestCallbackComplete); + if (EFI_ERROR (Status)) { + Context->Http->Cancel (Context->Http, &Context->RequestToken); + } + +Error: + SHELL_FREE_NON_NULL (RequestHeader[HdrHost].FieldValue); + if (Context->RequestToken.Event) { + gBS->CloseEvent (Context->RequestToken.Event); + ZeroMem (&Context->RequestToken, sizeof (Context->RequestToken)); + } + + return Status; +} + +/** + Update the progress of a file download + This procedure is called each time a new HTTP body portion is received. + + @param[in] Context HTTP download context. + @param[in] DownloadLen Portion size, in bytes. + @param[in] Buffer The pointer to the parsed buffer. + + @retval EFI_SUCCESS Portion saved. + @retval Other Error saving the portion. +**/ +STATIC +EFI_STATUS +EFIAPI +SavePortion ( + IN HTTP_DOWNLOAD_CONTEXT *Context, + IN UINTN DownloadLen, + IN CHAR8 *Buffer + ) +{ + CHAR16 Progress[HTTP_PROGRESS_MESSAGE_SIZE]; + UINTN NbOfKb; + UINTN Index; + UINTN LastStep; + UINTN Step; + EFI_STATUS Status; + + LastStep = 0; + Step = 0; + + ShellSetFilePosition (mFileHandle, Context->LastReportedNbOfBytes); + Status = ShellWriteFile (mFileHandle, &DownloadLen, Buffer); + if (EFI_ERROR (Status)) { + if (Context->ContentDownloaded > 0) { + PRINT_HII (STRING_TOKEN (STR_GEN_CRLF), NULL); + } + + PRINT_HII (STRING_TOKEN (STR_HTTP_ERR_WRITE), mLocalFilePath, Status); + return Status; + } + + if (Context->ContentDownloaded == 0) { + ShellPrintEx (-1, -1, L"%s 0 Kb", HTTP_PROGR_FRAME); + } + + Context->ContentDownloaded += DownloadLen; + NbOfKb = Context->ContentDownloaded >> 10; + + Progress[0] = L'\0'; + if (Context->ContentLength) { + LastStep = (Context->LastReportedNbOfBytes * HTTP_PROGRESS_SLIDER_STEPS) / + Context->ContentLength; + Step = (Context->ContentDownloaded * HTTP_PROGRESS_SLIDER_STEPS) / + Context->ContentLength; + } + + Context->LastReportedNbOfBytes = Context->ContentDownloaded; + + if (Step <= LastStep) { + if (!Context->ContentLength) { + // + // Update downloaded size, there is no length info available. + // + ShellPrintEx (-1, -1, L"%s", HTTP_KB); + ShellPrintEx (-1, -1, L"%7d Kb", NbOfKb); + } + + return EFI_SUCCESS; + } + + ShellPrintEx (-1, -1, L"%s", HTTP_PROGRESS_DEL); + + Status = StrCpyS (Progress, HTTP_PROGRESS_MESSAGE_SIZE, HTTP_PROGR_FRAME); + if (EFI_ERROR (Status)) { + return Status; + } + + for (Index = 1; Index < Step; Index++) { + Progress[Index] = L'='; + } + + if (Step) { + Progress[Step] = L'>'; + } + + UnicodeSPrint ( + Progress + (sizeof (HTTP_PROGR_FRAME) / sizeof (CHAR16)) - 1, + sizeof (Progress) - sizeof (HTTP_PROGR_FRAME), + L" %7d Kb", + NbOfKb + ); + + + ShellPrintEx (-1, -1, L"%s", Progress); + + return EFI_SUCCESS; +} + +/** + Replace the original Host and Uri with Host and Uri returned by the + HTTP server in 'Location' header (redirection). + + @param[in] Location A pointer to the 'Location' string + provided by HTTP server. + @param[in] Context A pointer to HTTP download context. + @param[in] DownloadUrl Fully qualified HTTP URL. + + @retval EFI_SUCCESS Host and Uri were successfully set. + @retval EFI_OUT_OF_RESOURCES Error setting Host or Uri. +**/ +STATIC +EFI_STATUS +SetHostURI ( + IN CHAR8 *Location, + IN HTTP_DOWNLOAD_CONTEXT *Context, + IN CHAR16 *DownloadUrl + ) +{ + EFI_STATUS Status; + UINTN StringSize; + UINTN FirstStep; + UINTN Idx; + UINTN Step; + CHAR8 *Walker; + CHAR16 *Temp; + CHAR8 *Tmp; + CHAR16 *Url; + BOOLEAN IsAbEmptyUrl; + + Tmp = NULL; + Url = NULL; + IsAbEmptyUrl = FALSE; + FirstStep = 0; + + StringSize = (AsciiStrSize (Location) * sizeof (CHAR16)); + Url = AllocateZeroPool (StringSize); + if (!Url) { + return EFI_OUT_OF_RESOURCES; + } + + Status = AsciiStrToUnicodeStrS ( + (CONST CHAR8 *)Location, + Url, + StringSize + ); + + if (EFI_ERROR (Status)) { + goto Error; + } + + // + // If an HTTP server redirects to the same location more than once, + // then stop attempts and tell it is not reachable. + // + if (!StrCmp (Url, DownloadUrl)) { + Status = EFI_NO_MAPPING; + goto Error; + } + + if (AsciiStrLen (Location) > 2) { + // + // Some servers return 'Location: //server/resource' + // + IsAbEmptyUrl = (Location[0] == '/') && (Location[1] == '/'); + if (IsAbEmptyUrl) { + // + // Skip first "//" + // + Location += 2; + FirstStep = 1; + } + } + + if (AsciiStrStr (Location, "://") || IsAbEmptyUrl) { + Idx = 0; + Walker = Location; + + for (Step = FirstStep; Step < 2; Step++) { + for (; *Walker != '/' && *Walker != '\0'; Walker++) { + Idx++; + } + + if (!Step) { + // + // Skip "//" + // + Idx += 2; + Walker += 2; + } + } + + Tmp = AllocateZeroPool (Idx + 1); + if (!Tmp) { + Status = EFI_OUT_OF_RESOURCES; + goto Error; + } + + CopyMem (Tmp, Location, Idx); + + // + // Location now points to Uri + // + Location += Idx; + StringSize = (Idx + 1) * sizeof (CHAR16); + + SHELL_FREE_NON_NULL (Context->ServerAddrAndProto); + + Temp = AllocateZeroPool (StringSize); + if (!Temp) { + Status = EFI_OUT_OF_RESOURCES; + goto Error; + } + + Status = AsciiStrToUnicodeStrS ( + (CONST CHAR8 *)Tmp, + Temp, + StringSize + ); + if (EFI_ERROR (Status)) { + SHELL_FREE_NON_NULL (Temp); + goto Error; + } + + Idx = 0; + if (IsAbEmptyUrl) { + Context->ServerAddrAndProto = StrnCatGrow ( + &Context->ServerAddrAndProto, + &Idx, + L"http://", + StrLen (L"http://") + ); + } + + Context->ServerAddrAndProto = StrnCatGrow ( + &Context->ServerAddrAndProto, + &Idx, + Temp, + StrLen (Temp) + ); + SHELL_FREE_NON_NULL (Temp); + if (!Context->ServerAddrAndProto) { + Status = EFI_OUT_OF_RESOURCES; + goto Error; + } + } + + SHELL_FREE_NON_NULL (Context->Uri); + + StringSize = AsciiStrSize (Location) * sizeof (CHAR16); + Context->Uri = AllocateZeroPool (StringSize); + if (!Context->Uri) { + Status = EFI_OUT_OF_RESOURCES; + goto Error; + } + + // + // Now make changes to the Uri part. + // + Status = AsciiStrToUnicodeStrS ( + (CONST CHAR8 *)Location, + Context->Uri, + StringSize + ); +Error: + SHELL_FREE_NON_NULL (Tmp); + SHELL_FREE_NON_NULL (Url); + + return Status; +} + +/** + Message parser callback. + Save a portion of HTTP body. + + @param[in] EventType Type of event. Can be either + OnComplete or OnData. + @param[in] Data A pointer to the buffer with data. + @param[in] Length Data length of this portion. + @param[in] Context A pointer to the HTTP download context. + + @retval EFI_SUCCESS The portion was processed successfully. + @retval Other Error returned by SavePortion. +**/ +STATIC +EFI_STATUS +EFIAPI +ParseMsg ( + IN HTTP_BODY_PARSE_EVENT EventType, + IN CHAR8 *Data, + IN UINTN Length, + IN VOID *Context + ) +{ + if ((Data == NULL) + || (EventType == BodyParseEventOnComplete) + || (Context == NULL)) + { + return EFI_SUCCESS; + } + + return SavePortion (Context, Length, Data); +} + + +/** + Get HTTP server response and collect the whole body as a file. + Set appropriate status in Context (REQ_OK, REQ_REPEAT, REQ_ERROR). + Note that even if HTTP server returns an error code, it might send + the body as well. This body will be collected in the resultant file. + + @param[in] Context A pointer to the HTTP download context. + @param[in] DownloadUrl A pointer to the fully qualified URL to download. + + @retval EFI_SUCCESS Valid file. Body successfully collected. + @retval EFI_HTTP_ERROR Response is a valid HTTP response, but the + HTTP server + indicated an error (HTTP code >= 400). + Response body MAY contain full + HTTP server response. + @retval Others Error getting the reponse from the HTTP server. + Response body is not collected. +**/ +STATIC +EFI_STATUS +GetResponse ( + IN HTTP_DOWNLOAD_CONTEXT *Context, + IN CHAR16 *DownloadUrl + ) +{ + EFI_HTTP_RESPONSE_DATA ResponseData; + EFI_HTTP_MESSAGE ResponseMessage; + EFI_HTTP_HEADER *Header; + EFI_STATUS Status; + VOID *MsgParser; + EFI_TIME StartTime; + EFI_TIME EndTime; + CONST CHAR16 *Desc; + UINTN ElapsedSeconds; + BOOLEAN IsTrunked; + BOOLEAN CanMeasureTime; + + ZeroMem (&ResponseData, sizeof (ResponseData)); + ZeroMem (&ResponseMessage, sizeof (ResponseMessage)); + ZeroMem (&Context->ResponseToken, sizeof (Context->ResponseToken)); + IsTrunked = FALSE; + + ResponseMessage.Body = Context->Buffer; + Context->ResponseToken.Status = EFI_SUCCESS; + Context->ResponseToken.Message = &ResponseMessage; + Context->ContentLength = 0; + Context->Status = REQ_OK; + Status = EFI_SUCCESS; + MsgParser = NULL; + ResponseData.StatusCode = HTTP_STATUS_UNSUPPORTED_STATUS; + ResponseMessage.Data.Response = &ResponseData; + Context->ResponseToken.Event = NULL; + CanMeasureTime = FALSE; + if (Context->Flags & DL_FLAG_TIME) { + ZeroMem (&StartTime, sizeof (StartTime)); + CanMeasureTime = !EFI_ERROR (gRT->GetTime (&StartTime, NULL)); + } + + do { + SHELL_FREE_NON_NULL (ResponseMessage.Headers); + ResponseMessage.HeaderCount = 0; + gResponseCallbackComplete = FALSE; + ResponseMessage.BodyLength = Context->BufferSize; + + if (ShellGetExecutionBreakFlag ()) { + Status = EFI_ABORTED; + break; + } + + if (!Context->ContentDownloaded && !Context->ResponseToken.Event) { + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + ResponseCallback, + Context, + &Context->ResponseToken.Event + ); + ASSERT_EFI_ERROR (Status); + } else { + ResponseMessage.Data.Response = NULL; + } + + if (EFI_ERROR (Status)) { + break; + } + + Status = Context->Http->Response (Context->Http, &Context->ResponseToken); + if (EFI_ERROR (Status)) { + break; + } + + Status = WaitForCompletion (Context, &gResponseCallbackComplete); + if (EFI_ERROR (Status) && ResponseMessage.HeaderCount) { + Status = EFI_SUCCESS; + } + + if (EFI_ERROR (Status)) { + Context->Http->Cancel (Context->Http, &Context->ResponseToken); + break; + } + + if (!Context->ContentDownloaded) { + if (NEED_REDIRECTION (ResponseData.StatusCode)) { + // + // Need to repeat the request with new Location (server redirected). + // + Context->Status = REQ_NEED_REPEAT; + + Header = HttpFindHeader ( + ResponseMessage.HeaderCount, + ResponseMessage.Headers, + "Location" + ); + if (Header) { + Status = SetHostURI (Header->FieldValue, Context, DownloadUrl); + if (Status == EFI_NO_MAPPING) { + PRINT_HII ( + STRING_TOKEN (STR_HTTP_ERR_STATUSCODE), + Context->ServerAddrAndProto, + L"Recursive HTTP server relocation", + Context->Uri + ); + } + } else { + // + // Bad reply from the server. Server must specify the location. + // Indicate that resource was not found, and no body collected. + // + Status = EFI_NOT_FOUND; + } + + Context->Http->Cancel (Context->Http, &Context->ResponseToken); + break; + } + + // + // Init message-body parser by header information. + // + if (!MsgParser) { + Status = HttpInitMsgParser ( + ResponseMessage.Data.Request->Method, + ResponseData.StatusCode, + ResponseMessage.HeaderCount, + ResponseMessage.Headers, + ParseMsg, + Context, + &MsgParser + ); + if (EFI_ERROR (Status)) { + break; + } + } + + // + // If it is a trunked message, rely on the parser. + // + Header = HttpFindHeader ( + ResponseMessage.HeaderCount, + ResponseMessage.Headers, + "Transfer-Encoding" + ); + IsTrunked = (Header && !AsciiStrCmp (Header->FieldValue, "chunked")); + + HttpGetEntityLength (MsgParser, &Context->ContentLength); + + if (ResponseData.StatusCode >= HTTP_STATUS_400_BAD_REQUEST + && (ResponseData.StatusCode != HTTP_STATUS_308_PERMANENT_REDIRECT)) + { + // + // Server reported an error via Response code. + // Collect the body if any. + // + if (!gHttpError) { + gHttpError = TRUE; + + Desc = ErrStatusDesc[ResponseData.StatusCode - + HTTP_STATUS_400_BAD_REQUEST]; + PRINT_HII ( + STRING_TOKEN (STR_HTTP_ERR_STATUSCODE), + Context->ServerAddrAndProto, + Desc, + Context->Uri + ); + + // + // This gives an RFC HTTP error. + // + Context->Status = ShellStrToUintn (Desc); + Status = ENCODE_ERROR (Context->Status); + } + } + } + + // + // Do NOT try to parse an empty body. + // + if (ResponseMessage.BodyLength || IsTrunked) { + Status = HttpParseMessageBody ( + MsgParser, + ResponseMessage.BodyLength, + ResponseMessage.Body + ); + } + } while (!HttpIsMessageComplete (MsgParser) + && !EFI_ERROR (Status) + && ResponseMessage.BodyLength); + + if (Context->Status != REQ_NEED_REPEAT + && Status == EFI_SUCCESS + && CanMeasureTime) + { + if (!EFI_ERROR (gRT->GetTime (&EndTime, NULL))) { + ElapsedSeconds = EfiTimeToEpoch (&EndTime) - EfiTimeToEpoch (&StartTime); + Print ( + L",%a%Lus\n", + ElapsedSeconds ? " " : " < ", + ElapsedSeconds > 1 ? (UINT64)ElapsedSeconds : 1 + ); + } + } + + SHELL_FREE_NON_NULL (MsgParser); + if (Context->ResponseToken.Event) { + gBS->CloseEvent (Context->ResponseToken.Event); + ZeroMem (&Context->ResponseToken, sizeof (Context->ResponseToken)); + } + + return Status; +} + +/** + Worker function that downloads the data of a file from an HTTP server given + the path of the file and its size. + + @param[in] Context A pointer to the HTTP download context. + @param[in] ControllerHandle The handle of the network interface controller + @param[in] NicName NIC name + + @retval EFI_SUCCESS The file was downloaded. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. + #return EFI_HTTP_ERROR The server returned a valid HTTP error. + Examine the mLocalFilePath file + to get error body. + @retval Others The downloading of the file from the server + failed. +**/ +STATIC +EFI_STATUS +DownloadFile ( + IN HTTP_DOWNLOAD_CONTEXT *Context, + IN EFI_HANDLE ControllerHandle, + IN CHAR16 *NicName + ) +{ + EFI_STATUS Status; + CHAR16 *DownloadUrl; + UINTN UrlSize; + EFI_HANDLE HttpChildHandle; + + ASSERT (Context); + if (Context == NULL) { + return EFI_INVALID_PARAMETER; + } + + DownloadUrl = NULL; + HttpChildHandle = NULL; + + Context->Buffer = AllocatePool (Context->BufferSize); + if (Context->Buffer == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_EXIT; + } + + // + // Open the file. + // + if (!EFI_ERROR (ShellFileExists (mLocalFilePath))) { + ShellDeleteFileByName (mLocalFilePath); + } + + Status = ShellOpenFileByName ( + mLocalFilePath, + &mFileHandle, + EFI_FILE_MODE_CREATE | + EFI_FILE_MODE_WRITE | + EFI_FILE_MODE_READ, + 0 + ); + if (EFI_ERROR (Status)) { + PRINT_HII_APP (STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL), mLocalFilePath); + goto ON_EXIT; + } + + do { + SHELL_FREE_NON_NULL (DownloadUrl); + + CLOSE_HTTP_HANDLE (ControllerHandle, HttpChildHandle); + + Status = CreateServiceChildAndOpenProtocol ( + ControllerHandle, + &gEfiHttpServiceBindingProtocolGuid, + &gEfiHttpProtocolGuid, + &HttpChildHandle, + (VOID**)&Context->Http + ); + + if (EFI_ERROR (Status)) { + PRINT_HII (STRING_TOKEN (STR_HTTP_ERR_OPEN_PROTOCOL), NicName, Status); + goto ON_EXIT; + } + + Status = Context->Http->Configure (Context->Http, &Context->HttpConfigData); + if (EFI_ERROR (Status)) { + PRINT_HII (STRING_TOKEN (STR_HTTP_ERR_CONFIGURE), NicName, Status); + goto ON_EXIT; + } + + UrlSize = 0; + DownloadUrl = StrnCatGrow ( + &DownloadUrl, + &UrlSize, + Context->ServerAddrAndProto, + StrLen (Context->ServerAddrAndProto) + ); + if (Context->Uri[0] != L'/') { + DownloadUrl = StrnCatGrow ( + &DownloadUrl, + &UrlSize, + L"/", + StrLen (Context->ServerAddrAndProto) + ); + } + + DownloadUrl = StrnCatGrow ( + &DownloadUrl, + &UrlSize, + Context->Uri, + StrLen (Context->Uri)); + + PRINT_HII (STRING_TOKEN (STR_HTTP_DOWNLOADING), DownloadUrl); + + Status = SendRequest (Context, DownloadUrl); + if (Status) { + goto ON_EXIT; + } + + Status = GetResponse (Context, DownloadUrl); + + if (Status) { + goto ON_EXIT; + } + + } while (Context->Status == REQ_NEED_REPEAT); + + if (Context->Status) { + Status = ENCODE_ERROR (Context->Status); + } + +ON_EXIT: + // + // Close the file. + // + if (mFileHandle != NULL) { + if (EFI_ERROR (Status) && !(Context->Flags & DL_FLAG_KEEP_BAD)) { + ShellDeleteFile (&mFileHandle); + } else { + ShellCloseFile (&mFileHandle); + } + } + + SHELL_FREE_NON_NULL (DownloadUrl); + SHELL_FREE_NON_NULL (Context->Buffer); + + CLOSE_HTTP_HANDLE (ControllerHandle, HttpChildHandle); + + return Status; +} + +/** + Retrive HII package list from ImageHandle and publish to HII database. + + @param[in] ImageHandle The image handle of the process. + + @retval HII handle. +**/ +EFI_HII_HANDLE +InitializeHiiPackage ( + IN 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/HttpDynamicCommand/Http.h b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/HttpDynamicCommand/Http.h new file mode 100644 index 00000000..c09096af --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/HttpDynamicCommand/Http.h @@ -0,0 +1,92 @@ +/** @file + Header file for 'http' command functions. + + Copyright (c) 2010 - 2017, Intel Corporation. All rights reserved.
+ Copyright (c) 2015, ARM Ltd. All rights reserved.
+ Copyright (c) 2020, Broadcom. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _HTTP_H_ +#define _HTTP_H_ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define HTTP_APP_NAME L"http" + +#define REQ_OK 0 +#define REQ_NEED_REPEAT 1 + +// +// Download Flags. +// +#define DL_FLAG_TIME BIT0 // Show elapsed time. +#define DL_FLAG_KEEP_BAD BIT1 // Keep files even if download failed. + +extern EFI_HII_HANDLE mHttpHiiHandle; + +typedef struct { + UINTN ContentDownloaded; + UINTN ContentLength; + UINTN LastReportedNbOfBytes; + UINTN BufferSize; + UINTN Status; + UINTN Flags; + UINT8 *Buffer; + CHAR16 *ServerAddrAndProto; + CHAR16 *Uri; + EFI_HTTP_TOKEN ResponseToken; + EFI_HTTP_TOKEN RequestToken; + EFI_HTTP_PROTOCOL *Http; + EFI_HTTP_CONFIG_DATA HttpConfigData; +} HTTP_DOWNLOAD_CONTEXT; + +/** + Function for 'http' command. + + @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 +RunHttp ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Retrieve HII package list from ImageHandle and publish to HII database. + + @param[in] ImageHandle The image handle of the process. + + @retval HII handle. +**/ +EFI_HII_HANDLE +InitializeHiiPackage ( + IN EFI_HANDLE ImageHandle + ); +#endif // _HTTP_H_ diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/HttpDynamicCommand/Http.uni b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/HttpDynamicCommand/Http.uni new file mode 100644 index 00000000..00cf05de --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/HttpDynamicCommand/Http.uni @@ -0,0 +1,117 @@ +// /** +// +// (C) Copyright 2015-2016 Hewlett Packard Enterprise Development LP
+// Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.
+// Copyright (c) 2020, Broadcom. All rights reserved.
+// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// Module Name: +// +// Http.uni +// +// Abstract: +// +// String definitions for UEFI Shell HTTP command +// +// +// **/ + +/=# + +#langdef en-US "english" + +#string STR_GEN_TOO_MANY #language en-US "%H%s%N: Too many arguments. Try help http.\r\n" +#string STR_GEN_TOO_FEW #language en-US "%H%s%N: Too few arguments. Try help http.\r\n" +#string STR_GEN_PARAM_INV #language en-US "%H%s%N: Invalid argument - '%H%s%N'. Try help http.\r\n" +#string STR_GEN_PROBLEM #language en-US "%H%s%N: Unknown flag - '%H%s%N'. Try help http.\r\n" +#string STR_GEN_FILE_OPEN_FAIL #language en-US "%H%s%N: Cannot open file - '%H%s%N'\r\n" +#string STR_GEN_CRLF #language en-US "\r\n" + +#string STR_HTTP_ERR_NO_NIC #language en-US "No network interface card found.\r\n" +#string STR_HTTP_ERR_NIC_NAME #language en-US "Failed to get the name of the network interface card number %d - %r\r\n" +#string STR_HTTP_ERR_OPEN_PROTOCOL #language en-US "Unable to open HTTP protocol on '%H%s%N' - %r\r\n" +#string STR_HTTP_ERR_CONFIGURE #language en-US "Unable to configure HTTP protocol on '%H%s%N' - %r\r\n" +#string STR_HTTP_ERR_DOWNLOAD #language en-US "Unable to download the file '%H%s%N' on '%H%s%N' - %r\r\n" +#string STR_HTTP_ERR_WRITE #language en-US "Unable to write into file '%H%s%N' - %r\r\n" +#string STR_HTTP_ERR_NIC_NOT_FOUND #language en-US "Network Interface Card '%H%s%N' not found.\r\n" +#string STR_HTTP_ERR_STATUSCODE #language en-US "\r'%H%s%N' reports '%s' for '%H%s%N' \r\n" +#string STR_HTTP_DOWNLOADING #language en-US "Downloading '%H%s%N'\r\n" + +#string STR_GET_HELP_HTTP #language en-US "" +".TH http 0 "Download a file from HTTP server."\r\n" +".SH NAME\r\n" +"Download a file from HTTP server.\r\n" +".SH SYNOPSIS\r\n" +" \r\n" +"HTTP [-i interface] [-l port] [-t timeout] [-s size] [-m] [-k]\r\n" +" [localfilepath]\r\n" +".SH OPTIONS\r\n" +" \r\n" +" -i interface - Specifies an adapter name, i.e., eth0.\r\n" +" -k Keep the downloaded file even if there was an error.\r\n" +" If this parameter is not used, the file will be deleted.\r\n" +" -l port - Specifies the local port number. Default value is 0\r\n" +" and the port number is automatically assigned.\r\n" +" -m Measure and report download time (in seconds). \r\n" +" -s size The size of the download buffer for a chunk, in bytes.\r\n" +" Default is 32K. Note that larger buffer does not imply\r\n" +" better speed.\r\n" +" -t timeout - The number of seconds to wait for completion of\r\n" +" requests and responses. Default is 0 which is 'automatic'.\r\n" +" %HURL%N\r\n" +" Two types of providing of URLs are supported:\r\n" +" 1. tftp-like, where host and http_uri are separate parameters\r\n" +" (example: host /host_uri), and\r\n\" +" 2. wget-like, where host and host_uri is one parameter.\r\n" +" (example: host/host_uri)\r\n" +"\r\n" +" host - Specifies HTTP Server address.\r\n + Can be either IPv4 address or 'http (or https)://addr'\r\n + Can use addresses resolvable by DNS as well. \r\n + Port can be specified after ':' if needed. \r\n + By default port 80 is used.\r\n" +" http_uri - HTTP server URI to download the file.\r\n" +"\r\n" +" localfilepath - Local destination file path.\r\n" +".SH DESCRIPTION\r\n" +" \r\n" +"NOTES:\r\n" +" 1. The HTTP command allows geting of the file specified by its 'http_uri'\r\n" +" path from the HTTP server specified by its 'host' IPv4 address. If the\r\n" +" optional 'localfilepath' parameter is provided, the downloaded file is\r\n" +" stored locally using the provided file path. If the local file path is\r\n" +" not specified, the file is stored in the current directory using the file\r\n" +" server's name.\r\n" +" 2. Before using the HTTP command, the network interface intended to be\r\n" +" used to retrieve the file must be configured. This configuration may be\r\n" +" done by means of the 'ifconfig' command.\r\n" +" 3. If a network interface is defined with the '-i' option then only this\r\n" +" interface will be used to retrieve the remote file. Otherwise, all network\r\n" +" interfaces are tried in the order they have been discovered during the\r\n" +" DXE phase.\r\n" +".SH EXAMPLES\r\n" +" \r\n" +"EXAMPLES:\r\n" +" * To get the file "dir1/file1.dat" from the HTTP server 192.168.1.1, port 8080, and\r\n" +" store it as file2.dat in the current directory (use tftp-like URL format) :\r\n" +" fs0:\> http 192.168.1.1:8080 dir1/file1.dat file2.dat\r\n" +" * To get the file /image.bin via HTTPS from server 192.168.1.1 at port 443 \r\n" +" (default HTTPS port), and store it in the current directory: \r\n" +" fs0:\> http https://192.168.1.1 image.bin\r\n" +" To get an index file from http://google.com and place it into the \r\n" +" current directory:\r\n" +" fs0:\> http google.com index.html\r\n" +".SH RETURNVALUES\r\n" +" \r\n" +"RETURN VALUES:\r\n" +" SHELL_SUCCESS The action was completed as requested.\r\n" +" SHELL_INVALID_PARAMETER One of the passed-in parameters was incorrectly\r\n" +" formatted or its value was out of bounds.\r\n" +" HTTP_ERROR No EFI errors, but the server reported a status code\r\n" +" which should be treated as an error. If an error body sent\r\n" +" by the server, and -k parameter is on command line, +" the file wil be saved either as localfilepath filename,\r\n" +" or as an URI name in the current directory.\r\n" +" If '/' is at the end of the URL, and no locafilepath filename\r\n" +" is given on the command line, the file will be retrieved as\r\n" +" index.html.\r\n" diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/HttpDynamicCommand/HttpApp.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/HttpDynamicCommand/HttpApp.c new file mode 100644 index 00000000..b262e463 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/HttpDynamicCommand/HttpApp.c @@ -0,0 +1,61 @@ +/** @file + Entrypoint of "http" shell standalone application. + + Copyright (c) 2010 - 2017, Intel Corporation. All rights reserved.
+ Copyright (c) 2015, ARM Ltd. All rights reserved.
+ Copyright (c) 2020, Broadcom. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ +#include "Http.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_HTTP); + +/** + Entry point of Http standalone application. + + @param ImageHandle The image handle of the process. + @param SystemTable The EFI System Table pointer. + + @retval EFI_SUCCESS Http command is executed sucessfully. + @retval EFI_ABORTED HII package was failed to initialize. + @retval others Other errors when executing http command. +**/ +EFI_STATUS +EFIAPI +HttpAppInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + SHELL_STATUS ShellStatus; + + mHttpHiiHandle = InitializeHiiPackage (ImageHandle); + if (mHttpHiiHandle == NULL) { + return EFI_ABORTED; + } + + Status = EFI_SUCCESS; + + ShellStatus = RunHttp (ImageHandle, SystemTable); + + HiiRemovePackages (mHttpHiiHandle); + + if (Status != SHELL_SUCCESS) { + Status = ENCODE_ERROR (ShellStatus); + } + + return Status; +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/HttpDynamicCommand/HttpApp.inf b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/HttpDynamicCommand/HttpApp.inf new file mode 100644 index 00000000..bdea1fc1 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/HttpDynamicCommand/HttpApp.inf @@ -0,0 +1,57 @@ +## @file +# Provides Shell 'http' standalone application. +# +# Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.
+# Copyright (c) 2015, ARM Ltd. All rights reserved.
+# Copyright (c) 2020, Broadcom. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +## + +[Defines] + INF_VERSION = 0x00010006 + BASE_NAME = http + FILE_GUID = 56B00FB7-91D2-869B-CE5C-26CD1A89C73C + MODULE_TYPE = UEFI_APPLICATION + VERSION_STRING = 1.0 + ENTRY_POINT = HttpAppInitialize +# +# This flag specifies whether HII resource section is generated into PE image. +# + UEFI_HII_RESOURCE_SECTION = TRUE + +[Sources.common] + Http.c + HttpApp.c + Http.h + Http.uni + +[Packages] + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + NetworkPkg/NetworkPkg.dec + ShellPkg/ShellPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + DebugLib + FileHandleLib + HiiLib + HttpLib + MemoryAllocationLib + NetLib + ShellLib + UefiApplicationEntryPoint + UefiBootServicesTableLib + UefiHiiServicesLib + UefiLib + UefiRuntimeServicesTableLib + +[Protocols] + gEfiHiiPackageListProtocolGuid ## CONSUMES + gEfiHttpProtocolGuid ## CONSUMES + gEfiHttpServiceBindingProtocolGuid ## CONSUMES + gEfiManagedNetworkServiceBindingProtocolGuid ## CONSUMES diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/HttpDynamicCommand/HttpDynamicCommand.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/HttpDynamicCommand/HttpDynamicCommand.c new file mode 100644 index 00000000..5245cba3 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/HttpDynamicCommand/HttpDynamicCommand.c @@ -0,0 +1,137 @@ +/** @file + Produce "http" shell dynamic command. + + Copyright (c) 2010 - 2017, Intel Corporation. All rights reserved.
+ Copyright (c) 2015, ARM Ltd. All rights reserved.
+ Copyright (c) 2020, Broadcom. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ +#include +#include "Http.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 sucessful + @return other the operation failed. +**/ +SHELL_STATUS +EFIAPI +HttpCommandHandler ( + 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 RunHttp (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 +HttpCommandGetHelp ( + IN EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *This, + IN CONST CHAR8 *Language + ) +{ + return HiiGetString ( + mHttpHiiHandle, + STRING_TOKEN (STR_GET_HELP_HTTP), + Language + ); +} + +EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL mHttpDynamicCommand = { + HTTP_APP_NAME, + HttpCommandHandler, + HttpCommandGetHelp +}; + +/** + Entry point of Http Dynamic Command. + + Produce the DynamicCommand protocol to handle "http" command. + + @param ImageHandle The image handle of the process. + @param SystemTable The EFI System Table pointer. + + @retval EFI_SUCCESS Http command is executed sucessfully. + @retval EFI_ABORTED HII package was failed to initialize. + @retval others Other errors when executing http command. +**/ +EFI_STATUS +EFIAPI +HttpCommandInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + mHttpHiiHandle = InitializeHiiPackage (ImageHandle); + if (mHttpHiiHandle == NULL) { + return EFI_ABORTED; + } + + Status = gBS->InstallProtocolInterface ( + &ImageHandle, + &gEfiShellDynamicCommandProtocolGuid, + EFI_NATIVE_INTERFACE, + &mHttpDynamicCommand + ); + ASSERT_EFI_ERROR (Status); + return Status; +} + +/** + Http 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 +HttpUnload ( + IN EFI_HANDLE ImageHandle +) +{ + EFI_STATUS Status; + + Status = gBS->UninstallProtocolInterface ( + ImageHandle, + &gEfiShellDynamicCommandProtocolGuid, + &mHttpDynamicCommand + ); + if (EFI_ERROR (Status)) { + return Status; + } + + HiiRemovePackages (mHttpHiiHandle); + + return EFI_SUCCESS; +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/HttpDynamicCommand/HttpDynamicCommand.inf b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/HttpDynamicCommand/HttpDynamicCommand.inf new file mode 100644 index 00000000..2621bcb7 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/HttpDynamicCommand/HttpDynamicCommand.inf @@ -0,0 +1,62 @@ +## @file +# Provides Shell 'http' dynamic command. +# +# Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.
+# Copyright (c) 2015, ARM Ltd. All rights reserved.
+# Copyright (c) 2020, Broadcom. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +## + +[Defines] + INF_VERSION = 0x00010006 + BASE_NAME = httpDynamicCommand + FILE_GUID = 19618BCE-55AE-09C6-37E9-4CE04084C7A1 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = HttpCommandInitialize + UNLOAD_IMAGE = HttpUnload +# +# This flag specifies whether HII resource section is generated into PE image. +# + UEFI_HII_RESOURCE_SECTION = TRUE + +[Sources.common] + Http.c + HttpDynamicCommand.c + Http.h + Http.uni + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + NetworkPkg/NetworkPkg.dec + ShellPkg/ShellPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + DebugLib + FileHandleLib + HiiLib + HttpLib + MemoryAllocationLib + NetLib + ShellLib + UefiBootServicesTableLib + UefiDriverEntryPoint + UefiHiiServicesLib + UefiLib + UefiRuntimeServicesTableLib + +[Protocols] + gEfiHiiPackageListProtocolGuid ## CONSUMES + gEfiHttpProtocolGuid ## CONSUMES + gEfiHttpServiceBindingProtocolGuid ## CONSUMES + gEfiManagedNetworkServiceBindingProtocolGuid ## CONSUMES + gEfiShellDynamicCommandProtocolGuid ## PRODUCES + +[DEPEX] + TRUE diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/TftpDynamicCommand/Tftp.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/TftpDynamicCommand/Tftp.c new file mode 100644 index 00000000..589c227d --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/TftpDynamicCommand/Tftp.c @@ -0,0 +1,1129 @@ +/** @file + The implementation for the 'tftp' Shell command. + + Copyright (c) 2015, ARM Ltd. All rights reserved.
+ Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.
+ (C) Copyright 2015 Hewlett Packard Enterprise Development LP
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include "Tftp.h" + +#define IP4_CONFIG2_INTERFACE_INFO_NAME_LENGTH 32 +EFI_HII_HANDLE mTftpHiiHandle; + +/* + Constant strings and definitions related to the message indicating the amount of + progress in the downloading of a TFTP file. +*/ + +// Frame for the progression slider +STATIC CONST CHAR16 mTftpProgressFrame[] = L"[ ]"; + +// Number of steps in the progression slider +#define TFTP_PROGRESS_SLIDER_STEPS ((sizeof (mTftpProgressFrame) / sizeof (CHAR16)) - 3) + +// Size in number of characters plus one (final zero) of the message to +// indicate the progress of a TFTP download. The format is "[(progress slider: +// 40 characters)] (nb of KBytes downloaded so far: 7 characters) Kb". There +// are thus the number of characters in mTftpProgressFrame[] plus 11 characters +// (2 // spaces, "Kb" and seven characters for the number of KBytes). +#define TFTP_PROGRESS_MESSAGE_SIZE ((sizeof (mTftpProgressFrame) / sizeof (CHAR16)) + 12) + +// String to delete the TFTP progress message to be able to update it : +// (TFTP_PROGRESS_MESSAGE_SIZE-1) '\b' +STATIC CONST CHAR16 mTftpProgressDelete[] = L"\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"; + +// Local File Handle +SHELL_FILE_HANDLE mFileHandle; + +// Path of the local file, Unicode encoded +CONST CHAR16 *mLocalFilePath; + +/** + Check and convert the UINT16 option values of the 'tftp' command + + @param[in] ValueStr Value as an Unicode encoded string + @param[out] Value UINT16 value + + @return TRUE The value was returned. + @return FALSE A parsing error occurred. +**/ +STATIC +BOOLEAN +StringToUint16 ( + IN CONST CHAR16 *ValueStr, + OUT UINT16 *Value + ); + +/** + Get the name of the NIC. + + @param[in] ControllerHandle The network physical device handle. + @param[in] NicNumber The network physical device number. + @param[out] NicName Address where to store the NIC name. + The memory area has to be at least + IP4_CONFIG2_INTERFACE_INFO_NAME_LENGTH + double byte wide. + + @return EFI_SUCCESS The name of the NIC was returned. + @return Others The creation of the child for the Managed + Network Service failed or the opening of + the Managed Network Protocol failed or + the operational parameters for the + Managed Network Protocol could not be + read. +**/ +STATIC +EFI_STATUS +GetNicName ( + IN EFI_HANDLE ControllerHandle, + IN UINTN NicNumber, + OUT CHAR16 *NicName + ); + +/** + Create a child for the service identified by its service binding protocol GUID + and get from the child the interface of the protocol identified by its GUID. + + @param[in] ControllerHandle Controller handle. + @param[in] ServiceBindingProtocolGuid Service binding protocol GUID of the + service to be created. + @param[in] ProtocolGuid GUID of the protocol to be open. + @param[out] ChildHandle Address where the handler of the + created child is returned. NULL is + returned in case of error. + @param[out] Interface Address where a pointer to the + protocol interface is returned in + case of success. + + @return EFI_SUCCESS The child was created and the protocol opened. + @return Others Either the creation of the child or the opening + of the protocol failed. +**/ +STATIC +EFI_STATUS +CreateServiceChildAndOpenProtocol ( + IN EFI_HANDLE ControllerHandle, + IN EFI_GUID *ServiceBindingProtocolGuid, + IN EFI_GUID *ProtocolGuid, + OUT EFI_HANDLE *ChildHandle, + OUT VOID **Interface + ); + +/** + Close the protocol identified by its GUID on the child handle of the service + identified by its service binding protocol GUID, then destroy the child + handle. + + @param[in] ControllerHandle Controller handle. + @param[in] ServiceBindingProtocolGuid Service binding protocol GUID of the + service to be destroyed. + @param[in] ProtocolGuid GUID of the protocol to be closed. + @param[in] ChildHandle Handle of the child to be destroyed. + +**/ +STATIC +VOID +CloseProtocolAndDestroyServiceChild ( + IN EFI_HANDLE ControllerHandle, + IN EFI_GUID *ServiceBindingProtocolGuid, + IN EFI_GUID *ProtocolGuid, + IN EFI_HANDLE ChildHandle + ); + +/** + Worker function that gets the size in numbers of bytes of a file from a TFTP + server before to download the file. + + @param[in] Mtftp4 MTFTP4 protocol interface + @param[in] FilePath Path of the file, ASCII encoded + @param[out] FileSize Address where to store the file size in number of + bytes. + + @retval EFI_SUCCESS The size of the file was returned. + @retval EFI_UNSUPPORTED The server does not support the "tsize" option. + @retval Others Error when retrieving the information from the server + (see EFI_MTFTP4_PROTOCOL.GetInfo() status codes) + or error when parsing the response of the server. +**/ +STATIC +EFI_STATUS +GetFileSize ( + IN EFI_MTFTP4_PROTOCOL *Mtftp4, + IN CONST CHAR8 *FilePath, + OUT UINTN *FileSize + ); + +/** + Worker function that download the data of a file from a TFTP server given + the path of the file and its size. + + @param[in] Mtftp4 MTFTP4 protocol interface + @param[in] FilePath Path of the file, Unicode encoded + @param[in] AsciiFilePath Path of the file, ASCII encoded + @param[in] FileSize Size of the file in number of bytes + @param[in] BlockSize Value of the TFTP blksize option + @param[in] WindowSize Value of the TFTP window size option + + @retval EFI_SUCCESS The file was downloaded. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. + @retval Others The downloading of the file from the server failed + (see EFI_MTFTP4_PROTOCOL.ReadFile() status codes). + +**/ +STATIC +EFI_STATUS +DownloadFile ( + IN EFI_MTFTP4_PROTOCOL *Mtftp4, + IN CONST CHAR16 *FilePath, + IN CONST CHAR8 *AsciiFilePath, + IN UINTN FileSize, + IN UINT16 BlockSize, + IN UINT16 WindowSize + ); + +/** + Update the progress of a file download + This procedure is called each time a new TFTP packet is received. + + @param[in] This MTFTP4 protocol interface + @param[in] Token Parameters for the download of the file + @param[in] PacketLen Length of the packet + @param[in] Packet Address of the packet + + @retval EFI_SUCCESS All packets are accepted. + +**/ +STATIC +EFI_STATUS +EFIAPI +CheckPacket ( + IN EFI_MTFTP4_PROTOCOL *This, + IN EFI_MTFTP4_TOKEN *Token, + IN UINT16 PacketLen, + IN EFI_MTFTP4_PACKET *Packet + ); + +EFI_MTFTP4_CONFIG_DATA DefaultMtftp4ConfigData = { + TRUE, // Use default setting + { { 0, 0, 0, 0 } }, // StationIp - Not relevant as UseDefaultSetting=TRUE + { { 0, 0, 0, 0 } }, // SubnetMask - Not relevant as UseDefaultSetting=TRUE + 0, // LocalPort - Automatically assigned port number. + { { 0, 0, 0, 0 } }, // GatewayIp - Not relevant as UseDefaultSetting=TRUE + { { 0, 0, 0, 0 } }, // ServerIp - Not known yet + 69, // InitialServerPort - Standard TFTP server port + 6, // TryCount - The number of times to transmit request packets and wait for a response. + 4 // TimeoutValue - Retransmission timeout in seconds. +}; + +STATIC CONST SHELL_PARAM_ITEM ParamList[] = { + {L"-i", TypeValue}, + {L"-l", TypeValue}, + {L"-r", TypeValue}, + {L"-c", TypeValue}, + {L"-t", TypeValue}, + {L"-s", TypeValue}, + {L"-w", TypeValue}, + {NULL , TypeMax} + }; + +/// +/// The default block size (512) of tftp is defined in the RFC1350. +/// +#define MTFTP_DEFAULT_BLKSIZE 512 +/// +/// The valid range of block size option is defined in the RFC2348. +/// +#define MTFTP_MIN_BLKSIZE 8 +#define MTFTP_MAX_BLKSIZE 65464 +/// +/// The default windowsize (1) of tftp. +/// +#define MTFTP_DEFAULT_WINDOWSIZE 1 +/// +/// The valid range of window size option. +/// Note that: RFC 7440 does not mention max window size value, but for the +/// stability reason, the value is limited to 64. +/// +#define MTFTP_MIN_WINDOWSIZE 1 +#define MTFTP_MAX_WINDOWSIZE 64 + +/** + Function for 'tftp' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). + + @return SHELL_SUCCESS The 'tftp' command completed successfully. + @return SHELL_ABORTED The Shell Library initialization failed. + @return SHELL_INVALID_PARAMETER At least one of the command's arguments is + not valid. + @return SHELL_OUT_OF_RESOURCES A memory allocation failed. + @return SHELL_NOT_FOUND Network Interface Card not found or server + error or file error. + +**/ +SHELL_STATUS +RunTftp ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + SHELL_STATUS ShellStatus; + EFI_STATUS Status; + LIST_ENTRY *CheckPackage; + CHAR16 *ProblemParam; + UINTN ParamCount; + CONST CHAR16 *UserNicName; + BOOLEAN NicFound; + CONST CHAR16 *ValueStr; + CONST CHAR16 *RemoteFilePath; + CHAR8 *AsciiRemoteFilePath; + UINTN FilePathSize; + CONST CHAR16 *Walker; + EFI_MTFTP4_CONFIG_DATA Mtftp4ConfigData; + EFI_HANDLE *Handles; + UINTN HandleCount; + UINTN NicNumber; + CHAR16 NicName[IP4_CONFIG2_INTERFACE_INFO_NAME_LENGTH]; + EFI_HANDLE ControllerHandle; + EFI_HANDLE Mtftp4ChildHandle; + EFI_MTFTP4_PROTOCOL *Mtftp4; + UINTN FileSize; + UINT16 BlockSize; + UINT16 WindowSize; + + ShellStatus = SHELL_INVALID_PARAMETER; + ProblemParam = NULL; + NicFound = FALSE; + AsciiRemoteFilePath = NULL; + Handles = NULL; + FileSize = 0; + BlockSize = MTFTP_DEFAULT_BLKSIZE; + WindowSize = MTFTP_DEFAULT_WINDOWSIZE; + + // + // Initialize the Shell library (we must be in non-auto-init...) + // + Status = ShellInitialize (); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return SHELL_ABORTED; + } + + // + // Parse the command line. + // + Status = ShellCommandLineParse (ParamList, &CheckPackage, &ProblemParam, TRUE); + if (EFI_ERROR (Status)) { + if ((Status == EFI_VOLUME_CORRUPTED) && + (ProblemParam != NULL) ) { + ShellPrintHiiEx ( + -1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), mTftpHiiHandle, + L"tftp", ProblemParam + ); + FreePool (ProblemParam); + } else { + ASSERT (FALSE); + } + goto Error; + } + + // + // Check the number of parameters + // + ParamCount = ShellCommandLineGetCount (CheckPackage); + if (ParamCount > 4) { + ShellPrintHiiEx ( + -1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), + mTftpHiiHandle, L"tftp" + ); + goto Error; + } + if (ParamCount < 3) { + ShellPrintHiiEx ( + -1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), + mTftpHiiHandle, L"tftp" + ); + goto Error; + } + + CopyMem (&Mtftp4ConfigData, &DefaultMtftp4ConfigData, sizeof (EFI_MTFTP4_CONFIG_DATA)); + + // + // Check the host IPv4 address + // + ValueStr = ShellCommandLineGetRawValue (CheckPackage, 1); + Status = NetLibStrToIp4 (ValueStr, &Mtftp4ConfigData.ServerIp); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx ( + -1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), + mTftpHiiHandle, L"tftp", ValueStr + ); + goto Error; + } + + RemoteFilePath = ShellCommandLineGetRawValue (CheckPackage, 2); + ASSERT(RemoteFilePath != NULL); + FilePathSize = StrLen (RemoteFilePath) + 1; + AsciiRemoteFilePath = AllocatePool (FilePathSize); + if (AsciiRemoteFilePath == NULL) { + ShellStatus = SHELL_OUT_OF_RESOURCES; + goto Error; + } + UnicodeStrToAsciiStrS (RemoteFilePath, AsciiRemoteFilePath, FilePathSize); + + if (ParamCount == 4) { + mLocalFilePath = ShellCommandLineGetRawValue (CheckPackage, 3); + } else { + Walker = RemoteFilePath + StrLen (RemoteFilePath); + while ((--Walker) >= RemoteFilePath) { + if ((*Walker == L'\\') || + (*Walker == L'/' ) ) { + break; + } + } + mLocalFilePath = Walker + 1; + } + + // + // Get the name of the Network Interface Card to be used if any. + // + UserNicName = ShellCommandLineGetValue (CheckPackage, L"-i"); + + ValueStr = ShellCommandLineGetValue (CheckPackage, L"-l"); + if (ValueStr != NULL) { + if (!StringToUint16 (ValueStr, &Mtftp4ConfigData.LocalPort)) { + goto Error; + } + } + + ValueStr = ShellCommandLineGetValue (CheckPackage, L"-r"); + if (ValueStr != NULL) { + if (!StringToUint16 (ValueStr, &Mtftp4ConfigData.InitialServerPort)) { + goto Error; + } + } + + ValueStr = ShellCommandLineGetValue (CheckPackage, L"-c"); + if (ValueStr != NULL) { + if (!StringToUint16 (ValueStr, &Mtftp4ConfigData.TryCount)) { + goto Error; + } + + if (Mtftp4ConfigData.TryCount == 0) { + Mtftp4ConfigData.TryCount = 6; + } + } + + ValueStr = ShellCommandLineGetValue (CheckPackage, L"-t"); + if (ValueStr != NULL) { + if (!StringToUint16 (ValueStr, &Mtftp4ConfigData.TimeoutValue)) { + goto Error; + } + if (Mtftp4ConfigData.TimeoutValue == 0) { + ShellPrintHiiEx ( + -1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), + mTftpHiiHandle, L"tftp", ValueStr + ); + goto Error; + } + } + + ValueStr = ShellCommandLineGetValue (CheckPackage, L"-s"); + if (ValueStr != NULL) { + if (!StringToUint16 (ValueStr, &BlockSize)) { + goto Error; + } + if (BlockSize < MTFTP_MIN_BLKSIZE || BlockSize > MTFTP_MAX_BLKSIZE) { + ShellPrintHiiEx ( + -1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), + mTftpHiiHandle, L"tftp", ValueStr + ); + goto Error; + } + } + + ValueStr = ShellCommandLineGetValue (CheckPackage, L"-w"); + if (ValueStr != NULL) { + if (!StringToUint16 (ValueStr, &WindowSize)) { + goto Error; + } + if (WindowSize < MTFTP_MIN_WINDOWSIZE || WindowSize > MTFTP_MAX_WINDOWSIZE) { + ShellPrintHiiEx ( + -1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), + mTftpHiiHandle, L"tftp", ValueStr + ); + goto Error; + } + } + + // + // Locate all MTFTP4 Service Binding protocols + // + ShellStatus = SHELL_NOT_FOUND; + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiManagedNetworkServiceBindingProtocolGuid, + NULL, + &HandleCount, + &Handles + ); + if (EFI_ERROR (Status) || (HandleCount == 0)) { + ShellPrintHiiEx ( + -1, -1, NULL, STRING_TOKEN (STR_TFTP_ERR_NO_NIC), + mTftpHiiHandle + ); + goto Error; + } + + for (NicNumber = 0; + (NicNumber < HandleCount) && (ShellStatus != SHELL_SUCCESS); + NicNumber++) { + ControllerHandle = Handles[NicNumber]; + + Status = GetNicName (ControllerHandle, NicNumber, NicName); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx ( + -1, -1, NULL, STRING_TOKEN (STR_TFTP_ERR_NIC_NAME), + mTftpHiiHandle, NicNumber, Status + ); + continue; + } + + if (UserNicName != NULL) { + if (StrCmp (NicName, UserNicName) != 0) { + continue; + } + NicFound = TRUE; + } + + Status = CreateServiceChildAndOpenProtocol ( + ControllerHandle, + &gEfiMtftp4ServiceBindingProtocolGuid, + &gEfiMtftp4ProtocolGuid, + &Mtftp4ChildHandle, + (VOID**)&Mtftp4 + ); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx ( + -1, -1, NULL, STRING_TOKEN (STR_TFTP_ERR_OPEN_PROTOCOL), + mTftpHiiHandle, NicName, Status + ); + continue; + } + + Status = Mtftp4->Configure (Mtftp4, &Mtftp4ConfigData); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx ( + -1, -1, NULL, STRING_TOKEN (STR_TFTP_ERR_CONFIGURE), + mTftpHiiHandle, NicName, Status + ); + goto NextHandle; + } + + Status = GetFileSize (Mtftp4, AsciiRemoteFilePath, &FileSize); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx ( + -1, -1, NULL, STRING_TOKEN (STR_TFTP_ERR_FILE_SIZE), + mTftpHiiHandle, RemoteFilePath, NicName, Status + ); + goto NextHandle; + } + + Status = DownloadFile (Mtftp4, RemoteFilePath, AsciiRemoteFilePath, FileSize, BlockSize, WindowSize); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx ( + -1, -1, NULL, STRING_TOKEN (STR_TFTP_ERR_DOWNLOAD), + mTftpHiiHandle, RemoteFilePath, NicName, Status + ); + goto NextHandle; + } + + ShellStatus = SHELL_SUCCESS; + + NextHandle: + + CloseProtocolAndDestroyServiceChild ( + ControllerHandle, + &gEfiMtftp4ServiceBindingProtocolGuid, + &gEfiMtftp4ProtocolGuid, + Mtftp4ChildHandle + ); + } + + if ((UserNicName != NULL) && (!NicFound)) { + ShellPrintHiiEx ( + -1, -1, NULL, STRING_TOKEN (STR_TFTP_ERR_NIC_NOT_FOUND), + mTftpHiiHandle, UserNicName + ); + } + + Error: + + ShellCommandLineFreeVarList (CheckPackage); + if (AsciiRemoteFilePath != NULL) { + FreePool (AsciiRemoteFilePath); + } + if (Handles != NULL) { + FreePool (Handles); + } + + if ((ShellStatus != SHELL_SUCCESS) && (EFI_ERROR(Status))) { + ShellStatus = Status & ~MAX_BIT; + } + + return ShellStatus; +} + +/** + Check and convert the UINT16 option values of the 'tftp' command + + @param[in] ValueStr Value as an Unicode encoded string + @param[out] Value UINT16 value + + @return TRUE The value was returned. + @return FALSE A parsing error occurred. +**/ +STATIC +BOOLEAN +StringToUint16 ( + IN CONST CHAR16 *ValueStr, + OUT UINT16 *Value + ) +{ + UINTN Val; + + Val = ShellStrToUintn (ValueStr); + if (Val > MAX_UINT16) { + ShellPrintHiiEx ( + -1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), + mTftpHiiHandle, L"tftp", ValueStr + ); + return FALSE; + } + + *Value = (UINT16)Val; + return TRUE; +} + +/** + Get the name of the NIC. + + @param[in] ControllerHandle The network physical device handle. + @param[in] NicNumber The network physical device number. + @param[out] NicName Address where to store the NIC name. + The memory area has to be at least + IP4_CONFIG2_INTERFACE_INFO_NAME_LENGTH + double byte wide. + + @return EFI_SUCCESS The name of the NIC was returned. + @return Others The creation of the child for the Managed + Network Service failed or the opening of + the Managed Network Protocol failed or + the operational parameters for the + Managed Network Protocol could not be + read. +**/ +STATIC +EFI_STATUS +GetNicName ( + IN EFI_HANDLE ControllerHandle, + IN UINTN NicNumber, + OUT CHAR16 *NicName + ) +{ + EFI_STATUS Status; + EFI_HANDLE MnpHandle; + EFI_MANAGED_NETWORK_PROTOCOL *Mnp; + EFI_SIMPLE_NETWORK_MODE SnpMode; + + Status = CreateServiceChildAndOpenProtocol ( + ControllerHandle, + &gEfiManagedNetworkServiceBindingProtocolGuid, + &gEfiManagedNetworkProtocolGuid, + &MnpHandle, + (VOID**)&Mnp + ); + if (EFI_ERROR (Status)) { + goto Error; + } + + Status = Mnp->GetModeData (Mnp, NULL, &SnpMode); + if (EFI_ERROR (Status) && (Status != EFI_NOT_STARTED)) { + goto Error; + } + + UnicodeSPrint ( + NicName, + IP4_CONFIG2_INTERFACE_INFO_NAME_LENGTH, + SnpMode.IfType == NET_IFTYPE_ETHERNET ? + L"eth%d" : + L"unk%d" , + NicNumber + ); + + Status = EFI_SUCCESS; + +Error: + + if (MnpHandle != NULL) { + CloseProtocolAndDestroyServiceChild ( + ControllerHandle, + &gEfiManagedNetworkServiceBindingProtocolGuid, + &gEfiManagedNetworkProtocolGuid, + MnpHandle + ); + } + + return Status; +} + +/** + Create a child for the service identified by its service binding protocol GUID + and get from the child the interface of the protocol identified by its GUID. + + @param[in] ControllerHandle Controller handle. + @param[in] ServiceBindingProtocolGuid Service binding protocol GUID of the + service to be created. + @param[in] ProtocolGuid GUID of the protocol to be open. + @param[out] ChildHandle Address where the handler of the + created child is returned. NULL is + returned in case of error. + @param[out] Interface Address where a pointer to the + protocol interface is returned in + case of success. + + @return EFI_SUCCESS The child was created and the protocol opened. + @return Others Either the creation of the child or the opening + of the protocol failed. +**/ +STATIC +EFI_STATUS +CreateServiceChildAndOpenProtocol ( + IN EFI_HANDLE ControllerHandle, + IN EFI_GUID *ServiceBindingProtocolGuid, + IN EFI_GUID *ProtocolGuid, + OUT EFI_HANDLE *ChildHandle, + OUT VOID **Interface + ) +{ + EFI_STATUS Status; + + *ChildHandle = NULL; + Status = NetLibCreateServiceChild ( + ControllerHandle, + gImageHandle, + ServiceBindingProtocolGuid, + ChildHandle + ); + if (!EFI_ERROR (Status)) { + Status = gBS->OpenProtocol ( + *ChildHandle, + ProtocolGuid, + Interface, + gImageHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + NetLibDestroyServiceChild ( + ControllerHandle, + gImageHandle, + ServiceBindingProtocolGuid, + *ChildHandle + ); + *ChildHandle = NULL; + } + } + + return Status; +} + +/** + Close the protocol identified by its GUID on the child handle of the service + identified by its service binding protocol GUID, then destroy the child + handle. + + @param[in] ControllerHandle Controller handle. + @param[in] ServiceBindingProtocolGuid Service binding protocol GUID of the + service to be destroyed. + @param[in] ProtocolGuid GUID of the protocol to be closed. + @param[in] ChildHandle Handle of the child to be destroyed. + +**/ +STATIC +VOID +CloseProtocolAndDestroyServiceChild ( + IN EFI_HANDLE ControllerHandle, + IN EFI_GUID *ServiceBindingProtocolGuid, + IN EFI_GUID *ProtocolGuid, + IN EFI_HANDLE ChildHandle + ) +{ + gBS->CloseProtocol ( + ChildHandle, + ProtocolGuid, + gImageHandle, + ControllerHandle + ); + + NetLibDestroyServiceChild ( + ControllerHandle, + gImageHandle, + ServiceBindingProtocolGuid, + ChildHandle + ); +} + +/** + Worker function that gets the size in numbers of bytes of a file from a TFTP + server before to download the file. + + @param[in] Mtftp4 MTFTP4 protocol interface + @param[in] FilePath Path of the file, ASCII encoded + @param[out] FileSize Address where to store the file size in number of + bytes. + + @retval EFI_SUCCESS The size of the file was returned. + @retval EFI_UNSUPPORTED The server does not support the "tsize" option. + @retval Others Error when retrieving the information from the server + (see EFI_MTFTP4_PROTOCOL.GetInfo() status codes) + or error when parsing the response of the server. +**/ +STATIC +EFI_STATUS +GetFileSize ( + IN EFI_MTFTP4_PROTOCOL *Mtftp4, + IN CONST CHAR8 *FilePath, + OUT UINTN *FileSize + ) +{ + EFI_STATUS Status; + EFI_MTFTP4_OPTION ReqOpt[1]; + EFI_MTFTP4_PACKET *Packet; + UINT32 PktLen; + EFI_MTFTP4_OPTION *TableOfOptions; + EFI_MTFTP4_OPTION *Option; + UINT32 OptCnt; + UINT8 OptBuf[128]; + + ReqOpt[0].OptionStr = (UINT8*)"tsize"; + OptBuf[0] = '0'; + OptBuf[1] = 0; + ReqOpt[0].ValueStr = OptBuf; + + Status = Mtftp4->GetInfo ( + Mtftp4, + NULL, + (UINT8*)FilePath, + NULL, + 1, + ReqOpt, + &PktLen, + &Packet + ); + + if (EFI_ERROR (Status)) { + goto Error; + } + + Status = Mtftp4->ParseOptions ( + Mtftp4, + PktLen, + Packet, + (UINT32 *) &OptCnt, + &TableOfOptions + ); + if (EFI_ERROR (Status)) { + goto Error; + } + + Option = TableOfOptions; + while (OptCnt != 0) { + if (AsciiStrnCmp ((CHAR8 *)Option->OptionStr, "tsize", 5) == 0) { + *FileSize = AsciiStrDecimalToUintn ((CHAR8 *)Option->ValueStr); + break; + } + OptCnt--; + Option++; + } + FreePool (TableOfOptions); + + if (OptCnt == 0) { + Status = EFI_UNSUPPORTED; + } + +Error : + + return Status; +} + +/** + Worker function that download the data of a file from a TFTP server given + the path of the file and its size. + + @param[in] Mtftp4 MTFTP4 protocol interface + @param[in] FilePath Path of the file, Unicode encoded + @param[in] AsciiFilePath Path of the file, ASCII encoded + @param[in] FileSize Size of the file in number of bytes + @param[in] BlockSize Value of the TFTP blksize option + @param[in] WindowSize Value of the TFTP window size option + + @retval EFI_SUCCESS The file was downloaded. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. + @retval Others The downloading of the file from the server failed + (see EFI_MTFTP4_PROTOCOL.ReadFile() status codes). + +**/ +STATIC +EFI_STATUS +DownloadFile ( + IN EFI_MTFTP4_PROTOCOL *Mtftp4, + IN CONST CHAR16 *FilePath, + IN CONST CHAR8 *AsciiFilePath, + IN UINTN FileSize, + IN UINT16 BlockSize, + IN UINT16 WindowSize + ) +{ + EFI_STATUS Status; + DOWNLOAD_CONTEXT *TftpContext; + EFI_MTFTP4_TOKEN Mtftp4Token; + UINT8 BlksizeBuf[10]; + UINT8 WindowsizeBuf[10]; + + ZeroMem (&Mtftp4Token, sizeof (EFI_MTFTP4_TOKEN)); + + TftpContext = AllocatePool (sizeof (DOWNLOAD_CONTEXT)); + if (TftpContext == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Error; + } + TftpContext->FileSize = FileSize; + TftpContext->DownloadedNbOfBytes = 0; + TftpContext->LastReportedNbOfBytes = 0; + + Mtftp4Token.Filename = (UINT8*)AsciiFilePath; + Mtftp4Token.CheckPacket = CheckPacket; + Mtftp4Token.Context = (VOID*)TftpContext; + Mtftp4Token.OptionCount = 0; + Mtftp4Token.OptionList = AllocatePool (sizeof (EFI_MTFTP4_OPTION) * 2); + if (Mtftp4Token.OptionList == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Error; + } + + if (BlockSize != MTFTP_DEFAULT_BLKSIZE) { + Mtftp4Token.OptionList[Mtftp4Token.OptionCount].OptionStr = (UINT8 *) "blksize"; + AsciiSPrint ((CHAR8 *) BlksizeBuf, sizeof (BlksizeBuf), "%d", BlockSize); + Mtftp4Token.OptionList[Mtftp4Token.OptionCount].ValueStr = BlksizeBuf; + Mtftp4Token.OptionCount ++; + } + + if (WindowSize != MTFTP_DEFAULT_WINDOWSIZE) { + Mtftp4Token.OptionList[Mtftp4Token.OptionCount].OptionStr = (UINT8 *) "windowsize"; + AsciiSPrint ((CHAR8 *) WindowsizeBuf, sizeof (WindowsizeBuf), "%d", WindowSize); + Mtftp4Token.OptionList[Mtftp4Token.OptionCount].ValueStr = WindowsizeBuf; + Mtftp4Token.OptionCount ++; + } + + ShellPrintHiiEx ( + -1, -1, NULL, STRING_TOKEN (STR_TFTP_DOWNLOADING), + mTftpHiiHandle, FilePath + ); + + // + // OPEN FILE + // + if (!EFI_ERROR (ShellFileExists (mLocalFilePath))) { + ShellDeleteFileByName (mLocalFilePath); + } + + Status = ShellOpenFileByName ( + mLocalFilePath, + &mFileHandle, + EFI_FILE_MODE_CREATE | + EFI_FILE_MODE_WRITE | + EFI_FILE_MODE_READ, + 0 + ); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx ( + -1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL), + mTftpHiiHandle, L"tftp", mLocalFilePath + ); + goto Error; + } + + Status = Mtftp4->ReadFile (Mtftp4, &Mtftp4Token); + ShellPrintHiiEx ( + -1, -1, NULL, STRING_TOKEN (STR_GEN_CRLF), + mTftpHiiHandle + ); + + // + // CLOSE FILE + // + ShellCloseFile (&mFileHandle); + +Error : + if (TftpContext != NULL) { + FreePool (TftpContext); + } + + if (Mtftp4Token.OptionList != NULL) { + FreePool (Mtftp4Token.OptionList); + } + + return Status; +} + +/** + Update the progress of a file download + This procedure is called each time a new TFTP packet is received. + + @param[in] This MTFTP4 protocol interface + @param[in] Token Parameters for the download of the file + @param[in] PacketLen Length of the packet + @param[in] Packet Address of the packet + + @retval EFI_SUCCESS All packets are accepted. + +**/ +STATIC +EFI_STATUS +EFIAPI +CheckPacket ( + IN EFI_MTFTP4_PROTOCOL *This, + IN EFI_MTFTP4_TOKEN *Token, + IN UINT16 PacketLen, + IN EFI_MTFTP4_PACKET *Packet + ) +{ + DOWNLOAD_CONTEXT *Context; + CHAR16 Progress[TFTP_PROGRESS_MESSAGE_SIZE]; + UINTN NbOfKb; + UINTN Index; + UINTN LastStep; + UINTN Step; + UINTN DownloadLen; + EFI_STATUS Status; + + if ((NTOHS (Packet->OpCode)) != EFI_MTFTP4_OPCODE_DATA) { + return EFI_SUCCESS; + } + + Context = (DOWNLOAD_CONTEXT*)Token->Context; + + // + // The data in the packet are prepended with two UINT16 : + // . OpCode = EFI_MTFTP4_OPCODE_DATA + // . Block = the number of this block of data + // + DownloadLen = (UINTN)PacketLen - sizeof (Packet->OpCode) - sizeof (Packet->Data.Block); + + ShellSetFilePosition(mFileHandle, Context->DownloadedNbOfBytes); + Status = ShellWriteFile (mFileHandle, &DownloadLen, Packet->Data.Data); + if (EFI_ERROR (Status)) { + if (Context->DownloadedNbOfBytes > 0) { + ShellPrintHiiEx ( + -1, -1, NULL, STRING_TOKEN (STR_GEN_CRLF), + mTftpHiiHandle + ); + } + ShellPrintHiiEx ( + -1, -1, NULL, STRING_TOKEN (STR_TFTP_ERR_WRITE), + mTftpHiiHandle, mLocalFilePath, Status + ); + return Status; + } + + if (Context->DownloadedNbOfBytes == 0) { + ShellPrintEx (-1, -1, L"%s 0 Kb", mTftpProgressFrame); + } + + Context->DownloadedNbOfBytes += DownloadLen; + NbOfKb = Context->DownloadedNbOfBytes / 1024; + + Progress[0] = L'\0'; + LastStep = (Context->LastReportedNbOfBytes * TFTP_PROGRESS_SLIDER_STEPS) / Context->FileSize; + Step = (Context->DownloadedNbOfBytes * TFTP_PROGRESS_SLIDER_STEPS) / Context->FileSize; + + if (Step <= LastStep) { + return EFI_SUCCESS; + } + + ShellPrintEx (-1, -1, L"%s", mTftpProgressDelete); + + Status = StrCpyS (Progress, TFTP_PROGRESS_MESSAGE_SIZE, mTftpProgressFrame); + if (EFI_ERROR(Status)) { + return Status; + } + for (Index = 1; Index < Step; Index++) { + Progress[Index] = L'='; + } + Progress[Step] = L'>'; + + UnicodeSPrint ( + Progress + (sizeof (mTftpProgressFrame) / sizeof (CHAR16)) - 1, + sizeof (Progress) - sizeof (mTftpProgressFrame), + L" %7d Kb", + NbOfKb + ); + Context->LastReportedNbOfBytes = Context->DownloadedNbOfBytes; + + ShellPrintEx (-1, -1, L"%s", Progress); + + return EFI_SUCCESS; +} + +/** + 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/TftpDynamicCommand/Tftp.h b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/TftpDynamicCommand/Tftp.h new file mode 100644 index 00000000..e4c90fa8 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/TftpDynamicCommand/Tftp.h @@ -0,0 +1,69 @@ +/** @file + Header file for 'tftp' command functions. + + Copyright (c) 2010 - 2017, Intel Corporation. All rights reserved.
+ Copyright (c) 2015, ARM Ltd. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _TFTP_H_ +#define _TFTP_H_ + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern EFI_HII_HANDLE mTftpHiiHandle; + +typedef struct { + UINTN FileSize; + UINTN DownloadedNbOfBytes; + UINTN LastReportedNbOfBytes; +} DOWNLOAD_CONTEXT; + +/** + Function for 'tftp' command. + + @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 +RunTftp ( + 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 // _TFTP_H_ diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/TftpDynamicCommand/Tftp.uni b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/TftpDynamicCommand/Tftp.uni new file mode 100644 index 00000000..ebac9c6c --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/TftpDynamicCommand/Tftp.uni @@ -0,0 +1,94 @@ +// /** +// +// (C) Copyright 2015-2016 Hewlett Packard Enterprise Development LP
+// Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.
+// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// Module Name: +// +// Tftp.uni +// +// Abstract: +// +// String definitions for UEFI Shell TFTP command +// +// +// **/ + +/=# + +#langdef en-US "english" + +#string STR_GEN_TOO_MANY #language en-US "%H%s%N: Too many arguments\r\n" +#string STR_GEN_TOO_FEW #language en-US "%H%s%N: Too few arguments\r\n" +#string STR_GEN_PARAM_INV #language en-US "%H%s%N: Invalid argument - '%H%s%N'\r\n" +#string STR_GEN_PROBLEM #language en-US "%H%s%N: Unknown flag - '%H%s%N'\r\n" +#string STR_GEN_FILE_OPEN_FAIL #language en-US "%H%s%N: Cannot open file - '%H%s%N'\r\n" +#string STR_GEN_CRLF #language en-US "\r\n" + +#string STR_TFTP_ERR_NO_NIC #language en-US "No network interface card found.\r\n" +#string STR_TFTP_ERR_NIC_NAME #language en-US "Failed to get the name of the network interface card number %d - %r\r\n" +#string STR_TFTP_ERR_OPEN_PROTOCOL #language en-US "Unable to open MTFTP4 protocol on '%H%s%N' - %r\r\n" +#string STR_TFTP_ERR_CONFIGURE #language en-US "Unable to configure MTFTP4 protocol on '%H%s%N' - %r\r\n" +#string STR_TFTP_ERR_FILE_SIZE #language en-US "Unable to get the size of the file '%H%s%N' on '%H%s%N' - %r\r\n" +#string STR_TFTP_ERR_DOWNLOAD #language en-US "Unable to download the file '%H%s%N' on '%H%s%N' - %r\r\n" +#string STR_TFTP_ERR_WRITE #language en-US "Unable to write into file '%H%s%N' - %r\r\n" +#string STR_TFTP_ERR_NIC_NOT_FOUND #language en-US "Network Interface Card '%H%s%N' not found.\r\n" +#string STR_TFTP_DOWNLOADING #language en-US "Downloading the file '%H%s%N'\r\n" +#string STR_TFTP_STRING #language en-US "%s" + +#string STR_GET_HELP_TFTP #language en-US "" +".TH tftp 0 "Download a file from TFTP server."\r\n" +".SH NAME\r\n" +"Download a file from TFTP server.\r\n" +".SH SYNOPSIS\r\n" +" \r\n" +"TFTP [-i interface] [-l ] [-r ] [-c ] [-t ]\r\n" +" [-s ] [-w ] host remotefilepath [localfilepath]\r\n" +".SH OPTIONS\r\n" +" \r\n" +" -i interface - Specifies an adapter name, i.e., eth0.\r\n" +" -l port - Specifies the local port number. Default value is 0\r\n" +" and the port number is automatically assigned.\r\n" +" -r port - Specifies the remote port number. Default value is 69.\r\n" +" -c - The number of times to transmit request packets and\r\n" +" wait for a response. The default value is 6. Set to zero\r\n" +" also means to use the default value.\r\n" +" -t - The number of seconds to wait for a response after\r\n" +" sending a request packet. Default value is 4s.\r\n" +" -s - Specifies the TFTP blksize option as defined in RFC 2348.\r\n" +" Valid range is between 8 and 65464, default value is 512.\r\n" +" -w - Specifies the TFTP windowsize option as defined in RFC 7440.\r\n" +" Valid range is between 1 and 64, default value is 1.\r\n" +" host - Specify TFTP Server IPv4 address.\r\n" +" remotefilepath - TFTP server file path to download the file.\r\n" +" localfilepath - Local destination file path.\r\n" +".SH DESCRIPTION\r\n" +" \r\n" +"NOTES:\r\n" +" 1. The TFTP command allows to get the file specified by its 'remotefilepath'\r\n" +" path from the TFTP server specified by its 'host' IPv4 address. If the\r\n" +" optional 'localfilepath' parameter is provided, the downloaded file is\r\n" +" stored locally using the provided file path. If the local file path is\r\n" +" not specified, the file is stored in the current directory using the file\r\n" +" server's name.\r\n" +" 2. Before using the TFTP command, the network interface intended to be\r\n" +" used to retrieve the file must be configured. This configuration may be\r\n" +" done by means of the 'ifconfig' command.\r\n" +" 3. If a network interface is defined with the '-i' option then only this\r\n" +" interface will be used to retrieve the remote file. Otherwise, all network\r\n" +" interfaces are tried in the order they have been discovered during the\r\n" +" DXE phase.\r\n" +".SH EXAMPLES\r\n" +" \r\n" +"EXAMPLES:\r\n" +" * To get the file "dir1/file1.dat" from the TFTP server 192.168.1.1 and\r\n" +" store it as file2.dat in the current directory :\r\n" +" fs0:\> tftp 192.168.1.1 dir1/file1.dat file2.dat\r\n" +".SH RETURNVALUES\r\n" +" \r\n" +"RETURN VALUES:\r\n" +" SHELL_SUCCESS The action was completed as requested.\r\n" +" SHELL_INVALID_PARAMETER One of the passed-in parameters was incorrectly\r\n" +" formatted or its value was out of bounds.\r\n" + diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/TftpDynamicCommand/TftpApp.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/TftpDynamicCommand/TftpApp.c new file mode 100644 index 00000000..c43755bf --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/TftpDynamicCommand/TftpApp.c @@ -0,0 +1,48 @@ +/** @file + Entrypoint of "tftp" shell standalone application. + + Copyright (c) 2010 - 2017, Intel Corporation. All rights reserved.
+ Copyright (c) 2015, ARM Ltd. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ +#include "Tftp.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_TFTP); + +/** + 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 +TftpAppInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + mTftpHiiHandle = InitializeHiiPackage (ImageHandle); + if (mTftpHiiHandle == NULL) { + return EFI_ABORTED; + } + + Status = (EFI_STATUS)RunTftp (ImageHandle, SystemTable); + HiiRemovePackages (mTftpHiiHandle); + return Status; +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/TftpDynamicCommand/TftpApp.inf b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/TftpDynamicCommand/TftpApp.inf new file mode 100644 index 00000000..4eb02f86 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/TftpDynamicCommand/TftpApp.inf @@ -0,0 +1,55 @@ +## @file +# Provides Shell 'tftp' standalone application. +# +# Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.
+# Copyright (c) 2015, ARM Ltd. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +## + +[Defines] + INF_VERSION = 0x00010006 + BASE_NAME = tftp + FILE_GUID = 8DC58D0D-67F5-4B97-9DFC-E442BB9A5648 + MODULE_TYPE = UEFI_APPLICATION + VERSION_STRING = 1.0 + ENTRY_POINT = TftpAppInitialize +# +# This flag specifies whether HII resource section is generated into PE image. +# + UEFI_HII_RESOURCE_SECTION = TRUE + +[Sources.common] + Tftp.uni + Tftp.h + Tftp.c + TftpApp.c + +[Packages] + MdePkg/MdePkg.dec + ShellPkg/ShellPkg.dec + MdeModulePkg/MdeModulePkg.dec + NetworkPkg/NetworkPkg.dec + +[LibraryClasses] + MemoryAllocationLib + BaseLib + BaseMemoryLib + DebugLib + ShellLib + UefiLib + UefiRuntimeServicesTableLib + UefiBootServicesTableLib + UefiApplicationEntryPoint + UefiHiiServicesLib + HiiLib + FileHandleLib + NetLib + +[Protocols] + gEfiManagedNetworkServiceBindingProtocolGuid ## CONSUMES + gEfiMtftp4ServiceBindingProtocolGuid ## CONSUMES + gEfiMtftp4ProtocolGuid ## CONSUMES + gEfiHiiPackageListProtocolGuid ## CONSUMES diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/TftpDynamicCommand/TftpDynamicCommand.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/TftpDynamicCommand/TftpDynamicCommand.c new file mode 100644 index 00000000..a657fc2c --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/TftpDynamicCommand/TftpDynamicCommand.c @@ -0,0 +1,126 @@ +/** @file + Produce "tftp" shell dynamic command. + + Copyright (c) 2010 - 2017, Intel Corporation. All rights reserved.
+ Copyright (c) 2015, ARM Ltd. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ +#include "Tftp.h" +#include + +/** + 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 +TftpCommandHandler ( + 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 RunTftp (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 +TftpCommandGetHelp ( + IN EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *This, + IN CONST CHAR8 *Language + ) +{ + return HiiGetString (mTftpHiiHandle, STRING_TOKEN (STR_GET_HELP_TFTP), Language); +} + +EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL mTftpDynamicCommand = { + L"tftp", + TftpCommandHandler, + TftpCommandGetHelp +}; + +/** + 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 +TftpCommandInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + mTftpHiiHandle = InitializeHiiPackage (ImageHandle); + if (mTftpHiiHandle == NULL) { + return EFI_ABORTED; + } + + Status = gBS->InstallProtocolInterface ( + &ImageHandle, + &gEfiShellDynamicCommandProtocolGuid, + EFI_NATIVE_INTERFACE, + &mTftpDynamicCommand + ); + 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 +TftpUnload ( + IN EFI_HANDLE ImageHandle +) +{ + EFI_STATUS Status; + Status = gBS->UninstallProtocolInterface ( + ImageHandle, + &gEfiShellDynamicCommandProtocolGuid, + &mTftpDynamicCommand + ); + if (EFI_ERROR (Status)) { + return Status; + } + HiiRemovePackages (mTftpHiiHandle); + return EFI_SUCCESS; +} diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/TftpDynamicCommand/TftpDynamicCommand.inf b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/TftpDynamicCommand/TftpDynamicCommand.inf new file mode 100644 index 00000000..695af555 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/DynamicCommand/TftpDynamicCommand/TftpDynamicCommand.inf @@ -0,0 +1,60 @@ +## @file +# Provides Shell 'tftp' dynamic command. +# +# Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.
+# Copyright (c) 2015, ARM Ltd. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +## + +[Defines] + INF_VERSION = 0x00010006 + BASE_NAME = tftpDynamicCommand + FILE_GUID = A487A478-51EF-48AA-8794-7BEE2A0562F1 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = TftpCommandInitialize + UNLOAD_IMAGE = TftpUnload +# +# This flag specifies whether HII resource section is generated into PE image. +# + UEFI_HII_RESOURCE_SECTION = TRUE + +[Sources.common] + Tftp.uni + Tftp.h + Tftp.c + TftpDynamicCommand.c + +[Packages] + MdePkg/MdePkg.dec + ShellPkg/ShellPkg.dec + MdeModulePkg/MdeModulePkg.dec + NetworkPkg/NetworkPkg.dec + +[LibraryClasses] + MemoryAllocationLib + BaseLib + BaseMemoryLib + DebugLib + ShellLib + UefiLib + UefiRuntimeServicesTableLib + UefiBootServicesTableLib + UefiDriverEntryPoint + UefiHiiServicesLib + HiiLib + FileHandleLib + NetLib + +[Protocols] + gEfiManagedNetworkServiceBindingProtocolGuid ## CONSUMES + gEfiMtftp4ServiceBindingProtocolGuid ## CONSUMES + gEfiMtftp4ProtocolGuid ## CONSUMES + gEfiHiiPackageListProtocolGuid ## CONSUMES + gEfiShellDynamicCommandProtocolGuid ## PRODUCES + +[DEPEX] + TRUE -- cgit v1.2.3