--- /dev/null
+/** @file\r
+ Prints information about the PRM configuration loaded by the system firmware.\r
+\r
+ This application also provides some additional testing features for PRM configuration. For example,\r
+ the application can be used to selectively invoke PRM handlers in the UEFI shell environment to\r
+ provide a quick testing path of the PRM infrastructure on the firmware and the PRM module implementation.\r
+\r
+ This can also be useful to prepare a PRM enabled firmware and PRM modules prior to formal OS support to\r
+ test the PRM code.\r
+\r
+ Copyright (C) Microsoft Corporation. All rights reserved.\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+#include <Guid/ZeroGuid.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/HiiLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/PcdLib.h>\r
+#include <Library/PrmContextBufferLib.h>\r
+#include <Library/PrmModuleDiscoveryLib.h>\r
+#include <Library/PrmPeCoffLib.h>\r
+#include <Library/ShellLib.h>\r
+#include <Library/TimerLib.h>\r
+#include <Library/UefiApplicationEntryPoint.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/UefiHiiServicesLib.h>\r
+#include <Library/UefiLib.h>\r
+\r
+#include "PrmInfo.h"\r
+\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_STRING_ID mStringPrmInfoHelpTokenId = STRING_TOKEN (STR_PRMINFO_HELP);\r
+//\r
+// This is the generated String package data for all .UNI files.\r
+// This data array is ready to be used as input of HiiAddPackages() to\r
+// create a packagelist (which contains Form packages, String packages, etc).\r
+//\r
+extern UINT8 PrmInfoStrings[];\r
+\r
+STATIC UINTN mPrmHandlerCount;\r
+STATIC UINTN mPrmModuleCount;\r
+\r
+STATIC EFI_HII_HANDLE mPrmInfoHiiHandle;\r
+STATIC LIST_ENTRY mPrmHandlerList;\r
+\r
+STATIC CONST SHELL_PARAM_ITEM mParamList[] = {\r
+ {L"-l", TypeFlag},\r
+ {L"-t", TypeValue},\r
+ {NULL, TypeMax}\r
+ };\r
+\r
+/**\r
+ Frees all of the nodes in a linked list.\r
+\r
+ @param[in] ListHead A pointer to the head of the list that should be freed.\r
+\r
+ **/\r
+VOID\r
+EFIAPI\r
+FreeList (\r
+ IN LIST_ENTRY *ListHead\r
+ )\r
+{\r
+ LIST_ENTRY *Link;\r
+ LIST_ENTRY *NextLink;\r
+ PRM_HANDLER_CONTEXT_LIST_ENTRY *ListEntry;\r
+\r
+ if (ListHead == NULL) {\r
+ return;\r
+ }\r
+\r
+ Link = GetFirstNode (&mPrmHandlerList);\r
+ while (!IsNull (&mPrmHandlerList, Link)) {\r
+ ListEntry = CR (Link, PRM_HANDLER_CONTEXT_LIST_ENTRY, Link, PRM_HANDLER_CONTEXT_LIST_ENTRY_SIGNATURE);\r
+ NextLink = GetNextNode (&mPrmHandlerList, Link);\r
+\r
+ RemoveEntryList (Link);\r
+ FreePool (ListEntry);\r
+\r
+ Link = NextLink;\r
+ }\r
+}\r
+\r
+/**\r
+ Creates a new PRM Module Image Context linked list entry.\r
+\r
+ @retval PrmHandlerContextListEntry If successful, a pointer a PRM Handler Context linked list entry\r
+ otherwise, NULL is returned.\r
+\r
+**/\r
+PRM_HANDLER_CONTEXT_LIST_ENTRY *\r
+CreateNewPrmHandlerListEntry (\r
+ VOID\r
+ )\r
+{\r
+ PRM_HANDLER_CONTEXT_LIST_ENTRY *PrmHandlerContextListEntry;\r
+\r
+ PrmHandlerContextListEntry = AllocateZeroPool (sizeof (*PrmHandlerContextListEntry));\r
+ if (PrmHandlerContextListEntry == NULL) {\r
+ return NULL;\r
+ }\r
+ PrmHandlerContextListEntry->Signature = PRM_HANDLER_CONTEXT_LIST_ENTRY_SIGNATURE;\r
+\r
+ return PrmHandlerContextListEntry;\r
+}\r
+\r
+/**\r
+ Creates a new PRM Module Image Context linked list entry.\r
+\r
+ @param[in] RuntimeMmioRanges A pointer to an array of PRM module config runtime MMIO ranges.\r
+\r
+**/\r
+VOID\r
+PrintMmioRuntimeRangeInfo (\r
+ IN PRM_RUNTIME_MMIO_RANGES *RuntimeMmioRanges\r
+ )\r
+{\r
+ UINTN RuntimeMmioRangeCount;\r
+ UINTN RuntimeMmioRangeIndex;\r
+\r
+ if (RuntimeMmioRanges == NULL) {\r
+ return;\r
+ }\r
+\r
+ RuntimeMmioRangeCount = (UINTN) RuntimeMmioRanges->Count;\r
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PRMINFO_RUNTIME_MMIO_COUNT), mPrmInfoHiiHandle, RuntimeMmioRangeCount);\r
+\r
+ for (RuntimeMmioRangeIndex = 0; RuntimeMmioRangeIndex < RuntimeMmioRangeCount; RuntimeMmioRangeIndex++) {\r
+ ShellPrintHiiEx (\r
+ -1,\r
+ -1,\r
+ NULL,\r
+ STRING_TOKEN (STR_PRMINFO_RUNTIME_MMIO_INFO),\r
+ mPrmInfoHiiHandle,\r
+ RuntimeMmioRangeIndex,\r
+ RuntimeMmioRanges->Range[RuntimeMmioRangeIndex].PhysicalBaseAddress,\r
+ RuntimeMmioRanges->Range[RuntimeMmioRangeIndex].VirtualBaseAddress,\r
+ RuntimeMmioRanges->Range[RuntimeMmioRangeIndex].Length\r
+ );\r
+ }\r
+}\r
+\r
+/**\r
+ Gathers the PRM handler (and by extension module) information discovered on this system.\r
+\r
+ This function must be called to build up the discovered context for other functions in the application. The\r
+ function will optionally print results as determed by the value of the PrintInformation parameter.\r
+\r
+ @param[in] PrintInformation Indicates whether to print information as discovered in the function.\r
+\r
+**/\r
+VOID\r
+GatherPrmHandlerInfo (\r
+ IN BOOLEAN PrintInformation\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT16 MajorVersion;\r
+ UINT16 MinorVersion;\r
+ UINT16 HandlerCount;\r
+ UINTN HandlerIndex;\r
+ EFI_PHYSICAL_ADDRESS CurrentHandlerPhysicalAddress;\r
+ EFI_PHYSICAL_ADDRESS CurrentImageAddress;\r
+ PRM_HANDLER_CONTEXT CurrentHandlerContext;\r
+ EFI_GUID *CurrentModuleGuid;\r
+ EFI_IMAGE_EXPORT_DIRECTORY *CurrentImageExportDirectory;\r
+ PRM_CONTEXT_BUFFER *CurrentContextBuffer;\r
+ PRM_MODULE_EXPORT_DESCRIPTOR_STRUCT *CurrentExportDescriptorStruct;\r
+ PRM_MODULE_CONTEXT_BUFFERS *CurrentModuleContextBuffers;\r
+ PRM_HANDLER_CONTEXT_LIST_ENTRY *CurrentHandlerContextListEntry;\r
+ PRM_MODULE_IMAGE_CONTEXT *CurrentPrmModuleImageContext;\r
+ PRM_RUNTIME_MMIO_RANGES *CurrentPrmModuleRuntimeMmioRanges;\r
+\r
+ ASSERT (mPrmModuleCount <= mPrmHandlerCount);\r
+\r
+ if (mPrmHandlerCount == 0) {\r
+ return;\r
+ }\r
+\r
+ // Iterate across all PRM modules discovered\r
+ for (\r
+ CurrentPrmModuleImageContext = NULL, Status = GetNextPrmModuleEntry (&CurrentPrmModuleImageContext);\r
+ !EFI_ERROR (Status);\r
+ Status = GetNextPrmModuleEntry (&CurrentPrmModuleImageContext)) {\r
+\r
+ CurrentImageAddress = CurrentPrmModuleImageContext->PeCoffImageContext.ImageAddress;\r
+ CurrentImageExportDirectory = CurrentPrmModuleImageContext->ExportDirectory;\r
+ CurrentExportDescriptorStruct = CurrentPrmModuleImageContext->ExportDescriptor;\r
+\r
+ CurrentModuleGuid = &CurrentExportDescriptorStruct->Header.ModuleGuid;\r
+ HandlerCount = CurrentExportDescriptorStruct->Header.NumberPrmHandlers;\r
+\r
+ MajorVersion = 0;\r
+ MinorVersion = 0;\r
+ Status = GetImageVersionInPeCoffImage (\r
+ (VOID *) (UINTN) CurrentImageAddress,\r
+ &CurrentPrmModuleImageContext->PeCoffImageContext,\r
+ &MajorVersion,\r
+ &MinorVersion\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ if (PrintInformation) {\r
+ ShellPrintHiiEx (\r
+ -1,\r
+ -1,\r
+ NULL,\r
+ STRING_TOKEN (STR_PRMINFO_MODULE_NAME),\r
+ mPrmInfoHiiHandle,\r
+ (CHAR8 *) ((UINTN) CurrentImageAddress + CurrentImageExportDirectory->Name)\r
+ );\r
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PRMINFO_MODULE_GUID), mPrmInfoHiiHandle, CurrentModuleGuid);\r
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PRMINFO_MODULE_VERSION), mPrmInfoHiiHandle, MajorVersion, MinorVersion);\r
+ }\r
+\r
+ // It is currently valid for a PRM module not to use a context buffer\r
+ CurrentPrmModuleRuntimeMmioRanges = NULL;\r
+ Status = GetModuleContextBuffers (\r
+ ByModuleGuid,\r
+ CurrentModuleGuid,\r
+ &CurrentModuleContextBuffers\r
+ );\r
+ ASSERT (!EFI_ERROR (Status) || Status == EFI_NOT_FOUND);\r
+ if (!EFI_ERROR (Status) && CurrentModuleContextBuffers != NULL) {\r
+ CurrentPrmModuleRuntimeMmioRanges = CurrentModuleContextBuffers->RuntimeMmioRanges;\r
+ }\r
+\r
+ if (PrintInformation) {\r
+ if (CurrentPrmModuleRuntimeMmioRanges != NULL) {\r
+ PrintMmioRuntimeRangeInfo (CurrentPrmModuleRuntimeMmioRanges);\r
+ } else {\r
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PRMINFO_NO_MMIO_RANGES), mPrmInfoHiiHandle);\r
+ }\r
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PRMINFO_LINE_BREAK), mPrmInfoHiiHandle);\r
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PRMINFO_HANDLER_COUNT), mPrmInfoHiiHandle, HandlerCount);\r
+ }\r
+\r
+ for (HandlerIndex = 0; HandlerIndex < HandlerCount; HandlerIndex++) {\r
+ ZeroMem (&CurrentHandlerContext, sizeof (CurrentHandlerContext));\r
+\r
+ CurrentHandlerContext.ModuleName = (CHAR8 *) ((UINTN) CurrentImageAddress + CurrentImageExportDirectory->Name);\r
+ CurrentHandlerContext.Guid = &CurrentExportDescriptorStruct->PrmHandlerExportDescriptors[HandlerIndex].PrmHandlerGuid;\r
+ CurrentHandlerContext.Name = (CHAR8 *) CurrentExportDescriptorStruct->PrmHandlerExportDescriptors[HandlerIndex].PrmHandlerName;\r
+\r
+ if (PrintInformation) {\r
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PRMINFO_HANDLER_NAME), mPrmInfoHiiHandle, CurrentHandlerContext.Name);\r
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PRMINFO_HANDLER_GUID), mPrmInfoHiiHandle, CurrentHandlerContext.Guid);\r
+ }\r
+\r
+ Status = GetExportEntryAddress (\r
+ CurrentHandlerContext.Name,\r
+ CurrentImageAddress,\r
+ CurrentImageExportDirectory,\r
+ &CurrentHandlerPhysicalAddress\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ if (!EFI_ERROR (Status)) {\r
+ CurrentHandlerContext.Handler = (PRM_HANDLER *) (UINTN) CurrentHandlerPhysicalAddress;\r
+\r
+ if (PrintInformation) {\r
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PRMINFO_HANDLER_PA), mPrmInfoHiiHandle, CurrentHandlerPhysicalAddress);\r
+ }\r
+ } else {\r
+ if (PrintInformation) {\r
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PRMINFO_HANDLER_PA_ERROR), mPrmInfoHiiHandle, Status);\r
+ }\r
+ }\r
+\r
+ Status = GetContextBuffer (\r
+ CurrentHandlerContext.Guid,\r
+ CurrentModuleContextBuffers,\r
+ &CurrentContextBuffer\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ CurrentHandlerContext.StaticDataBuffer = CurrentContextBuffer->StaticDataBuffer;\r
+ }\r
+\r
+ if (PrintInformation) {\r
+ if (CurrentHandlerContext.StaticDataBuffer != NULL) {\r
+ ShellPrintHiiEx (\r
+ -1,\r
+ -1,\r
+ NULL,\r
+ STRING_TOKEN (STR_PRMINFO_STATIC_DATA_BUFFER),\r
+ mPrmInfoHiiHandle,\r
+ (UINTN) CurrentHandlerContext.StaticDataBuffer\r
+ );\r
+ } else {\r
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PRMINFO_LINE_BREAK), mPrmInfoHiiHandle);\r
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PRMINFO_NO_STATIC_BUFFER), mPrmInfoHiiHandle);\r
+ }\r
+ }\r
+\r
+ CurrentHandlerContextListEntry = CreateNewPrmHandlerListEntry ();\r
+ ASSERT (CurrentHandlerContextListEntry != NULL);\r
+ if (CurrentHandlerContextListEntry != NULL) {\r
+ CopyMem (\r
+ &CurrentHandlerContextListEntry->Context,\r
+ &CurrentHandlerContext,\r
+ sizeof (CurrentHandlerContextListEntry->Context)\r
+ );\r
+ InsertTailList (&mPrmHandlerList, &CurrentHandlerContextListEntry->Link);\r
+ }\r
+ }\r
+ }\r
+}\r
+\r
+/**\r
+ Populates the given context buffer so it can be passed to a PRM handler.\r
+\r
+ @param[in] StaticDataBuffer A pointer to the static data buffer that will be referenced in the context\r
+ buffer that is populated. This is an optional pointer that, if not provided,\r
+ by passing NULL will be ignored.\r
+ @param[in] HandlerGuid A pointer to the GUID of the PRM handler.\r
+ @param[in] ContextBuffer A pointer to a caller allocated ContextBuffer structure that will be populated\r
+ by this function.\r
+\r
+ @retval EFI_SUCCESS The given ContextBuffer was populated successfully.\r
+ @retval EFI_INVALID_PARAMETER The HandlerGuid or ContextBuffer actual argument is NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+PopulateContextBuffer (\r
+ IN PRM_DATA_BUFFER *StaticDataBuffer OPTIONAL,\r
+ IN EFI_GUID *HandlerGuid,\r
+ IN PRM_CONTEXT_BUFFER *ContextBuffer\r
+ )\r
+{\r
+ if (HandlerGuid == NULL || ContextBuffer == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ ZeroMem (ContextBuffer, sizeof (*ContextBuffer));\r
+\r
+ ContextBuffer->Signature = PRM_CONTEXT_BUFFER_SIGNATURE;\r
+ ContextBuffer->Version = PRM_CONTEXT_BUFFER_INTERFACE_VERSION;\r
+ CopyGuid (&ContextBuffer->HandlerGuid, HandlerGuid);\r
+\r
+ if (StaticDataBuffer != NULL) {\r
+ ContextBuffer->StaticDataBuffer = StaticDataBuffer;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Prints a given execution time in the appropriate unit.\r
+\r
+ @param[in] TimeInNanoSec The time to print in unit of nanoseconds.\r
+\r
+**/\r
+VOID\r
+PrintExecutionTime (\r
+ IN UINT64 TimeInNanoSec\r
+ )\r
+{\r
+ UINT64 Sec;\r
+ UINT64 MilliSec;\r
+ UINT64 MicroSec;\r
+ UINT64 NanoSec;\r
+ UINT64 RemainingTime;\r
+\r
+ Sec = 0;\r
+ MilliSec = 0;\r
+ MicroSec = 0;\r
+ NanoSec = 0;\r
+ RemainingTime = TimeInNanoSec;\r
+\r
+ if (RemainingTime > ONE_SECOND) {\r
+ Sec = DivU64x32 (RemainingTime, ONE_SECOND);\r
+ RemainingTime -= MultU64x32 (Sec, ONE_SECOND);\r
+ }\r
+\r
+ if (RemainingTime > ONE_MILLISECOND) {\r
+ MilliSec = DivU64x32 (RemainingTime, ONE_MILLISECOND);\r
+ RemainingTime -= MultU64x32 (MilliSec, ONE_MILLISECOND);\r
+ }\r
+\r
+ if (RemainingTime > ONE_MICROSECOND) {\r
+ MicroSec = DivU64x32 (RemainingTime, ONE_MICROSECOND);\r
+ RemainingTime -= MultU64x32 (MicroSec, ONE_MICROSECOND);\r
+ }\r
+\r
+ if (RemainingTime > 0) {\r
+ NanoSec = RemainingTime;\r
+ }\r
+\r
+ if (Sec > 0) {\r
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PRMINFO_SECS), mPrmInfoHiiHandle, Sec, MilliSec, MicroSec, NanoSec);\r
+ } else if (MilliSec > 0) {\r
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PRMINFO_MILLI_SECS), mPrmInfoHiiHandle, MilliSec, MicroSec, NanoSec);\r
+ } else if (MicroSec > 0) {\r
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PRMINFO_USECS), mPrmInfoHiiHandle, MicroSec, NanoSec);\r
+ } else {\r
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PRMINFO_NANO_SECS), mPrmInfoHiiHandle, NanoSec);\r
+ }\r
+}\r
+\r
+/**\r
+ Executes the PRM handler with the provided GUID.\r
+\r
+ @param[in] HandlerGuid A pointer to the GUID of the PRM handler to execute.\r
+ A zero GUID indicates that all PRM handlers present should be executed.\r
+\r
+ @retval EFI_SUCCESS The PRM handler(s) were executed.\r
+ @retval EFI_INVALID_PARAMETER The HandlerGuid actual argument is NULL.\r
+ @retval EFI_NOT_FOUND The PRM handler could not be found.\r
+\r
+**/\r
+EFI_STATUS\r
+ExecutePrmHandlerByGuid (\r
+ IN EFI_GUID *HandlerGuid\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ BOOLEAN ExecuteAllHandlers;\r
+ BOOLEAN HandlerFound;\r
+ UINT64 StartTime;\r
+ UINT64 EndTime;\r
+ PRM_CONTEXT_BUFFER CurrentContextBuffer;\r
+ PRM_HANDLER_CONTEXT *HandlerContext;\r
+ PRM_HANDLER_CONTEXT_LIST_ENTRY *HandlerContextListEntry;\r
+ LIST_ENTRY *Link;\r
+\r
+ Link = NULL;\r
+ HandlerFound = FALSE;\r
+\r
+ if (HandlerGuid == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Zero GUID means execute all discovered handlers\r
+ //\r
+ ExecuteAllHandlers = CompareGuid (HandlerGuid, &gZeroGuid);\r
+\r
+ EFI_LIST_FOR_EACH (Link, &mPrmHandlerList) {\r
+ HandlerContextListEntry = CR (Link, PRM_HANDLER_CONTEXT_LIST_ENTRY, Link, PRM_HANDLER_CONTEXT_LIST_ENTRY_SIGNATURE);\r
+ HandlerContext = &HandlerContextListEntry->Context;\r
+\r
+ if (!ExecuteAllHandlers && !CompareGuid (HandlerGuid, HandlerContext->Guid)) {\r
+ continue;\r
+ }\r
+\r
+ HandlerFound = TRUE;\r
+ Status = PopulateContextBuffer (HandlerContext->StaticDataBuffer, HandlerContext->Guid, &CurrentContextBuffer);\r
+ if (!EFI_ERROR (Status)) {\r
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PRMINFO_LINE_BREAK), mPrmInfoHiiHandle);\r
+ ShellPrintHiiEx (\r
+ -1,\r
+ -1,\r
+ NULL,\r
+ STRING_TOKEN (STR_PRMINFO_MODULE_NAME),\r
+ mPrmInfoHiiHandle,\r
+ HandlerContext->ModuleName\r
+ );\r
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PRMINFO_HANDLER_NAME_HL), mPrmInfoHiiHandle, HandlerContext->Name);\r
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PRMINFO_HANDLER_GUID), mPrmInfoHiiHandle, HandlerContext->Guid);\r
+\r
+ StartTime = 0;\r
+ EndTime = 0;\r
+ if (PcdGetBool (PcdPrmInfoPrintHandlerExecutionTime)) {\r
+ StartTime = GetPerformanceCounter ();\r
+ }\r
+ Status = HandlerContext->Handler (NULL, &CurrentContextBuffer);\r
+ if (PcdGetBool (PcdPrmInfoPrintHandlerExecutionTime)) {\r
+ EndTime = GetPerformanceCounter ();\r
+ }\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PRMINFO_HANDLER_ERR_STATUS), mPrmInfoHiiHandle, Status);\r
+ } else {\r
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PRMINFO_HANDLER_SUCC_STATUS), mPrmInfoHiiHandle, Status);\r
+ }\r
+\r
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PRMINFO_HANDLER_EXEC_TIME), mPrmInfoHiiHandle);\r
+ if (StartTime == 0 && EndTime == 0) {\r
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PRMINFO_UNKNOWN), mPrmInfoHiiHandle);\r
+ } else {\r
+ PrintExecutionTime (GetTimeInNanoSecond (EndTime - StartTime));\r
+ }\r
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PRMINFO_LINE_BREAK), mPrmInfoHiiHandle);\r
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PRMINFO_LINE_BREAK), mPrmInfoHiiHandle);\r
+ } else {\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "%a - %a: An error occurred creating a context buffer for handler %g\n",\r
+ gEfiCallerBaseName,\r
+ __FUNCTION__,\r
+ HandlerContext->Guid\r
+ ));\r
+ }\r
+\r
+ if (!ExecuteAllHandlers) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (!HandlerFound) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Parses the application parameter list and performs the appropriate operations based on the results.\r
+\r
+ @retval EFI_SUCCESS The parameter list was parsed successfully.\r
+ @retval EFI_INVALID_PARAMETER An invalid parameter was given to the application.\r
+ @retval EFI_LOAD_ERROR An error occurred loading the application.\r
+\r
+**/\r
+EFI_STATUS\r
+ParseParameterList (\r
+ VOID\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ SHELL_STATUS ReturnStatus;\r
+ UINTN ArgumentCount;\r
+ EFI_GUID HandlerGuid;\r
+ BOOLEAN PrintHandlerInfo;\r
+ LIST_ENTRY *Package;\r
+ LIST_ENTRY *TempNode;\r
+ CHAR16 *ProblemParam;\r
+ CONST CHAR16 *HandlerGuidStr;\r
+\r
+ HandlerGuidStr = NULL;\r
+ Package = NULL;\r
+ PrintHandlerInfo = FALSE;\r
+ ReturnStatus = EFI_SUCCESS;\r
+\r
+ InitializeListHead (&mPrmHandlerList);\r
+\r
+ //\r
+ // Basic application parameter validation\r
+ //\r
+ Status = ShellCommandLineParseEx (mParamList, &Package, &ProblemParam, FALSE, FALSE);\r
+ if (EFI_ERROR (Status)) {\r
+ if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) {\r
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PRMINFO_GEN_PROBLEM), mPrmInfoHiiHandle, APPLICATION_NAME, ProblemParam);\r
+ ReturnStatus = EFI_INVALID_PARAMETER;\r
+ FreePool (ProblemParam);\r
+ } else {\r
+ ReturnStatus = EFI_LOAD_ERROR;\r
+ ASSERT (FALSE);\r
+ }\r
+\r
+ goto Done;\r
+ } else if (Package == NULL) {\r
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PRMINFO_NO_ARG), mPrmInfoHiiHandle, APPLICATION_NAME);\r
+ ReturnStatus = EFI_INVALID_PARAMETER;\r
+ goto Done;\r
+ }\r
+\r
+ //\r
+ // Get argument count including flags\r
+ //\r
+ for (\r
+ ArgumentCount = 0, TempNode = Package;\r
+ GetNextNode (Package, TempNode) != Package;\r
+ ArgumentCount++, TempNode = GetNextNode (Package, TempNode)\r
+ );\r
+\r
+ if (ArgumentCount == 1) {\r
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PRMINFO_NO_ARG), mPrmInfoHiiHandle, APPLICATION_NAME);\r
+ ReturnStatus = EFI_INVALID_PARAMETER;\r
+ goto Done;\r
+ }\r
+\r
+ if (ArgumentCount > 6) {\r
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PRMINFO_TOO_MANY), mPrmInfoHiiHandle, APPLICATION_NAME);\r
+ ReturnStatus = EFI_INVALID_PARAMETER;\r
+ goto Done;\r
+ }\r
+\r
+ //\r
+ // Parse the actual arguments provided\r
+ //\r
+ if (ShellCommandLineGetFlag (Package, L"-b")) {\r
+ if (ArgumentCount <= 2) {\r
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PRMINFO_PARAM_INV), mPrmInfoHiiHandle, APPLICATION_NAME, L"-b");\r
+ ReturnStatus = EFI_INVALID_PARAMETER;\r
+ goto Done;\r
+ } else {\r
+ ShellSetPageBreakMode (TRUE);\r
+ }\r
+ }\r
+\r
+ if (ShellCommandLineGetFlag (Package, L"-l")) {\r
+ PrintHandlerInfo = TRUE;\r
+ }\r
+\r
+ if (ShellCommandLineGetFlag (Package, L"-t")) {\r
+ HandlerGuidStr = ShellCommandLineGetValue (Package, L"-t");\r
+ if (HandlerGuidStr != NULL) {\r
+ if (StrnCmp (HandlerGuidStr, L"all", StrLen (HandlerGuidStr)) == 0) {\r
+ CopyGuid (&HandlerGuid, &gZeroGuid);\r
+ } else {\r
+ Status = StrToGuid (HandlerGuidStr, &HandlerGuid);\r
+ if (EFI_ERROR (Status) || (HandlerGuidStr[GUID_STRING_LENGTH] != L'\0')) {\r
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PRMINFO_GUID_INV), mPrmInfoHiiHandle, APPLICATION_NAME, HandlerGuidStr);\r
+ ReturnStatus = EFI_INVALID_PARAMETER;\r
+ goto Done;\r
+ }\r
+ }\r
+ } else {\r
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PRMINFO_NO_VALUE), mPrmInfoHiiHandle, APPLICATION_NAME, L"-t");\r
+ ReturnStatus = EFI_INVALID_PARAMETER;\r
+ goto Done;\r
+ }\r
+ }\r
+\r
+ Status = DiscoverPrmModules (&mPrmModuleCount, &mPrmHandlerCount);\r
+ if (EFI_ERROR (Status)) {\r
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PRMINFO_DISCOVERY_FAILED), mPrmInfoHiiHandle, APPLICATION_NAME);\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "%a - %a: An error occurred during PRM module discovery (%r)\n",\r
+ gEfiCallerBaseName,\r
+ __FUNCTION__,\r
+ Status\r
+ ));\r
+ ReturnStatus = Status;\r
+ goto Done;\r
+ }\r
+\r
+ if (PrintHandlerInfo) {\r
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PRMINFO_LIST_TITLE), mPrmInfoHiiHandle);\r
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PRMINFO_MODULES_FOUND), mPrmInfoHiiHandle, mPrmModuleCount);\r
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PRMINFO_HANDLERS_FOUND), mPrmInfoHiiHandle, mPrmHandlerCount);\r
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PRMINFO_LINE_BREAK), mPrmInfoHiiHandle);\r
+ }\r
+ GatherPrmHandlerInfo (PrintHandlerInfo);\r
+\r
+ if (HandlerGuidStr != NULL) {\r
+ Status = ExecutePrmHandlerByGuid (&HandlerGuid);\r
+ if (Status == EFI_NOT_FOUND) {\r
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PRMINFO_HANDLER_NOT_FOUND), mPrmInfoHiiHandle, APPLICATION_NAME, HandlerGuid);\r
+ }\r
+ }\r
+\r
+Done:\r
+ FreeList (&mPrmHandlerList);\r
+\r
+ if (Package != NULL) {\r
+ ShellCommandLineFreeVarList (Package);\r
+ }\r
+\r
+ return ReturnStatus;\r
+}\r
+\r
+/**\r
+ Entry point of this UEFI application.\r
+\r
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.\r
+ @param[in] SystemTable A pointer to the EFI System Table.\r
+\r
+ @retval EFI_SUCCESS The entry point is executed successfully.\r
+ @retval other Some error occurs when executing this entry point.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UefiMain (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_HII_PACKAGE_LIST_HEADER *PackageList;\r
+\r
+ //\r
+ // Retrieve the HII package list from ImageHandle\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ ImageHandle,\r
+ &gEfiHiiPackageListProtocolGuid,\r
+ (VOID **) &PackageList,\r
+ ImageHandle,\r
+ NULL,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Publish the HII package list to the HII Database\r
+ //\r
+ Status = gHiiDatabase->NewPackageList (\r
+ gHiiDatabase,\r
+ PackageList,\r
+ NULL,\r
+ &mPrmInfoHiiHandle\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if (mPrmInfoHiiHandle == NULL) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ Status = ParseParameterList ();\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "%a - %a: An error occurred parsing user-provided arguments (%r)\n",\r
+ gEfiCallerBaseName,\r
+ __FUNCTION__,\r
+ Status\r
+ ));\r
+ }\r
+\r
+ if (mPrmInfoHiiHandle != NULL) {\r
+ HiiRemovePackages (mPrmInfoHiiHandle);\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
--- /dev/null
+/** @file\r
+ String definitions for the PRM Information UEFI shell application.\r
+\r
+ Copyright (C) Microsoft Corporation. All rights reserved.\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+*/\r
+\r
+#langdef en-US "English"\r
+\r
+//\r
+// Parameter error messages\r
+//\r
+#string STR_PRMINFO_DISCOVERY_FAILED #language en-US "%H%s%N: PRM module discovery failed.\r\n"\r
+#string STR_PRMINFO_GEN_PROBLEM #language en-US "%H%s%N: Unknown flag - '%H%s%N'\r\n"\r
+#string STR_PRMINFO_GUID_INV #language en-US "%H%s%N: Invalid GUID - '%H%s%N'\r\n"\r
+#string STR_PRMINFO_HANDLER_NOT_FOUND #language en-US "%H%s%N: PRM Handler not found - '%H{%g}%N'\r\n"\r
+#string STR_PRMINFO_MISSING_OPTION #language en-US "%H%s%N: Missing option '%H%s%N' required by flag - '%H%s%N'\r\n"\r
+#string STR_PRMINFO_NO_ARG #language en-US "%H%s%N: An argument must be provided, try "-?" for help.\n"\r
+#string STR_PRMINFO_NO_VALUE #language en-US "%H%s%N: Missing argument for flag - '%H%s%N'\r\n"\r
+#string STR_PRMINFO_PARAM_INV #language en-US "%H%s%N: Invalid argument - '%H%s%N', try "-?" for help.\r\n"\r
+#string STR_PRMINFO_TOO_MANY #language en-US "%H%s%N: Too many arguments.\r\n"\r
+\r
+//\r
+// Application informational messages\r
+//\r
+#string STR_PRMINFO_HANDLER_COUNT #language en-US " Handler Count: %d\r\n"\r
+#string STR_PRMINFO_HANDLER_EXEC_TIME #language en-US " Execution Time: "\r
+#string STR_PRMINFO_HANDLER_GUID #language en-US " Handler GUID: %g\r\n"\r
+#string STR_PRMINFO_HANDLER_NAME #language en-US " Handler Name: %a\r\n"\r
+#string STR_PRMINFO_HANDLER_NAME_HL #language en-US " Handler Name: %H%a%N\r\n"\r
+#string STR_PRMINFO_HANDLER_PA #language en-US " Handler Physical Address: 0x%016x\r\n"\r
+#string STR_PRMINFO_HANDLER_ERR_STATUS #language en-US " Return Status: %E%r%N\r\n"\r
+#string STR_PRMINFO_HANDLER_SUCC_STATUS #language en-US " Return Status: %V%r%N\r\n"\r
+#string STR_PRMINFO_HANDLERS_FOUND #language en-US " %d PRM handlers found.\r\n"\r
+#string STR_PRMINFO_LINE_BREAK #language en-US "\r\n"\r
+#string STR_PRMINFO_LIST_TITLE #language en-US "PRM Modules and Handlers:\r\n"\r
+#string STR_PRMINFO_MODULE_GUID #language en-US "Module GUID: %g\r\n"\r
+#string STR_PRMINFO_MODULE_NAME #language en-US "Module Name: %a\r\n"\r
+#string STR_PRMINFO_MODULE_VERSION #language en-US "Module Version: %02d.%02d\r\n\r\n"\r
+#string STR_PRMINFO_MODULES_FOUND #language en-US " %d PRM modules found.\r\n"\r
+#string STR_PRMINFO_NO_MMIO_RANGES #language en-US " No runtime MMIO ranges used by this module.\r\n"\r
+#string STR_PRMINFO_NO_STATIC_BUFFER #language en-US " This handler does not define a static data buffer.\r\n\r\n"\r
+#string STR_PRMINFO_RUNTIME_MMIO_COUNT #language en-US " Runtime MMIO Range Count: %d\r\n"\r
+#string STR_PRMINFO_RUNTIME_MMIO_INFO #language en-US " [%d]: Physical Base Address = 0x%016x\r\n Virtual Base Address = 0x%016x\r\n Length = 0x%x\r\n"\r
+#string STR_PRMINFO_STATIC_DATA_BUFFER #language en-US " Static Data Buffer: 0x%016x\r\n"\r
+#string STR_PRMINFO_UNKNOWN #language en-US "Unknown"\r
+#string STR_PRMINFO_USECS #language en-US "%H%ld.%ld microseconds%N"\r
+#string STR_PRMINFO_NANO_SECS #language en-US "%H%ld nanoseconds%N"\r
+#string STR_PRMINFO_SECS #language en-US "%H%ld.%ld%ld%ld seconds%N"\r
+#string STR_PRMINFO_MILLI_SECS #language en-US "%H%ld.%ld%ld milliseconds%N"\r
+\r
+//\r
+// Application error messages\r
+//\r
+#string STR_PRMINFO_HANDLER_PA_ERROR #language en-US " An ERROR (%r) occurred determining the handler physical address.\r\n"\r
+\r
+#string STR_PRMINFO_HELP #language en-US ""\r
+".TH PrmInfo 0 "Display and test Platform Runtime Mechanism (PRM) modules."\r\n"\r
+".SH NAME:\r\n"\r
+"Display and test Platform Runtime Mechanism (PRM) modules.\r\n"\r
+".SH SYNOPSIS\r\n"\r
+"\r\n"\r
+"PRMINFO [[-?] | [-b] [-l] [-r] [-t (guid | all)]]\r\n"\r
+".SH OPTIONS\r\n"\r
+" \r\n"\r
+" -? - Show help.\r\n"\r
+" -b - Displays one screen of output at a time.\r\n"\r
+" -l - Display a list of installed PRM modules and handlers.\r\n"\r
+" -t - Call a given PRM handler by the specified GUID.\r\n"\r
+" guid - A 32 digit GUID string with hyphen separation with no enclosing\r\n"\r
+" character such as braces.\r\n"\r
+" Example: 00000000-0000-0000-0000-000000000000\r\n"\r
+" all - The string 'all' indicating all PRM handlers should be called\r\n"\r
+" in order discovered.\r\n"\r
+".SH DESCRIPTION\r\n"\r
+" \r\n"\r
+" This program is provided to allow examination of the Platform Runtime\r\n"\r
+" Mechanism (PRM) configuration present on the current system. In addition,\r\n"\r
+" the application contains some lightweight tests to verify that the firmware\r\n"\r
+" set up the PRM information that will be conveyed to the loaded operating\r\n"\r
+" system correctly.\r\n"\r
+" \r\n"\r
+" Default behavior is to display the content of all the PRM modules and\r\n"\r
+" handlers currently installed (equivalent to the -l argument). To facilitate\r\n"\r
+" debugging and verifying correct implementation of the PRM infrastructure\r\n"\r
+" and PRM modules in a given firmware, the application can also call a\r\n"\r
+" given PRM handler and perform basic validation of the PRMT ACPI table\r\n"\r
+" to confirm it satisfies the basic constraints required for the table\r\n"\r
+" in the PRM Specification.\r\n"\r
+" \r\n"\r
+"NOTES:\r\n"\r
+" 1. Calling PRM handlers from this application:\r\n"\r
+" - The user should exercise caution when calling PRM handlers in the\r\n"\r
+" pre-OS environment. The PRM author may have only considered\r\n"\r
+" execution within the context of OS runtime."\r
+"\r\n"\r
+" - The application will not perform any manipulation of PRM handler\r\n"\r
+" parameter buffers prior to calling the handler.\r\n"\r
+"\r\n"\r
+" - This feature is intended to provide a quick method to exercise\r\n"\r
+" PRM code without loading a full OS that is PRM aware and to perform\r\n"\r
+" testing of PRM code that is aware it will be executed in such an\r\n"\r
+" environment. It is not recommended to call PRM handlers on a\r\n"\r
+" production system if you are not fully aware of how the PRM handler\r\n"\r
+" behaves and any side effect(s) it might have on the system.\r\n"\r
+".SH STANDARDS\r\n"\r
+" \r\n"\r
+"STANDARDS:\r\n"\r
+" Platform Runtime Mechanism (PRM) is currently in a draft state and the\r\n"\r
+" specification is not yet publicly available. A reference to the publicly\r\n"\r
+" available document will replace this text when it is available.\r\n"\r
+".SH EXAMPLES\r\n"\r
+" \r\n"\r
+"EXAMPLES:\r\n"\r
+" * To display a list of the installed PRM modules and PRM handlers:\r\n"\r
+" fs0:\> prminfo -l\r\n"\r
+" \r\n"\r
+" * To validate the installed PRMT ACPI table:\r\n"\r
+" fs0:\> prminfo -r\r\n"\r
+" \r\n"\r
+" * To call a PRM handler by GUID:\r\n"\r
+" fs0:\> prminfo -t e1466081-7562-430f-896b-b0e523dc335a\r\n"\r
+" \r\n"\r
+" * To call all of the PRM handlers discovered on the system:\r\n"\r
+" fs0:\> prminfo -t all\r\n"\r
+".SH RETURNVALUES\r\n"\r
+" \r\n"\r
+"RETURN VALUES:\r\n"\r
+" SHELL_SUCCESS Data was displayed as requested.\r\n"\r
+" SHELL_INVALID_PARAMETER The operation failed.\r\n"\r
+" \r\n"\r