diff options
author | Levi Yun <yeoreum.yun@arm.com> | 2024-08-06 09:57:25 +0100 |
---|---|---|
committer | mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> | 2025-01-17 14:55:42 +0000 |
commit | 73b2831879f35a707974cbafcd38c3dde49ae63c (patch) | |
tree | 2cc92c03c6857b80df0704caa0329298f3dd4714 /ArmPkg | |
parent | 9f9a3de9e4c5595cd42d14c705570887630209d8 (diff) | |
download | edk2-73b2831879f35a707974cbafcd38c3dde49ae63c.tar.gz |
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>
Diffstat (limited to 'ArmPkg')
-rw-r--r-- | ArmPkg/Drivers/MmCommunicationPei/MmCommunicationPei.c | 437 | ||||
-rw-r--r-- | ArmPkg/Drivers/MmCommunicationPei/MmCommunicationPei.inf | 4 |
2 files changed, 372 insertions, 69 deletions
diff --git a/ArmPkg/Drivers/MmCommunicationPei/MmCommunicationPei.c b/ArmPkg/Drivers/MmCommunicationPei/MmCommunicationPei.c index ccb182668d..864781ee32 100644 --- a/ArmPkg/Drivers/MmCommunicationPei/MmCommunicationPei.c +++ b/ArmPkg/Drivers/MmCommunicationPei/MmCommunicationPei.c @@ -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);
}
diff --git a/ArmPkg/Drivers/MmCommunicationPei/MmCommunicationPei.inf b/ArmPkg/Drivers/MmCommunicationPei/MmCommunicationPei.inf index c74c539539..2bd4d71826 100644 --- a/ArmPkg/Drivers/MmCommunicationPei/MmCommunicationPei.inf +++ b/ArmPkg/Drivers/MmCommunicationPei/MmCommunicationPei.inf @@ -25,6 +25,7 @@ [LibraryClasses]
DebugLib
ArmSmcLib
+ ArmFfaLib
PeimEntryPoint
PeiServicesLib
HobLib
@@ -33,6 +34,9 @@ gArmTokenSpaceGuid.PcdMmBufferBase
gArmTokenSpaceGuid.PcdMmBufferSize
+[Protocols]
+ gEfiMmCommunication2ProtocolGuid
+
[Ppis]
gEfiPeiMmCommunicationPpiGuid ## PRODUCES
|