/** @file | |
Arm Ffa library code for Dxe Driver | |
Copyright (c) 2024, 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/ArmSmcLib.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" | |
STATIC EFI_EVENT mFfaExitBootServiceEvent; | |
/** | |
Unmap RX/TX buffer on Exit Boot Service. | |
@param [in] Event Registered exit boot service event. | |
@param [in] Context Additional data. | |
**/ | |
STATIC | |
VOID | |
EFIAPI | |
ArmFfaLibExitBootServiceEvent ( | |
IN EFI_EVENT Event, | |
IN VOID *Context | |
) | |
{ | |
ArmFfaLibRxTxUnmap (); | |
} | |
/** | |
ArmFfaLib Constructor. | |
@param [in] ImageHandle Image Handle | |
@param [in] SystemTable System Table | |
@retval EFI_SUCCESS Success | |
@retval EFI_INVALID_PARAMETER Invalid alignment of Rx/Tx buffer | |
@retval EFI_OUT_OF_RESOURCES Out of memory | |
@retval Others Error | |
**/ | |
EFI_STATUS | |
EFIAPI | |
ArmFfaDxeLibConstructor ( | |
IN EFI_HANDLE ImageHandle, | |
IN EFI_SYSTEM_TABLE *SystemTable | |
) | |
{ | |
EFI_STATUS Status; | |
EFI_HOB_GUID_TYPE *RxTxBufferHob; | |
ARM_FFA_RX_TX_BUFFER_INFO *BufferInfo; | |
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; | |
} | |
if (PcdGetBool (PcdFfaExitBootEventRegistered)) { | |
return EFI_SUCCESS; | |
} | |
RxTxBufferHob = GetFirstGuidHob (&gArmFfaRxTxBufferInfoGuid); | |
if (RxTxBufferHob != NULL) { | |
BufferInfo = GET_GUID_HOB_DATA (RxTxBufferHob); | |
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 (); | |
/* | |
* When first Dxe instance (library or driver) which uses ArmFfaLib loaded, | |
* It already maps Rx/Tx buffer. | |
* From Next Dxe instance which uses ArmFfaLib it doesn't need to map Rx/Tx | |
* buffer again but it uses the mapped one. | |
* ArmFfaLibRxTxMap() returns EFI_ALREADY_STARTED when the Rx/Tx buffers | |
* already maps. | |
*/ | |
if ((Status != EFI_SUCCESS) && (Status != EFI_ALREADY_STARTED)) { | |
DEBUG (( | |
DEBUG_ERROR, | |
"%a: Failed to Map Rx/Tx buffer. Status: %r\n", | |
__func__, | |
Status | |
)); | |
return Status; | |
} | |
} | |
Status = gBS->CreateEventEx ( | |
EVT_NOTIFY_SIGNAL, | |
TPL_CALLBACK, | |
ArmFfaLibExitBootServiceEvent, | |
NULL, | |
&gEfiEventExitBootServicesGuid, | |
&mFfaExitBootServiceEvent | |
); | |
if (EFI_ERROR (Status)) { | |
DEBUG (( | |
DEBUG_ERROR, | |
"%a: Failed to register ExitBootService event. Status: %r\n", | |
__func__, | |
Status | |
)); | |
goto ErrorHandler; | |
} | |
PcdSetBoolS (PcdFfaExitBootEventRegistered, TRUE); | |
return EFI_SUCCESS; | |
ErrorHandler: | |
if (RxTxBufferHob != NULL) { | |
ArmFfaLibRxTxUnmap (); | |
} | |
return Status; | |
} |