mirror of
https://github.com/tianocore/edk2
synced 2026-08-27 00:23:19 -04:00
If a secure partition on AArch64 platforms would consume extended time to operate with peripherals, it might elect to yield the control back to normal world and expect the normal world to callback after hinted period of time. This change adds the FFA_YIELD handling from ArmFfaLib to support long operations from secure partitions. Timeout arguments are ignored because systems in this context cannot benefit from the timeout period. Treating FFA_YIELD like FFA_INTERRUPT and expecting the caller to invoke FFA_RUN is the least disruptive approach while achieving the intended behavior. This was tested on proprietary hardware platforms and booted to Windows. Signed-off-by: Kun Qin <kun.qin@microsoft.com>
935 lines
23 KiB
C
935 lines
23 KiB
C
/** @file
|
|
Arm Ffa library common code.
|
|
|
|
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/ArmFfaLib.h>
|
|
#include <Library/ArmSmcLib.h>
|
|
#include <Library/ArmSvcLib.h>
|
|
#include <Library/BaseLib.h>
|
|
#include <Library/BaseMemoryLib.h>
|
|
#include <Library/DebugLib.h>
|
|
#include <Library/HobLib.h>
|
|
#include <Library/PcdLib.h>
|
|
|
|
#include <IndustryStandard/ArmFfaSvc.h>
|
|
#include <IndustryStandard/ArmFfaPartInfo.h>
|
|
#include <IndustryStandard/ArmStdSmc.h>
|
|
|
|
#include <Guid/ArmFfaRxTxBufferInfo.h>
|
|
|
|
#include "ArmFfaCommon.h"
|
|
|
|
BOOLEAN gFfaSupported;
|
|
UINT16 gPartId;
|
|
|
|
/**
|
|
Convert EFI_STATUS to FFA return code.
|
|
|
|
@param [in] Status edk2 status code.
|
|
|
|
@retval ARM_FFA_RET_* return value correspond to EFI_STATUS.
|
|
|
|
**/
|
|
UINTN
|
|
EFIAPI
|
|
EfiStatusToFfaStatus (
|
|
IN EFI_STATUS Status
|
|
)
|
|
{
|
|
switch (Status) {
|
|
case EFI_SUCCESS:
|
|
return ARM_FFA_RET_SUCCESS;
|
|
case EFI_INVALID_PARAMETER:
|
|
return ARM_FFA_RET_INVALID_PARAMETERS;
|
|
case EFI_OUT_OF_RESOURCES:
|
|
return ARM_FFA_RET_NO_MEMORY;
|
|
case EFI_NO_RESPONSE:
|
|
return ARM_FFA_RET_BUSY;
|
|
case EFI_INTERRUPT_PENDING:
|
|
return ARM_FFA_RET_INTERRUPTED;
|
|
case EFI_ACCESS_DENIED:
|
|
return ARM_FFA_RET_DENIED;
|
|
case EFI_ABORTED:
|
|
return ARM_FFA_RET_ABORTED;
|
|
case EFI_NOT_FOUND:
|
|
return ARM_FFA_RET_NODATA;
|
|
case EFI_NOT_READY:
|
|
return ARM_FFA_RET_NOT_READY;
|
|
default:
|
|
return ARM_FFA_RET_NOT_SUPPORTED;
|
|
}
|
|
}
|
|
|
|
/**
|
|
Convert FFA return code to EFI_STATUS.
|
|
|
|
@param [in] FfaStatus Ffa return Status
|
|
|
|
@retval EFI_STATUS return value correspond EFI_STATUS to FfaStatus
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
FfaStatusToEfiStatus (
|
|
IN UINTN FfaStatus
|
|
)
|
|
{
|
|
switch ((UINT32)FfaStatus) {
|
|
case ARM_FFA_RET_SUCCESS:
|
|
return EFI_SUCCESS;
|
|
case ARM_FFA_RET_INVALID_PARAMETERS:
|
|
return EFI_INVALID_PARAMETER;
|
|
case ARM_FFA_RET_NO_MEMORY:
|
|
return EFI_OUT_OF_RESOURCES;
|
|
case ARM_FFA_RET_BUSY:
|
|
return EFI_NO_RESPONSE;
|
|
case ARM_FFA_RET_INTERRUPTED:
|
|
return EFI_INTERRUPT_PENDING;
|
|
case ARM_FFA_RET_DENIED:
|
|
return EFI_ACCESS_DENIED;
|
|
case ARM_FFA_RET_ABORTED:
|
|
return EFI_ABORTED;
|
|
case ARM_FFA_RET_NODATA:
|
|
return EFI_NOT_FOUND;
|
|
case ARM_FFA_RET_NOT_READY:
|
|
return EFI_NOT_READY;
|
|
default:
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
}
|
|
|
|
/**
|
|
Convert FfArgs to EFI_STATUS.
|
|
|
|
@param [in] FfaArgs Ffa arguments
|
|
|
|
@retval EFI_STATUS return value correspond EFI_STATUS to FfaStatus
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
FfaArgsToEfiStatus (
|
|
IN ARM_FFA_ARGS *FfaArgs
|
|
)
|
|
{
|
|
UINT32 FfaStatus;
|
|
|
|
if (FfaArgs == NULL) {
|
|
FfaStatus = ARM_FFA_RET_INVALID_PARAMETERS;
|
|
} else if (IS_FID_FFA_ERROR (FfaArgs->Arg0)) {
|
|
/*
|
|
* In case of error, the Arg0 will be set to the fid FFA_ERROR.
|
|
* and Error code is set in Arg2.
|
|
*/
|
|
FfaStatus = FfaArgs->Arg2;
|
|
} else if (FfaArgs->Arg0 == ARM_FFA_RET_NOT_SUPPORTED) {
|
|
/*
|
|
* If Some FF-A ABI doesn't support, it sets ARM_FFA_RET_NOT_SUPPORTED
|
|
* in Arg0 and other register has no meaning.
|
|
* In this case, set Arg2 as ARM_FFA_RET_NOT_SUPPORTED so that
|
|
* FfaStatusToEfiStatus (FfaARgs.Arg2) returns proper EFI_STATUS.
|
|
*/
|
|
FfaStatus = ARM_FFA_RET_NOT_SUPPORTED;
|
|
} else if ((FfaArgs->Arg0 == ARM_FID_FFA_INTERRUPT) || (FfaArgs->Arg0 == ARM_FID_FFA_YIELD)) {
|
|
FfaStatus = ARM_FFA_RET_INTERRUPTED;
|
|
} else {
|
|
FfaStatus = ARM_FFA_RET_SUCCESS;
|
|
}
|
|
|
|
return FfaStatusToEfiStatus (FfaStatus);
|
|
}
|
|
|
|
/**
|
|
Trigger FF-A ABI call according to PcdFfaLibConduitSmc.
|
|
|
|
@param [in, out] FfaArgs Ffa arguments
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
ArmCallFfa (
|
|
IN OUT ARM_FFA_ARGS *FfaArgs
|
|
)
|
|
{
|
|
if (PcdGetBool (PcdFfaLibConduitSmc)) {
|
|
ArmCallSmc ((ARM_SMC_ARGS *)FfaArgs);
|
|
} else {
|
|
ArmCallSvc ((ARM_SVC_ARGS *)FfaArgs);
|
|
}
|
|
}
|
|
|
|
/**
|
|
Check FF-A support or not.
|
|
|
|
@retval TRUE Supported
|
|
@retval FALSE Not supported
|
|
|
|
**/
|
|
BOOLEAN
|
|
EFIAPI
|
|
IsFfaSupported (
|
|
IN VOID
|
|
)
|
|
{
|
|
return gFfaSupported;
|
|
}
|
|
|
|
/**
|
|
Get FF-A version.
|
|
|
|
@param [in] RequestMajorVersion Minimal request major version
|
|
@param [in] RequestMinorVersion Minimal request minor version
|
|
@param [out] CurrentMajorVersion Current major version
|
|
@param [out] CurrentMinorVersion Current minor version
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
ArmFfaLibGetVersion (
|
|
IN UINT16 RequestMajorVersion,
|
|
IN UINT16 RequestMinorVersion,
|
|
OUT UINT16 *CurrentMajorVersion,
|
|
OUT UINT16 *CurrentMinorVersion
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
ARM_FFA_ARGS FfaArgs;
|
|
|
|
ZeroMem (&FfaArgs, sizeof (ARM_FFA_ARGS));
|
|
|
|
FfaArgs.Arg0 = ARM_FID_FFA_VERSION;
|
|
FfaArgs.Arg1 = ARM_FFA_CREATE_VERSION (
|
|
RequestMajorVersion,
|
|
RequestMinorVersion
|
|
);
|
|
|
|
ArmCallFfa (&FfaArgs);
|
|
|
|
Status = FfaArgsToEfiStatus (&FfaArgs);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
if (CurrentMajorVersion != NULL) {
|
|
*CurrentMajorVersion = ARM_FFA_MAJOR_VERSION_GET (FfaArgs.Arg0);
|
|
}
|
|
|
|
if (CurrentMinorVersion != NULL) {
|
|
*CurrentMinorVersion = ARM_FFA_MINOR_VERSION_GET (FfaArgs.Arg0);
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Get FF-A features.
|
|
|
|
@param [in] Id Feature id or function id
|
|
@param [in] InputProperties Input properties according to Id
|
|
@param [out] Property1 First property.
|
|
@param [out] Property2 Second property.
|
|
|
|
@retval EFI_SUCCESS
|
|
@retval Others Error
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
ArmFfaLibGetFeatures (
|
|
IN UINT32 Id,
|
|
IN UINT32 InputProperties,
|
|
OUT UINTN *Property1,
|
|
OUT UINTN *Property2
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
ARM_FFA_ARGS FfaArgs;
|
|
|
|
if ((Property1 == NULL) || (Property2 == NULL)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
*Property1 = 0x00;
|
|
*Property2 = 0x00;
|
|
|
|
switch (Id) {
|
|
case ARM_FID_FFA_RXTX_MAP_AARCH32:
|
|
case ARM_FID_FFA_RXTX_MAP_AARCH64:
|
|
if ((InputProperties != FFA_RXTX_MAP_INPUT_PROPERTY_DEFAULT)) {
|
|
DEBUG ((DEBUG_ERROR, "%a: Invalid Parameter for FunctionId: 0x%x", __func__, Id));
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
ZeroMem (&FfaArgs, sizeof (ARM_FFA_ARGS));
|
|
FfaArgs.Arg0 = ARM_FID_FFA_FEATURES;
|
|
FfaArgs.Arg1 = Id;
|
|
FfaArgs.Arg2 = InputProperties;
|
|
|
|
ArmCallFfa (&FfaArgs);
|
|
|
|
Status = FfaArgsToEfiStatus (&FfaArgs);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
switch (Id) {
|
|
case ARM_FID_FFA_RXTX_MAP_AARCH32:
|
|
case ARM_FID_FFA_RXTX_MAP_AARCH64:
|
|
case ARM_FFA_FEATURE_ID_NOTIFICATION_PENDING_INTERRUPT:
|
|
case ARM_FFA_FEATURE_ID_SCHEDULE_RECEIVER_INTERRUPT:
|
|
case ARM_FFA_FEATURE_ID_MANAGED_EXIT_INTERRUPT:
|
|
*Property1 = FfaArgs.Arg2;
|
|
break;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Acquire ownership of the Rx buffer.
|
|
|
|
@param [in] PartId Partition Id
|
|
|
|
@retval EFI_SUCCESS
|
|
@retval Others Error
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
ArmFfaLibRxAcquire (
|
|
IN UINT16 PartId
|
|
)
|
|
{
|
|
ARM_FFA_ARGS FfaArgs;
|
|
|
|
ZeroMem (&FfaArgs, sizeof (ARM_FFA_ARGS));
|
|
|
|
FfaArgs.Arg0 = ARM_FID_FFA_RX_ACQUIRE;
|
|
FfaArgs.Arg1 = PartId;
|
|
|
|
ArmCallFfa (&FfaArgs);
|
|
|
|
return FfaArgsToEfiStatus (&FfaArgs);
|
|
}
|
|
|
|
/**
|
|
Release ownership of the Rx buffer.
|
|
|
|
@param [in] PartId Partition Id
|
|
|
|
@retval EFI_SUCCESS
|
|
@retval Others Error
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
ArmFfaLibRxRelease (
|
|
IN UINT16 PartId
|
|
)
|
|
{
|
|
ARM_FFA_ARGS FfaArgs;
|
|
|
|
ZeroMem (&FfaArgs, sizeof (ARM_FFA_ARGS));
|
|
|
|
FfaArgs.Arg0 = ARM_FID_FFA_RX_RELEASE;
|
|
FfaArgs.Arg1 = PartId;
|
|
|
|
ArmCallFfa (&FfaArgs);
|
|
|
|
return FfaArgsToEfiStatus (&FfaArgs);
|
|
}
|
|
|
|
/**
|
|
Get partition or VM id.
|
|
|
|
@param [out] PartId Partition id
|
|
|
|
@retval EFI_SUCCESS
|
|
@retval Others Error
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
ArmFfaLibPartitionIdGet (
|
|
OUT UINT16 *PartId
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
ARM_FFA_ARGS FfaArgs;
|
|
|
|
if (PartId == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
ZeroMem (&FfaArgs, sizeof (ARM_FFA_ARGS));
|
|
|
|
FfaArgs.Arg0 = ARM_FID_FFA_ID_GET;
|
|
|
|
ArmCallFfa (&FfaArgs);
|
|
|
|
Status = FfaArgsToEfiStatus (&FfaArgs);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((
|
|
DEBUG_ERROR,
|
|
"%a: Failed to get partition id. Status: %r\n",
|
|
__func__,
|
|
Status
|
|
));
|
|
return Status;
|
|
}
|
|
|
|
*PartId = (FfaArgs.Arg2 >> ARM_FFA_DEST_EP_SHIFT) & ARM_FFA_PARTITION_ID_MASK;
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Get spmc or spmd partition id.
|
|
|
|
@param [out] SpmPartId spmc/spmd partition id
|
|
|
|
@retval EFI_SUCCESS
|
|
@retval Others Error
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
ArmFfaLibSpmIdGet (
|
|
OUT UINT16 *SpmPartId
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
ARM_FFA_ARGS FfaArgs;
|
|
|
|
if (SpmPartId == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
ZeroMem (&FfaArgs, sizeof (ARM_FFA_ARGS));
|
|
|
|
FfaArgs.Arg0 = ARM_FID_FFA_SPM_ID_GET;
|
|
|
|
ArmCallFfa (&FfaArgs);
|
|
|
|
Status = FfaArgsToEfiStatus (&FfaArgs);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((
|
|
DEBUG_ERROR,
|
|
"%a: Failed to get partition id. Status: %r\n",
|
|
__func__,
|
|
Status
|
|
));
|
|
return Status;
|
|
}
|
|
|
|
*SpmPartId = (FfaArgs.Arg2 >> ARM_FFA_DEST_EP_SHIFT) & ARM_FFA_PARTITION_ID_MASK;
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Get Partition info.
|
|
If This function is called to get partition descriptors
|
|
(Flags isn't set with FFA_PART_INFO_FLAG_TYPE_COUNT),
|
|
It should call ArmFfaLibRxRelease() to release RX buffer.
|
|
|
|
@param [in] ServiceGuid Service guid.
|
|
@param [in] Flags If this function called to get partition desc
|
|
and get successfully,
|
|
Caller should release RX buffer by calling
|
|
ArmFfaLibRxRelease
|
|
@param [out] Count Number of partition or partition descriptor
|
|
@param [out] Size Size of Partition Info structure in Rx Buffer
|
|
|
|
@retval EFI_SUCCESS
|
|
@retval Others Error
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
ArmFfaLibPartitionInfoGet (
|
|
IN EFI_GUID *ServiceGuid,
|
|
IN UINT32 Flags,
|
|
OUT UINT32 *Count,
|
|
OUT UINT32 *Size OPTIONAL
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
ARM_FFA_ARGS FfaArgs;
|
|
UINT64 Uuid[2];
|
|
UINT32 *SmcUuid;
|
|
|
|
if (Count == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
if ((((Flags >> FFA_PART_INFO_FLAG_TYPE_SHIFT) & FFA_PART_INFO_FLAG_TYPE_MASK) !=
|
|
FFA_PART_INFO_FLAG_TYPE_COUNT) && (Size == NULL))
|
|
{
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (ServiceGuid != NULL) {
|
|
ConvertGuidToUuid (ServiceGuid, (GUID *)Uuid);
|
|
} else {
|
|
ZeroMem (Uuid, sizeof (Uuid));
|
|
}
|
|
|
|
ZeroMem (&FfaArgs, sizeof (ARM_FFA_ARGS));
|
|
SmcUuid = (UINT32 *)Uuid;
|
|
|
|
FfaArgs.Arg0 = ARM_FID_FFA_PARTITION_INFO_GET;
|
|
FfaArgs.Arg1 = SmcUuid[0];
|
|
FfaArgs.Arg2 = SmcUuid[1];
|
|
FfaArgs.Arg3 = SmcUuid[2];
|
|
FfaArgs.Arg4 = SmcUuid[3];
|
|
FfaArgs.Arg5 = Flags;
|
|
|
|
ArmCallFfa (&FfaArgs);
|
|
|
|
Status = FfaArgsToEfiStatus (&FfaArgs);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((
|
|
DEBUG_ERROR,
|
|
"%a: Failed to get partition information of %g. Status: %r\n",
|
|
__func__,
|
|
(ServiceGuid != NULL) ? ServiceGuid : (EFI_GUID *)Uuid,
|
|
Status
|
|
));
|
|
goto ErrorHandler;
|
|
}
|
|
|
|
*Count = FfaArgs.Arg2;
|
|
if (Size != NULL) {
|
|
*Size = FfaArgs.Arg3;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
ErrorHandler:
|
|
*Count = 0;
|
|
if (Size != NULL) {
|
|
*Size = 0;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Restore the context which was interrupted with FFA_INTERRUPT (EFI_INTERRUPT_PENDING).
|
|
|
|
@param [in] PartId Partition id
|
|
@param [in] CpuNumber Cpu number in partition
|
|
@param [out] DirectMsgArg return arguments for direct msg resp/resp2
|
|
|
|
@retval EFI_SUCCESS
|
|
@retval Other Error
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
ArmFfaLibRun (
|
|
IN UINT16 PartId,
|
|
IN UINT16 CpuNumber,
|
|
OUT DIRECT_MSG_ARGS *DirectMsgArg OPTIONAL
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
ARM_FFA_ARGS FfaArgs;
|
|
|
|
ZeroMem (&FfaArgs, sizeof (ARM_FFA_ARGS));
|
|
|
|
FfaArgs.Arg0 = ARM_FID_FFA_RUN;
|
|
FfaArgs.Arg1 = PACK_PARTITION_ID_INFO (PartId, CpuNumber);
|
|
|
|
ArmCallFfa (&FfaArgs);
|
|
|
|
Status = FfaArgsToEfiStatus (&FfaArgs);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
if (DirectMsgArg != NULL) {
|
|
ZeroMem (DirectMsgArg, sizeof (DIRECT_MSG_ARGS));
|
|
|
|
if (FfaArgs.Arg0 == ARM_FID_FFA_MSG_SEND_DIRECT_RESP) {
|
|
DirectMsgArg->Arg0 = FfaArgs.Arg3;
|
|
DirectMsgArg->Arg1 = FfaArgs.Arg4;
|
|
DirectMsgArg->Arg2 = FfaArgs.Arg5;
|
|
DirectMsgArg->Arg3 = FfaArgs.Arg6;
|
|
DirectMsgArg->Arg4 = FfaArgs.Arg7;
|
|
} else if (FfaArgs.Arg0 == ARM_FID_FFA_MSG_SEND_DIRECT_RESP2) {
|
|
DirectMsgArg->Arg0 = FfaArgs.Arg4;
|
|
DirectMsgArg->Arg1 = FfaArgs.Arg5;
|
|
DirectMsgArg->Arg2 = FfaArgs.Arg6;
|
|
DirectMsgArg->Arg3 = FfaArgs.Arg7;
|
|
DirectMsgArg->Arg4 = FfaArgs.Arg8;
|
|
DirectMsgArg->Arg5 = FfaArgs.Arg9;
|
|
DirectMsgArg->Arg6 = FfaArgs.Arg10;
|
|
DirectMsgArg->Arg7 = FfaArgs.Arg11;
|
|
DirectMsgArg->Arg8 = FfaArgs.Arg12;
|
|
DirectMsgArg->Arg9 = FfaArgs.Arg13;
|
|
DirectMsgArg->Arg10 = FfaArgs.Arg14;
|
|
DirectMsgArg->Arg11 = FfaArgs.Arg15;
|
|
DirectMsgArg->Arg12 = FfaArgs.Arg16;
|
|
DirectMsgArg->Arg13 = FfaArgs.Arg17;
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Send direct message request version 1.
|
|
|
|
@param [in] DestPartId Dest partition id
|
|
@param [in] Flags Message flags
|
|
@param [in, out] ImpDefArgs Implemented defined arguments and
|
|
Implemented defined return values
|
|
|
|
@retval EFI_SUCCESS Success
|
|
@retval Others Error
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
ArmFfaLibMsgSendDirectReq (
|
|
IN UINT16 DestPartId,
|
|
IN UINT32 Flags,
|
|
IN OUT DIRECT_MSG_ARGS *ImpDefArgs
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
ARM_FFA_ARGS FfaArgs;
|
|
|
|
if ((DestPartId == gPartId) || (ImpDefArgs == NULL)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
ZeroMem (&FfaArgs, sizeof (ARM_FFA_ARGS));
|
|
|
|
FfaArgs.Arg0 = ARM_FID_FFA_MSG_SEND_DIRECT_REQ;
|
|
FfaArgs.Arg1 = PACK_PARTITION_ID_INFO (gPartId, DestPartId);
|
|
FfaArgs.Arg2 = Flags;
|
|
FfaArgs.Arg3 = ImpDefArgs->Arg0;
|
|
FfaArgs.Arg4 = ImpDefArgs->Arg1;
|
|
FfaArgs.Arg5 = ImpDefArgs->Arg2;
|
|
FfaArgs.Arg6 = ImpDefArgs->Arg3;
|
|
FfaArgs.Arg7 = ImpDefArgs->Arg4;
|
|
|
|
ArmCallFfa (&FfaArgs);
|
|
|
|
Status = FfaArgsToEfiStatus (&FfaArgs);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
ImpDefArgs->Arg0 = FfaArgs.Arg3;
|
|
ImpDefArgs->Arg1 = FfaArgs.Arg4;
|
|
ImpDefArgs->Arg2 = FfaArgs.Arg5;
|
|
ImpDefArgs->Arg3 = FfaArgs.Arg6;
|
|
ImpDefArgs->Arg4 = FfaArgs.Arg7;
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Send direct message request version 2.
|
|
|
|
@param [in] DestPartId Dest partition id
|
|
@param [in] ServiceGuid Service guid
|
|
@param [in, out] ImpDefArgs Implemented defined arguments and
|
|
Implemented defined return values
|
|
|
|
@retval EFI_SUCCESS Success
|
|
@retval Others Error
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
ArmFfaLibMsgSendDirectReq2 (
|
|
IN UINT16 DestPartId,
|
|
IN EFI_GUID *ServiceGuid,
|
|
IN OUT DIRECT_MSG_ARGS *ImpDefArgs
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT64 Uuid[2];
|
|
ARM_FFA_ARGS FfaArgs;
|
|
|
|
/*
|
|
* Direct message request 2 is only supported on AArch64.
|
|
*/
|
|
if (sizeof (UINTN) != sizeof (UINT64)) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
if ((DestPartId == gPartId) || (ImpDefArgs == NULL)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (ServiceGuid != NULL) {
|
|
ConvertGuidToUuid (ServiceGuid, (GUID *)Uuid);
|
|
} else {
|
|
ZeroMem (Uuid, sizeof (Uuid));
|
|
}
|
|
|
|
ZeroMem (&FfaArgs, sizeof (ARM_FFA_ARGS));
|
|
|
|
FfaArgs.Arg0 = ARM_FID_FFA_MSG_SEND_DIRECT_REQ2;
|
|
FfaArgs.Arg1 = PACK_PARTITION_ID_INFO (gPartId, DestPartId);
|
|
FfaArgs.Arg2 = Uuid[0];
|
|
FfaArgs.Arg3 = Uuid[1];
|
|
FfaArgs.Arg4 = ImpDefArgs->Arg0;
|
|
FfaArgs.Arg5 = ImpDefArgs->Arg1;
|
|
FfaArgs.Arg6 = ImpDefArgs->Arg2;
|
|
FfaArgs.Arg7 = ImpDefArgs->Arg3;
|
|
FfaArgs.Arg8 = ImpDefArgs->Arg4;
|
|
FfaArgs.Arg9 = ImpDefArgs->Arg5;
|
|
FfaArgs.Arg10 = ImpDefArgs->Arg6;
|
|
FfaArgs.Arg11 = ImpDefArgs->Arg7;
|
|
FfaArgs.Arg12 = ImpDefArgs->Arg8;
|
|
FfaArgs.Arg13 = ImpDefArgs->Arg9;
|
|
FfaArgs.Arg14 = ImpDefArgs->Arg10;
|
|
FfaArgs.Arg15 = ImpDefArgs->Arg11;
|
|
FfaArgs.Arg16 = ImpDefArgs->Arg12;
|
|
FfaArgs.Arg17 = ImpDefArgs->Arg13;
|
|
|
|
ArmCallFfa (&FfaArgs);
|
|
|
|
Status = FfaArgsToEfiStatus (&FfaArgs);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
ImpDefArgs->Arg0 = FfaArgs.Arg4;
|
|
ImpDefArgs->Arg1 = FfaArgs.Arg5;
|
|
ImpDefArgs->Arg2 = FfaArgs.Arg6;
|
|
ImpDefArgs->Arg3 = FfaArgs.Arg7;
|
|
ImpDefArgs->Arg4 = FfaArgs.Arg8;
|
|
ImpDefArgs->Arg5 = FfaArgs.Arg9;
|
|
ImpDefArgs->Arg6 = FfaArgs.Arg10;
|
|
ImpDefArgs->Arg7 = FfaArgs.Arg11;
|
|
ImpDefArgs->Arg8 = FfaArgs.Arg12;
|
|
ImpDefArgs->Arg9 = FfaArgs.Arg13;
|
|
ImpDefArgs->Arg10 = FfaArgs.Arg14;
|
|
ImpDefArgs->Arg11 = FfaArgs.Arg15;
|
|
ImpDefArgs->Arg12 = FfaArgs.Arg16;
|
|
ImpDefArgs->Arg13 = FfaArgs.Arg17;
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Common ArmFfaLib init.
|
|
|
|
@retval EFI_SUCCESS Success
|
|
@retval EFI_UNSUPPORTED FF-A isn't supported
|
|
@retval Others Error
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
ArmFfaLibCommonInit (
|
|
IN VOID
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT16 CurrentMajorVersion;
|
|
UINT16 CurrentMinorVersion;
|
|
|
|
gFfaSupported = FALSE;
|
|
|
|
Status = ArmFfaLibGetVersion (
|
|
ARM_FFA_MAJOR_VERSION,
|
|
ARM_FFA_MINOR_VERSION,
|
|
&CurrentMajorVersion,
|
|
&CurrentMinorVersion
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
if ((ARM_FFA_MAJOR_VERSION != CurrentMajorVersion) ||
|
|
(ARM_FFA_MINOR_VERSION > CurrentMinorVersion))
|
|
{
|
|
DEBUG ((
|
|
DEBUG_INFO,
|
|
"Incompatible FF-A Versions.\n" \
|
|
"Request Version: Major=0x%x, Minor=0x%x.\n" \
|
|
"Current Version: Major=0x%x, Minor>=0x%x.\n",
|
|
ARM_FFA_MAJOR_VERSION,
|
|
ARM_FFA_MINOR_VERSION,
|
|
CurrentMajorVersion,
|
|
CurrentMinorVersion
|
|
));
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
Status = ArmFfaLibPartitionIdGet (&gPartId);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
gFfaSupported = TRUE;
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Get first Rx/Tx Buffer allocation hob.
|
|
If UseGuid is TRUE, BufferAddr and BufferSize parameters are ignored.
|
|
|
|
@param[in] BufferAddr Buffer address
|
|
@param[in] BufferSize Buffer Size
|
|
@param[in] UseGuid Find MemoryAllocationHob using gArmFfaRxTxBufferInfoGuid.
|
|
|
|
@retval NULL Not found
|
|
@retval Other MemoryAllocationHob related to Rx/Tx buffer
|
|
|
|
**/
|
|
EFI_HOB_MEMORY_ALLOCATION *
|
|
EFIAPI
|
|
GetRxTxBufferAllocationHob (
|
|
IN EFI_PHYSICAL_ADDRESS BufferAddr,
|
|
IN UINT64 BufferSize,
|
|
IN BOOLEAN UseGuid
|
|
)
|
|
{
|
|
EFI_PEI_HOB_POINTERS Hob;
|
|
EFI_HOB_MEMORY_ALLOCATION *MemoryAllocationHob;
|
|
EFI_PHYSICAL_ADDRESS MemoryBase;
|
|
UINT64 MemorySize;
|
|
|
|
if (!UseGuid && (BufferAddr == 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 && (BufferAddr >= MemoryBase) &&
|
|
((BufferAddr + 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;
|
|
}
|
|
|
|
/**
|
|
Get Rx/Tx buffer MinSizeAndAign and MaxSize
|
|
|
|
@param[out] MinSizeAndAlign Minimum size of Buffer.
|
|
|
|
@retval EFI_SUCCESS
|
|
@retval EFI_UNSUPPORTED Wrong min size received from SPMC
|
|
@retval EFI_INVALID_PARAMETER Wrong buffer size
|
|
@retval Others Failure of ArmFfaLibGetFeatures()
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
GetRxTxBufferMinSizeAndAlign (
|
|
OUT UINTN *MinSizeAndAlign
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN MinAndAlign;
|
|
UINTN MaxSize;
|
|
UINTN Property1;
|
|
UINTN Property2;
|
|
|
|
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;
|
|
}
|
|
|
|
MinAndAlign =
|
|
((Property1 >>
|
|
ARM_FFA_BUFFER_MINSIZE_AND_ALIGN_SHIFT) &
|
|
ARM_FFA_BUFFER_MINSIZE_AND_ALIGN_MASK);
|
|
|
|
switch (MinAndAlign) {
|
|
case ARM_FFA_BUFFER_MINSIZE_AND_ALIGN_4K:
|
|
MinAndAlign = SIZE_4KB;
|
|
break;
|
|
case ARM_FFA_BUFFER_MINSIZE_AND_ALIGN_16K:
|
|
MinAndAlign = SIZE_16KB;
|
|
break;
|
|
case ARM_FFA_BUFFER_MINSIZE_AND_ALIGN_64K:
|
|
MinAndAlign = SIZE_64KB;
|
|
break;
|
|
default:
|
|
DEBUG ((DEBUG_ERROR, "%a: Invalid MinSizeAndAlign: 0x%x\n", __func__, MinAndAlign));
|
|
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 * MinAndAlign));
|
|
|
|
if ((MinAndAlign > (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__,
|
|
MinAndAlign,
|
|
MaxSize,
|
|
PcdGet64 (PcdFfaTxRxPageCount)
|
|
));
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
*MinSizeAndAlign = MinAndAlign;
|
|
|
|
return EFI_SUCCESS;
|
|
}
|