summaryrefslogtreecommitdiffstats
path: root/PrmPkg/Library/DxePrmModuleDiscoveryLib/DxePrmModuleDiscoveryLib.c
diff options
context:
space:
mode:
Diffstat (limited to 'PrmPkg/Library/DxePrmModuleDiscoveryLib/DxePrmModuleDiscoveryLib.c')
-rw-r--r--PrmPkg/Library/DxePrmModuleDiscoveryLib/DxePrmModuleDiscoveryLib.c382
1 files changed, 382 insertions, 0 deletions
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.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiMm.h>
+#include <Protocol/MmAccess.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PrmModuleDiscoveryLib.h>
+#include <Library/PrmPeCoffLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Protocol/LoadedImage.h>
+
+#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;
+}