MdeModulePkg/Library: fix memory leak Rx/Tx Buffer in ArmFfaPeiLib

The commit e15fe06603
("MdeModulePkg/Library: make ArmFfaPeiLib available early PEIM stage")
uses ArmFfaPeiLib in the early PEIM stage.

However, the Rx/Tx buffer allocated in the early PEIM stage uses
temporary memory. This results in a memory leak when the temporary
memory's heap is relocated to permanent memory.

For example, if the Rx/Tx buffer memory is allocated at 0x20006000
in temporary memory, and if offset between temporary memory and
permanent is 0x40000000, then:

 - Once permanent memory installed the temporary memory at 0x20006000
   is migrated to 0x60006000.
 - However, ArmFfaPeiLib allocates new Rx/Tx buffer without freeing
   the migrated Rx/Tx buffers, i.e. the buffers at 0x60006000.

This results in a memory leak as the migrated Rx/Tx buffer area is
lost.
To address this memory leak, use the MemoryAllocationHob's name, so
that the migrated memory area will be reused as Rx/Tx buffer.

This patch also includes rename ArmFfaRxTxStmm.c to
ArmFfaStandaloneMmRxTxMap.c to keep the file name convention in
ArmFfaLib with ArmFfa{Phase}{...}.c

Fixes: e15fe06603 ("MdeModulePkg/Library: ...")
Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
Continuous-integration-options: PatchCheck.ignore-multi-package
This commit is contained in:
Levi Yun
2025-06-02 23:11:56 +01:00
committed by mergify[bot]
parent 460f2705b4
commit b336d9b87a
7 changed files with 370 additions and 54 deletions

View File

@@ -14,16 +14,22 @@
*/
typedef struct ArmFfaRxTxBuffersInfo {
/// Tx Buffer Address.
VOID *TxBufferAddr;
VOID *TxBufferAddr;
/// Tx Buffer Size.
UINT64 TxBufferSize;
UINT64 TxBufferSize;
/// Rx Buffer Address.
VOID *RxBufferAddr;
VOID *RxBufferAddr;
/// Rx Buffer Size.
UINT64 RxBufferSize;
UINT64 RxBufferSize;
/// Rx/Tx buffer should be remapped to permanent memory.
BOOLEAN RemapRequired;
/// Rx/Tx buffer offset from its allocation base.
UINT64 RemapOffset;
} ARM_FFA_RX_TX_BUFFER_INFO;
extern EFI_GUID gArmFfaRxTxBufferInfoGuid;

View File

