mirror of https://github.com/acidanthera/audk.git
387 lines
13 KiB
C
387 lines
13 KiB
C
/** @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.
|
|
|
|
**/
|
|
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;
|
|
}
|