summaryrefslogtreecommitdiffstats
path: root/PrmPkg/Application/PrmInfo/PrmInfo.c
diff options
context:
space:
mode:
Diffstat (limited to 'PrmPkg/Application/PrmInfo/PrmInfo.c')
-rw-r--r--PrmPkg/Application/PrmInfo/PrmInfo.c725
1 files changed, 725 insertions, 0 deletions
diff --git a/PrmPkg/Application/PrmInfo/PrmInfo.c b/PrmPkg/Application/PrmInfo/PrmInfo.c
new file mode 100644
index 0000000000..431a6f2061
--- /dev/null
+++ b/PrmPkg/Application/PrmInfo/PrmInfo.c
@@ -0,0 +1,725 @@
+/** @file
+ Prints information about the PRM configuration loaded by the system firmware.
+
+ This application also provides some additional testing features for PRM configuration. For example,
+ the application can be used to selectively invoke PRM handlers in the UEFI shell environment to
+ provide a quick testing path of the PRM infrastructure on the firmware and the PRM module implementation.
+
+ This can also be useful to prepare a PRM enabled firmware and PRM modules prior to formal OS support to
+ test the PRM code.
+
+ Copyright (C) Microsoft Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Guid/ZeroGuid.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/HiiLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PrmContextBufferLib.h>
+#include <Library/PrmModuleDiscoveryLib.h>
+#include <Library/PrmPeCoffLib.h>
+#include <Library/ShellLib.h>
+#include <Library/TimerLib.h>
+#include <Library/UefiApplicationEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiHiiServicesLib.h>
+#include <Library/UefiLib.h>
+
+#include "PrmInfo.h"
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_STRING_ID mStringPrmInfoHelpTokenId = STRING_TOKEN (STR_PRMINFO_HELP);
+//
+// This is the generated String package data for all .UNI files.
+// This data array is ready to be used as input of HiiAddPackages() to
+// create a packagelist (which contains Form packages, String packages, etc).
+//
+extern UINT8 PrmInfoStrings[];
+
+STATIC UINTN mPrmHandlerCount;
+STATIC UINTN mPrmModuleCount;
+
+STATIC EFI_HII_HANDLE mPrmInfoHiiHandle;
+STATIC LIST_ENTRY mPrmHandlerList;
+
+STATIC CONST SHELL_PARAM_ITEM mParamList[] = {
+ {L"-l", TypeFlag},
+ {L"-t", TypeValue},
+ {NULL, TypeMax}
+ };
+
+/**
+ Frees all of the nodes in a linked list.
+
+ @param[in] ListHead A pointer to the head of the list that should be freed.
+
+ **/
+VOID
+EFIAPI
+FreeList (
+ IN LIST_ENTRY *ListHead
+ )
+{
+ LIST_ENTRY *Link;
+ LIST_ENTRY *NextLink;
+ PRM_HANDLER_CONTEXT_LIST_ENTRY *ListEntry;
+
+ if (ListHead == NULL) {
+ return;
+ }
+
+ Link = GetFirstNode (&mPrmHandlerList);
+ while (!IsNull (&mPrmHandlerList, Link)) {
+ ListEntry = CR (Link, PRM_HANDLER_CONTEXT_LIST_ENTRY, Link, PRM_HANDLER_CONTEXT_LIST_ENTRY_SIGNATURE);
+ NextLink = GetNextNode (&mPrmHandlerList, Link);
+
+ RemoveEntryList (Link);
+ FreePool (ListEntry);
+
+ Link = NextLink;
+ }
+}
+
+/**
+ Creates a new PRM Module Image Context linked list entry.
+
+ @retval PrmHandlerContextListEntry If successful, a pointer a PRM Handler Context linked list entry
+ otherwise, NULL is returned.
+
+**/
+PRM_HANDLER_CONTEXT_LIST_ENTRY *
+CreateNewPrmHandlerListEntry (
+ VOID
+ )
+{
+ PRM_HANDLER_CONTEXT_LIST_ENTRY *PrmHandlerContextListEntry;
+
+ PrmHandlerContextListEntry = AllocateZeroPool (sizeof (*PrmHandlerContextListEntry));
+ if (PrmHandlerContextListEntry == NULL) {
+ return NULL;
+ }
+ PrmHandlerContextListEntry->Signature = PRM_HANDLER_CONTEXT_LIST_ENTRY_SIGNATURE;
+
+ return PrmHandlerContextListEntry;
+}
+
+/**
+ Creates a new PRM Module Image Context linked list entry.
+
+ @param[in] RuntimeMmioRanges A pointer to an array of PRM module config runtime MMIO ranges.
+
+**/
+VOID
+PrintMmioRuntimeRangeInfo (
+ IN PRM_RUNTIME_MMIO_RANGES *RuntimeMmioRanges
+ )
+{
+ UINTN RuntimeMmioRangeCount;
+ UINTN RuntimeMmioRangeIndex;
+
+ if (RuntimeMmioRanges == NULL) {
+ return;
+ }
+
+ RuntimeMmioRangeCount = (UINTN) RuntimeMmioRanges->Count;
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PRMINFO_RUNTIME_MMIO_COUNT), mPrmInfoHiiHandle, RuntimeMmioRangeCount);
+
+ for (RuntimeMmioRangeIndex = 0; RuntimeMmioRangeIndex < RuntimeMmioRangeCount; RuntimeMmioRangeIndex++) {
+ ShellPrintHiiEx (
+ -1,
+ -1,
+ NULL,
+ STRING_TOKEN (STR_PRMINFO_RUNTIME_MMIO_INFO),
+ mPrmInfoHiiHandle,
+ RuntimeMmioRangeIndex,
+ RuntimeMmioRanges->Range[RuntimeMmioRangeIndex].PhysicalBaseAddress,
+ RuntimeMmioRanges->Range[RuntimeMmioRangeIndex].VirtualBaseAddress,
+ RuntimeMmioRanges->Range[RuntimeMmioRangeIndex].Length
+ );
+ }
+}
+
+/**
+ Gathers the PRM handler (and by extension module) information discovered on this system.
+
+ This function must be called to build up the discovered context for other functions in the application. The
+ function will optionally print results as determed by the value of the PrintInformation parameter.
+
+ @param[in] PrintInformation Indicates whether to print information as discovered in the function.
+
+**/
+VOID
+GatherPrmHandlerInfo (
+ IN BOOLEAN PrintInformation
+ )
+{
+ EFI_STATUS Status;
+ UINT16 MajorVersion;
+ UINT16 MinorVersion;
+ UINT16 HandlerCount;
+ UINTN HandlerIndex;
+ EFI_PHYSICAL_ADDRESS CurrentHandlerPhysicalAddress;
+ EFI_PHYSICAL_ADDRESS CurrentImageAddress;
+ PRM_HANDLER_CONTEXT CurrentHandlerContext;
+ EFI_GUID *CurrentModuleGuid;
+ EFI_IMAGE_EXPORT_DIRECTORY *CurrentImageExportDirectory;
+ PRM_CONTEXT_BUFFER *CurrentContextBuffer;
+ PRM_MODULE_EXPORT_DESCRIPTOR_STRUCT *CurrentExportDescriptorStruct;
+ PRM_MODULE_CONTEXT_BUFFERS *CurrentModuleContextBuffers;
+ PRM_HANDLER_CONTEXT_LIST_ENTRY *CurrentHandlerContextListEntry;
+ PRM_MODULE_IMAGE_CONTEXT *CurrentPrmModuleImageContext;
+ PRM_RUNTIME_MMIO_RANGES *CurrentPrmModuleRuntimeMmioRanges;
+
+ ASSERT (mPrmModuleCount <= mPrmHandlerCount);
+
+ if (mPrmHandlerCount == 0) {
+ return;
+ }
+
+ // Iterate across all PRM modules discovered
+ for (
+ CurrentPrmModuleImageContext = NULL, Status = GetNextPrmModuleEntry (&CurrentPrmModuleImageContext);
+ !EFI_ERROR (Status);
+ Status = GetNextPrmModuleEntry (&CurrentPrmModuleImageContext)) {
+
+ CurrentImageAddress = CurrentPrmModuleImageContext->PeCoffImageContext.ImageAddress;
+ CurrentImageExportDirectory = CurrentPrmModuleImageContext->ExportDirectory;
+ CurrentExportDescriptorStruct = CurrentPrmModuleImageContext->ExportDescriptor;
+
+ CurrentModuleGuid = &CurrentExportDescriptorStruct->Header.ModuleGuid;
+ HandlerCount = CurrentExportDescriptorStruct->Header.NumberPrmHandlers;
+
+ MajorVersion = 0;
+ MinorVersion = 0;
+ Status = GetImageVersionInPeCoffImage (
+ (VOID *) (UINTN) CurrentImageAddress,
+ &CurrentPrmModuleImageContext->PeCoffImageContext,
+ &MajorVersion,
+ &MinorVersion
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ if (PrintInformation) {
+ ShellPrintHiiEx (
+ -1,
+ -1,
+ NULL,
+ STRING_TOKEN (STR_PRMINFO_MODULE_NAME),
+ mPrmInfoHiiHandle,
+ (CHAR8 *) ((UINTN) CurrentImageAddress + CurrentImageExportDirectory->Name)
+ );
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PRMINFO_MODULE_GUID), mPrmInfoHiiHandle, CurrentModuleGuid);
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PRMINFO_MODULE_VERSION), mPrmInfoHiiHandle, MajorVersion, MinorVersion);
+ }
+
+ // It is currently valid for a PRM module not to use a context buffer
+ CurrentPrmModuleRuntimeMmioRanges = NULL;
+ Status = GetModuleContextBuffers (
+ ByModuleGuid,
+ CurrentModuleGuid,
+ &CurrentModuleContextBuffers
+ );
+ ASSERT (!EFI_ERROR (Status) || Status == EFI_NOT_FOUND);
+ if (!EFI_ERROR (Status) && CurrentModuleContextBuffers != NULL) {
+ CurrentPrmModuleRuntimeMmioRanges = CurrentModuleContextBuffers->RuntimeMmioRanges;
+ }
+
+ if (PrintInformation) {
+ if (CurrentPrmModuleRuntimeMmioRanges != NULL) {
+ PrintMmioRuntimeRangeInfo (CurrentPrmModuleRuntimeMmioRanges);
+ } else {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PRMINFO_NO_MMIO_RANGES), mPrmInfoHiiHandle);
+ }
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PRMINFO_LINE_BREAK), mPrmInfoHiiHandle);
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PRMINFO_HANDLER_COUNT), mPrmInfoHiiHandle, HandlerCount);
+ }
+
+ for (HandlerIndex = 0; HandlerIndex < HandlerCount; HandlerIndex++) {
+ ZeroMem (&CurrentHandlerContext, sizeof (CurrentHandlerContext));
+
+ CurrentHandlerContext.ModuleName = (CHAR8 *) ((UINTN) CurrentImageAddress + CurrentImageExportDirectory->Name);
+ CurrentHandlerContext.Guid = &CurrentExportDescriptorStruct->PrmHandlerExportDescriptors[HandlerIndex].PrmHandlerGuid;
+ CurrentHandlerContext.Name = (CHAR8 *) CurrentExportDescriptorStruct->PrmHandlerExportDescriptors[HandlerIndex].PrmHandlerName;
+
+ if (PrintInformation) {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PRMINFO_HANDLER_NAME), mPrmInfoHiiHandle, CurrentHandlerContext.Name);
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PRMINFO_HANDLER_GUID), mPrmInfoHiiHandle, CurrentHandlerContext.Guid);
+ }
+
+ Status = GetExportEntryAddress (
+ CurrentHandlerContext.Name,
+ CurrentImageAddress,
+ CurrentImageExportDirectory,
+ &CurrentHandlerPhysicalAddress
+ );
+ ASSERT_EFI_ERROR (Status);
+ if (!EFI_ERROR (Status)) {
+ CurrentHandlerContext.Handler = (PRM_HANDLER *) (UINTN) CurrentHandlerPhysicalAddress;
+
+ if (PrintInformation) {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PRMINFO_HANDLER_PA), mPrmInfoHiiHandle, CurrentHandlerPhysicalAddress);
+ }
+ } else {
+ if (PrintInformation) {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PRMINFO_HANDLER_PA_ERROR), mPrmInfoHiiHandle, Status);
+ }
+ }
+
+ Status = GetContextBuffer (
+ CurrentHandlerContext.Guid,
+ CurrentModuleContextBuffers,
+ &CurrentContextBuffer
+ );
+ if (!EFI_ERROR (Status)) {
+ CurrentHandlerContext.StaticDataBuffer = CurrentContextBuffer->StaticDataBuffer;
+ }
+
+ if (PrintInformation) {
+ if (CurrentHandlerContext.StaticDataBuffer != NULL) {
+ ShellPrintHiiEx (
+ -1,
+ -1,
+ NULL,
+ STRING_TOKEN (STR_PRMINFO_STATIC_DATA_BUFFER),
+ mPrmInfoHiiHandle,
+ (UINTN) CurrentHandlerContext.StaticDataBuffer
+ );
+ } else {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PRMINFO_LINE_BREAK), mPrmInfoHiiHandle);
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PRMINFO_NO_STATIC_BUFFER), mPrmInfoHiiHandle);
+ }
+ }
+
+ CurrentHandlerContextListEntry = CreateNewPrmHandlerListEntry ();
+ ASSERT (CurrentHandlerContextListEntry != NULL);
+ if (CurrentHandlerContextListEntry != NULL) {
+ CopyMem (
+ &CurrentHandlerContextListEntry->Context,
+ &CurrentHandlerContext,
+ sizeof (CurrentHandlerContextListEntry->Context)
+ );
+ InsertTailList (&mPrmHandlerList, &CurrentHandlerContextListEntry->Link);
+ }
+ }
+ }
+}
+
+/**
+ Populates the given context buffer so it can be passed to a PRM handler.
+
+ @param[in] StaticDataBuffer A pointer to the static data buffer that will be referenced in the context
+ buffer that is populated. This is an optional pointer that, if not provided,
+ by passing NULL will be ignored.
+ @param[in] HandlerGuid A pointer to the GUID of the PRM handler.
+ @param[in] ContextBuffer A pointer to a caller allocated ContextBuffer structure that will be populated
+ by this function.
+
+ @retval EFI_SUCCESS The given ContextBuffer was populated successfully.
+ @retval EFI_INVALID_PARAMETER The HandlerGuid or ContextBuffer actual argument is NULL.
+
+**/
+EFI_STATUS
+PopulateContextBuffer (
+ IN PRM_DATA_BUFFER *StaticDataBuffer OPTIONAL,
+ IN EFI_GUID *HandlerGuid,
+ IN PRM_CONTEXT_BUFFER *ContextBuffer
+ )
+{
+ if (HandlerGuid == NULL || ContextBuffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ZeroMem (ContextBuffer, sizeof (*ContextBuffer));
+
+ ContextBuffer->Signature = PRM_CONTEXT_BUFFER_SIGNATURE;
+ ContextBuffer->Version = PRM_CONTEXT_BUFFER_INTERFACE_VERSION;
+ CopyGuid (&ContextBuffer->HandlerGuid, HandlerGuid);
+
+ if (StaticDataBuffer != NULL) {
+ ContextBuffer->StaticDataBuffer = StaticDataBuffer;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Prints a given execution time in the appropriate unit.
+
+ @param[in] TimeInNanoSec The time to print in unit of nanoseconds.
+
+**/
+VOID
+PrintExecutionTime (
+ IN UINT64 TimeInNanoSec
+ )
+{
+ UINT64 Sec;
+ UINT64 MilliSec;
+ UINT64 MicroSec;
+ UINT64 NanoSec;
+ UINT64 RemainingTime;
+
+ Sec = 0;
+ MilliSec = 0;
+ MicroSec = 0;
+ NanoSec = 0;
+ RemainingTime = TimeInNanoSec;
+
+ if (RemainingTime > ONE_SECOND) {
+ Sec = DivU64x32 (RemainingTime, ONE_SECOND);
+ RemainingTime -= MultU64x32 (Sec, ONE_SECOND);
+ }
+
+ if (RemainingTime > ONE_MILLISECOND) {
+ MilliSec = DivU64x32 (RemainingTime, ONE_MILLISECOND);
+ RemainingTime -= MultU64x32 (MilliSec, ONE_MILLISECOND);
+ }
+
+ if (RemainingTime > ONE_MICROSECOND) {
+ MicroSec = DivU64x32 (RemainingTime, ONE_MICROSECOND);
+ RemainingTime -= MultU64x32 (MicroSec, ONE_MICROSECOND);
+ }
+
+ if (RemainingTime > 0) {
+ NanoSec = RemainingTime;
+ }
+
+ if (Sec > 0) {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PRMINFO_SECS), mPrmInfoHiiHandle, Sec, MilliSec, MicroSec, NanoSec);
+ } else if (MilliSec > 0) {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PRMINFO_MILLI_SECS), mPrmInfoHiiHandle, MilliSec, MicroSec, NanoSec);
+ } else if (MicroSec > 0) {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PRMINFO_USECS), mPrmInfoHiiHandle, MicroSec, NanoSec);
+ } else {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PRMINFO_NANO_SECS), mPrmInfoHiiHandle, NanoSec);
+ }
+}
+
+/**
+ Executes the PRM handler with the provided GUID.
+
+ @param[in] HandlerGuid A pointer to the GUID of the PRM handler to execute.
+ A zero GUID indicates that all PRM handlers present should be executed.
+
+ @retval EFI_SUCCESS The PRM handler(s) were executed.
+ @retval EFI_INVALID_PARAMETER The HandlerGuid actual argument is NULL.
+ @retval EFI_NOT_FOUND The PRM handler could not be found.
+
+**/
+EFI_STATUS
+ExecutePrmHandlerByGuid (
+ IN EFI_GUID *HandlerGuid
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN ExecuteAllHandlers;
+ BOOLEAN HandlerFound;
+ UINT64 StartTime;
+ UINT64 EndTime;
+ PRM_CONTEXT_BUFFER CurrentContextBuffer;
+ PRM_HANDLER_CONTEXT *HandlerContext;
+ PRM_HANDLER_CONTEXT_LIST_ENTRY *HandlerContextListEntry;
+ LIST_ENTRY *Link;
+
+ Link = NULL;
+ HandlerFound = FALSE;
+
+ if (HandlerGuid == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Zero GUID means execute all discovered handlers
+ //
+ ExecuteAllHandlers = CompareGuid (HandlerGuid, &gZeroGuid);
+
+ EFI_LIST_FOR_EACH (Link, &mPrmHandlerList) {
+ HandlerContextListEntry = CR (Link, PRM_HANDLER_CONTEXT_LIST_ENTRY, Link, PRM_HANDLER_CONTEXT_LIST_ENTRY_SIGNATURE);
+ HandlerContext = &HandlerContextListEntry->Context;
+
+ if (!ExecuteAllHandlers && !CompareGuid (HandlerGuid, HandlerContext->Guid)) {
+ continue;
+ }
+
+ HandlerFound = TRUE;
+ Status = PopulateContextBuffer (HandlerContext->StaticDataBuffer, HandlerContext->Guid, &CurrentContextBuffer);
+ if (!EFI_ERROR (Status)) {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PRMINFO_LINE_BREAK), mPrmInfoHiiHandle);
+ ShellPrintHiiEx (
+ -1,
+ -1,
+ NULL,
+ STRING_TOKEN (STR_PRMINFO_MODULE_NAME),
+ mPrmInfoHiiHandle,
+ HandlerContext->ModuleName
+ );
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PRMINFO_HANDLER_NAME_HL), mPrmInfoHiiHandle, HandlerContext->Name);
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PRMINFO_HANDLER_GUID), mPrmInfoHiiHandle, HandlerContext->Guid);
+
+ StartTime = 0;
+ EndTime = 0;
+ if (PcdGetBool (PcdPrmInfoPrintHandlerExecutionTime)) {
+ StartTime = GetPerformanceCounter ();
+ }
+ Status = HandlerContext->Handler (NULL, &CurrentContextBuffer);
+ if (PcdGetBool (PcdPrmInfoPrintHandlerExecutionTime)) {
+ EndTime = GetPerformanceCounter ();
+ }
+
+ if (EFI_ERROR (Status)) {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PRMINFO_HANDLER_ERR_STATUS), mPrmInfoHiiHandle, Status);
+ } else {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PRMINFO_HANDLER_SUCC_STATUS), mPrmInfoHiiHandle, Status);
+ }
+
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PRMINFO_HANDLER_EXEC_TIME), mPrmInfoHiiHandle);
+ if (StartTime == 0 && EndTime == 0) {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PRMINFO_UNKNOWN), mPrmInfoHiiHandle);
+ } else {
+ PrintExecutionTime (GetTimeInNanoSecond (EndTime - StartTime));
+ }
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PRMINFO_LINE_BREAK), mPrmInfoHiiHandle);
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PRMINFO_LINE_BREAK), mPrmInfoHiiHandle);
+ } else {
+ DEBUG ((
+ DEBUG_ERROR,
+ "%a - %a: An error occurred creating a context buffer for handler %g\n",
+ gEfiCallerBaseName,
+ __FUNCTION__,
+ HandlerContext->Guid
+ ));
+ }
+
+ if (!ExecuteAllHandlers) {
+ break;
+ }
+ }
+
+ if (!HandlerFound) {
+ return EFI_NOT_FOUND;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Parses the application parameter list and performs the appropriate operations based on the results.
+
+ @retval EFI_SUCCESS The parameter list was parsed successfully.
+ @retval EFI_INVALID_PARAMETER An invalid parameter was given to the application.
+ @retval EFI_LOAD_ERROR An error occurred loading the application.
+
+**/
+EFI_STATUS
+ParseParameterList (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ SHELL_STATUS ReturnStatus;
+ UINTN ArgumentCount;
+ EFI_GUID HandlerGuid;
+ BOOLEAN PrintHandlerInfo;
+ LIST_ENTRY *Package;
+ LIST_ENTRY *TempNode;
+ CHAR16 *ProblemParam;
+ CONST CHAR16 *HandlerGuidStr;
+
+ HandlerGuidStr = NULL;
+ Package = NULL;
+ PrintHandlerInfo = FALSE;
+ ReturnStatus = EFI_SUCCESS;
+
+ InitializeListHead (&mPrmHandlerList);
+
+ //
+ // Basic application parameter validation
+ //
+ Status = ShellCommandLineParseEx (mParamList, &Package, &ProblemParam, FALSE, FALSE);
+ if (EFI_ERROR (Status)) {
+ if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PRMINFO_GEN_PROBLEM), mPrmInfoHiiHandle, APPLICATION_NAME, ProblemParam);
+ ReturnStatus = EFI_INVALID_PARAMETER;
+ FreePool (ProblemParam);
+ } else {
+ ReturnStatus = EFI_LOAD_ERROR;
+ ASSERT (FALSE);
+ }
+
+ goto Done;
+ } else if (Package == NULL) {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PRMINFO_NO_ARG), mPrmInfoHiiHandle, APPLICATION_NAME);
+ ReturnStatus = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ //
+ // Get argument count including flags
+ //
+ for (
+ ArgumentCount = 0, TempNode = Package;
+ GetNextNode (Package, TempNode) != Package;
+ ArgumentCount++, TempNode = GetNextNode (Package, TempNode)
+ );
+
+ if (ArgumentCount == 1) {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PRMINFO_NO_ARG), mPrmInfoHiiHandle, APPLICATION_NAME);
+ ReturnStatus = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ if (ArgumentCount > 6) {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PRMINFO_TOO_MANY), mPrmInfoHiiHandle, APPLICATION_NAME);
+ ReturnStatus = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ //
+ // Parse the actual arguments provided
+ //
+ if (ShellCommandLineGetFlag (Package, L"-b")) {
+ if (ArgumentCount <= 2) {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PRMINFO_PARAM_INV), mPrmInfoHiiHandle, APPLICATION_NAME, L"-b");
+ ReturnStatus = EFI_INVALID_PARAMETER;
+ goto Done;
+ } else {
+ ShellSetPageBreakMode (TRUE);
+ }
+ }
+
+ if (ShellCommandLineGetFlag (Package, L"-l")) {
+ PrintHandlerInfo = TRUE;
+ }
+
+ if (ShellCommandLineGetFlag (Package, L"-t")) {
+ HandlerGuidStr = ShellCommandLineGetValue (Package, L"-t");
+ if (HandlerGuidStr != NULL) {
+ if (StrnCmp (HandlerGuidStr, L"all", StrLen (HandlerGuidStr)) == 0) {
+ CopyGuid (&HandlerGuid, &gZeroGuid);
+ } else {
+ Status = StrToGuid (HandlerGuidStr, &HandlerGuid);
+ if (EFI_ERROR (Status) || (HandlerGuidStr[GUID_STRING_LENGTH] != L'\0')) {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PRMINFO_GUID_INV), mPrmInfoHiiHandle, APPLICATION_NAME, HandlerGuidStr);
+ ReturnStatus = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ }
+ } else {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PRMINFO_NO_VALUE), mPrmInfoHiiHandle, APPLICATION_NAME, L"-t");
+ ReturnStatus = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ }
+
+ Status = DiscoverPrmModules (&mPrmModuleCount, &mPrmHandlerCount);
+ if (EFI_ERROR (Status)) {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PRMINFO_DISCOVERY_FAILED), mPrmInfoHiiHandle, APPLICATION_NAME);
+ DEBUG ((
+ DEBUG_ERROR,
+ "%a - %a: An error occurred during PRM module discovery (%r)\n",
+ gEfiCallerBaseName,
+ __FUNCTION__,
+ Status
+ ));
+ ReturnStatus = Status;
+ goto Done;
+ }
+
+ if (PrintHandlerInfo) {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PRMINFO_LIST_TITLE), mPrmInfoHiiHandle);
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PRMINFO_MODULES_FOUND), mPrmInfoHiiHandle, mPrmModuleCount);
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PRMINFO_HANDLERS_FOUND), mPrmInfoHiiHandle, mPrmHandlerCount);
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PRMINFO_LINE_BREAK), mPrmInfoHiiHandle);
+ }
+ GatherPrmHandlerInfo (PrintHandlerInfo);
+
+ if (HandlerGuidStr != NULL) {
+ Status = ExecutePrmHandlerByGuid (&HandlerGuid);
+ if (Status == EFI_NOT_FOUND) {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PRMINFO_HANDLER_NOT_FOUND), mPrmInfoHiiHandle, APPLICATION_NAME, HandlerGuid);
+ }
+ }
+
+Done:
+ FreeList (&mPrmHandlerList);
+
+ if (Package != NULL) {
+ ShellCommandLineFreeVarList (Package);
+ }
+
+ return ReturnStatus;
+}
+
+/**
+ Entry point of this UEFI application.
+
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
+ @param[in] SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The entry point is executed successfully.
+ @retval other Some error occurs when executing this entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+UefiMain (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_HII_PACKAGE_LIST_HEADER *PackageList;
+
+ //
+ // Retrieve the HII package list from ImageHandle
+ //
+ Status = gBS->OpenProtocol (
+ ImageHandle,
+ &gEfiHiiPackageListProtocolGuid,
+ (VOID **) &PackageList,
+ ImageHandle,
+ NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Publish the HII package list to the HII Database
+ //
+ Status = gHiiDatabase->NewPackageList (
+ gHiiDatabase,
+ PackageList,
+ NULL,
+ &mPrmInfoHiiHandle
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (mPrmInfoHiiHandle == NULL) {
+ return EFI_SUCCESS;
+ }
+
+ Status = ParseParameterList ();
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "%a - %a: An error occurred parsing user-provided arguments (%r)\n",
+ gEfiCallerBaseName,
+ __FUNCTION__,
+ Status
+ ));
+ }
+
+ if (mPrmInfoHiiHandle != NULL) {
+ HiiRemovePackages (mPrmInfoHiiHandle);
+ }
+
+ return EFI_SUCCESS;
+}