--- /dev/null
+/** @file\r
+\r
+ The PRM Module Discovery library provides functionality to discover PRM modules installed by platform firmware.\r
+\r
+ Copyright (c) Microsoft Corporation\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+#ifndef PRM_MODULE_DISCOVERY_LIB_H_\r
+#define PRM_MODULE_DISCOVERY_LIB_H_\r
+\r
+#include <Base.h>\r
+#include <PrmContextBuffer.h>\r
+#include <PrmModuleImageContext.h>\r
+#include <Uefi.h>\r
+\r
+/**\r
+ Gets the next PRM module discovered after the given PRM module.\r
+\r
+ @param[in,out] ModuleImageContext A pointer to a pointer to a PRM module image context structure.\r
+\r
+ @retval EFI_SUCCESS The next PRM module was found successfully.\r
+ @retval EFI_INVALID_PARAMETER The given ModuleImageContext structure is invalid or the pointer is NULL.\r
+ @retval EFI_NOT_FOUND The next PRM module was not found.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+GetNextPrmModuleEntry (\r
+ IN OUT PRM_MODULE_IMAGE_CONTEXT **ModuleImageContext\r
+ );\r
+\r
+/**\r
+ Discovers all PRM Modules loaded during boot.\r
+\r
+ Each PRM Module discovered is placed into a linked list so the list can br processsed in the future.\r
+\r
+ @param[out] ModuleCount An optional pointer parameter that, if provided, is set to the number\r
+ of PRM modules discovered.\r
+ @param[out] HandlerCount An optional pointer parameter that, if provided, is set to the number\r
+ of PRM handlers discovered.\r
+\r
+ @retval EFI_SUCCESS All PRM Modules were discovered successfully.\r
+ @retval EFI_INVALID_PARAMETER An actual pointer parameter was passed as NULL.\r
+ @retval EFI_NOT_FOUND The gEfiLoadedImageProtocolGuid protocol could not be found.\r
+ @retval EFI_OUT_OF_RESOURCES Insufficient memory resources to allocate the new PRM Context\r
+ linked list nodes.\r
+ @retval EFI_ALREADY_STARTED The function was called previously and already discovered the PRM modules\r
+ loaded on this boot.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DiscoverPrmModules (\r
+ OUT UINTN *ModuleCount OPTIONAL,\r
+ OUT UINTN *HandlerCount OPTIONAL\r
+ );\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+\r
+ The PRM PE/COFF library provides functionality to support additional PE/COFF functionality needed to use\r
+ Platform Runtime Mechanism (PRM) modules.\r
+\r
+ Copyright (c) Microsoft Corporation\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+#ifndef PRM_PECOFF_LIB_H_\r
+#define PRM_PECOFF_LIB_H_\r
+\r
+#include <Base.h>\r
+#include <PrmExportDescriptor.h>\r
+#include <IndustryStandard/PeImage.h>\r
+#include <Library/PeCoffLib.h>\r
+\r
+/**\r
+ Gets a pointer to the export directory in a given PE/COFF image.\r
+\r
+ @param[in] ImageExportDirectory A pointer to an export directory table in a PE/COFF image.\r
+ @param[in] PeCoffLoaderImageContext A pointer to a PE_COFF_LOADER_IMAGE_CONTEXT structure that contains the\r
+ PE/COFF image context for the Image containing the PRM Module Export\r
+ Descriptor table.\r
+ @param[out] ExportDescriptor A pointer to a pointer to the PRM Module Export Descriptor table found\r
+ in the ImageExportDirectory given.\r
+\r
+ @retval EFI_SUCCESS The PRM Module Export Descriptor table was found successfully.\r
+ @retval EFI_INVALID_PARAMETER A required parameter is NULL.\r
+ @retval EFI_NOT_FOUND The PRM Module Export Descriptor table was not found in the given\r
+ ImageExportDirectory.\r
+\r
+**/\r
+EFI_STATUS\r
+GetPrmModuleExportDescriptorTable (\r
+ IN EFI_IMAGE_EXPORT_DIRECTORY *ImageExportDirectory,\r
+ IN PE_COFF_LOADER_IMAGE_CONTEXT *PeCoffLoaderImageContext,\r
+ OUT PRM_MODULE_EXPORT_DESCRIPTOR_STRUCT **ExportDescriptor\r
+ );\r
+\r
+/**\r
+ Gets a pointer to the export directory in a given PE/COFF image.\r
+\r
+ @param[in] Image A pointer to a PE32/COFF image base address that is loaded into memory\r
+ and already relocated to the memory base address. RVAs in the image given\r
+ should be valid.\r
+ @param[in] PeCoffLoaderImageContext A pointer to a PE_COFF_LOADER_IMAGE_CONTEXT structure that contains the\r
+ PE/COFF image context for the Image given.\r
+ @param[out] ImageExportDirectory A pointer to a pointer to the export directory found in the Image given.\r
+\r
+ @retval EFI_SUCCESS The export directory was found successfully.\r
+ @retval EFI_INVALID_PARAMETER A required parameter is NULL.\r
+ @retval EFI_UNSUPPORTED The PE/COFF image given is not supported as a PRM Module.\r
+ @retval EFI_NOT_FOUND The image export directory could not be found for this image.\r
+\r
+**/\r
+EFI_STATUS\r
+GetExportDirectoryInPeCoffImage (\r
+ IN VOID *Image,\r
+ IN PE_COFF_LOADER_IMAGE_CONTEXT *PeCoffLoaderImageContext,\r
+ OUT EFI_IMAGE_EXPORT_DIRECTORY **ImageExportDirectory\r
+ );\r
+\r
+/**\r
+ Returns the image major and image minor version in a given PE/COFF image.\r
+\r
+ @param[in] Image A pointer to a PE32/COFF image base address that is loaded into memory\r
+ and already relocated to the memory base address. RVAs in the image given\r
+ should be valid.\r
+ @param[in] PeCoffLoaderImageContext A pointer to a PE_COFF_LOADER_IMAGE_CONTEXT structure that contains the\r
+ PE/COFF image context for the Image given.\r
+ @param[out] ImageMajorVersion A pointer to a UINT16 buffer to hold the image major version.\r
+ @param[out] ImageMinorVersion A pointer to a UINT16 buffer to hold the image minor version.\r
+\r
+ @retval EFI_SUCCESS The image version was read successfully.\r
+ @retval EFI_INVALID_PARAMETER A required parameter is NULL.\r
+ @retval EFI_UNSUPPORTED The PE/COFF image given is not supported.\r
+\r
+**/\r
+EFI_STATUS\r
+GetImageVersionInPeCoffImage (\r
+ IN VOID *Image,\r
+ IN PE_COFF_LOADER_IMAGE_CONTEXT *PeCoffLoaderImageContext,\r
+ OUT UINT16 *ImageMajorVersion,\r
+ OUT UINT16 *ImageMinorVersion\r
+ );\r
+\r
+/**\r
+ Gets the address of an entry in an image export table by ASCII name.\r
+\r
+ @param[in] ExportName A pointer to an ASCII name string of the entry name.\r
+ @param[in] ImageBaseAddress The base address of the PE/COFF image.\r
+ @param[in] ImageExportDirectory A pointer to the export directory in the image.\r
+ @param[out] ExportPhysicalAddress A pointer that will be updated with the address of the address of the\r
+ export entry if found.\r
+\r
+ @retval EFI_SUCCESS The export entry was found successfully.\r
+ @retval EFI_INVALID_PARAMETER A required pointer argument is NULL.\r
+ @retval EFI_NOT_FOUND An entry with the given ExportName was not found.\r
+\r
+**/\r
+EFI_STATUS\r
+GetExportEntryAddress (\r
+ IN CONST CHAR8 *ExportName,\r
+ IN EFI_PHYSICAL_ADDRESS ImageBaseAddress,\r
+ IN EFI_IMAGE_EXPORT_DIRECTORY *ImageExportDirectory,\r
+ OUT EFI_PHYSICAL_ADDRESS *ExportPhysicalAddress\r
+ );\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+\r
+ Definitions used internal to the PrmPkg implementation for PRM module image context.\r
+\r
+ Copyright (c) Microsoft Corporation\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+#ifndef PRM_MODULE_IMAGE_CONTEXT_H_\r
+#define PRM_MODULE_IMAGE_CONTEXT_H_\r
+\r
+#include <IndustryStandard/PeImage.h>\r
+#include <Library/PeCoffLib.h>\r
+\r
+#include <PrmExportDescriptor.h>\r
+\r
+#pragma pack(push, 1)\r
+\r
+typedef struct {\r
+ PE_COFF_LOADER_IMAGE_CONTEXT PeCoffImageContext;\r
+ EFI_IMAGE_EXPORT_DIRECTORY *ExportDirectory;\r
+ PRM_MODULE_EXPORT_DESCRIPTOR_STRUCT *ExportDescriptor;\r
+} PRM_MODULE_IMAGE_CONTEXT;\r
+\r
+#pragma pack(pop)\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+\r
+ The PRM Module Discovery library provides functionality to discover PRM modules installed by platform firmware.\r
+\r
+ Copyright (c) Microsoft Corporation\r
+ Copyright (c) 2020 - 2022, Intel Corporation. All rights reserved.<BR>\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+#include <PiMm.h>\r
+#include <Protocol/MmAccess.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/PrmModuleDiscoveryLib.h>\r
+#include <Library/PrmPeCoffLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Protocol/LoadedImage.h>\r
+\r
+#include "PrmModuleDiscovery.h"\r
+\r
+#define _DBGMSGID_ "[PRMMODULEDISCOVERYLIB]"\r
+\r
+LIST_ENTRY mPrmModuleList;\r
+\r
+/**\r
+ Gets the next PRM module discovered after the given PRM module.\r
+\r
+ @param[in,out] ModuleImageContext A pointer to a pointer to a PRM module image context structure.\r
+ ModuleImageContext should point to a pointer that points to NULL to\r
+ get the first PRM module discovered.\r
+\r
+ @retval EFI_SUCCESS The next PRM module was found successfully.\r
+ @retval EFI_INVALID_PARAMETER The given ModuleImageContext structure is invalid or the pointer is NULL.\r
+ @retval EFI_NOT_FOUND The next PRM module was not found.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+GetNextPrmModuleEntry (\r
+ IN OUT PRM_MODULE_IMAGE_CONTEXT **ModuleImageContext\r
+ )\r
+{\r
+ LIST_ENTRY *CurrentLink;\r
+ LIST_ENTRY *ForwardLink;\r
+ PRM_MODULE_IMAGE_CONTEXT_LIST_ENTRY *CurrentListEntry;\r
+ PRM_MODULE_IMAGE_CONTEXT_LIST_ENTRY *ForwardListEntry;\r
+\r
+ DEBUG ((DEBUG_INFO, "%a %a - Entry.\n", _DBGMSGID_, __FUNCTION__));\r
+\r
+ if (ModuleImageContext == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (*ModuleImageContext == NULL) {\r
+ ForwardLink = GetFirstNode (&mPrmModuleList);\r
+ } else {\r
+ CurrentListEntry = NULL;\r
+ CurrentListEntry = CR (*ModuleImageContext, PRM_MODULE_IMAGE_CONTEXT_LIST_ENTRY, Context, PRM_MODULE_IMAGE_CONTEXT_LIST_ENTRY_SIGNATURE);\r
+ if (CurrentListEntry == NULL || CurrentListEntry->Signature != PRM_MODULE_IMAGE_CONTEXT_LIST_ENTRY_SIGNATURE) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ CurrentLink = &CurrentListEntry->Link;\r
+ ForwardLink = GetNextNode (&mPrmModuleList, CurrentLink);\r
+\r
+ if (ForwardLink == &mPrmModuleList) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+ }\r
+\r
+ ForwardListEntry = BASE_CR (ForwardLink, PRM_MODULE_IMAGE_CONTEXT_LIST_ENTRY, Link);\r
+ if (ForwardListEntry->Signature == PRM_MODULE_IMAGE_CONTEXT_LIST_ENTRY_SIGNATURE) {\r
+ *ModuleImageContext = &ForwardListEntry->Context;\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ return EFI_NOT_FOUND;\r
+}\r
+\r
+/**\r
+ Creates a new PRM Module Image Context linked list entry.\r
+\r
+ @retval PrmModuleImageContextListEntry If successful, a pointer a PRM Module Image Context linked list entry\r
+ otherwise, NULL is returned.\r
+\r
+**/\r
+STATIC\r
+PRM_MODULE_IMAGE_CONTEXT_LIST_ENTRY *\r
+CreateNewPrmModuleImageContextListEntry (\r
+ VOID\r
+ )\r
+{\r
+ PRM_MODULE_IMAGE_CONTEXT_LIST_ENTRY *PrmModuleImageContextListEntry;\r
+\r
+ DEBUG ((DEBUG_INFO, "%a %a - Entry.\n", _DBGMSGID_, __FUNCTION__));\r
+\r
+ PrmModuleImageContextListEntry = AllocateZeroPool (sizeof (*PrmModuleImageContextListEntry));\r
+ if (PrmModuleImageContextListEntry == NULL) {\r
+ return NULL;\r
+ }\r
+ DEBUG ((\r
+ DEBUG_INFO,\r
+ " %a %a: Allocated PrmModuleImageContextListEntry at 0x%x of size 0x%x bytes.\n",\r
+ _DBGMSGID_,\r
+ __FUNCTION__,\r
+ (UINTN) PrmModuleImageContextListEntry,\r
+ sizeof (*PrmModuleImageContextListEntry)\r
+ ));\r
+\r
+ PrmModuleImageContextListEntry->Signature = PRM_MODULE_IMAGE_CONTEXT_LIST_ENTRY_SIGNATURE;\r
+\r
+ return PrmModuleImageContextListEntry;\r
+}\r
+\r
+/**\r
+ Check whether the address is within any of the MMRAM ranges.\r
+\r
+ @param[in] Address The address to be checked.\r
+ @param[in] MmramRanges Pointer to MMRAM descriptor.\r
+ @param[in] MmramRangeCount MMRAM range count.\r
+\r
+ @retval TRUE The address is in MMRAM ranges.\r
+ @retval FALSE The address is out of MMRAM ranges.\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+IsAddressInMmram (\r
+ IN EFI_PHYSICAL_ADDRESS Address,\r
+ IN EFI_MMRAM_DESCRIPTOR *MmramRanges,\r
+ IN UINTN MmramRangeCount\r
+ )\r
+{\r
+ UINTN Index;\r
+\r
+ for (Index = 0; Index < MmramRangeCount; Index++) {\r
+ if ((Address >= MmramRanges[Index].CpuStart) &&\r
+ (Address < (MmramRanges[Index].CpuStart + MmramRanges[Index].PhysicalSize)))\r
+ {\r
+ return TRUE;\r
+ }\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+/**\r
+ Discovers all PRM Modules loaded during boot.\r
+\r
+ Each PRM Module discovered is placed into a linked list so the list can br processsed in the future.\r
+\r
+ @param[out] ModuleCount An optional pointer parameter that, if provided, is set to the number\r
+ of PRM modules discovered.\r
+ @param[out] HandlerCount An optional pointer parameter that, if provided, is set to the number\r
+ of PRM handlers discovered.\r
+\r
+ @retval EFI_SUCCESS All PRM Modules were discovered successfully.\r
+ @retval EFI_INVALID_PARAMETER An actual pointer parameter was passed as NULL.\r
+ @retval EFI_NOT_FOUND The gEfiLoadedImageProtocolGuid protocol could not be found.\r
+ @retval EFI_OUT_OF_RESOURCES Insufficient memory resources to allocate the new PRM Context\r
+ linked list nodes.\r
+ @retval EFI_ALREADY_STARTED The function was called previously and already discovered the PRM modules\r
+ loaded on this boot.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DiscoverPrmModules (\r
+ OUT UINTN *ModuleCount OPTIONAL,\r
+ OUT UINTN *HandlerCount OPTIONAL\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ PRM_MODULE_IMAGE_CONTEXT TempPrmModuleImageContext;\r
+ PRM_MODULE_IMAGE_CONTEXT_LIST_ENTRY *PrmModuleImageContextListEntry;\r
+ EFI_LOADED_IMAGE_PROTOCOL *LoadedImageProtocol;\r
+ EFI_HANDLE *HandleBuffer;\r
+ UINTN HandleCount;\r
+ UINTN Index;\r
+ UINTN PrmHandlerCount;\r
+ UINTN PrmModuleCount;\r
+ EFI_MM_ACCESS_PROTOCOL *MmAccess;\r
+ UINTN Size;\r
+ EFI_MMRAM_DESCRIPTOR *MmramRanges;\r
+ UINTN MmramRangeCount;\r
+\r
+ DEBUG ((DEBUG_INFO, "%a %a - Entry.\n", _DBGMSGID_, __FUNCTION__));\r
+\r
+ PrmHandlerCount = 0;\r
+ PrmModuleCount = 0;\r
+\r
+ if (!IsListEmpty (&mPrmModuleList)) {\r
+ return EFI_ALREADY_STARTED;\r
+ }\r
+\r
+ Status = gBS->LocateHandleBuffer (\r
+ ByProtocol,\r
+ &gEfiLoadedImageProtocolGuid,\r
+ NULL,\r
+ &HandleCount,\r
+ &HandleBuffer\r
+ );\r
+ if (EFI_ERROR (Status) && (HandleCount == 0)) {\r
+ DEBUG ((DEBUG_ERROR, "%a %a: No LoadedImageProtocol instances found!\n", _DBGMSGID_, __FUNCTION__));\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ MmramRanges = NULL;\r
+ MmramRangeCount = 0;\r
+ Status = gBS->LocateProtocol (\r
+ &gEfiMmAccessProtocolGuid,\r
+ NULL,\r
+ (VOID **)&MmAccess\r
+ );\r
+ if (Status == EFI_SUCCESS) {\r
+ //\r
+ // Get MMRAM range information\r
+ //\r
+ Size = 0;\r
+ Status = MmAccess->GetCapabilities (MmAccess, &Size, NULL);\r
+ if ((Status == EFI_BUFFER_TOO_SMALL) && (Size != 0)) {\r
+ MmramRanges = (EFI_MMRAM_DESCRIPTOR *)AllocatePool (Size);\r
+ if (MmramRanges != NULL) {\r
+ Status = MmAccess->GetCapabilities (MmAccess, &Size, MmramRanges);\r
+ if (Status == EFI_SUCCESS) {\r
+ MmramRangeCount = Size / sizeof (EFI_MMRAM_DESCRIPTOR);\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ for (Index = 0; Index < HandleCount; Index++) {\r
+ Status = gBS->HandleProtocol (\r
+ HandleBuffer[Index],\r
+ &gEfiLoadedImageProtocolGuid,\r
+ (VOID **) &LoadedImageProtocol\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ continue;\r
+ }\r
+\r
+ if (IsAddressInMmram ((EFI_PHYSICAL_ADDRESS)(UINTN)(LoadedImageProtocol->ImageBase), MmramRanges, MmramRangeCount)) {\r
+ continue;\r
+ }\r
+\r
+ ZeroMem (&TempPrmModuleImageContext, sizeof (TempPrmModuleImageContext));\r
+ TempPrmModuleImageContext.PeCoffImageContext.Handle = LoadedImageProtocol->ImageBase;\r
+ TempPrmModuleImageContext.PeCoffImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;\r
+\r
+ Status = PeCoffLoaderGetImageInfo (&TempPrmModuleImageContext.PeCoffImageContext);\r
+ if (EFI_ERROR (Status) || TempPrmModuleImageContext.PeCoffImageContext.ImageError != IMAGE_ERROR_SUCCESS) {\r
+ DEBUG ((\r
+ DEBUG_WARN,\r
+ "%a %a: ImageHandle 0x%016lx is not a valid PE/COFF image. It cannot be considered a PRM module.\n",\r
+ _DBGMSGID_,\r
+ __FUNCTION__,\r
+ (EFI_PHYSICAL_ADDRESS) (UINTN) LoadedImageProtocol->ImageBase\r
+ ));\r
+ continue;\r
+ }\r
+ if (TempPrmModuleImageContext.PeCoffImageContext.IsTeImage) {\r
+ // A PRM Module is not allowed to be a TE image\r
+ continue;\r
+ }\r
+\r
+ // Attempt to find an export table in this image\r
+ Status = GetExportDirectoryInPeCoffImage (\r
+ LoadedImageProtocol->ImageBase,\r
+ &TempPrmModuleImageContext.PeCoffImageContext,\r
+ &TempPrmModuleImageContext.ExportDirectory\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ continue;\r
+ }\r
+\r
+ // Attempt to find the PRM Module Export Descriptor in the export table\r
+ Status = GetPrmModuleExportDescriptorTable (\r
+ TempPrmModuleImageContext.ExportDirectory,\r
+ &TempPrmModuleImageContext.PeCoffImageContext,\r
+ &TempPrmModuleImageContext.ExportDescriptor\r
+ );\r
+ if (EFI_ERROR (Status) || TempPrmModuleImageContext.ExportDescriptor == NULL) {\r
+ continue;\r
+ }\r
+ // A PRM Module Export Descriptor was successfully found, this is considered a PRM Module.\r
+\r
+ //\r
+ // Create a new PRM Module image context node\r
+ //\r
+ PrmModuleImageContextListEntry = CreateNewPrmModuleImageContextListEntry ();\r
+ if (PrmModuleImageContextListEntry == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ CopyMem (\r
+ &PrmModuleImageContextListEntry->Context,\r
+ &TempPrmModuleImageContext,\r
+ sizeof (PrmModuleImageContextListEntry->Context)\r
+ );\r
+ InsertTailList (&mPrmModuleList, &PrmModuleImageContextListEntry->Link);\r
+ PrmHandlerCount += TempPrmModuleImageContext.ExportDescriptor->Header.NumberPrmHandlers;\r
+ PrmModuleCount++;\r
+ DEBUG ((DEBUG_INFO, "%a %a: New PRM Module inserted into list to be processed.\n", _DBGMSGID_, __FUNCTION__));\r
+ }\r
+\r
+ if (HandlerCount != NULL) {\r
+ *HandlerCount = PrmHandlerCount;\r
+ }\r
+ if (ModuleCount != NULL) {\r
+ *ModuleCount = PrmModuleCount;\r
+ }\r
+\r
+ if (MmramRanges != NULL) {\r
+ FreePool (MmramRanges);\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ The destructor function for this library instance.\r
+\r
+ Frees global resources allocated by this library instance.\r
+\r
+ @param ImageHandle The firmware allocated handle for the EFI image.\r
+ @param SystemTable A pointer to the EFI System Table.\r
+\r
+ @retval EFI_SUCCESS The destructor always returns EFI_SUCCESS.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PrmModuleDiscoveryLibDestructor (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+{\r
+ LIST_ENTRY *Link;\r
+ LIST_ENTRY *NextLink;\r
+ PRM_MODULE_IMAGE_CONTEXT_LIST_ENTRY *ListEntry;\r
+\r
+ if (IsListEmpty (&mPrmModuleList)) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ Link = GetFirstNode (&mPrmModuleList);\r
+ while (!IsNull (&mPrmModuleList, Link)) {\r
+ ListEntry = CR (Link, PRM_MODULE_IMAGE_CONTEXT_LIST_ENTRY, Link, PRM_MODULE_IMAGE_CONTEXT_LIST_ENTRY_SIGNATURE);\r
+ NextLink = GetNextNode (&mPrmModuleList, Link);\r
+\r
+ RemoveEntryList (Link);\r
+ FreePool (ListEntry);\r
+\r
+ Link = NextLink;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ The constructor function for this library instance.\r
+\r
+ Internally initializes data structures used later during library execution.\r
+\r
+ @param ImageHandle The firmware allocated handle for the EFI image.\r
+ @param SystemTable A pointer to the EFI System Table.\r
+\r
+ @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PrmModuleDiscoveryLibConstructor (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+{\r
+ InitializeListHead (&mPrmModuleList);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
--- /dev/null
+## @file\r
+# PRM Module Discovery Library\r
+#\r
+# Provides functionality to discover PRM modules loaded in the system boot.\r
+#\r
+# Copyright (c) Microsoft Corporation\r
+#\r
+# SPDX-License-Identifier: BSD-2-Clause-Patent\r
+#\r
+##\r
+\r
+[Defines]\r
+ INF_VERSION = 0x00010005\r
+ BASE_NAME = DxePrmModuleDiscoveryLib\r
+ FILE_GUID = 95D3893F-4CBA-4C20-92C1-D24BFE3CE7B9\r
+ MODULE_TYPE = DXE_DRIVER\r
+ VERSION_STRING = 1.0\r
+ LIBRARY_CLASS = PrmModuleDiscoveryLib|DXE_DRIVER UEFI_DRIVER UEFI_APPLICATION\r
+ CONSTRUCTOR = PrmModuleDiscoveryLibConstructor\r
+ DESTRUCTOR = PrmModuleDiscoveryLibDestructor\r
+\r
+[Sources]\r
+ PrmModuleDiscovery.h\r
+ DxePrmModuleDiscoveryLib.c\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+ MdeModulePkg/MdeModulePkg.dec\r
+ PrmPkg/PrmPkg.dec\r
+\r
+[LibraryClasses]\r
+ BaseLib\r
+ BaseMemoryLib\r
+ DebugLib\r
+ MemoryAllocationLib\r
+ PrmPeCoffLib\r
+ UefiBootServicesTableLib\r
+\r
+[Protocols]\r
+ gEfiLoadedImageProtocolGuid\r
+ gEfiMmAccessProtocolGuid\r
--- /dev/null
+/** @file\r
+\r
+ Definitions internally used for Platform Runtime Mechanism (PRM) module discovery.\r
+\r
+ Copyright (c) Microsoft Corporation\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+#ifndef PRM_MODULE_DISCOVERY_H_\r
+#define PRM_MODULE_DISCOVERY_H_\r
+\r
+#include <PrmModuleImageContext.h>\r
+\r
+#define PRM_MODULE_IMAGE_CONTEXT_LIST_ENTRY_SIGNATURE SIGNATURE_32('P','R','M','E')\r
+\r
+#pragma pack(push, 1)\r
+\r
+typedef struct {\r
+ UINTN Signature;\r
+ LIST_ENTRY Link;\r
+ PRM_MODULE_IMAGE_CONTEXT Context;\r
+} PRM_MODULE_IMAGE_CONTEXT_LIST_ENTRY;\r
+\r
+#pragma pack(pop)\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+\r
+ This file contains implementation for additional PE/COFF functionality needed to use\r
+ Platform Runtime Mechanism (PRM) modules.\r
+\r
+ Copyright (c) Microsoft Corporation\r
+ Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+#include <IndustryStandard/PeImage.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/PeCoffLib.h>\r
+\r
+#include <PrmExportDescriptor.h>\r
+#include <PrmModuleImageContext.h>\r
+\r
+#define _DBGMSGID_ "[PRMPECOFFLIB]"\r
+\r
+/**\r
+ Gets a pointer to the export directory in a given PE/COFF image.\r
+\r
+ @param[in] ImageExportDirectory A pointer to an export directory table in a PE/COFF image.\r
+ @param[in] PeCoffLoaderImageContext A pointer to a PE_COFF_LOADER_IMAGE_CONTEXT structure that contains the\r
+ PE/COFF image context for the Image containing the PRM Module Export\r
+ Descriptor table.\r
+ @param[out] ExportDescriptor A pointer to a pointer to the PRM Module Export Descriptor table found\r
+ in the ImageExportDirectory given.\r
+\r
+ @retval EFI_SUCCESS The PRM Module Export Descriptor table was found successfully.\r
+ @retval EFI_INVALID_PARAMETER A required parameter is NULL.\r
+ @retval EFI_NOT_FOUND The PRM Module Export Descriptor table was not found in the given\r
+ ImageExportDirectory.\r
+\r
+**/\r
+EFI_STATUS\r
+GetPrmModuleExportDescriptorTable (\r
+ IN EFI_IMAGE_EXPORT_DIRECTORY *ImageExportDirectory,\r
+ IN PE_COFF_LOADER_IMAGE_CONTEXT *PeCoffLoaderImageContext,\r
+ OUT PRM_MODULE_EXPORT_DESCRIPTOR_STRUCT **ExportDescriptor\r
+ )\r
+{\r
+ UINTN Index;\r
+ EFI_PHYSICAL_ADDRESS CurrentImageAddress;\r
+ UINT16 PrmModuleExportDescriptorOrdinal;\r
+ CONST CHAR8 *CurrentExportName;\r
+ UINT16 *OrdinalTable;\r
+ UINT32 *ExportNamePointerTable;\r
+ UINT32 *ExportAddressTable;\r
+ PRM_MODULE_EXPORT_DESCRIPTOR_STRUCT *TempExportDescriptor;\r
+\r
+ DEBUG ((DEBUG_INFO, "%a %a - Entry.\n", _DBGMSGID_, __FUNCTION__));\r
+\r
+ if (ImageExportDirectory == NULL ||\r
+ PeCoffLoaderImageContext == NULL ||\r
+ PeCoffLoaderImageContext->ImageAddress == 0 ||\r
+ ExportDescriptor == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ *ExportDescriptor = NULL;\r
+\r
+ DEBUG ((\r
+ DEBUG_INFO,\r
+ " %a %a: %d exported names found in this image.\n",\r
+ _DBGMSGID_,\r
+ __FUNCTION__,\r
+ ImageExportDirectory->NumberOfNames\r
+ ));\r
+\r
+ //\r
+ // The export name pointer table and export ordinal table form two parallel arrays associated by index.\r
+ //\r
+ CurrentImageAddress = PeCoffLoaderImageContext->ImageAddress;\r
+ ExportAddressTable = (UINT32 *) ((UINTN) CurrentImageAddress + ImageExportDirectory->AddressOfFunctions);\r
+ ExportNamePointerTable = (UINT32 *) ((UINTN) CurrentImageAddress + ImageExportDirectory->AddressOfNames);\r
+ OrdinalTable = (UINT16 *) ((UINTN) CurrentImageAddress + ImageExportDirectory->AddressOfNameOrdinals);\r
+\r
+ for (Index = 0; Index < ImageExportDirectory->NumberOfNames; Index++) {\r
+ CurrentExportName = (CONST CHAR8 *) ((UINTN) CurrentImageAddress + ExportNamePointerTable[Index]);\r
+ DEBUG ((\r
+ DEBUG_INFO,\r
+ " %a %a: Export Name[0x%x] - %a.\n",\r
+ _DBGMSGID_,\r
+ __FUNCTION__,\r
+ Index,\r
+ CurrentExportName\r
+ ));\r
+ if (\r
+ AsciiStrnCmp (\r
+ PRM_STRING(PRM_MODULE_EXPORT_DESCRIPTOR_NAME),\r
+ CurrentExportName,\r
+ AsciiStrLen (PRM_STRING(PRM_MODULE_EXPORT_DESCRIPTOR_NAME))\r
+ ) == 0) {\r
+ PrmModuleExportDescriptorOrdinal = OrdinalTable[Index];\r
+ DEBUG ((\r
+ DEBUG_INFO,\r
+ " %a %a: PRM Module Export Descriptor found. Ordinal = %d.\n",\r
+ _DBGMSGID_,\r
+ __FUNCTION__,\r
+ PrmModuleExportDescriptorOrdinal\r
+ ));\r
+ if (PrmModuleExportDescriptorOrdinal >= ImageExportDirectory->NumberOfFunctions) {\r
+ DEBUG ((DEBUG_ERROR, "%a %a: The PRM Module Export Descriptor ordinal value is invalid.\n", _DBGMSGID_, __FUNCTION__));\r
+ return EFI_NOT_FOUND;\r
+ }\r
+ TempExportDescriptor = (PRM_MODULE_EXPORT_DESCRIPTOR_STRUCT *) ((UINTN) CurrentImageAddress + ExportAddressTable[PrmModuleExportDescriptorOrdinal]);\r
+ if (TempExportDescriptor->Header.Signature == PRM_MODULE_EXPORT_DESCRIPTOR_SIGNATURE) {\r
+ *ExportDescriptor = TempExportDescriptor;\r
+ DEBUG ((DEBUG_INFO, " %a %a: PRM Module Export Descriptor found at 0x%x.\n", _DBGMSGID_, __FUNCTION__, (UINTN) ExportDescriptor));\r
+ } else {\r
+ DEBUG ((\r
+ DEBUG_INFO,\r
+ " %a %a: PRM Module Export Descriptor found at 0x%x but signature check failed.\n",\r
+ _DBGMSGID_,\r
+ __FUNCTION__,\r
+ (UINTN) TempExportDescriptor\r
+ ));\r
+ }\r
+ DEBUG ((DEBUG_INFO, " %a %a: Exiting export iteration since export descriptor found.\n", _DBGMSGID_, __FUNCTION__));\r
+ return EFI_SUCCESS;\r
+ }\r
+ }\r
+\r
+ return EFI_NOT_FOUND;\r
+}\r
+\r
+/**\r
+ Gets a pointer to the export directory in a given PE/COFF image.\r
+\r
+ @param[in] Image A pointer to a PE32/COFF image base address that is loaded into memory\r
+ and already relocated to the memory base address. RVAs in the image given\r
+ should be valid.\r
+ @param[in] PeCoffLoaderImageContext A pointer to a PE_COFF_LOADER_IMAGE_CONTEXT structure that contains the\r
+ PE/COFF image context for the Image given.\r
+ @param[out] ImageExportDirectory A pointer to a pointer to the export directory found in the Image given.\r
+\r
+ @retval EFI_SUCCESS The export directory was found successfully.\r
+ @retval EFI_INVALID_PARAMETER A required parameter is NULL.\r
+ @retval EFI_UNSUPPORTED The PE/COFF image given is not supported as a PRM Module.\r
+ @retval EFI_NOT_FOUND The image export directory could not be found for this image.\r
+\r
+**/\r
+EFI_STATUS\r
+GetExportDirectoryInPeCoffImage (\r
+ IN VOID *Image,\r
+ IN PE_COFF_LOADER_IMAGE_CONTEXT *PeCoffLoaderImageContext,\r
+ OUT EFI_IMAGE_EXPORT_DIRECTORY **ImageExportDirectory\r
+ )\r
+{\r
+ UINT16 Magic;\r
+ UINT32 NumberOfRvaAndSizes;\r
+ EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION OptionalHeaderPtrUnion;\r
+ EFI_IMAGE_DATA_DIRECTORY *DirectoryEntry;\r
+ EFI_IMAGE_EXPORT_DIRECTORY *ExportDirectory;\r
+\r
+ if (Image == NULL || PeCoffLoaderImageContext == NULL || ImageExportDirectory == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ DirectoryEntry = NULL;\r
+ ExportDirectory = NULL;\r
+\r
+ //\r
+ // NOTE: For backward compatibility, use the Machine field to identify a PE32/PE32+\r
+ // image instead of using the Magic field. Some systems might generate a PE32+\r
+ // image with PE32 magic.\r
+ //\r
+ switch (PeCoffLoaderImageContext->Machine) {\r
+ case EFI_IMAGE_MACHINE_IA32:\r
+ //\r
+ // Assume PE32 image with IA32 Machine field.\r
+ //\r
+ Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC;\r
+ break;\r
+ case EFI_IMAGE_MACHINE_X64:\r
+ case EFI_IMAGE_MACHINE_AARCH64:\r
+ //\r
+ // Assume PE32+ image with X64 Machine field\r
+ //\r
+ Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
+ break;\r
+ default:\r
+ //\r
+ // For unknown Machine field, use Magic in optional header\r
+ //\r
+ DEBUG ((\r
+ DEBUG_WARN,\r
+ "%a %a: The machine type for this image is not valid for a PRM module.\n",\r
+ _DBGMSGID_,\r
+ __FUNCTION__\r
+ ));\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ OptionalHeaderPtrUnion.Pe32 = (EFI_IMAGE_NT_HEADERS32 *) (\r
+ (UINTN) Image +\r
+ PeCoffLoaderImageContext->PeCoffHeaderOffset\r
+ );\r
+\r
+ //\r
+ // Check the PE/COFF Header Signature. Determine if the image is valid and/or a TE image.\r
+ //\r
+ if (OptionalHeaderPtrUnion.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {\r
+ DEBUG ((DEBUG_ERROR, "%a %a: The PE signature is not valid for the current image.\n", _DBGMSGID_, __FUNCTION__));\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
+ //\r
+ // Use the PE32 offset to get the Export Directory Entry\r
+ //\r
+ NumberOfRvaAndSizes = OptionalHeaderPtrUnion.Pe32->OptionalHeader.NumberOfRvaAndSizes;\r
+ DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *) &(OptionalHeaderPtrUnion.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXPORT]);\r
+ } else if (OptionalHeaderPtrUnion.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {\r
+ //\r
+ // Use the PE32+ offset get the Export Directory Entry\r
+ //\r
+ NumberOfRvaAndSizes = OptionalHeaderPtrUnion.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;\r
+ DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *) &(OptionalHeaderPtrUnion.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXPORT]);\r
+ } else {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_EXPORT || DirectoryEntry->VirtualAddress == 0) {\r
+ //\r
+ // The export directory is not present\r
+ //\r
+ return EFI_NOT_FOUND;\r
+ } else if (((UINT32) (~0) - DirectoryEntry->VirtualAddress) < DirectoryEntry->Size) {\r
+ //\r
+ // The directory address overflows\r
+ //\r
+ DEBUG ((DEBUG_ERROR, "%a %a: The export directory entry in this image results in overflow.\n", _DBGMSGID_, __FUNCTION__));\r
+ return EFI_UNSUPPORTED;\r
+ } else {\r
+ DEBUG ((DEBUG_INFO, "%a %a: Export Directory Entry found in the image at 0x%x.\n", _DBGMSGID_, __FUNCTION__, (UINTN) OptionalHeaderPtrUnion.Pe32));\r
+ DEBUG ((DEBUG_INFO, " %a %a: Directory Entry Virtual Address = 0x%x.\n", _DBGMSGID_, __FUNCTION__, DirectoryEntry->VirtualAddress));\r
+\r
+ ExportDirectory = (EFI_IMAGE_EXPORT_DIRECTORY *) ((UINTN) Image + DirectoryEntry->VirtualAddress);\r
+ DEBUG ((\r
+ DEBUG_INFO,\r
+ " %a %a: Export Directory Table found successfully at 0x%x. Name address = 0x%x. Name = %a.\n",\r
+ _DBGMSGID_,\r
+ __FUNCTION__,\r
+ (UINTN) ExportDirectory,\r
+ ((UINTN) Image + ExportDirectory->Name),\r
+ (CHAR8 *) ((UINTN) Image + ExportDirectory->Name)\r
+ ));\r
+ }\r
+ *ImageExportDirectory = ExportDirectory;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Returns the image major and image minor version in a given PE/COFF image.\r
+\r
+ @param[in] Image A pointer to a PE32/COFF image base address that is loaded into memory\r
+ and already relocated to the memory base address. RVAs in the image given\r
+ should be valid.\r
+ @param[in] PeCoffLoaderImageContext A pointer to a PE_COFF_LOADER_IMAGE_CONTEXT structure that contains the\r
+ PE/COFF image context for the Image given.\r
+ @param[out] ImageMajorVersion A pointer to a UINT16 buffer to hold the image major version.\r
+ @param[out] ImageMinorVersion A pointer to a UINT16 buffer to hold the image minor version.\r
+\r
+ @retval EFI_SUCCESS The image version was read successfully.\r
+ @retval EFI_INVALID_PARAMETER A required parameter is NULL.\r
+ @retval EFI_UNSUPPORTED The PE/COFF image given is not supported.\r
+\r
+**/\r
+EFI_STATUS\r
+GetImageVersionInPeCoffImage (\r
+ IN VOID *Image,\r
+ IN PE_COFF_LOADER_IMAGE_CONTEXT *PeCoffLoaderImageContext,\r
+ OUT UINT16 *ImageMajorVersion,\r
+ OUT UINT16 *ImageMinorVersion\r
+ )\r
+{\r
+ EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION OptionalHeaderPtrUnion;\r
+ UINT16 Magic;\r
+\r
+ DEBUG ((DEBUG_INFO, " %a %a - Entry.\n", _DBGMSGID_, __FUNCTION__));\r
+\r
+ if (Image == NULL || PeCoffLoaderImageContext == NULL || ImageMajorVersion == NULL || ImageMinorVersion == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // NOTE: For backward compatibility, use the Machine field to identify a PE32/PE32+\r
+ // image instead of using the Magic field. Some systems might generate a PE32+\r
+ // image with PE32 magic.\r
+ //\r
+ switch (PeCoffLoaderImageContext->Machine) {\r
+ case EFI_IMAGE_MACHINE_IA32:\r
+ //\r
+ // Assume PE32 image\r
+ //\r
+ Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC;\r
+ break;\r
+ case EFI_IMAGE_MACHINE_X64:\r
+ case EFI_IMAGE_MACHINE_AARCH64:\r
+ //\r
+ // Assume PE32+ image\r
+ //\r
+ Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
+ break;\r
+ default:\r
+ //\r
+ // For unknown Machine field, use Magic in optional header\r
+ //\r
+ DEBUG ((\r
+ DEBUG_WARN,\r
+ "%a %a: The machine type for this image is not valid for a PRM module.\n",\r
+ _DBGMSGID_,\r
+ __FUNCTION__\r
+ ));\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ OptionalHeaderPtrUnion.Pe32 = (EFI_IMAGE_NT_HEADERS32 *) (\r
+ (UINTN) Image +\r
+ PeCoffLoaderImageContext->PeCoffHeaderOffset\r
+ );\r
+ //\r
+ // Check the PE/COFF Header Signature. Determine if the image is valid and/or a TE image.\r
+ //\r
+ if (OptionalHeaderPtrUnion.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {\r
+ DEBUG ((DEBUG_ERROR, "%a %a: The PE signature is not valid for the current image.\n", _DBGMSGID_, __FUNCTION__));\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
+ //\r
+ // Use the PE32 offset to get the Export Directory Entry\r
+ //\r
+ *ImageMajorVersion = OptionalHeaderPtrUnion.Pe32->OptionalHeader.MajorImageVersion;\r
+ *ImageMinorVersion = OptionalHeaderPtrUnion.Pe32->OptionalHeader.MinorImageVersion;\r
+ } else {\r
+ //\r
+ // Use the PE32+ offset to get the Export Directory Entry\r
+ //\r
+ *ImageMajorVersion = OptionalHeaderPtrUnion.Pe32Plus->OptionalHeader.MajorImageVersion;\r
+ *ImageMinorVersion = OptionalHeaderPtrUnion.Pe32Plus->OptionalHeader.MinorImageVersion;\r
+ }\r
+\r
+ DEBUG ((DEBUG_INFO, " %a %a - Image Major Version: 0x%02x.\n", _DBGMSGID_, __FUNCTION__, *ImageMajorVersion));\r
+ DEBUG ((DEBUG_INFO, " %a %a - Image Minor Version: 0x%02x.\n", _DBGMSGID_, __FUNCTION__, *ImageMinorVersion));\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Gets the address of an entry in an image export table by ASCII name.\r
+\r
+ @param[in] ExportName A pointer to an ASCII name string of the entry name.\r
+ @param[in] ImageBaseAddress The base address of the PE/COFF image.\r
+ @param[in] ImageExportDirectory A pointer to the export directory in the image.\r
+ @param[out] ExportPhysicalAddress A pointer that will be updated with the address of the address of the\r
+ export entry if found.\r
+\r
+ @retval EFI_SUCCESS The export entry was found successfully.\r
+ @retval EFI_INVALID_PARAMETER A required pointer argument is NULL.\r
+ @retval EFI_NOT_FOUND An entry with the given ExportName was not found.\r
+\r
+**/\r
+EFI_STATUS\r
+GetExportEntryAddress (\r
+ IN CONST CHAR8 *ExportName,\r
+ IN EFI_PHYSICAL_ADDRESS ImageBaseAddress,\r
+ IN EFI_IMAGE_EXPORT_DIRECTORY *ImageExportDirectory,\r
+ OUT EFI_PHYSICAL_ADDRESS *ExportPhysicalAddress\r
+ )\r
+{\r
+ UINTN ExportNameIndex;\r
+ UINT16 CurrentExportOrdinal;\r
+ UINT32 *ExportAddressTable;\r
+ UINT32 *ExportNamePointerTable;\r
+ UINT16 *OrdinalTable;\r
+ CONST CHAR8 *ExportNameTablePointerName;\r
+\r
+ if (ExportName == NULL || ImageBaseAddress == 0 || ImageExportDirectory == NULL || ExportPhysicalAddress == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ *ExportPhysicalAddress = 0;\r
+\r
+ ExportAddressTable = (UINT32 *) ((UINTN) ImageBaseAddress + ImageExportDirectory->AddressOfFunctions);\r
+ ExportNamePointerTable = (UINT32 *) ((UINTN) ImageBaseAddress + ImageExportDirectory->AddressOfNames);\r
+ OrdinalTable = (UINT16 *) ((UINTN) ImageBaseAddress + ImageExportDirectory->AddressOfNameOrdinals);\r
+\r
+ for (ExportNameIndex = 0; ExportNameIndex < ImageExportDirectory->NumberOfNames; ExportNameIndex++) {\r
+ ExportNameTablePointerName = (CONST CHAR8 *) ((UINTN) ImageBaseAddress + ExportNamePointerTable[ExportNameIndex]);\r
+\r
+ if (AsciiStrnCmp (ExportName, ExportNameTablePointerName, PRM_HANDLER_NAME_MAXIMUM_LENGTH) == 0) {\r
+ CurrentExportOrdinal = OrdinalTable[ExportNameIndex];\r
+\r
+ ASSERT (CurrentExportOrdinal < ImageExportDirectory->NumberOfFunctions);\r
+ if (CurrentExportOrdinal >= ImageExportDirectory->NumberOfFunctions) {\r
+ DEBUG ((DEBUG_ERROR, " %a %a: The export ordinal value is invalid.\n", _DBGMSGID_, __FUNCTION__));\r
+ break;\r
+ }\r
+\r
+ *ExportPhysicalAddress = (EFI_PHYSICAL_ADDRESS) ((UINTN) ImageBaseAddress + ExportAddressTable[CurrentExportOrdinal]);\r
+ return EFI_SUCCESS;\r
+ }\r
+ }\r
+\r
+ return EFI_NOT_FOUND;\r
+}\r
--- /dev/null
+## @file\r
+# PRM PE/COFF Library\r
+#\r
+# Provides functionality to support additional PE/COFF functionality needed to use Platform Runtime Mechanism (PRM)\r
+# modules.\r
+#\r
+# Copyright (c) Microsoft Corporation\r
+#\r
+# SPDX-License-Identifier: BSD-2-Clause-Patent\r
+#\r
+##\r
+\r
+[Defines]\r
+ INF_VERSION = 0x00010005\r
+ BASE_NAME = DxePrmPeCoffLib\r
+ FILE_GUID = 0B9AEEAC-D79A-46A5-A784-84BDBC6291B5\r
+ MODULE_TYPE = DXE_DRIVER\r
+ VERSION_STRING = 1.0\r
+ LIBRARY_CLASS = PrmPeCoffLib|DXE_DRIVER UEFI_DRIVER UEFI_APPLICATION\r
+\r
+[Sources]\r
+ DxePrmPeCoffLib.c\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+ MdeModulePkg/MdeModulePkg.dec\r
+ PrmPkg/PrmPkg.dec\r
+\r
+[LibraryClasses]\r
+ BaseLib\r
+ DebugLib\r
+ PeCoffLib\r
+++ /dev/null
-/** @file\r
-\r
- Definitions specific to the Platform Runtime Mechanism (PRM) loader.x\r
-\r
- Copyright (c) Microsoft Corporation\r
- SPDX-License-Identifier: BSD-2-Clause-Patent\r
-\r
-**/\r
-\r
-#ifndef PRM_LOADER_H_\r
-#define PRM_LOADER_H_\r
-\r
-#include <IndustryStandard/PeImage.h>\r
-#include <Library/PeCoffLib.h>\r
-\r
-#include <PrmExportDescriptor.h>\r
-\r
-#define _DBGMSGID_ "[PRMLOADER]"\r
-#define PRM_MODULE_IMAGE_CONTEXT_LIST_ENTRY_SIGNATURE SIGNATURE_32('P','R','M','E')\r
-\r
-#pragma pack(push, 1)\r
-\r
-typedef struct {\r
- PE_COFF_LOADER_IMAGE_CONTEXT PeCoffImageContext;\r
- EFI_IMAGE_EXPORT_DIRECTORY *ExportDirectory;\r
- PRM_MODULE_EXPORT_DESCRIPTOR_STRUCT *ExportDescriptor;\r
-} PRM_MODULE_IMAGE_CONTEXT;\r
-\r
-typedef struct {\r
- UINTN Signature;\r
- LIST_ENTRY Link;\r
- PRM_MODULE_IMAGE_CONTEXT *Context;\r
-} PRM_MODULE_IMAGE_CONTEXT_LIST_ENTRY;\r
-\r
-#pragma pack(pop)\r
-\r
-//\r
-// Iterate through the double linked list. NOT delete safe.\r
-//\r
-#define EFI_LIST_FOR_EACH(Entry, ListHead) \\r
- for(Entry = (ListHead)->ForwardLink; Entry != (ListHead); Entry = Entry->ForwardLink)\r
-\r
-//\r
-// Iterate through the double linked list. This is delete-safe.\r
-// Don't touch NextEntry.\r
-//\r
-#define EFI_LIST_FOR_EACH_SAFE(Entry, NextEntry, ListHead) \\r
- for(Entry = (ListHead)->ForwardLink, NextEntry = Entry->ForwardLink;\\r
- Entry != (ListHead); Entry = NextEntry, NextEntry = Entry->ForwardLin\r
-\r
-#endif\r
**/\r
\r
#include "PrmAcpiTable.h"\r
-#include "PrmLoader.h"\r
\r
#include <IndustryStandard/Acpi.h>\r
#include <Library/BaseLib.h>\r
#include <Library/DebugLib.h>\r
#include <Library/MemoryAllocationLib.h>\r
#include <Library/PrmContextBufferLib.h>\r
+#include <Library/PrmModuleDiscoveryLib.h>\r
+#include <Library/PrmPeCoffLib.h>\r
#include <Library/UefiBootServicesTableLib.h>\r
#include <Library/UefiLib.h>\r
#include <Protocol/AcpiTable.h>\r
-#include <Protocol/LoadedImage.h>\r
#include <Protocol/PrmConfig.h>\r
\r
#include <PrmContextBuffer.h>\r
#include <PrmMmio.h>\r
\r
-LIST_ENTRY mPrmModuleList;\r
+#define _DBGMSGID_ "[PRMLOADER]"\r
\r
-// Todo: Potentially refactor mPrmHandlerCount and mPrmModuleCount into localized structures\r
-// in the future.\r
-UINT32 mPrmHandlerCount;\r
-UINT32 mPrmModuleCount;\r
-\r
-/**\r
- Gets a pointer to the export directory in a given PE/COFF image.\r
-\r
- @param[in] ImageExportDirectory A pointer to an export directory table in a PE/COFF image.\r
- @param[in] PeCoffLoaderImageContext A pointer to a PE_COFF_LOADER_IMAGE_CONTEXT structure that contains the\r
- PE/COFF image context for the Image containing the PRM Module Export\r
- Descriptor table.\r
- @param[out] ExportDescriptor A pointer to a pointer to the PRM Module Export Descriptor table found\r
- in the ImageExportDirectory given.\r
-\r
- @retval EFI_SUCCESS The PRM Module Export Descriptor table was found successfully.\r
- @retval EFI_INVALID_PARAMETER A required parameter is NULL.\r
- @retval EFI_NOT_FOUND The PRM Module Export Descriptor table was not found in the given\r
- ImageExportDirectory.\r
-\r
-**/\r
-EFI_STATUS\r
-GetPrmModuleExportDescriptorTable (\r
- IN EFI_IMAGE_EXPORT_DIRECTORY *ImageExportDirectory,\r
- IN PE_COFF_LOADER_IMAGE_CONTEXT *PeCoffLoaderImageContext,\r
- OUT PRM_MODULE_EXPORT_DESCRIPTOR_STRUCT **ExportDescriptor\r
- )\r
-{\r
- UINTN Index;\r
- EFI_PHYSICAL_ADDRESS CurrentImageAddress;\r
- UINT16 PrmModuleExportDescriptorOrdinal;\r
- CONST CHAR8 *CurrentExportName;\r
- UINT16 *OrdinalTable;\r
- UINT32 *ExportNamePointerTable;\r
- UINT32 *ExportAddressTable;\r
- PRM_MODULE_EXPORT_DESCRIPTOR_STRUCT *TempExportDescriptor;\r
-\r
- DEBUG ((DEBUG_INFO, "%a %a - Entry.\n", _DBGMSGID_, __FUNCTION__));\r
-\r
- *ExportDescriptor = NULL;\r
-\r
- if (ImageExportDirectory == NULL ||\r
- PeCoffLoaderImageContext == NULL ||\r
- PeCoffLoaderImageContext->ImageAddress == 0 ||\r
- ExportDescriptor == NULL) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- DEBUG ((\r
- DEBUG_INFO,\r
- " %a %a: %d exported names found in this image.\n",\r
- _DBGMSGID_,\r
- __FUNCTION__,\r
- ImageExportDirectory->NumberOfNames\r
- ));\r
-\r
- //\r
- // The export name pointer table and export ordinal table form two parallel arrays associated by index.\r
- //\r
- CurrentImageAddress = PeCoffLoaderImageContext->ImageAddress;\r
- ExportAddressTable = (UINT32 *) ((UINTN) CurrentImageAddress + ImageExportDirectory->AddressOfFunctions);\r
- ExportNamePointerTable = (UINT32 *) ((UINTN) CurrentImageAddress + ImageExportDirectory->AddressOfNames);\r
- OrdinalTable = (UINT16 *) ((UINTN) CurrentImageAddress + ImageExportDirectory->AddressOfNameOrdinals);\r
-\r
- for (Index = 0; Index < ImageExportDirectory->NumberOfNames; Index++) {\r
- CurrentExportName = (CONST CHAR8 *) ((UINTN) CurrentImageAddress + ExportNamePointerTable[Index]);\r
- DEBUG ((\r
- DEBUG_INFO,\r
- " %a %a: Export Name[0x%x] - %a.\n",\r
- _DBGMSGID_,\r
- __FUNCTION__,\r
- Index,\r
- CurrentExportName\r
- ));\r
- if (\r
- AsciiStrnCmp (\r
- PRM_STRING(PRM_MODULE_EXPORT_DESCRIPTOR_NAME),\r
- CurrentExportName,\r
- AsciiStrLen (PRM_STRING(PRM_MODULE_EXPORT_DESCRIPTOR_NAME))\r
- ) == 0) {\r
- PrmModuleExportDescriptorOrdinal = OrdinalTable[Index];\r
- DEBUG ((\r
- DEBUG_INFO,\r
- " %a %a: PRM Module Export Descriptor found. Ordinal = %d.\n",\r
- _DBGMSGID_,\r
- __FUNCTION__,\r
- PrmModuleExportDescriptorOrdinal\r
- ));\r
- if (PrmModuleExportDescriptorOrdinal >= ImageExportDirectory->NumberOfFunctions) {\r
- DEBUG ((DEBUG_ERROR, "%a %a: The PRM Module Export Descriptor ordinal value is invalid.\n", _DBGMSGID_, __FUNCTION__));\r
- return EFI_NOT_FOUND;\r
- }\r
- TempExportDescriptor = (PRM_MODULE_EXPORT_DESCRIPTOR_STRUCT *) ((UINTN) CurrentImageAddress + ExportAddressTable[PrmModuleExportDescriptorOrdinal]);\r
- if (TempExportDescriptor->Header.Signature == PRM_MODULE_EXPORT_DESCRIPTOR_SIGNATURE) {\r
- *ExportDescriptor = TempExportDescriptor;\r
- DEBUG ((DEBUG_INFO, " %a %a: PRM Module Export Descriptor found at 0x%x.\n", _DBGMSGID_, __FUNCTION__, (UINTN) ExportDescriptor));\r
- } else {\r
- DEBUG ((\r
- DEBUG_INFO,\r
- " %a %a: PRM Module Export Descriptor found at 0x%x but signature check failed.\n",\r
- _DBGMSGID_,\r
- __FUNCTION__,\r
- (UINTN) TempExportDescriptor\r
- ));\r
- }\r
- DEBUG ((DEBUG_INFO, " %a %a: Exiting export iteration since export descriptor found.\n", _DBGMSGID_, __FUNCTION__));\r
- return EFI_SUCCESS;\r
- }\r
- }\r
-\r
- return EFI_NOT_FOUND;\r
-}\r
-\r
-/**\r
- Gets a pointer to the export directory in a given PE/COFF image.\r
-\r
- @param[in] Image A pointer to a PE32/COFF image base address that is loaded into memory\r
- and already relocated to the memory base address. RVAs in the image given\r
- should be valid.\r
- @param[in] PeCoffLoaderImageContext A pointer to a PE_COFF_LOADER_IMAGE_CONTEXT structure that contains the\r
- PE/COFF image context for the Image given.\r
- @param[out] ImageExportDirectory A pointer to a pointer to the export directory found in the Image given.\r
-\r
- @retval EFI_SUCCESS The export directory was found successfully.\r
- @retval EFI_INVALID_PARAMETER A required parameter is NULL.\r
- @retval EFI_UNSUPPORTED The PE/COFF image given is not supported as a PRM Module.\r
- @retval EFI_NOT_FOUND The image export directory could not be found for this image.\r
-\r
-**/\r
-EFI_STATUS\r
-GetExportDirectoryInPeCoffImage (\r
- IN VOID *Image,\r
- IN PE_COFF_LOADER_IMAGE_CONTEXT *PeCoffLoaderImageContext,\r
- OUT EFI_IMAGE_EXPORT_DIRECTORY **ImageExportDirectory\r
- )\r
-{\r
- UINT16 Magic;\r
- UINT32 NumberOfRvaAndSizes;\r
- EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION OptionalHeaderPtrUnion;\r
- EFI_IMAGE_DATA_DIRECTORY *DirectoryEntry;\r
- EFI_IMAGE_EXPORT_DIRECTORY *ExportDirectory;\r
- EFI_IMAGE_SECTION_HEADER *SectionHeader;\r
-\r
- if (Image == NULL || PeCoffLoaderImageContext == NULL || ImageExportDirectory == NULL) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- DirectoryEntry = NULL;\r
- ExportDirectory = NULL;\r
-\r
- //\r
- // NOTE: For backward compatibility, use the Machine field to identify a PE32/PE32+\r
- // image instead of using the Magic field. Some systems might generate a PE32+\r
- // image with PE32 magic.\r
- //\r
- switch (PeCoffLoaderImageContext->Machine) {\r
- case EFI_IMAGE_MACHINE_IA32:\r
- // Todo: Add EFI_IMAGE_MACHINE_ARMT\r
- //\r
- // Assume PE32 image with IA32 Machine field.\r
- //\r
- Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC;\r
- break;\r
- case EFI_IMAGE_MACHINE_X64:\r
- //\r
- // Assume PE32+ image with X64 Machine field\r
- //\r
- Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
- break;\r
- default:\r
- //\r
- // For unknown Machine field, use Magic in optional header\r
- //\r
- DEBUG ((\r
- DEBUG_WARN,\r
- "%a %a: The machine type for this image is not valid for a PRM module.\n",\r
- _DBGMSGID_,\r
- __FUNCTION__\r
- ));\r
- return EFI_UNSUPPORTED;\r
- }\r
-\r
- OptionalHeaderPtrUnion.Pe32 = (EFI_IMAGE_NT_HEADERS32 *) (\r
- (UINTN) Image +\r
- PeCoffLoaderImageContext->PeCoffHeaderOffset\r
- );\r
-\r
- //\r
- // Check the PE/COFF Header Signature. Determine if the image is valid and/or a TE image.\r
- //\r
- if (OptionalHeaderPtrUnion.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {\r
- DEBUG ((DEBUG_ERROR, "%a %a: The PE signature is not valid for the current image.\n", _DBGMSGID_, __FUNCTION__));\r
- return EFI_UNSUPPORTED;\r
- }\r
-\r
- SectionHeader = (EFI_IMAGE_SECTION_HEADER *) (\r
- (UINTN) Image +\r
- PeCoffLoaderImageContext->PeCoffHeaderOffset +\r
- sizeof (UINT32) +\r
- sizeof (EFI_IMAGE_FILE_HEADER) +\r
- PeCoffLoaderImageContext->SizeOfHeaders\r
- );\r
- if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
- //\r
- // Use the PE32 offset to get the Export Directory Entry\r
- //\r
- NumberOfRvaAndSizes = OptionalHeaderPtrUnion.Pe32->OptionalHeader.NumberOfRvaAndSizes;\r
- DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *) &(OptionalHeaderPtrUnion.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXPORT]);\r
- } else if (OptionalHeaderPtrUnion.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {\r
- //\r
- // Use the PE32+ offset get the Export Directory Entry\r
- //\r
- NumberOfRvaAndSizes = OptionalHeaderPtrUnion.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;\r
- DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *) &(OptionalHeaderPtrUnion.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXPORT]);\r
- } else {\r
- return EFI_UNSUPPORTED;\r
- }\r
-\r
- if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_EXPORT || DirectoryEntry->VirtualAddress == 0) {\r
- //\r
- // The export directory is not present\r
- //\r
- return EFI_NOT_FOUND;\r
- } else if (((UINT32) (~0) - DirectoryEntry->VirtualAddress) < DirectoryEntry->Size) {\r
- //\r
- // The directory address overflows\r
- //\r
- DEBUG ((DEBUG_ERROR, "%a %a: The export directory entry in this image results in overflow.\n", _DBGMSGID_, __FUNCTION__));\r
- return EFI_UNSUPPORTED;\r
- } else {\r
- DEBUG ((DEBUG_INFO, "%a %a: Export Directory Entry found in the image at 0x%x.\n", _DBGMSGID_, __FUNCTION__, (UINTN) OptionalHeaderPtrUnion.Pe32));\r
- DEBUG ((DEBUG_INFO, " %a %a: Directory Entry Virtual Address = 0x%x.\n", _DBGMSGID_, __FUNCTION__, DirectoryEntry->VirtualAddress));\r
-\r
- ExportDirectory = (EFI_IMAGE_EXPORT_DIRECTORY *) ((UINTN) Image + DirectoryEntry->VirtualAddress);\r
- DEBUG ((\r
- DEBUG_INFO,\r
- " %a %a: Export Directory Table found successfully at 0x%x. Name address = 0x%x. Name = %a.\n",\r
- _DBGMSGID_,\r
- __FUNCTION__,\r
- (UINTN) ExportDirectory,\r
- ((UINTN) Image + ExportDirectory->Name),\r
- (CHAR8 *) ((UINTN) Image + ExportDirectory->Name)\r
- ));\r
- }\r
- *ImageExportDirectory = ExportDirectory;\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
- Returns the image major and image minor version in a given PE/COFF image.\r
-\r
- @param[in] Image A pointer to a PE32/COFF image base address that is loaded into memory\r
- and already relocated to the memory base address. RVAs in the image given\r
- should be valid.\r
- @param[in] PeCoffLoaderImageContext A pointer to a PE_COFF_LOADER_IMAGE_CONTEXT structure that contains the\r
- PE/COFF image context for the Image given.\r
- @param[out] ImageMajorVersion A pointer to a UINT16 buffer to hold the image major version.\r
- @param[out] ImageMinorVersion A pointer to a UINT16 buffer to hold the image minor version.\r
-\r
- @retval EFI_SUCCESS The image version was read successfully.\r
- @retval EFI_INVALID_PARAMETER A required parameter is NULL.\r
- @retval EFI_UNSUPPORTED The PE/COFF image given is not supported.\r
-\r
-**/\r
-EFI_STATUS\r
-GetImageVersionInPeCoffImage (\r
- IN VOID *Image,\r
- IN PE_COFF_LOADER_IMAGE_CONTEXT *PeCoffLoaderImageContext,\r
- OUT UINT16 *ImageMajorVersion,\r
- OUT UINT16 *ImageMinorVersion\r
- )\r
-{\r
- EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION OptionalHeaderPtrUnion;\r
- UINT16 Magic;\r
-\r
- DEBUG ((DEBUG_INFO, " %a %a - Entry.\n", _DBGMSGID_, __FUNCTION__));\r
-\r
- if (Image == NULL || PeCoffLoaderImageContext == NULL || ImageMajorVersion == NULL || ImageMinorVersion == NULL) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- //\r
- // NOTE: For backward compatibility, use the Machine field to identify a PE32/PE32+\r
- // image instead of using the Magic field. Some systems might generate a PE32+\r
- // image with PE32 magic.\r
- //\r
- switch (PeCoffLoaderImageContext->Machine) {\r
- case EFI_IMAGE_MACHINE_IA32:\r
- // Todo: Add EFI_IMAGE_MACHINE_ARMT\r
- //\r
- // Assume PE32 image with IA32 Machine field.\r
- //\r
- Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC;\r
- break;\r
- case EFI_IMAGE_MACHINE_X64:\r
- //\r
- // Assume PE32+ image with X64 Machine field\r
- //\r
- Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
- break;\r
- default:\r
- //\r
- // For unknown Machine field, use Magic in optional header\r
- //\r
- DEBUG ((\r
- DEBUG_WARN,\r
- "%a %a: The machine type for this image is not valid for a PRM module.\n",\r
- _DBGMSGID_,\r
- __FUNCTION__\r
- ));\r
- return EFI_UNSUPPORTED;\r
- }\r
-\r
- OptionalHeaderPtrUnion.Pe32 = (EFI_IMAGE_NT_HEADERS32 *) (\r
- (UINTN) Image +\r
- PeCoffLoaderImageContext->PeCoffHeaderOffset\r
- );\r
- //\r
- // Check the PE/COFF Header Signature. Determine if the image is valid and/or a TE image.\r
- //\r
- if (OptionalHeaderPtrUnion.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {\r
- DEBUG ((DEBUG_ERROR, "%a %a: The PE signature is not valid for the current image.\n", _DBGMSGID_, __FUNCTION__));\r
- return EFI_UNSUPPORTED;\r
- }\r
-\r
- if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
- //\r
- // Use the PE32 offset to get the Export Directory Entry\r
- //\r
- *ImageMajorVersion = OptionalHeaderPtrUnion.Pe32->OptionalHeader.MajorImageVersion;\r
- *ImageMinorVersion = OptionalHeaderPtrUnion.Pe32->OptionalHeader.MinorImageVersion;\r
- } else {\r
- //\r
- // Use the PE32+ offset to get the Export Directory Entry\r
- //\r
- *ImageMajorVersion = OptionalHeaderPtrUnion.Pe32Plus->OptionalHeader.MajorImageVersion;\r
- *ImageMinorVersion = OptionalHeaderPtrUnion.Pe32Plus->OptionalHeader.MinorImageVersion;\r
- }\r
-\r
- DEBUG ((DEBUG_INFO, " %a %a - Image Major Version: 0x%02x.\n", _DBGMSGID_, __FUNCTION__, *ImageMajorVersion));\r
- DEBUG ((DEBUG_INFO, " %a %a - Image Minor Version: 0x%02x.\n", _DBGMSGID_, __FUNCTION__, *ImageMinorVersion));\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
- Creates a new PRM Module Image Context linked list entry.\r
-\r
- @retval PrmModuleImageContextListEntry If successful, a pointer a PRM Module Image Context linked list entry\r
- otherwise, NULL is returned.\r
-\r
-**/\r
-STATIC\r
-PRM_MODULE_IMAGE_CONTEXT_LIST_ENTRY *\r
-CreateNewPrmModuleImageContextListEntry (\r
- VOID\r
- )\r
-{\r
- PRM_MODULE_IMAGE_CONTEXT *PrmModuleImageContext;\r
- PRM_MODULE_IMAGE_CONTEXT_LIST_ENTRY *PrmModuleImageContextListEntry;\r
-\r
- DEBUG ((DEBUG_INFO, "%a %a - Entry.\n", _DBGMSGID_, __FUNCTION__));\r
-\r
- PrmModuleImageContext = AllocateZeroPool (sizeof (*PrmModuleImageContext));\r
- if (PrmModuleImageContext == NULL) {\r
- return NULL;\r
- }\r
- DEBUG ((\r
- DEBUG_INFO,\r
- " %a %a: Allocated PrmModuleImageContext at 0x%x of size 0x%x bytes.\n",\r
- _DBGMSGID_,\r
- __FUNCTION__,\r
- (UINTN) PrmModuleImageContext,\r
- sizeof (*PrmModuleImageContext)\r
- ));\r
-\r
- PrmModuleImageContextListEntry = AllocateZeroPool (sizeof (*PrmModuleImageContextListEntry));\r
- if (PrmModuleImageContextListEntry == NULL) {\r
- FreePool (PrmModuleImageContext);\r
- return NULL;\r
- }\r
- DEBUG ((\r
- DEBUG_INFO,\r
- " %a %a: Allocated PrmModuleImageContextListEntry at 0x%x of size 0x%x bytes.\n",\r
- _DBGMSGID_,\r
- __FUNCTION__,\r
- (UINTN) PrmModuleImageContextListEntry,\r
- sizeof (*PrmModuleImageContextListEntry)\r
- ));\r
-\r
- PrmModuleImageContextListEntry->Signature = PRM_MODULE_IMAGE_CONTEXT_LIST_ENTRY_SIGNATURE;\r
- PrmModuleImageContextListEntry->Context = PrmModuleImageContext;\r
-\r
- return PrmModuleImageContextListEntry;\r
-}\r
-\r
-/**\r
- Discovers all PRM Modules loaded during the DXE boot phase.\r
-\r
- Each PRM Module discovered is placed into a linked list so the list can br processsed in the future.\r
-\r
- @retval EFI_SUCCESS All PRM Modules were discovered successfully.\r
- @retval EFI_NOT_FOUND The gEfiLoadedImageProtocolGuid protocol could not be found.\r
- @retval EFI_OUT_OF_RESOURCES Insufficient memory resources to allocate the new PRM Context\r
- linked list nodes.\r
-\r
-**/\r
-EFI_STATUS\r
-DiscoverPrmModules (\r
- VOID\r
- )\r
-{\r
- EFI_STATUS Status;\r
- PRM_MODULE_IMAGE_CONTEXT TempPrmModuleImageContext;\r
- PRM_MODULE_IMAGE_CONTEXT_LIST_ENTRY *PrmModuleImageContextListEntry;\r
- EFI_LOADED_IMAGE_PROTOCOL *LoadedImageProtocol;\r
- EFI_HANDLE *HandleBuffer;\r
- UINTN HandleCount;\r
- UINTN Index;\r
-\r
- DEBUG ((DEBUG_INFO, "%a %a - Entry.\n", _DBGMSGID_, __FUNCTION__));\r
-\r
- Status = gBS->LocateHandleBuffer (\r
- ByProtocol,\r
- &gEfiLoadedImageProtocolGuid,\r
- NULL,\r
- &HandleCount,\r
- &HandleBuffer\r
- );\r
- if (EFI_ERROR (Status) && (HandleCount == 0)) {\r
- DEBUG ((DEBUG_ERROR, "%a %a: No LoadedImageProtocol instances found!\n", _DBGMSGID_, __FUNCTION__));\r
- return EFI_NOT_FOUND;\r
- }\r
-\r
- for (Index = 0; Index < HandleCount; Index++) {\r
- Status = gBS->HandleProtocol (\r
- HandleBuffer[Index],\r
- &gEfiLoadedImageProtocolGuid,\r
- (VOID **) &LoadedImageProtocol\r
- );\r
- if (EFI_ERROR (Status)) {\r
- continue;\r
- }\r
-\r
- ZeroMem (&TempPrmModuleImageContext, sizeof (TempPrmModuleImageContext));\r
- TempPrmModuleImageContext.PeCoffImageContext.Handle = LoadedImageProtocol->ImageBase;\r
- TempPrmModuleImageContext.PeCoffImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;\r
-\r
- Status = PeCoffLoaderGetImageInfo (&TempPrmModuleImageContext.PeCoffImageContext);\r
- if (EFI_ERROR (Status) || TempPrmModuleImageContext.PeCoffImageContext.ImageError != IMAGE_ERROR_SUCCESS) {\r
- DEBUG ((\r
- DEBUG_WARN,\r
- "%a %a: ImageHandle 0x%016lx is not a valid PE/COFF image. It cannot be considered a PRM module.\n",\r
- _DBGMSGID_,\r
- __FUNCTION__,\r
- (EFI_PHYSICAL_ADDRESS) (UINTN) LoadedImageProtocol->ImageBase\r
- ));\r
- continue;\r
- }\r
- if (TempPrmModuleImageContext.PeCoffImageContext.IsTeImage) {\r
- // A PRM Module is not allowed to be a TE image\r
- continue;\r
- }\r
-\r
- // Attempt to find an export table in this image\r
- Status = GetExportDirectoryInPeCoffImage (\r
- LoadedImageProtocol->ImageBase,\r
- &TempPrmModuleImageContext.PeCoffImageContext,\r
- &TempPrmModuleImageContext.ExportDirectory\r
- );\r
- if (EFI_ERROR (Status)) {\r
- continue;\r
- }\r
-\r
- // Attempt to find the PRM Module Export Descriptor in the export table\r
- Status = GetPrmModuleExportDescriptorTable (\r
- TempPrmModuleImageContext.ExportDirectory,\r
- &TempPrmModuleImageContext.PeCoffImageContext,\r
- &TempPrmModuleImageContext.ExportDescriptor\r
- );\r
- if (EFI_ERROR (Status)) {\r
- continue;\r
- }\r
- // A PRM Module Export Descriptor was successfully found, this is considered a PRM Module.\r
-\r
- //\r
- // Create a new PRM Module image context node\r
- //\r
- PrmModuleImageContextListEntry = CreateNewPrmModuleImageContextListEntry ();\r
- if (PrmModuleImageContextListEntry == NULL) {\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
- CopyMem (\r
- PrmModuleImageContextListEntry->Context,\r
- &TempPrmModuleImageContext,\r
- sizeof (*(PrmModuleImageContextListEntry->Context))\r
- );\r
- InsertTailList (&mPrmModuleList, &PrmModuleImageContextListEntry->Link);\r
- mPrmHandlerCount += TempPrmModuleImageContext.ExportDescriptor->Header.NumberPrmHandlers;\r
- mPrmModuleCount++; // Todo: Match with global variable refactor change in the future\r
- DEBUG ((DEBUG_INFO, "%a %a: New PRM Module inserted into list to be processed.\n", _DBGMSGID_, __FUNCTION__));\r
- }\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
- Gets the address of an entry in an image export table by ASCII name.\r
-\r
- @param[in] ExportName A pointer to an ASCII name string of the entry name.\r
- @param[in] ImageBaseAddress The base address of the PE/COFF image.\r
- @param[in] ImageExportDirectory A pointer to the export directory in the image.\r
- @param[out] ExportPhysicalAddress A pointer that will be updated with the address of the address of the\r
- export entry if found.\r
-\r
- @retval EFI_SUCCESS The export entry was found successfully.\r
- @retval EFI_INVALID_PARAMETER A required pointer argument is NULL.\r
- @retval EFI_NOT_FOUND An entry with the given ExportName was not found.\r
-\r
-**/\r
-EFI_STATUS\r
-GetExportEntryAddress (\r
- IN CONST CHAR8 *ExportName,\r
- IN EFI_PHYSICAL_ADDRESS ImageBaseAddress,\r
- IN EFI_IMAGE_EXPORT_DIRECTORY *ImageExportDirectory,\r
- OUT EFI_PHYSICAL_ADDRESS *ExportPhysicalAddress\r
- )\r
-{\r
- UINTN ExportNameIndex;\r
- UINT16 CurrentExportOrdinal;\r
- UINT32 *ExportAddressTable;\r
- UINT32 *ExportNamePointerTable;\r
- UINT16 *OrdinalTable;\r
- CONST CHAR8 *ExportNameTablePointerName;\r
-\r
- if (ExportName == NULL || ImageBaseAddress == 0 || ImageExportDirectory == NULL || ExportPhysicalAddress == NULL) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
- *ExportPhysicalAddress = 0;\r
-\r
- ExportAddressTable = (UINT32 *) ((UINTN) ImageBaseAddress + ImageExportDirectory->AddressOfFunctions);\r
- ExportNamePointerTable = (UINT32 *) ((UINTN) ImageBaseAddress + ImageExportDirectory->AddressOfNames);\r
- OrdinalTable = (UINT16 *) ((UINTN) ImageBaseAddress + ImageExportDirectory->AddressOfNameOrdinals);\r
-\r
- for (ExportNameIndex = 0; ExportNameIndex < ImageExportDirectory->NumberOfNames; ExportNameIndex++) {\r
- ExportNameTablePointerName = (CONST CHAR8 *) ((UINTN) ImageBaseAddress + ExportNamePointerTable[ExportNameIndex]);\r
-\r
- if (AsciiStrnCmp (ExportName, ExportNameTablePointerName, PRM_HANDLER_NAME_MAXIMUM_LENGTH) == 0) {\r
- CurrentExportOrdinal = OrdinalTable[ExportNameIndex];\r
-\r
- ASSERT (CurrentExportOrdinal < ImageExportDirectory->NumberOfFunctions);\r
- if (CurrentExportOrdinal >= ImageExportDirectory->NumberOfFunctions) {\r
- DEBUG ((DEBUG_ERROR, " %a %a: The export ordinal value is invalid.\n", _DBGMSGID_, __FUNCTION__));\r
- break;\r
- }\r
-\r
- *ExportPhysicalAddress = (EFI_PHYSICAL_ADDRESS) ((UINTN) ImageBaseAddress + ExportAddressTable[CurrentExportOrdinal]);\r
- return EFI_SUCCESS;\r
- }\r
- }\r
-\r
- return EFI_NOT_FOUND;\r
-}\r
+UINTN mPrmHandlerCount;\r
+UINTN mPrmModuleCount;\r
\r
/**\r
Processes a list of PRM context entries to build a PRM ACPI table.\r
{\r
EFI_IMAGE_EXPORT_DIRECTORY *CurrentImageExportDirectory;\r
PRM_MODULE_EXPORT_DESCRIPTOR_STRUCT *CurrentExportDescriptorStruct;\r
- LIST_ENTRY *Link;\r
PRM_ACPI_DESCRIPTION_TABLE *PrmAcpiTable;\r
- PRM_MODULE_IMAGE_CONTEXT_LIST_ENTRY *TempListEntry;\r
+ PRM_MODULE_IMAGE_CONTEXT *CurrentPrmModuleImageContext;\r
CONST CHAR8 *CurrentExportDescriptorHandlerName;\r
\r
ACPI_PARAMETER_BUFFER_DESCRIPTOR *CurrentModuleAcpiParamDescriptors;\r
if (PrmAcpiDescriptionTable == NULL) {\r
return EFI_INVALID_PARAMETER;\r
}\r
- Link = NULL;\r
*PrmAcpiDescriptionTable = NULL;\r
\r
DEBUG ((DEBUG_INFO, " %a %a: %d total PRM modules to process.\n", _DBGMSGID_, __FUNCTION__, mPrmModuleCount));\r
DEBUG ((DEBUG_INFO, " %a %a: %d total PRM handlers to process.\n", _DBGMSGID_, __FUNCTION__, mPrmHandlerCount));\r
\r
- PrmAcpiDescriptionTableBufferSize = (OFFSET_OF (PRM_ACPI_DESCRIPTION_TABLE, PrmModuleInfoStructure) +\r
+ PrmAcpiDescriptionTableBufferSize = (UINT32) (OFFSET_OF (PRM_ACPI_DESCRIPTION_TABLE, PrmModuleInfoStructure) +\r
(OFFSET_OF (PRM_MODULE_INFORMATION_STRUCT, HandlerInfoStructure) * mPrmModuleCount) +\r
(sizeof (PRM_HANDLER_INFORMATION_STRUCT) * mPrmHandlerCount)\r
);\r
PrmAcpiTable->Header.CreatorId = PcdGet32 (PcdAcpiDefaultCreatorId);\r
PrmAcpiTable->Header.CreatorRevision = PcdGet32 (PcdAcpiDefaultCreatorRevision);\r
PrmAcpiTable->PrmModuleInfoOffset = OFFSET_OF (PRM_ACPI_DESCRIPTION_TABLE, PrmModuleInfoStructure);\r
- PrmAcpiTable->PrmModuleInfoCount = mPrmModuleCount;\r
+ PrmAcpiTable->PrmModuleInfoCount = (UINT32) mPrmModuleCount;\r
\r
//\r
// Iterate across all PRM Modules on the list\r
//\r
CurrentModuleInfoStruct = &PrmAcpiTable->PrmModuleInfoStructure[0];\r
- EFI_LIST_FOR_EACH(Link, &mPrmModuleList)\r
- {\r
- TempListEntry = CR(Link, PRM_MODULE_IMAGE_CONTEXT_LIST_ENTRY, Link, PRM_MODULE_IMAGE_CONTEXT_LIST_ENTRY_SIGNATURE);\r
- CurrentImageAddress = TempListEntry->Context->PeCoffImageContext.ImageAddress;\r
- CurrentImageExportDirectory = TempListEntry->Context->ExportDirectory;\r
- CurrentExportDescriptorStruct = TempListEntry->Context->ExportDescriptor;\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
CurrentModuleAcpiParamDescriptors = NULL;\r
\r
DEBUG ((\r
CurrentModuleInfoStruct->MinorRevision = 0;\r
Status = GetImageVersionInPeCoffImage (\r
(VOID *) (UINTN) CurrentImageAddress,\r
- &TempListEntry->Context->PeCoffImageContext,\r
+ &CurrentPrmModuleImageContext->PeCoffImageContext,\r
&CurrentModuleInfoStruct->MajorRevision,\r
&CurrentModuleInfoStruct->MinorRevision\r
);\r
\r
DEBUG ((DEBUG_INFO, "%a %a - Entry.\n", _DBGMSGID_, __FUNCTION__));\r
\r
- InitializeListHead (&mPrmModuleList);\r
-\r
- Status = DiscoverPrmModules ();\r
+ Status = DiscoverPrmModules (&mPrmModuleCount, &mPrmHandlerCount);\r
ASSERT_EFI_ERROR (Status);\r
\r
Status = ProcessPrmModules (&PrmAcpiDescriptionTable);\r
\r
[Sources]\r
PrmAcpiTable.h\r
- PrmLoader.h\r
PrmLoaderDxe.c\r
\r
[Packages]\r
DebugLib\r
MemoryAllocationLib\r
PcdLib\r
- PeCoffLib\r
PrmContextBufferLib\r
+ PrmModuleDiscoveryLib\r
+ PrmPeCoffLib\r
UefiBootServicesTableLib\r
UefiDriverEntryPoint\r
UefiLib\r
\r
[Protocols]\r
gEfiAcpiTableProtocolGuid\r
- gEfiLoadedImageProtocolGuid\r
gPrmConfigProtocolGuid\r
\r
[Depex]\r
#\r
PrmContextBufferLib|Include/Library/PrmContextBufferLib.h\r
\r
+ ## @libraryclass Provides functionality to discover PRM modules installed by platform firmware\r
+ #\r
+ PrmModuleDiscoveryLib|Include/Library/PrmModuleDiscoveryLib.h\r
+\r
+ ## @libraryclass Provides additional PE/COFF functionality needed to support the Platform Runtime Mechanism (PRM) loader driver.\r
+ #\r
+ PrmPeCoffLib|Include/Library/PrmPeCoffLib.h\r
+\r
[Protocols]\r
## PRM Configuration Protocol\r
#\r
# PRM Package\r
#\r
PrmContextBufferLib|$(PLATFORM_PACKAGE)/Library/DxePrmContextBufferLib/DxePrmContextBufferLib.inf\r
+ PrmModuleDiscoveryLib|$(PLATFORM_PACKAGE)/Library/DxePrmModuleDiscoveryLib/DxePrmModuleDiscoveryLib.inf\r
+ PrmPeCoffLib|$(PLATFORM_PACKAGE)/Library/DxePrmPeCoffLib/DxePrmPeCoffLib.inf\r
+\r
\r
###################################################################################################\r
#\r
$(PLATFORM_PACKAGE)/Samples/PrmSampleContextBufferModule/Library/DxeContextBufferModuleConfigLib/DxeContextBufferModuleConfigLib.inf\r
$(PLATFORM_PACKAGE)/Samples/PrmSampleHardwareAccessModule/Library/DxeHardwareAccessModuleConfigLib/DxeHardwareAccessModuleConfigLib.inf\r
\r
+ #\r
+ # PRM Module Discovery Library\r
+ #\r
+ $(PLATFORM_PACKAGE)/Library/DxePrmModuleDiscoveryLib/DxePrmModuleDiscoveryLib.inf\r
+\r
+ #\r
+ # PRM PE/COFF Library\r
+ #\r
+ $(PLATFORM_PACKAGE)/Library/DxePrmPeCoffLib/DxePrmPeCoffLib.inf\r
+\r
#\r
# PRM Configuration Driver\r
#\r