mirror of
https://github.com/tianocore/edk2
synced 2026-08-27 00:23:19 -04:00
Replaced all instances of PcdGet64 (PcdFfaTxRxPageCount) * EFI_PAGE_SIZE, with EFI_PAGES_TO_SIZE macro. Signed-off-by: Raymond Diaz <raymonddiaz@microsoft.com>
411 lines
12 KiB
C
411 lines
12 KiB
C
/** @file
|
|
Arm Ffa library common code.
|
|
|
|
Copyright (c) 2025, Arm Limited. All rights reserved.<BR>
|
|
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 <Uefi.h>
|
|
#include <Pi/PiMultiPhase.h>
|
|
|
|
#include <Library/ArmLib.h>
|
|
#include <Library/ArmFfaLib.h>
|
|
#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"
|
|
|
|
/**
|
|
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
|
|
)
|
|
{
|
|
EFI_HOB_MEMORY_ALLOCATION *RxTxBufferAllocationHob;
|
|
UINT64 BufferSize;
|
|
|
|
/*
|
|
* Attempt to find the allocation HOB, if it exists then the
|
|
* Rx/Tx buffers have already been mapped.
|
|
*/
|
|
RxTxBufferAllocationHob = FindRxTxBufferAllocationHob (TRUE);
|
|
if (RxTxBufferAllocationHob == NULL) {
|
|
return EFI_NOT_READY;
|
|
}
|
|
|
|
BufferSize = EFI_PAGES_TO_SIZE (PcdGet64 (PcdFfaTxRxPageCount));
|
|
|
|
if (TxBuffer != NULL) {
|
|
*TxBuffer = (VOID *)RxTxBufferAllocationHob->AllocDescriptor.MemoryBaseAddress;
|
|
}
|
|
|
|
if (TxBufferSize != NULL) {
|
|
*TxBufferSize = BufferSize;
|
|
}
|
|
|
|
if (RxBuffer != NULL) {
|
|
*RxBuffer = (VOID *)RxTxBufferAllocationHob->AllocDescriptor.MemoryBaseAddress + BufferSize;
|
|
}
|
|
|
|
if (RxBufferSize != NULL) {
|
|
*RxBufferSize = BufferSize;
|
|
}
|
|
|
|
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;
|
|
ARM_FFA_RX_TX_BUFFER_INFO *BufferInfo;
|
|
EFI_HOB_MEMORY_ALLOCATION *RxTxBufferAllocationHob;
|
|
UINT16 PartId;
|
|
|
|
/*
|
|
* Attempt to find the allocation HOB, if it exists then the
|
|
* Rx/Tx buffers have already been mapped.
|
|
*/
|
|
RxTxBufferAllocationHob = FindRxTxBufferAllocationHob (TRUE);
|
|
if (RxTxBufferAllocationHob != 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 > (EFI_PAGES_TO_SIZE (PcdGet64 (PcdFfaTxRxPageCount)))) ||
|
|
(MaxSize < (EFI_PAGES_TO_SIZE (PcdGet64 (PcdFfaTxRxPageCount)))))
|
|
{
|
|
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 + (EFI_PAGES_TO_SIZE (PcdGet64 (PcdFfaTxRxPageCount)));
|
|
|
|
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;
|
|
}
|
|
|
|
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__));
|
|
goto Unmap;
|
|
}
|
|
|
|
RxTxBufferAllocationHob = GetRxTxBufferAllocationHob ((EFI_PHYSICAL_ADDRESS)((UINTN)TxBuffer), EFI_PAGES_TO_SIZE (PcdGet64 (PcdFfaTxRxPageCount)) * 2, FALSE);
|
|
if (RxTxBufferAllocationHob == NULL) {
|
|
DEBUG ((DEBUG_ERROR, "%a: Failed to acquire RxTxBufferAllocationHob\n", __func__));
|
|
goto Unmap;
|
|
}
|
|
|
|
/*
|
|
* Set then Name with gArmFfaRxTxBufferInfoGuid, so that ArmFfaPeiLib or
|
|
* ArmFfaDxeLib can find the Rx/Tx buffer allocation area.
|
|
*/
|
|
CopyGuid (&RxTxBufferAllocationHob->AllocDescriptor.Name, &gArmFfaRxTxBufferInfoGuid);
|
|
|
|
BufferInfo->TxBufferAddr = (UINTN)RxTxBufferAllocationHob->AllocDescriptor.MemoryBaseAddress;
|
|
BufferInfo->TxBufferSize = EFI_PAGES_TO_SIZE (PcdGet64 (PcdFfaTxRxPageCount));
|
|
BufferInfo->RxBufferAddr = (UINTN)RxTxBufferAllocationHob->AllocDescriptor.MemoryBaseAddress + BufferInfo->TxBufferSize;
|
|
BufferInfo->RxBufferSize = EFI_PAGES_TO_SIZE (PcdGet64 (PcdFfaTxRxPageCount));
|
|
BufferInfo->RemapOffset = (UINTN)(BufferInfo->TxBufferAddr - RxTxBufferAllocationHob->AllocDescriptor.MemoryBaseAddress);
|
|
BufferInfo->RemapRequired = TRUE;
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
Unmap:
|
|
Status = ArmFfaLibPartitionIdGet (&PartId);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, "%a, Failed to acquire partition ID. Status: %r\n", __func__, Status));
|
|
goto ErrorHandler;
|
|
}
|
|
|
|
ZeroMem (&FfaArgs, sizeof (ARM_FFA_ARGS));
|
|
|
|
FfaArgs.Arg0 = ARM_FID_FFA_RXTX_UNMAP;
|
|
FfaArgs.Arg1 = (PartId << 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));
|
|
goto ErrorHandler;
|
|
}
|
|
|
|
/*
|
|
* If we successfully unmap, we only got here if we were
|
|
* unable to build the HOB or find the allocation HOB. Due
|
|
* to Status being overwritten we still need to indicate a
|
|
* failure occurred.
|
|
*/
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
|
|
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;
|
|
UINT16 PartId;
|
|
EFI_HOB_MEMORY_ALLOCATION *RxTxBufferAllocationHob;
|
|
|
|
/*
|
|
* Rx/Tx buffers are allocated with continuous pages.
|
|
* See ArmFfaLibRxTxMap(). If HOB is not found, the Rx/Tx
|
|
* buffers were not successfully mapped.
|
|
*/
|
|
RxTxBufferAllocationHob = FindRxTxBufferAllocationHob (TRUE);
|
|
if (RxTxBufferAllocationHob == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
Status = ArmFfaLibPartitionIdGet (&PartId);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, "%a, Failed to acquire partition ID. Status: %r\n", __func__, Status));
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
ZeroMem (&FfaArgs, sizeof (ARM_FFA_ARGS));
|
|
|
|
FfaArgs.Arg0 = ARM_FID_FFA_RXTX_UNMAP;
|
|
FfaArgs.Arg1 = (PartId << ARM_FFA_SOURCE_EP_SHIFT);
|
|
|
|
ArmCallFfa (&FfaArgs);
|
|
|
|
Status = FfaArgsToEfiStatus (&FfaArgs);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
Buffers = (VOID *)RxTxBufferAllocationHob->AllocDescriptor.MemoryBaseAddress;
|
|
if (Buffers != NULL) {
|
|
FreePages (Buffers, (PcdGet64 (PcdFfaTxRxPageCount) * 2));
|
|
}
|
|
|
|
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
|
|
)
|
|
{
|
|
EFI_HOB_MEMORY_ALLOCATION *RxTxBufferAllocationHob;
|
|
|
|
/*
|
|
* Attempt to find the HOB containing the Rx/Tx buffer information.
|
|
* If it is not found, the Rx/Tx buffers were not successfully mapped.
|
|
*/
|
|
RxTxBufferAllocationHob = FindRxTxBufferAllocationHob (TRUE);
|
|
|
|
if ((RxTxBufferAllocationHob != NULL) && (BufferInfo != NULL)) {
|
|
BufferInfo->TxBufferAddr = (UINTN)RxTxBufferAllocationHob->AllocDescriptor.MemoryBaseAddress;
|
|
BufferInfo->TxBufferSize = EFI_PAGES_TO_SIZE (PcdGet64 (PcdFfaTxRxPageCount));
|
|
BufferInfo->RxBufferAddr = (UINTN)RxTxBufferAllocationHob->AllocDescriptor.MemoryBaseAddress + BufferInfo->TxBufferSize;
|
|
BufferInfo->RxBufferSize = EFI_PAGES_TO_SIZE (PcdGet64 (PcdFfaTxRxPageCount));
|
|
}
|
|
}
|
|
|
|
/**
|
|
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
|
|
)
|
|
{
|
|
(void)UseGuid;
|
|
|
|
/*
|
|
* Mapping the Rx/Tx buffer should have generated the HOB, if not,
|
|
* then the allocation HOB will not be found and NULL will be returned.
|
|
* Note that BufferAddr and BufferSize are ignored when UseGuid is TRUE.
|
|
*/
|
|
return GetRxTxBufferAllocationHob (0, 0, TRUE);
|
|
}
|
|
|
|
/**
|
|
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;
|
|
}
|