| /** @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, | |
| (CONST PRM_MODULE_CONTEXT_BUFFERS **)&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, | |
| (CONST PRM_CONTEXT_BUFFER **)&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, | |
| __func__, | |
| 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; | |
| EFI_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, | |
| __func__, | |
| 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, | |
| __func__, | |
| Status | |
| )); | |
| } | |
| if (mPrmInfoHiiHandle != NULL) { | |
| HiiRemovePackages (mPrmInfoHiiHandle); | |
| } | |
| return EFI_SUCCESS; | |
| } |