@@ -34,25 +34,6 @@
#include "ArmFfaCommon.h"
#include "ArmFfaRxTxMap.h"
/**
Update Rx/TX buffer information.
@param BufferInfo Rx/Tx buffer information.
**/
STATIC
VOID
EFIAPI
UpdateRxTxBufferInfo (
OUT ARM_FFA_RX_TX_BUFFER_INFO *BufferInfo
)
{
BufferInfo->TxBufferAddr = (VOID *)(UINTN)PcdGet64 (PcdFfaTxBuffer);
BufferInfo->TxBufferSize = PcdGet64 (PcdFfaTxRxPageCount) * EFI_PAGE_SIZE;
BufferInfo->RxBufferAddr = (VOID *)(UINTN)PcdGet64 (PcdFfaRxBuffer);
BufferInfo->RxBufferSize = PcdGet64 (PcdFfaTxRxPageCount) * EFI_PAGE_SIZE;
}
/**
Notification service to be called when gEfiPeiMemoryDiscoveredPpiGuid is installed.
This function change reamp Rx/Tx buffer with permanent memory from
@@ -81,7 +62,6 @@ PeiServicesMemoryDiscoveredNotifyCallback (
IN VOID *Ppi
)
{
EFI_STATUS Status;
EFI_HOB_GUID_TYPE *RxTxBufferHob;
ARM_FFA_RX_TX_BUFFER_INFO *BufferInfo;
@@ -89,26 +69,7 @@ PeiServicesMemoryDiscoveredNotifyCallback (
ASSERT (RxTxBufferHob != NULL);
BufferInfo = GET_GUID_HOB_DATA (RxTxBufferHob);
/*
* Temporary memory doesn't need to be free.
* otherwise PEI memory manager using permanent memory will be confused.
*/
PcdSet64S (PcdFfaTxBuffer, 0x00);
PcdSet64S (PcdFfaRxBuffer, 0x00);
Status = ArmFfaLibRxTxUnmap ();
if (EFI_ERROR (Status)) {
return Status;
}
Status = ArmFfaLibRxTxMap ();
if (EFI_ERROR (Status)) {
return Status;
}
UpdateRxTxBufferInfo (BufferInfo);
return EFI_SUCCESS;
return RemapFfaRxTxBuffer (BufferInfo);
}
STATIC EFI_PEI_NOTIFY_DESCRIPTOR mNotifyOnPeiMemoryDiscovered = {
@@ -138,6 +99,7 @@ ArmFfaPeiLibConstructor (
EFI_HOB_GUID_TYPE *RxTxBufferHob;
ARM_FFA_RX_TX_BUFFER_INFO *BufferInfo;
VOID *Dummy;
EFI_HOB_MEMORY_ALLOCATION *RxTxBufferAllocationHob;
Status = ArmFfaLibCommonInit ();
if (EFI_ERROR (Status)) {
@@ -176,6 +138,11 @@ ArmFfaPeiLibConstructor (
UpdateRxTxBufferInfo (BufferInfo);
/*
* When permanent memory is used, gEfiPeiMemoryDiscoveredPpiGuid
* is installed. If gEfiPeiMemoryDiscoveredPpiGuid is found,
* It doesn't need to remap Rx/Tx buffer.
*/
Status = (*PeiServices)->LocatePpi (
PeiServices,
&gEfiPeiMemoryDiscoveredPpiGuid,
@@ -183,10 +150,50 @@ ArmFfaPeiLibConstructor (
NULL,
&Dummy
);
if (EFI_ERROR (Status)) {
Status = (*PeiServices)->NotifyPpi (PeiServices, &mNotifyOnPeiMemoryDiscovered);
ASSERT_EFI_ERROR (Status);
BufferInfo->RemapRequired = EFI_ERROR (Status);
} else {
BufferInfo = GET_GUID_HOB_DATA (RxTxBufferHob);
}
if (BufferInfo->RemapRequired) {
/*
* If RxTxBufferAllocationHob can be found with gArmFfaRxTxBufferInfoGuid,
* This Rx/Tx buffer is mapped by ArmFfaSecLib.
*/
RxTxBufferAllocationHob = FindRxTxBufferAllocationHob (TRUE);
/*
* Below case Rx/Tx buffer mapped by ArmPeiLib but in temporary memory.
*/
if (RxTxBufferAllocationHob == NULL) {
RxTxBufferAllocationHob = FindRxTxBufferAllocationHob (FALSE);
ASSERT (RxTxBufferAllocationHob != NULL);
BufferInfo->RemapOffset =
(UINTN)((EFI_PHYSICAL_ADDRESS)((UINTN)BufferInfo->TxBufferAddr) -
RxTxBufferAllocationHob->AllocDescriptor.MemoryBaseAddress);
CopyGuid (
&RxTxBufferAllocationHob->AllocDescriptor.Name,
&gArmFfaRxTxBufferInfoGuid
);
}
Status = (*PeiServices)->NotifyPpi (PeiServices, &mNotifyOnPeiMemoryDiscovered);
/*
* Failed to register NotifyPpi.
* In this case, return ERROR to make failure of load for PPI
* and postpone to remap to other PEIM.
*/
if (EFI_ERROR (Status)) {
return Status;
}
/*
* Change RemapRequired to FALSE here to prevent other PEIM from
* registering notification again.
*/
BufferInfo->RemapRequired = FALSE;
}
return EFI_SUCCESS;

View File

@@ -19,12 +19,15 @@
#include <Library/BaseLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/DebugLib.h>
#include <Library/HobLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/PcdLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <IndustryStandard/ArmFfaSvc.h>
#include <Guid/ArmFfaRxTxBufferInfo.h>
#include "ArmFfaCommon.h"
#include "ArmFfaRxTxMap.h"
@@ -270,3 +273,197 @@ ArmFfaLibRxTxUnmap (
return EFI_SUCCESS;
}
/**
Update Rx/TX buffer information.
@param BufferInfo Rx/Tx buffer information.
**/
VOID
EFIAPI
UpdateRxTxBufferInfo (
OUT ARM_FFA_RX_TX_BUFFER_INFO *BufferInfo
)
{
BufferInfo->TxBufferAddr = (VOID *)(UINTN)PcdGet64 (PcdFfaTxBuffer);
BufferInfo->TxBufferSize = PcdGet64 (PcdFfaTxRxPageCount) * EFI_PAGE_SIZE;
BufferInfo->RxBufferAddr = (VOID *)(UINTN)PcdGet64 (PcdFfaRxBuffer);
BufferInfo->RxBufferSize = PcdGet64 (PcdFfaTxRxPageCount) * EFI_PAGE_SIZE;
}
/**
Find Rx/TX buffer memory allocation hob.
@param UseGuid Find MemoryAllocationHob using gArmFfaRxTxBufferInfoGuid.
@retval MemoryAllocationHob
@retval NULL No memory allocation hob related to Rx/Tx buffer
**/
EFI_HOB_MEMORY_ALLOCATION *
EFIAPI
FindRxTxBufferAllocationHob (
IN BOOLEAN UseGuid
)
{
EFI_PEI_HOB_POINTERS Hob;
EFI_HOB_MEMORY_ALLOCATION *MemoryAllocationHob;
EFI_PHYSICAL_ADDRESS BufferBase;
UINT64 BufferSize;
EFI_PHYSICAL_ADDRESS MemoryBase;
UINT64 MemorySize;
BufferBase = (EFI_PHYSICAL_ADDRESS)PcdGet64 (PcdFfaTxBuffer);
BufferSize = PcdGet64 (PcdFfaTxRxPageCount) * EFI_PAGE_SIZE * 2;
if (!UseGuid && (BufferBase == 0x00)) {
return NULL;
}
MemoryAllocationHob = NULL;
Hob.Raw = GetFirstHob (EFI_HOB_TYPE_MEMORY_ALLOCATION);
while (Hob.Raw != NULL) {
if (Hob.MemoryAllocation->AllocDescriptor.MemoryType == EfiConventionalMemory) {
continue;
}
MemoryBase = Hob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress;
MemorySize = Hob.MemoryAllocation->AllocDescriptor.MemoryLength;
if ((!UseGuid && (BufferBase >= MemoryBase) &&
((BufferBase + BufferSize) <= (MemoryBase + MemorySize))) ||
(UseGuid && CompareGuid (
&gArmFfaRxTxBufferInfoGuid,
&Hob.MemoryAllocation->AllocDescriptor.Name
)))
{
MemoryAllocationHob = (EFI_HOB_MEMORY_ALLOCATION *)Hob.Raw;
break;
}
Hob.Raw = GET_NEXT_HOB (Hob);
Hob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, Hob.Raw);
} // while
return MemoryAllocationHob;
}
/**
Remap Rx/TX buffer with converted Rx/Tx Buffer address after
using permanent memory.
@param[out] BufferInfo BufferInfo
@retval EFI_SUCCESS Success
@retval EFI_NOT_FOUND No memory allocation hob related to Rx/Tx buffer
**/
EFI_STATUS
EFIAPI
RemapFfaRxTxBuffer (
OUT ARM_FFA_RX_TX_BUFFER_INFO *BufferInfo
)
{
EFI_STATUS Status;
ARM_FFA_ARGS FfaArgs;
UINTN NewBufferBase;
UINTN NewTxBuffer;
UINTN NewRxBuffer;
UINTN Property1;
UINTN Property2;
UINTN MinSizeAndAlign;
EFI_HOB_MEMORY_ALLOCATION *RxTxBufferAllocationHob;
RxTxBufferAllocationHob = FindRxTxBufferAllocationHob (TRUE);
if (RxTxBufferAllocationHob == NULL) {
return EFI_NOT_FOUND;
}
Status = ArmFfaLibGetFeatures (
ARM_FID_FFA_RXTX_MAP,
FFA_RXTX_MAP_INPUT_PROPERTY_DEFAULT,
&Property1,
&Property2
);
if (EFI_ERROR (Status)) {
DEBUG ((
DEBUG_ERROR,
"%a: Failed to get RX/TX buffer property... Status: %r\n",
__func__,
Status
));
return Status;
}
MinSizeAndAlign =
((Property1 >>
ARM_FFA_BUFFER_MINSIZE_AND_ALIGN_SHIFT) &
ARM_FFA_BUFFER_MINSIZE_AND_ALIGN_MASK);
switch (MinSizeAndAlign) {
case ARM_FFA_BUFFER_MINSIZE_AND_ALIGN_4K:
MinSizeAndAlign = SIZE_4KB;
break;
case ARM_FFA_BUFFER_MINSIZE_AND_ALIGN_16K:
MinSizeAndAlign = SIZE_16KB;
break;
case ARM_FFA_BUFFER_MINSIZE_AND_ALIGN_64K:
MinSizeAndAlign = SIZE_64KB;
break;
default:
DEBUG ((DEBUG_ERROR, "%a: Invalid MinSizeAndAlign: 0x%x\n", __func__, MinSizeAndAlign));
return EFI_UNSUPPORTED;
}
ZeroMem (&FfaArgs, sizeof (ARM_FFA_ARGS));
FfaArgs.Arg0 = ARM_FID_FFA_RXTX_UNMAP;
FfaArgs.Arg1 = (gPartId << ARM_FFA_SOURCE_EP_SHIFT);
ArmCallFfa (&FfaArgs);
Status = FfaArgsToEfiStatus (&FfaArgs);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: Failed to unmap Rx/Tx buffer. Status: %r\n", __func__, Status));
return Status;
}
PcdSet64S (PcdFfaTxBuffer, 0x00);
PcdSet64S (PcdFfaRxBuffer, 0x00);
NewBufferBase = (UINTN)RxTxBufferAllocationHob->AllocDescriptor.MemoryBaseAddress + BufferInfo->RemapOffset;
NewTxBuffer = NewBufferBase;
NewRxBuffer = NewTxBuffer + (PcdGet64 (PcdFfaTxRxPageCount) * EFI_PAGE_SIZE);
ZeroMem (&FfaArgs, sizeof (ARM_FFA_ARGS));
FfaArgs.Arg0 = ARM_FID_FFA_RXTX_MAP;
FfaArgs.Arg1 = NewTxBuffer;
FfaArgs.Arg2 = NewRxBuffer;
/*
* PcdFfaTxRxPageCount sets with count of EFI_PAGE_SIZE granularity
* But, PageCounts for Tx/Rx buffer should set with
* count of Tx/Rx Buffer's MinSizeAndAlign. granularity.
*/
FfaArgs.Arg3 = PcdGet64 (PcdFfaTxRxPageCount) / EFI_SIZE_TO_PAGES (MinSizeAndAlign);
ArmCallFfa (&FfaArgs);
Status = FfaArgsToEfiStatus (&FfaArgs);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: Failed to map with new Rx/Tx buffer. Status: %r\n", __func__, Status));
return Status;
}
PcdSet64S (PcdFfaTxBuffer, NewTxBuffer);
PcdSet64S (PcdFfaRxBuffer, NewRxBuffer);
UpdateRxTxBufferInfo (BufferInfo);
/*
* Remap is done. clear to AllocDesciptor.Name
* so that unnecessary remap happen again.
*/
ZeroMem (&RxTxBufferAllocationHob->AllocDescriptor.Name, sizeof (EFI_GUID));
return EFI_SUCCESS;
}

View File

@@ -17,6 +17,8 @@
#ifndef ARM_FFA_RX_TX_MAP_LIB_H_
#define ARM_FFA_RX_TX_MAP_LIB_H_
#include <Guid/ArmFfaRxTxBufferInfo.h>
/**
Mapping Rx/Tx buffers.
This function is only called in ArmFfaLibConstructor because
@@ -51,4 +53,47 @@ ArmFfaLibRxTxUnmap (
IN VOID
);
/**
Update Rx/TX buffer information.
@param BufferInfo Rx/Tx buffer information.
**/
VOID
EFIAPI
UpdateRxTxBufferInfo (
OUT ARM_FFA_RX_TX_BUFFER_INFO *BufferInfo
);
/**
Find Rx/TX buffer memory allocation hob.
@param UseGuid Find MemoryAllocationHob using Guid.
@retval MemoryAllocationHob
@retval NULL No memory allocation hob related to Rx/Tx buffer
**/
EFI_HOB_MEMORY_ALLOCATION *
EFIAPI
FindRxTxBufferAllocationHob (
IN BOOLEAN UseGuid
);
/**
Remap Rx/TX buffer with converted Rx/Tx Buffer address after
using permanent memory.
@param[out] BufferInfo BufferInfo
@retval EFI_SUCCESS Success
@retval EFI_NOT_FOUND No memory allocation hob related to Rx/Tx buffer
**/
EFI_STATUS
EFIAPI
RemapFfaRxTxBuffer (
IN OUT ARM_FFA_RX_TX_BUFFER_INFO *BufferInfo
);
#endif

View File

@@ -19,9 +19,9 @@
[Sources]
ArmFfaCommon.h
ArmFfaCommon.c
ArmFfaStandaloneMmLib.c
ArmFfaRxTxMap.h
ArmFfaRxTxMapStmm.c
ArmFfaStandaloneMmRxTxMap.c
ArmFfaStandaloneMmLib.c
[Packages]
MdePkg/MdePkg.dec

View File

@@ -19,9 +19,9 @@
[Sources]
ArmFfaCommon.h
ArmFfaCommon.c
ArmFfaStandaloneMmLib.c
ArmFfaRxTxMap.h
ArmFfaRxTxMapStmm.c
ArmFfaStandaloneMmRxTxMap.c
ArmFfaStandaloneMmLib.c
[Packages]
MdePkg/MdePkg.dec

View File

@@ -1,7 +1,7 @@
/** @file
Arm Ffa library common code.
Copyright (c) 2024, Arm Limited. All rights reserved.<BR>
Copyright (c) 2024-2025, Arm Limited. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
@par Glossary:
@@ -11,8 +11,7 @@
- Arm Firmware Framework for Arm A-Profile v1.3 ALP1: [https://developer.arm.com/documentation/den0077/l]
**/
#include <Uefi.h>
#include <Pi/PiMultiPhase.h>
#include <PiMm.h>
#include <Library/ArmLib.h>
#include <Library/ArmFfaLib.h>
@@ -319,3 +318,65 @@ ArmFfaLibRxTxUnmap (
return EFI_SUCCESS;
}
/**
Update Rx/TX buffer information.
@param BufferInfo Rx/Tx buffer information.
**/
VOID
EFIAPI
UpdateRxTxBufferInfo (
OUT ARM_FFA_RX_TX_BUFFER_INFO *BufferInfo
)
{
/*
* StandaloneMm doesn't use Rx/Tx buffer.
*/
return;
}
/**
Find Rx/TX buffer memory allocation hob.
@param UseGuid Find MemoryAllocationHob using Guid.
@retval MemoryAllocationHob
@retval NULL No memory allocation hob related to Rx/Tx buffer
**/
EFI_HOB_MEMORY_ALLOCATION *
EFIAPI
FindRxTxBufferAllocationHob (
IN BOOLEAN UseGuid
)
{
/*
* StandaloneMm doesn't use Rx/Tx buffer.
*/
return NULL;
}
/**
Remap Rx/TX buffer with converted Rx/Tx Buffer address after
using permanent memory.
@param[out] BufferInfo BufferInfo
@retval EFI_SUCCESS Success
@retval EFI_NOT_FOUND No memory allocation hob related to Rx/Tx buffer
**/
EFI_STATUS
EFIAPI
RemapFfaRxTxBuffer (
OUT ARM_FFA_RX_TX_BUFFER_INFO *BufferInfo
)
{
/*
* StandaloneMm doesn't use Rx/Tx buffer.
* So, return EFI_UNSUPPORTED.
*/
return EFI_UNSUPPORTED;
}