ArmPkg/MmCommunicationPei: Mmcommunication via FF-A

Support Mmcommunication protocol via FF-A with StandaloneMm.
For this, FF-A v1.2 is required.

Signed-off-by: Levi Yun <yeoreum.yun@arm.com>
This commit is contained in:
Levi Yun 2024-08-06 09:57:25 +01:00 committed by mergify[bot]
parent 9f9a3de9e4
commit 73b2831879
2 changed files with 372 additions and 69 deletions

View File

@ -14,12 +14,339 @@
#include <Library/BaseLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/ArmFfaLib.h>
#include <Library/ArmSmcLib.h>
#include <Library/DebugLib.h>
#include <Library/PcdLib.h>
#include <Library/PeimEntryPoint.h>
#include <Library/PeiServicesLib.h>
#define MM_MAJOR_VER_MASK 0xEFFF0000
#define MM_MINOR_VER_MASK 0x0000FFFF
#define MM_MAJOR_VER_SHIFT 16
#define MM_MAJOR_VER(x) (((x) & MM_MAJOR_VER_MASK) >> MM_MAJOR_VER_SHIFT)
#define MM_MINOR_VER(x) ((x) & MM_MINOR_VER_MASK)
#define MM_CALLER_MAJOR_VER 0x1UL
#define MM_CALLER_MINOR_VER 0x0
//
// Partition ID if FF-A support is enabled
//
STATIC UINT16 mPartId;
STATIC UINT16 mStMmPartId;
/**
Check mm communication compatibility when use SPM_MM.
**/
STATIC
EFI_STATUS
EFIAPI
GetMmCompatibility (
VOID
)
{
EFI_STATUS Status;
UINT32 MmVersion;
ARM_SMC_ARGS MmVersionArgs;
// MM_VERSION uses SMC32 calling conventions
MmVersionArgs.Arg0 = ARM_SMC_ID_MM_VERSION_AARCH32;
ArmCallSmc (&MmVersionArgs);
if (MmVersionArgs.Arg0 == ARM_SMC_MM_RET_NOT_SUPPORTED) {
return EFI_UNSUPPORTED;
}
MmVersion = MmVersionArgs.Arg0;
if ((MM_MAJOR_VER (MmVersion) == MM_CALLER_MAJOR_VER) &&
(MM_MINOR_VER (MmVersion) >= MM_CALLER_MINOR_VER))
{
DEBUG ((
DEBUG_INFO,
"MM Version: Major=0x%x, Minor=0x%x\n",
MM_MAJOR_VER (MmVersion),
MM_MINOR_VER (MmVersion)
));
Status = EFI_SUCCESS;
} else {
DEBUG ((
DEBUG_ERROR,
"Incompatible MM Versions.\n Current Version: Major=0x%x, Minor=0x%x.\n Expected: Major=0x%x, Minor>=0x%x.\n",
MM_MAJOR_VER (MmVersion),
MM_MINOR_VER (MmVersion),
MM_CALLER_MAJOR_VER,
MM_CALLER_MINOR_VER
));
Status = EFI_UNSUPPORTED;
}
return Status;
}
/**
Check mm communication compatibility when use FF-A.
**/
STATIC
EFI_STATUS
EFIAPI
GetFfaCompatibility (
VOID
)
{
EFI_STATUS Status;
UINT16 CurrentMajorVersion;
UINT16 CurrentMinorVersion;
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 for MM_COMM.\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;
}
DEBUG ((
DEBUG_INFO,
"FF-A Version for MM_COMM: Major=0x%x, Minor=0x%x\n",
CurrentMajorVersion,
CurrentMinorVersion
));
return EFI_SUCCESS;
}
/**
Initialize communication via FF-A.
**/
STATIC
EFI_STATUS
EFIAPI
InitializeFfaCommunication (
VOID
)
{
EFI_STATUS Status;
VOID *TxBuffer;
UINT64 TxBufferSize;
VOID *RxBuffer;
UINT64 RxBufferSize;
EFI_FFA_PART_INFO_DESC *StmmPartInfo;
UINT32 Count;
UINT32 Size;
Status = ArmFfaLibPartitionIdGet (&mPartId);
if (EFI_ERROR (Status)) {
DEBUG ((
DEBUG_ERROR,
"Failed to get partition id. Status: %r\n",
Status
));
return Status;
}
Status = ArmFfaLibGetRxTxBuffers (
&TxBuffer,
&TxBufferSize,
&RxBuffer,
&RxBufferSize
);
if (EFI_ERROR (Status)) {
DEBUG ((
DEBUG_ERROR,
"Failed to get Rx/Tx Buffer. Status: %r\n",
Status
));
return Status;
}
Status = ArmFfaLibPartitionInfoGet (
&gEfiMmCommunication2ProtocolGuid,
FFA_PART_INFO_FLAG_TYPE_DESC,
&Count,
&Size
);
if (EFI_ERROR (Status)) {
DEBUG ((
DEBUG_ERROR,
"Failed to get Stmm(%g) partition Info. Status: %r\n",
&gEfiMmCommunication2ProtocolGuid,
Status
));
return Status;
}
if ((Count != 1) || (Size < sizeof (EFI_FFA_PART_INFO_DESC))) {
Status = EFI_INVALID_PARAMETER;
DEBUG ((
DEBUG_ERROR,
"Invalid partition Info(%g). Count: %d, Size: %d\n",
&gEfiMmCommunication2ProtocolGuid,
Count,
Size
));
goto ErrorHandler;
}
StmmPartInfo = (EFI_FFA_PART_INFO_DESC *)RxBuffer;
if ((StmmPartInfo->PartitionProps & FFA_PART_PROP_RECV_DIRECT_REQ) == 0x00) {
Status = EFI_UNSUPPORTED;
DEBUG ((DEBUG_ERROR, "StandaloneMm doesn't receive DIRECT_MSG_REQ...\n"));
goto ErrorHandler;
}
mStMmPartId = StmmPartInfo->PartitionId;
ErrorHandler:
ArmFfaLibRxRelease (mPartId);
return Status;
}
/**
Initialize mm communication.
**/
STATIC
EFI_STATUS
EFIAPI
InitializeCommunication (
VOID
)
{
EFI_STATUS Status;
Status = EFI_UNSUPPORTED;
if (IsFfaSupported ()) {
Status = GetFfaCompatibility ();
if (!EFI_ERROR (Status)) {
Status = InitializeFfaCommunication ();
}
} else {
Status = GetMmCompatibility ();
// No further initialisation required for SpmMM
}
return Status;
}
/**
Send mm communicate request via FF-A.
@retval EFI_SUCCESS
@retval Others Error.
**/
STATIC
EFI_STATUS
EFIAPI
SendFfaMmCommunicate (
VOID
)
{
EFI_STATUS Status;
DIRECT_MSG_ARGS CommunicateArgs;
ZeroMem (&CommunicateArgs, sizeof (DIRECT_MSG_ARGS));
CommunicateArgs.Arg0 = (UINTN)PcdGet64 (PcdMmBufferBase);
Status = ArmFfaLibMsgSendDirectReq (
mStMmPartId,
0,
&CommunicateArgs
);
while (Status == EFI_INTERRUPT_PENDING) {
// We are assuming vCPU0 of the StMM SP since it is UP.
Status = ArmFfaLibRun (mStMmPartId, 0x00);
}
return Status;
}
/**
Send mm communicate request via SPM_MM.
@retval EFI_SUCCESS
@retval Others Error.
**/
STATIC
EFI_STATUS
EFIAPI
SendSpmMmCommunicate (
VOID
)
{
EFI_STATUS Status;
ARM_SMC_ARGS CommunicateSmcArgs;
ZeroMem (&CommunicateSmcArgs, sizeof (ARM_SMC_ARGS));
// SMC Function ID
CommunicateSmcArgs.Arg0 = ARM_SMC_ID_MM_COMMUNICATE_AARCH64;
// Cookie
CommunicateSmcArgs.Arg1 = 0;
// comm_buffer_address (64-bit physical address)
CommunicateSmcArgs.Arg2 = (UINTN)PcdGet64 (PcdMmBufferBase);
// comm_size_address (not used, indicated by setting to zero)
CommunicateSmcArgs.Arg3 = 0;
// Call the Standalone MM environment.
ArmCallSmc (&CommunicateSmcArgs);
switch (CommunicateSmcArgs.Arg0) {
case ARM_SMC_MM_RET_SUCCESS:
Status = EFI_SUCCESS;
break;
case ARM_SMC_MM_RET_INVALID_PARAMS:
Status = EFI_INVALID_PARAMETER;
break;
case ARM_SMC_MM_RET_DENIED:
Status = EFI_ACCESS_DENIED;
break;
case ARM_SMC_MM_RET_NO_MEMORY:
// Unexpected error since the CommSize was checked for zero length
// prior to issuing the SMC
Status = EFI_OUT_OF_RESOURCES;
ASSERT (0);
break;
default:
Status = EFI_ACCESS_DENIED;
ASSERT (0);
}
return Status;
}
/**
MmCommunicationPeim
Communicates with a registered handler.
@ -54,22 +381,9 @@ MmCommunicationPeim (
{
EFI_MM_COMMUNICATE_HEADER *CommunicateHeader;
EFI_MM_COMMUNICATE_HEADER *TempCommHeader;
ARM_SMC_ARGS CommunicateSmcArgs;
EFI_STATUS Status;
UINTN BufferSize;
ZeroMem (&CommunicateSmcArgs, sizeof (ARM_SMC_ARGS));
// Check that our static buffer is looking good.
// We are using PcdMmBufferBase to transfer variable data.
// We are not using the full size of the buffer since there is a cost
// of copying data between Normal and Secure World.
if ((PcdGet64 (PcdMmBufferBase) == 0) || (PcdGet64 (PcdMmBufferSize) == 0)) {
ASSERT (PcdGet64 (PcdMmBufferSize) > 0);
ASSERT (PcdGet64 (PcdMmBufferBase) != 0);
return EFI_UNSUPPORTED;
}
//
// Check parameters
//
@ -123,65 +437,32 @@ MmCommunicationPeim (
CopyMem (CommunicateHeader, CommBuffer, *CommSize);
// SMC Function ID
CommunicateSmcArgs.Arg0 = ARM_SMC_ID_MM_COMMUNICATE_AARCH64;
// Cookie
CommunicateSmcArgs.Arg1 = 0;
// comm_buffer_address (64-bit physical address)
CommunicateSmcArgs.Arg2 = (UINTN)CommunicateHeader;
// comm_size_address (not used, indicated by setting to zero)
CommunicateSmcArgs.Arg3 = 0;
// Call the Standalone MM environment.
ArmCallSmc (&CommunicateSmcArgs);
switch (CommunicateSmcArgs.Arg0) {
case ARM_SMC_MM_RET_SUCCESS:
// On successful return, the size of data being returned is inferred from
// MessageLength + Header.
BufferSize = CommunicateHeader->MessageLength +
sizeof (CommunicateHeader->HeaderGuid) +
sizeof (CommunicateHeader->MessageLength);
if (BufferSize > (UINTN)PcdGet64 (PcdMmBufferSize)) {
// Something bad has happened, we should have landed in ARM_SMC_MM_RET_NO_MEMORY
DEBUG ((
DEBUG_ERROR,
"%a Returned buffer exceeds communication buffer limit. Has: 0x%llx vs. max: 0x%llx!\n",
__func__,
BufferSize,
(UINTN)PcdGet64 (PcdMmBufferSize)
));
Status = EFI_BAD_BUFFER_SIZE;
break;
}
if (IsFfaSupported ()) {
Status = SendFfaMmCommunicate ();
} else {
Status = SendSpmMmCommunicate ();
}
if (!EFI_ERROR (Status)) {
// On successful return, the size of data being returned is inferred from
// MessageLength + Header.
BufferSize = CommunicateHeader->MessageLength +
sizeof (CommunicateHeader->HeaderGuid) +
sizeof (CommunicateHeader->MessageLength);
if (BufferSize > (UINTN)PcdGet64 (PcdMmBufferSize)) {
// Something bad has happened, we should have landed in ARM_SMC_MM_RET_NO_MEMORY
Status = EFI_BAD_BUFFER_SIZE;
DEBUG ((
DEBUG_ERROR,
"%a Returned buffer exceeds communication buffer limit. Has: 0x%llx vs. max: 0x%llx!\n",
__func__,
BufferSize,
(UINTN)PcdGet64 (PcdMmBufferSize)
));
} else {
CopyMem (CommBuffer, CommunicateHeader, BufferSize);
*CommSize = BufferSize;
Status = EFI_SUCCESS;
break;
case ARM_SMC_MM_RET_INVALID_PARAMS:
Status = EFI_INVALID_PARAMETER;
break;
case ARM_SMC_MM_RET_DENIED:
Status = EFI_ACCESS_DENIED;
break;
case ARM_SMC_MM_RET_NO_MEMORY:
// Unexpected error since the CommSize was checked for zero length
// prior to issuing the SMC
Status = EFI_OUT_OF_RESOURCES;
ASSERT (0);
break;
default:
Status = EFI_ACCESS_DENIED;
ASSERT (0);
break;
}
}
return Status;
@ -217,5 +498,23 @@ MmCommunicationPeiInitialize (
IN CONST EFI_PEI_SERVICES **PeiServices
)
{
EFI_STATUS Status;
// Check that our static buffer is looking good.
// We are using PcdMmBufferBase to transfer variable data.
// We are not using the full size of the buffer since there is a cost
// of copying data between Normal and Secure World.
if ((PcdGet64 (PcdMmBufferBase) == 0) || (PcdGet64 (PcdMmBufferSize) == 0)) {
ASSERT (PcdGet64 (PcdMmBufferSize) > 0);
ASSERT (PcdGet64 (PcdMmBufferBase) != 0);
return EFI_UNSUPPORTED;
}
// Check if we can make the MM call
Status = InitializeCommunication ();
if (EFI_ERROR (Status)) {
return Status;
}
return PeiServicesInstallPpi (&mPeiMmCommunicationPpi);
}

View File

@ -25,6 +25,7 @@
[LibraryClasses]
DebugLib
ArmSmcLib
ArmFfaLib
PeimEntryPoint
PeiServicesLib
HobLib
@ -33,6 +34,9 @@
gArmTokenSpaceGuid.PcdMmBufferBase
gArmTokenSpaceGuid.PcdMmBufferSize
[Protocols]
gEfiMmCommunication2ProtocolGuid
[Ppis]
gEfiPeiMmCommunicationPpiGuid ## PRODUCES