ArmPkg/OpteeLib: Add APIs to communicate with OP-TEE
Add following APIs to communicate with OP-TEE pseudo/early TAs: 1. OpteeInit 2. OpteeOpenSession 3. OpteeCloseSession 4. OpteeInvokeFunc Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org> Cc: Leif Lindholm <leif.lindholm@linaro.org> Cc: Michael D Kinney <michael.d.kinney@intel.com> Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Sumit Garg <sumit.garg@linaro.org> Reviewed-by: Leif Lindholm <leif.lindholm@linaro.org>
This commit is contained in:
committed by
Leif Lindholm
parent
4222e8e7e4
commit
a0f01e8a22
@ -14,11 +14,18 @@
|
||||
|
||||
**/
|
||||
|
||||
#include <Library/ArmMmuLib.h>
|
||||
#include <Library/ArmSmcLib.h>
|
||||
#include <Library/BaseMemoryLib.h>
|
||||
#include <Library/BaseLib.h>
|
||||
#include <Library/DebugLib.h>
|
||||
#include <Library/OpteeLib.h>
|
||||
|
||||
#include <IndustryStandard/ArmStdSmc.h>
|
||||
#include <OpteeSmc.h>
|
||||
#include <Uefi.h>
|
||||
|
||||
STATIC OPTEE_SHARED_MEMORY_INFORMATION OpteeSharedMemoryInformation = { 0 };
|
||||
|
||||
/**
|
||||
Check for OP-TEE presence.
|
||||
@ -31,6 +38,7 @@ IsOpteePresent (
|
||||
{
|
||||
ARM_SMC_ARGS ArmSmcArgs;
|
||||
|
||||
ZeroMem (&ArmSmcArgs, sizeof (ARM_SMC_ARGS));
|
||||
// Send a Trusted OS Calls UID command
|
||||
ArmSmcArgs.Arg0 = ARM_SMC_ID_TOS_UID;
|
||||
ArmCallSmc (&ArmSmcArgs);
|
||||
@ -44,3 +52,387 @@ IsOpteePresent (
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
OpteeSharedMemoryRemap (
|
||||
VOID
|
||||
)
|
||||
{
|
||||
ARM_SMC_ARGS ArmSmcArgs;
|
||||
EFI_PHYSICAL_ADDRESS PhysicalAddress;
|
||||
EFI_PHYSICAL_ADDRESS Start;
|
||||
EFI_PHYSICAL_ADDRESS End;
|
||||
EFI_STATUS Status;
|
||||
UINTN Size;
|
||||
|
||||
ZeroMem (&ArmSmcArgs, sizeof (ARM_SMC_ARGS));
|
||||
ArmSmcArgs.Arg0 = OPTEE_SMC_GET_SHARED_MEMORY_CONFIG;
|
||||
|
||||
ArmCallSmc (&ArmSmcArgs);
|
||||
if (ArmSmcArgs.Arg0 != OPTEE_SMC_RETURN_OK) {
|
||||
DEBUG ((DEBUG_WARN, "OP-TEE shared memory not supported\n"));
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
||||
|
||||
if (ArmSmcArgs.Arg3 != OPTEE_SMC_SHARED_MEMORY_CACHED) {
|
||||
DEBUG ((DEBUG_WARN, "OP-TEE: Only normal cached shared memory supported\n"));
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
||||
|
||||
Start = (ArmSmcArgs.Arg1 + SIZE_4KB - 1) & ~(SIZE_4KB - 1);
|
||||
End = (ArmSmcArgs.Arg1 + ArmSmcArgs.Arg2) & ~(SIZE_4KB - 1);
|
||||
PhysicalAddress = Start;
|
||||
Size = End - Start;
|
||||
|
||||
if (Size < SIZE_4KB) {
|
||||
DEBUG ((DEBUG_WARN, "OP-TEE shared memory too small\n"));
|
||||
return EFI_BUFFER_TOO_SMALL;
|
||||
}
|
||||
|
||||
Status = ArmSetMemoryAttributes (PhysicalAddress, Size, EFI_MEMORY_WB);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
OpteeSharedMemoryInformation.Base = (UINTN)PhysicalAddress;
|
||||
OpteeSharedMemoryInformation.Size = Size;
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
OpteeInit (
|
||||
VOID
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
|
||||
if (!IsOpteePresent ()) {
|
||||
DEBUG ((DEBUG_WARN, "OP-TEE not present\n"));
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
||||
|
||||
Status = OpteeSharedMemoryRemap ();
|
||||
if (EFI_ERROR (Status)) {
|
||||
DEBUG ((DEBUG_WARN, "OP-TEE shared memory remap failed\n"));
|
||||
return Status;
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
Does Standard SMC to OP-TEE in secure world.
|
||||
|
||||
@param[in] PhysicalArg Physical address of message to pass to secure world
|
||||
|
||||
@return 0 on success, secure world return code otherwise
|
||||
|
||||
**/
|
||||
STATIC
|
||||
UINT32
|
||||
OpteeCallWithArg (
|
||||
IN EFI_PHYSICAL_ADDRESS PhysicalArg
|
||||
)
|
||||
{
|
||||
ARM_SMC_ARGS ArmSmcArgs;
|
||||
|
||||
ZeroMem (&ArmSmcArgs, sizeof (ARM_SMC_ARGS));
|
||||
ArmSmcArgs.Arg0 = OPTEE_SMC_CALL_WITH_ARG;
|
||||
ArmSmcArgs.Arg1 = (UINT32)(PhysicalArg >> 32);
|
||||
ArmSmcArgs.Arg2 = (UINT32)PhysicalArg;
|
||||
|
||||
while (TRUE) {
|
||||
ArmCallSmc (&ArmSmcArgs);
|
||||
|
||||
if (ArmSmcArgs.Arg0 == OPTEE_SMC_RETURN_RPC_FOREIGN_INTERRUPT) {
|
||||
//
|
||||
// A foreign interrupt was raised while secure world was
|
||||
// executing, since they are handled in UEFI a dummy RPC is
|
||||
// performed to let UEFI take the interrupt through the normal
|
||||
// vector.
|
||||
//
|
||||
ArmSmcArgs.Arg0 = OPTEE_SMC_RETURN_FROM_RPC;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ArmSmcArgs.Arg0;
|
||||
}
|
||||
|
||||
STATIC
|
||||
VOID
|
||||
EfiGuidToRfc4122Uuid (
|
||||
OUT RFC4122_UUID *Rfc4122Uuid,
|
||||
IN EFI_GUID *Guid
|
||||
)
|
||||
{
|
||||
Rfc4122Uuid->Data1 = SwapBytes32 (Guid->Data1);
|
||||
Rfc4122Uuid->Data2 = SwapBytes16 (Guid->Data2);
|
||||
Rfc4122Uuid->Data3 = SwapBytes16 (Guid->Data3);
|
||||
CopyMem (Rfc4122Uuid->Data4, Guid->Data4, sizeof (Rfc4122Uuid->Data4));
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
OpteeOpenSession (
|
||||
IN OUT OPTEE_OPEN_SESSION_ARG *OpenSessionArg
|
||||
)
|
||||
{
|
||||
OPTEE_MESSAGE_ARG *MessageArg;
|
||||
|
||||
MessageArg = NULL;
|
||||
|
||||
if (OpteeSharedMemoryInformation.Base == 0) {
|
||||
DEBUG ((DEBUG_WARN, "OP-TEE not initialized\n"));
|
||||
return EFI_NOT_STARTED;
|
||||
}
|
||||
|
||||
MessageArg = (OPTEE_MESSAGE_ARG *)OpteeSharedMemoryInformation.Base;
|
||||
ZeroMem (MessageArg, sizeof (OPTEE_MESSAGE_ARG));
|
||||
|
||||
MessageArg->Command = OPTEE_MESSAGE_COMMAND_OPEN_SESSION;
|
||||
|
||||
//
|
||||
// Initialize and add the meta parameters needed when opening a
|
||||
// session.
|
||||
//
|
||||
MessageArg->Params[0].Attribute = OPTEE_MESSAGE_ATTRIBUTE_TYPE_VALUE_INPUT |
|
||||
OPTEE_MESSAGE_ATTRIBUTE_META;
|
||||
MessageArg->Params[1].Attribute = OPTEE_MESSAGE_ATTRIBUTE_TYPE_VALUE_INPUT |
|
||||
OPTEE_MESSAGE_ATTRIBUTE_META;
|
||||
EfiGuidToRfc4122Uuid (
|
||||
(RFC4122_UUID *)&MessageArg->Params[0].Union.Value,
|
||||
&OpenSessionArg->Uuid
|
||||
);
|
||||
ZeroMem (&MessageArg->Params[1].Union.Value, sizeof (EFI_GUID));
|
||||
MessageArg->Params[1].Union.Value.C = OPTEE_LOGIN_PUBLIC;
|
||||
|
||||
MessageArg->NumParams = 2;
|
||||
|
||||
if (OpteeCallWithArg ((EFI_PHYSICAL_ADDRESS)MessageArg)) {
|
||||
MessageArg->Return = OPTEE_ERROR_COMMUNICATION;
|
||||
MessageArg->ReturnOrigin = OPTEE_ORIGIN_COMMUNICATION;
|
||||
}
|
||||
|
||||
OpenSessionArg->Session = MessageArg->Session;
|
||||
OpenSessionArg->Return = MessageArg->Return;
|
||||
OpenSessionArg->ReturnOrigin = MessageArg->ReturnOrigin;
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
OpteeCloseSession (
|
||||
IN UINT32 Session
|
||||
)
|
||||
{
|
||||
OPTEE_MESSAGE_ARG *MessageArg;
|
||||
|
||||
MessageArg = NULL;
|
||||
|
||||
if (OpteeSharedMemoryInformation.Base == 0) {
|
||||
DEBUG ((DEBUG_WARN, "OP-TEE not initialized\n"));
|
||||
return EFI_NOT_STARTED;
|
||||
}
|
||||
|
||||
MessageArg = (OPTEE_MESSAGE_ARG *)OpteeSharedMemoryInformation.Base;
|
||||
ZeroMem (MessageArg, sizeof (OPTEE_MESSAGE_ARG));
|
||||
|
||||
MessageArg->Command = OPTEE_MESSAGE_COMMAND_CLOSE_SESSION;
|
||||
MessageArg->Session = Session;
|
||||
|
||||
OpteeCallWithArg ((EFI_PHYSICAL_ADDRESS)MessageArg);
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
OpteeToMessageParam (
|
||||
OUT OPTEE_MESSAGE_PARAM *MessageParams,
|
||||
IN UINT32 NumParams,
|
||||
IN OPTEE_MESSAGE_PARAM *InParams
|
||||
)
|
||||
{
|
||||
UINT32 Idx;
|
||||
UINTN ParamSharedMemoryAddress;
|
||||
UINTN SharedMemorySize;
|
||||
UINTN Size;
|
||||
|
||||
Size = (sizeof (OPTEE_MESSAGE_ARG) + sizeof (UINT64) - 1) &
|
||||
~(sizeof (UINT64) - 1);
|
||||
ParamSharedMemoryAddress = OpteeSharedMemoryInformation.Base + Size;
|
||||
SharedMemorySize = OpteeSharedMemoryInformation.Size - Size;
|
||||
|
||||
for (Idx = 0; Idx < NumParams; Idx++) {
|
||||
CONST OPTEE_MESSAGE_PARAM *InParam;
|
||||
OPTEE_MESSAGE_PARAM *MessageParam;
|
||||
UINT32 Attribute;
|
||||
|
||||
InParam = InParams + Idx;
|
||||
MessageParam = MessageParams + Idx;
|
||||
Attribute = InParam->Attribute & OPTEE_MESSAGE_ATTRIBUTE_TYPE_MASK;
|
||||
|
||||
switch (Attribute) {
|
||||
case OPTEE_MESSAGE_ATTRIBUTE_TYPE_NONE:
|
||||
MessageParam->Attribute = OPTEE_MESSAGE_ATTRIBUTE_TYPE_NONE;
|
||||
ZeroMem (&MessageParam->Union, sizeof (MessageParam->Union));
|
||||
break;
|
||||
|
||||
case OPTEE_MESSAGE_ATTRIBUTE_TYPE_VALUE_INPUT:
|
||||
case OPTEE_MESSAGE_ATTRIBUTE_TYPE_VALUE_OUTPUT:
|
||||
case OPTEE_MESSAGE_ATTRIBUTE_TYPE_VALUE_INOUT:
|
||||
MessageParam->Attribute = Attribute;
|
||||
MessageParam->Union.Value.A = InParam->Union.Value.A;
|
||||
MessageParam->Union.Value.B = InParam->Union.Value.B;
|
||||
MessageParam->Union.Value.C = InParam->Union.Value.C;
|
||||
break;
|
||||
|
||||
case OPTEE_MESSAGE_ATTRIBUTE_TYPE_MEMORY_INPUT:
|
||||
case OPTEE_MESSAGE_ATTRIBUTE_TYPE_MEMORY_OUTPUT:
|
||||
case OPTEE_MESSAGE_ATTRIBUTE_TYPE_MEMORY_INOUT:
|
||||
MessageParam->Attribute = Attribute;
|
||||
|
||||
if (InParam->Union.Memory.Size > SharedMemorySize) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
CopyMem (
|
||||
(VOID *)ParamSharedMemoryAddress,
|
||||
(VOID *)InParam->Union.Memory.BufferAddress,
|
||||
InParam->Union.Memory.Size
|
||||
);
|
||||
MessageParam->Union.Memory.BufferAddress = (UINT64)ParamSharedMemoryAddress;
|
||||
MessageParam->Union.Memory.Size = InParam->Union.Memory.Size;
|
||||
|
||||
Size = (InParam->Union.Memory.Size + sizeof (UINT64) - 1) &
|
||||
~(sizeof (UINT64) - 1);
|
||||
ParamSharedMemoryAddress += Size;
|
||||
SharedMemorySize -= Size;
|
||||
break;
|
||||
|
||||
default:
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
OpteeFromMessageParam (
|
||||
OUT OPTEE_MESSAGE_PARAM *OutParams,
|
||||
IN UINT32 NumParams,
|
||||
IN OPTEE_MESSAGE_PARAM *MessageParams
|
||||
)
|
||||
{
|
||||
UINT32 Idx;
|
||||
|
||||
for (Idx = 0; Idx < NumParams; Idx++) {
|
||||
OPTEE_MESSAGE_PARAM *OutParam;
|
||||
CONST OPTEE_MESSAGE_PARAM *MessageParam;
|
||||
UINT32 Attribute;
|
||||
|
||||
OutParam = OutParams + Idx;
|
||||
MessageParam = MessageParams + Idx;
|
||||
Attribute = MessageParam->Attribute & OPTEE_MESSAGE_ATTRIBUTE_TYPE_MASK;
|
||||
|
||||
switch (Attribute) {
|
||||
case OPTEE_MESSAGE_ATTRIBUTE_TYPE_NONE:
|
||||
OutParam->Attribute = OPTEE_MESSAGE_ATTRIBUTE_TYPE_NONE;
|
||||
ZeroMem (&OutParam->Union, sizeof (OutParam->Union));
|
||||
break;
|
||||
|
||||
case OPTEE_MESSAGE_ATTRIBUTE_TYPE_VALUE_INPUT:
|
||||
case OPTEE_MESSAGE_ATTRIBUTE_TYPE_VALUE_OUTPUT:
|
||||
case OPTEE_MESSAGE_ATTRIBUTE_TYPE_VALUE_INOUT:
|
||||
OutParam->Attribute = Attribute;
|
||||
OutParam->Union.Value.A = MessageParam->Union.Value.A;
|
||||
OutParam->Union.Value.B = MessageParam->Union.Value.B;
|
||||
OutParam->Union.Value.C = MessageParam->Union.Value.C;
|
||||
break;
|
||||
|
||||
case OPTEE_MESSAGE_ATTRIBUTE_TYPE_MEMORY_INPUT:
|
||||
case OPTEE_MESSAGE_ATTRIBUTE_TYPE_MEMORY_OUTPUT:
|
||||
case OPTEE_MESSAGE_ATTRIBUTE_TYPE_MEMORY_INOUT:
|
||||
OutParam->Attribute = Attribute;
|
||||
|
||||
if (MessageParam->Union.Memory.Size > OutParam->Union.Memory.Size) {
|
||||
return EFI_BAD_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
CopyMem (
|
||||
(VOID *)OutParam->Union.Memory.BufferAddress,
|
||||
(VOID *)MessageParam->Union.Memory.BufferAddress,
|
||||
MessageParam->Union.Memory.Size
|
||||
);
|
||||
OutParam->Union.Memory.Size = MessageParam->Union.Memory.Size;
|
||||
break;
|
||||
|
||||
default:
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
OpteeInvokeFunction (
|
||||
IN OUT OPTEE_INVOKE_FUNCTION_ARG *InvokeFunctionArg
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
OPTEE_MESSAGE_ARG *MessageArg;
|
||||
|
||||
MessageArg = NULL;
|
||||
|
||||
if (OpteeSharedMemoryInformation.Base == 0) {
|
||||
DEBUG ((DEBUG_WARN, "OP-TEE not initialized\n"));
|
||||
return EFI_NOT_STARTED;
|
||||
}
|
||||
|
||||
MessageArg = (OPTEE_MESSAGE_ARG *)OpteeSharedMemoryInformation.Base;
|
||||
ZeroMem (MessageArg, sizeof (OPTEE_MESSAGE_ARG));
|
||||
|
||||
MessageArg->Command = OPTEE_MESSAGE_COMMAND_INVOKE_FUNCTION;
|
||||
MessageArg->Function = InvokeFunctionArg->Function;
|
||||
MessageArg->Session = InvokeFunctionArg->Session;
|
||||
|
||||
Status = OpteeToMessageParam (
|
||||
MessageArg->Params,
|
||||
OPTEE_MAX_CALL_PARAMS,
|
||||
InvokeFunctionArg->Params
|
||||
);
|
||||
if (Status) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
MessageArg->NumParams = OPTEE_MAX_CALL_PARAMS;
|
||||
|
||||
if (OpteeCallWithArg ((EFI_PHYSICAL_ADDRESS)MessageArg)) {
|
||||
MessageArg->Return = OPTEE_ERROR_COMMUNICATION;
|
||||
MessageArg->ReturnOrigin = OPTEE_ORIGIN_COMMUNICATION;
|
||||
}
|
||||
|
||||
if (OpteeFromMessageParam (
|
||||
InvokeFunctionArg->Params,
|
||||
OPTEE_MAX_CALL_PARAMS,
|
||||
MessageArg->Params
|
||||
)) {
|
||||
MessageArg->Return = OPTEE_ERROR_COMMUNICATION;
|
||||
MessageArg->ReturnOrigin = OPTEE_ORIGIN_COMMUNICATION;
|
||||
}
|
||||
|
||||
InvokeFunctionArg->Return = MessageArg->Return;
|
||||
InvokeFunctionArg->ReturnOrigin = MessageArg->ReturnOrigin;
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
Reference in New Issue
Block a user