mirror of
https://github.com/acidanthera/audk.git
synced 2025-04-08 17:05:09 +02:00
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:
parent
9f9a3de9e4
commit
73b2831879
@ -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);
|
||||
}
|
||||
|
@ -25,6 +25,7 @@
|
||||
[LibraryClasses]
|
||||
DebugLib
|
||||
ArmSmcLib
|
||||
ArmFfaLib
|
||||
PeimEntryPoint
|
||||
PeiServicesLib
|
||||
HobLib
|
||||
@ -33,6 +34,9 @@
|
||||
gArmTokenSpaceGuid.PcdMmBufferBase
|
||||
gArmTokenSpaceGuid.PcdMmBufferSize
|
||||
|
||||
[Protocols]
|
||||
gEfiMmCommunication2ProtocolGuid
|
||||
|
||||
[Ppis]
|
||||
gEfiPeiMmCommunicationPpiGuid ## PRODUCES
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user