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