diff --git a/MdeModulePkg/Library/ArmFfaLib/ArmFfaDxeLib.c b/MdeModulePkg/Library/ArmFfaLib/ArmFfaDxeLib.c index 8751f2f06e..ad2ed2f1fd 100644 --- a/MdeModulePkg/Library/ArmFfaLib/ArmFfaDxeLib.c +++ b/MdeModulePkg/Library/ArmFfaLib/ArmFfaDxeLib.c @@ -98,15 +98,32 @@ ArmFfaDxeLibConstructor ( return EFI_SUCCESS; } - /* - * If PEIM uses ArmFfaPeiLib, the Rx/Tx buffers is already mapped in PEI phase. - * In this case, get Rx/Tx buffer info from Hob. - */ RxTxBufferHob = GetFirstGuidHob (&gArmFfaRxTxBufferInfoGuid); if (RxTxBufferHob != NULL) { BufferInfo = GET_GUID_HOB_DATA (RxTxBufferHob); - PcdSet64S (PcdFfaTxBuffer, (UINTN)BufferInfo->TxBufferAddr); - PcdSet64S (PcdFfaRxBuffer, (UINTN)BufferInfo->RxBufferAddr); + if (!BufferInfo->RemapRequired) { + /* + * ArmFfaPeiLib handles the Rx/Tx buffer Remap and update the + * BufferInfo with permanant memory. So use it as it is. + */ + PcdSet64S (PcdFfaTxBuffer, (UINTN)BufferInfo->TxBufferAddr); + PcdSet64S (PcdFfaRxBuffer, (UINTN)BufferInfo->RxBufferAddr); + } else { + /* + * SEC maps Rx/Tx buffer, But no PEIM module doesn't use + * ArmFfaPeiLib. In this case, the BufferInfo includes + * temporary Rx/Tx buffer address. + * + * Therefore, remap Rx/Tx buffer with migrated address again. + */ + Status = RemapFfaRxTxBuffer (BufferInfo); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Failed to remap Rx/Tx buffer... Status: %r\n", __func__, Status)); + return Status; + } + + BufferInfo->RemapRequired = FALSE; + } } else { Status = ArmFfaLibRxTxMap (); diff --git a/MdeModulePkg/Library/ArmFfaLib/ArmFfaSecLib.c b/MdeModulePkg/Library/ArmFfaLib/ArmFfaSecLib.c new file mode 100644 index 0000000000..fb62e61eda --- /dev/null +++ b/MdeModulePkg/Library/ArmFfaLib/ArmFfaSecLib.c @@ -0,0 +1,107 @@ +/** @file + Arm Ffa library code for PeilessSec + + Copyright (c) 2025, Arm Limited. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + + @par Glossary: + - FF-A - Firmware Framework for Arm A-profile + + @par Reference(s): + - Arm Firmware Framework for Arm A-Profile [https://developer.arm.com/documentation/den0077/latest] + +**/ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include "ArmFfaCommon.h" +#include "ArmFfaRxTxMap.h" + +/** + ArmFfaLib Constructor. + + @param [in] FileHandle File Handle + @param [in] PeiServices Pei Service Table + + @retval EFI_SUCCESS Success + @retval Others Error + +**/ +EFI_STATUS +EFIAPI +ArmFfaSecLibConstructor ( + IN VOID + ) +{ + EFI_STATUS Status; + ARM_FFA_RX_TX_BUFFER_INFO *BufferInfo; + EFI_HOB_MEMORY_ALLOCATION *RxTxBufferAllocationHob; + + Status = ArmFfaLibCommonInit (); + if (EFI_ERROR (Status)) { + if (Status == EFI_UNSUPPORTED) { + /* + * EFI_UNSUPPORTED return from ArmFfaLibCommonInit() means + * FF-A interface doesn't support. + * However, It doesn't make failure of loading driver/library instance + * (i.e) ArmPkg's MmCommunication Dxe/PEI Driver uses as well as SpmMm. + * So If FF-A is not supported the the MmCommunication Dxe/PEI falls + * back to SpmMm. + * For this case, return EFI_SUCCESS. + */ + return EFI_SUCCESS; + } + + return Status; + } + + Status = ArmFfaLibRxTxMap (); + if (EFI_ERROR (Status)) { + return Status; + } + + BufferInfo = BuildGuidHob ( + &gArmFfaRxTxBufferInfoGuid, + sizeof (ARM_FFA_RX_TX_BUFFER_INFO) + ); + if (BufferInfo == NULL) { + DEBUG ((DEBUG_ERROR, "%a: Failed to create Rx/Tx Buffer Info Hob\n", __func__)); + ArmFfaLibRxTxUnmap (); + return EFI_OUT_OF_RESOURCES; + } + + RxTxBufferAllocationHob = FindRxTxBufferAllocationHob (FALSE); + ASSERT (RxTxBufferAllocationHob != NULL); + + /* + * Set then Name with gArmFfaRxTxBufferInfoGuid, so that ArmFfaPeiLib or + * ArmFfaDxeLib can find the Rx/Tx buffer allocation area. + */ + CopyGuid ( + &RxTxBufferAllocationHob->AllocDescriptor.Name, + &gArmFfaRxTxBufferInfoGuid + ); + + UpdateRxTxBufferInfo (BufferInfo); + BufferInfo->RemapOffset = + (UINTN)((EFI_PHYSICAL_ADDRESS)((UINTN)BufferInfo->TxBufferAddr) - + RxTxBufferAllocationHob->AllocDescriptor.MemoryBaseAddress); + BufferInfo->RemapRequired = TRUE; + + return EFI_SUCCESS; +} diff --git a/MdeModulePkg/Library/ArmFfaLib/ArmFfaSecLib.inf b/MdeModulePkg/Library/ArmFfaLib/ArmFfaSecLib.inf new file mode 100644 index 0000000000..611de85eb4 --- /dev/null +++ b/MdeModulePkg/Library/ArmFfaLib/ArmFfaSecLib.inf @@ -0,0 +1,42 @@ +## @file +# Provides FF-A ABI Library used in PeilessSec +# +# Copyright (c) 2025, Arm Limited. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = ArmFfaSecLib + FILE_GUID = 7b2c2aa6-3e20-11f0-a8b6-db774bafa249 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = ArmFfaLib|SEC + CONSTRUCTOR = ArmFfaSecLibConstructor + +[Sources] + ArmFfaCommon.h + ArmFfaCommon.c + ArmFfaRxTxMap.h + ArmFfaSecRxTxMap.c + ArmFfaSecLib.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + ArmSmcLib + ArmSvcLib + BaseLib + BaseMemoryLib + DebugLib + HobLib + +[Pcd] + gEfiMdeModulePkgTokenSpaceGuid.PcdFfaLibConduitSmc + gEfiMdeModulePkgTokenSpaceGuid.PcdFfaTxRxPageCount + +[Guids] + gArmFfaRxTxBufferInfoGuid diff --git a/MdeModulePkg/Library/ArmFfaLib/ArmFfaSecRxTxMap.c b/MdeModulePkg/Library/ArmFfaLib/ArmFfaSecRxTxMap.c new file mode 100644 index 0000000000..fdc0dcefb9 --- /dev/null +++ b/MdeModulePkg/Library/ArmFfaLib/ArmFfaSecRxTxMap.c @@ -0,0 +1,363 @@ +/** @file + Arm Ffa library common code. + + Copyright (c) 2025, Arm Limited. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + + @par Glossary: + - FF-A - Firmware Framework for Arm A-profile + + @par Reference(s): + - Arm Firmware Framework for Arm A-Profile [https://developer.arm.com/documentation/den0077/latest] + +**/ +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include "ArmFfaCommon.h" +#include "ArmFfaRxTxMap.h" + +STATIC VOID *mTxBuffer; +STATIC VOID *mRxBuffer; + +/** + Get mapped Rx/Tx buffers. + + @param [out] TxBuffer Address of TxBuffer + @param [out] TxBufferSize Size of TxBuffer + @param [out] RxBuffer Address of RxBuffer + @param [out] RxBufferSize Size of RxBuffer + + @retval EFI_SUCCESS + @retval Others Error. + +**/ +EFI_STATUS +EFIAPI +ArmFfaLibGetRxTxBuffers ( + OUT VOID **TxBuffer OPTIONAL, + OUT UINT64 *TxBufferSize OPTIONAL, + OUT VOID **RxBuffer OPTIONAL, + OUT UINT64 *RxBufferSize OPTIONAL + ) +{ + if ((mTxBuffer == NULL) || (mRxBuffer == NULL)) { + return EFI_NOT_READY; + } + + if (TxBuffer != NULL) { + *TxBuffer = mTxBuffer; + } + + if (TxBufferSize != NULL) { + *TxBufferSize = PcdGet64 (PcdFfaTxRxPageCount) * EFI_PAGE_SIZE; + } + + if (RxBuffer != NULL) { + *RxBuffer = mRxBuffer; + } + + if (RxBufferSize != NULL) { + *RxBufferSize = PcdGet64 (PcdFfaTxRxPageCount) * EFI_PAGE_SIZE; + } + + return EFI_SUCCESS; +} + +/** + Mapping Rx/Tx buffers. + This function is only called in ArmFfaLibConstructor because + Rx/Tx buffer is registered only once per partition. + + @retval EFI_SUCCESS + @retval EFI_ALREADY_STARTED Rx/Tx buffer already mapped. + @retval EFI_OUT_OF_RESOURCE Out of memory + @retval EFI_INVALID_PARAMETER Invalid alignment of Rx/Tx buffer + @retval Others Error + +**/ +EFI_STATUS +EFIAPI +ArmFfaLibRxTxMap ( + IN VOID + ) +{ + EFI_STATUS Status; + ARM_FFA_ARGS FfaArgs; + UINTN Property1; + UINTN Property2; + UINTN MinSizeAndAlign; + UINTN MaxSize; + VOID *Buffers; + VOID *TxBuffer; + VOID *RxBuffer; + + /* + * If someone already mapped Rx/Tx Buffers, return EFI_ALREADY_STARTED. + * return EFI_ALREADY_STARTED. + */ + if ((mTxBuffer != NULL) && (mRxBuffer != NULL)) { + return EFI_ALREADY_STARTED; + } + + 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; + } + + ZeroMem (&FfaArgs, sizeof (ARM_FFA_ARGS)); + + 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; + } + + MaxSize = + (((Property1 >> + ARM_FFA_BUFFER_MAXSIZE_PAGE_COUNT_SHIFT) & + ARM_FFA_BUFFER_MAXSIZE_PAGE_COUNT_MASK)); + + MaxSize = ((MaxSize == 0) ? MAX_UINTN : (MaxSize * MinSizeAndAlign)); + + if ((MinSizeAndAlign > (PcdGet64 (PcdFfaTxRxPageCount) * EFI_PAGE_SIZE)) || + (MaxSize < (PcdGet64 (PcdFfaTxRxPageCount) * EFI_PAGE_SIZE))) + { + DEBUG (( + DEBUG_ERROR, + "%a: Buffer is too small! MinSize: 0x%x, MaxSize: 0x%x, PageCount: %d\n", + __func__, + MinSizeAndAlign, + MaxSize, + PcdGet64 (PcdFfaTxRxPageCount) + )); + return EFI_INVALID_PARAMETER; + } + + Buffers = AllocateAlignedPages ((PcdGet64 (PcdFfaTxRxPageCount) * 2), MinSizeAndAlign); + if (Buffers == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + TxBuffer = Buffers; + RxBuffer = Buffers + (PcdGet64 (PcdFfaTxRxPageCount) * EFI_PAGE_SIZE); + + FfaArgs.Arg0 = ARM_FID_FFA_RXTX_MAP; + FfaArgs.Arg1 = (UINTN)TxBuffer; + FfaArgs.Arg2 = (UINTN)RxBuffer; + + /* + * 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 Rx/Tx buffer. Status: %r\n", + __func__, + Status + )); + goto ErrorHandler; + } + + mTxBuffer = TxBuffer; + mRxBuffer = RxBuffer; + + return EFI_SUCCESS; + +ErrorHandler: + FreePages (Buffers, (PcdGet64 (PcdFfaTxRxPageCount) * 2)); + + return Status; +} + +/** + Unmap Rx/Tx buffer. + This function is only called in Exit boot service because + Rx/Tx buffer is registered only once per partition. + + @retval EFI_SUCCESS + @retval EFI_INVALID_PARAMETERS Already unregistered + @retval EFI_UNSUPPORTED Not supported + +**/ +EFI_STATUS +EFIAPI +ArmFfaLibRxTxUnmap ( + IN VOID + ) +{ + EFI_STATUS Status; + ARM_FFA_ARGS FfaArgs; + VOID *Buffers; + + 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)) { + return Status; + } + + /* + * Rx/Tx Buffer are allocated with continuous pages. + * and start address of these pages is set on PcdFfaTxBuffer. + * See ArmFfaLibRxTxMap(). + */ + Buffers = mTxBuffer; + if (Buffers != NULL) { + FreePages (Buffers, (PcdGet64 (PcdFfaTxRxPageCount) * 2)); + } + + mTxBuffer = NULL; + mRxBuffer = NULL; + + 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 = mTxBuffer; + BufferInfo->TxBufferSize = PcdGet64 (PcdFfaTxRxPageCount) * EFI_PAGE_SIZE; + BufferInfo->RxBufferAddr = mRxBuffer; + BufferInfo->RxBufferSize = PcdGet64 (PcdFfaTxRxPageCount) * EFI_PAGE_SIZE; +} + +/** + 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 + ) +{ + 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)((UINTN)mTxBuffer); + 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); + } + + 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 + ) +{ + /* + * SEC binary shouldn't remap the Rx/Tx Buffer. + */ + return EFI_UNSUPPORTED; +} diff --git a/MdeModulePkg/MdeModulePkg.dsc b/MdeModulePkg/MdeModulePkg.dsc index 0c530c70c1..2e0c665219 100644 --- a/MdeModulePkg/MdeModulePkg.dsc +++ b/MdeModulePkg/MdeModulePkg.dsc @@ -535,6 +535,7 @@ MdeModulePkg/Universal/CapsulePei/CapsuleX64.inf [Components.ARM, Components.AARCH64] + MdeModulePkg/Library/ArmFfaLib/ArmFfaSecLib.inf MdeModulePkg/Library/ArmFfaLib/ArmFfaPeiLib.inf MdeModulePkg/Library/ArmFfaLib/ArmFfaDxeLib.inf MdeModulePkg/Library/ArmFfaLib/ArmFfaStandaloneMmCoreLib.inf