\r
**/\r
\r
+#include <Library/ArmMmuLib.h>\r
#include <Library/ArmSmcLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
#include <Library/BaseLib.h>\r
+#include <Library/DebugLib.h>\r
#include <Library/OpteeLib.h>\r
\r
#include <IndustryStandard/ArmStdSmc.h>\r
+#include <OpteeSmc.h>\r
+#include <Uefi.h>\r
+\r
+STATIC OPTEE_SHARED_MEMORY_INFORMATION OpteeSharedMemoryInformation = { 0 };\r
\r
/**\r
Check for OP-TEE presence.\r
{\r
ARM_SMC_ARGS ArmSmcArgs;\r
\r
+ ZeroMem (&ArmSmcArgs, sizeof (ARM_SMC_ARGS));\r
// Send a Trusted OS Calls UID command\r
ArmSmcArgs.Arg0 = ARM_SMC_ID_TOS_UID;\r
ArmCallSmc (&ArmSmcArgs);\r
return FALSE;\r
}\r
}\r
+\r
+STATIC\r
+EFI_STATUS\r
+OpteeSharedMemoryRemap (\r
+ VOID\r
+ )\r
+{\r
+ ARM_SMC_ARGS ArmSmcArgs;\r
+ EFI_PHYSICAL_ADDRESS PhysicalAddress;\r
+ EFI_PHYSICAL_ADDRESS Start;\r
+ EFI_PHYSICAL_ADDRESS End;\r
+ EFI_STATUS Status;\r
+ UINTN Size;\r
+\r
+ ZeroMem (&ArmSmcArgs, sizeof (ARM_SMC_ARGS));\r
+ ArmSmcArgs.Arg0 = OPTEE_SMC_GET_SHARED_MEMORY_CONFIG;\r
+\r
+ ArmCallSmc (&ArmSmcArgs);\r
+ if (ArmSmcArgs.Arg0 != OPTEE_SMC_RETURN_OK) {\r
+ DEBUG ((DEBUG_WARN, "OP-TEE shared memory not supported\n"));\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ if (ArmSmcArgs.Arg3 != OPTEE_SMC_SHARED_MEMORY_CACHED) {\r
+ DEBUG ((DEBUG_WARN, "OP-TEE: Only normal cached shared memory supported\n"));\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ Start = (ArmSmcArgs.Arg1 + SIZE_4KB - 1) & ~(SIZE_4KB - 1);\r
+ End = (ArmSmcArgs.Arg1 + ArmSmcArgs.Arg2) & ~(SIZE_4KB - 1);\r
+ PhysicalAddress = Start;\r
+ Size = End - Start;\r
+\r
+ if (Size < SIZE_4KB) {\r
+ DEBUG ((DEBUG_WARN, "OP-TEE shared memory too small\n"));\r
+ return EFI_BUFFER_TOO_SMALL;\r
+ }\r
+\r
+ Status = ArmSetMemoryAttributes (PhysicalAddress, Size, EFI_MEMORY_WB);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ OpteeSharedMemoryInformation.Base = (UINTN)PhysicalAddress;\r
+ OpteeSharedMemoryInformation.Size = Size;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+OpteeInit (\r
+ VOID\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ if (!IsOpteePresent ()) {\r
+ DEBUG ((DEBUG_WARN, "OP-TEE not present\n"));\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ Status = OpteeSharedMemoryRemap ();\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_WARN, "OP-TEE shared memory remap failed\n"));\r
+ return Status;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Does Standard SMC to OP-TEE in secure world.\r
+\r
+ @param[in] PhysicalArg Physical address of message to pass to secure world\r
+\r
+ @return 0 on success, secure world return code otherwise\r
+\r
+**/\r
+STATIC\r
+UINT32\r
+OpteeCallWithArg (\r
+ IN EFI_PHYSICAL_ADDRESS PhysicalArg\r
+ )\r
+{\r
+ ARM_SMC_ARGS ArmSmcArgs;\r
+\r
+ ZeroMem (&ArmSmcArgs, sizeof (ARM_SMC_ARGS));\r
+ ArmSmcArgs.Arg0 = OPTEE_SMC_CALL_WITH_ARG;\r
+ ArmSmcArgs.Arg1 = (UINT32)(PhysicalArg >> 32);\r
+ ArmSmcArgs.Arg2 = (UINT32)PhysicalArg;\r
+\r
+ while (TRUE) {\r
+ ArmCallSmc (&ArmSmcArgs);\r
+\r
+ if (ArmSmcArgs.Arg0 == OPTEE_SMC_RETURN_RPC_FOREIGN_INTERRUPT) {\r
+ //\r
+ // A foreign interrupt was raised while secure world was\r
+ // executing, since they are handled in UEFI a dummy RPC is\r
+ // performed to let UEFI take the interrupt through the normal\r
+ // vector.\r
+ //\r
+ ArmSmcArgs.Arg0 = OPTEE_SMC_RETURN_FROM_RPC;\r
+ } else {\r
+ break;\r
+ }\r
+ }\r
+\r
+ return ArmSmcArgs.Arg0;\r
+}\r
+\r
+STATIC\r
+VOID\r
+EfiGuidToRfc4122Uuid (\r
+ OUT RFC4122_UUID *Rfc4122Uuid,\r
+ IN EFI_GUID *Guid\r
+ )\r
+{\r
+ Rfc4122Uuid->Data1 = SwapBytes32 (Guid->Data1);\r
+ Rfc4122Uuid->Data2 = SwapBytes16 (Guid->Data2);\r
+ Rfc4122Uuid->Data3 = SwapBytes16 (Guid->Data3);\r
+ CopyMem (Rfc4122Uuid->Data4, Guid->Data4, sizeof (Rfc4122Uuid->Data4));\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+OpteeOpenSession (\r
+ IN OUT OPTEE_OPEN_SESSION_ARG *OpenSessionArg\r
+ )\r
+{\r
+ OPTEE_MESSAGE_ARG *MessageArg;\r
+\r
+ MessageArg = NULL;\r
+\r
+ if (OpteeSharedMemoryInformation.Base == 0) {\r
+ DEBUG ((DEBUG_WARN, "OP-TEE not initialized\n"));\r
+ return EFI_NOT_STARTED;\r
+ }\r
+\r
+ MessageArg = (OPTEE_MESSAGE_ARG *)OpteeSharedMemoryInformation.Base;\r
+ ZeroMem (MessageArg, sizeof (OPTEE_MESSAGE_ARG));\r
+\r
+ MessageArg->Command = OPTEE_MESSAGE_COMMAND_OPEN_SESSION;\r
+\r
+ //\r
+ // Initialize and add the meta parameters needed when opening a\r
+ // session.\r
+ //\r
+ MessageArg->Params[0].Attribute = OPTEE_MESSAGE_ATTRIBUTE_TYPE_VALUE_INPUT |\r
+ OPTEE_MESSAGE_ATTRIBUTE_META;\r
+ MessageArg->Params[1].Attribute = OPTEE_MESSAGE_ATTRIBUTE_TYPE_VALUE_INPUT |\r
+ OPTEE_MESSAGE_ATTRIBUTE_META;\r
+ EfiGuidToRfc4122Uuid (\r
+ (RFC4122_UUID *)&MessageArg->Params[0].Union.Value,\r
+ &OpenSessionArg->Uuid\r
+ );\r
+ ZeroMem (&MessageArg->Params[1].Union.Value, sizeof (EFI_GUID));\r
+ MessageArg->Params[1].Union.Value.C = OPTEE_LOGIN_PUBLIC;\r
+\r
+ MessageArg->NumParams = 2;\r
+\r
+ if (OpteeCallWithArg ((EFI_PHYSICAL_ADDRESS)MessageArg)) {\r
+ MessageArg->Return = OPTEE_ERROR_COMMUNICATION;\r
+ MessageArg->ReturnOrigin = OPTEE_ORIGIN_COMMUNICATION;\r
+ }\r
+\r
+ OpenSessionArg->Session = MessageArg->Session;\r
+ OpenSessionArg->Return = MessageArg->Return;\r
+ OpenSessionArg->ReturnOrigin = MessageArg->ReturnOrigin;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+OpteeCloseSession (\r
+ IN UINT32 Session\r
+ )\r
+{\r
+ OPTEE_MESSAGE_ARG *MessageArg;\r
+\r
+ MessageArg = NULL;\r
+\r
+ if (OpteeSharedMemoryInformation.Base == 0) {\r
+ DEBUG ((DEBUG_WARN, "OP-TEE not initialized\n"));\r
+ return EFI_NOT_STARTED;\r
+ }\r
+\r
+ MessageArg = (OPTEE_MESSAGE_ARG *)OpteeSharedMemoryInformation.Base;\r
+ ZeroMem (MessageArg, sizeof (OPTEE_MESSAGE_ARG));\r
+\r
+ MessageArg->Command = OPTEE_MESSAGE_COMMAND_CLOSE_SESSION;\r
+ MessageArg->Session = Session;\r
+\r
+ OpteeCallWithArg ((EFI_PHYSICAL_ADDRESS)MessageArg);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+OpteeToMessageParam (\r
+ OUT OPTEE_MESSAGE_PARAM *MessageParams,\r
+ IN UINT32 NumParams,\r
+ IN OPTEE_MESSAGE_PARAM *InParams\r
+ )\r
+{\r
+ UINT32 Idx;\r
+ UINTN ParamSharedMemoryAddress;\r
+ UINTN SharedMemorySize;\r
+ UINTN Size;\r
+\r
+ Size = (sizeof (OPTEE_MESSAGE_ARG) + sizeof (UINT64) - 1) &\r
+ ~(sizeof (UINT64) - 1);\r
+ ParamSharedMemoryAddress = OpteeSharedMemoryInformation.Base + Size;\r
+ SharedMemorySize = OpteeSharedMemoryInformation.Size - Size;\r
+\r
+ for (Idx = 0; Idx < NumParams; Idx++) {\r
+ CONST OPTEE_MESSAGE_PARAM *InParam;\r
+ OPTEE_MESSAGE_PARAM *MessageParam;\r
+ UINT32 Attribute;\r
+\r
+ InParam = InParams + Idx;\r
+ MessageParam = MessageParams + Idx;\r
+ Attribute = InParam->Attribute & OPTEE_MESSAGE_ATTRIBUTE_TYPE_MASK;\r
+\r
+ switch (Attribute) {\r
+ case OPTEE_MESSAGE_ATTRIBUTE_TYPE_NONE:\r
+ MessageParam->Attribute = OPTEE_MESSAGE_ATTRIBUTE_TYPE_NONE;\r
+ ZeroMem (&MessageParam->Union, sizeof (MessageParam->Union));\r
+ break;\r
+\r
+ case OPTEE_MESSAGE_ATTRIBUTE_TYPE_VALUE_INPUT:\r
+ case OPTEE_MESSAGE_ATTRIBUTE_TYPE_VALUE_OUTPUT:\r
+ case OPTEE_MESSAGE_ATTRIBUTE_TYPE_VALUE_INOUT:\r
+ MessageParam->Attribute = Attribute;\r
+ MessageParam->Union.Value.A = InParam->Union.Value.A;\r
+ MessageParam->Union.Value.B = InParam->Union.Value.B;\r
+ MessageParam->Union.Value.C = InParam->Union.Value.C;\r
+ break;\r
+\r
+ case OPTEE_MESSAGE_ATTRIBUTE_TYPE_MEMORY_INPUT:\r
+ case OPTEE_MESSAGE_ATTRIBUTE_TYPE_MEMORY_OUTPUT:\r
+ case OPTEE_MESSAGE_ATTRIBUTE_TYPE_MEMORY_INOUT:\r
+ MessageParam->Attribute = Attribute;\r
+\r
+ if (InParam->Union.Memory.Size > SharedMemorySize) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ CopyMem (\r
+ (VOID *)ParamSharedMemoryAddress,\r
+ (VOID *)InParam->Union.Memory.BufferAddress,\r
+ InParam->Union.Memory.Size\r
+ );\r
+ MessageParam->Union.Memory.BufferAddress = (UINT64)ParamSharedMemoryAddress;\r
+ MessageParam->Union.Memory.Size = InParam->Union.Memory.Size;\r
+\r
+ Size = (InParam->Union.Memory.Size + sizeof (UINT64) - 1) &\r
+ ~(sizeof (UINT64) - 1);\r
+ ParamSharedMemoryAddress += Size;\r
+ SharedMemorySize -= Size;\r
+ break;\r
+\r
+ default:\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+OpteeFromMessageParam (\r
+ OUT OPTEE_MESSAGE_PARAM *OutParams,\r
+ IN UINT32 NumParams,\r
+ IN OPTEE_MESSAGE_PARAM *MessageParams\r
+ )\r
+{\r
+ UINT32 Idx;\r
+\r
+ for (Idx = 0; Idx < NumParams; Idx++) {\r
+ OPTEE_MESSAGE_PARAM *OutParam;\r
+ CONST OPTEE_MESSAGE_PARAM *MessageParam;\r
+ UINT32 Attribute;\r
+\r
+ OutParam = OutParams + Idx;\r
+ MessageParam = MessageParams + Idx;\r
+ Attribute = MessageParam->Attribute & OPTEE_MESSAGE_ATTRIBUTE_TYPE_MASK;\r
+\r
+ switch (Attribute) {\r
+ case OPTEE_MESSAGE_ATTRIBUTE_TYPE_NONE:\r
+ OutParam->Attribute = OPTEE_MESSAGE_ATTRIBUTE_TYPE_NONE;\r
+ ZeroMem (&OutParam->Union, sizeof (OutParam->Union));\r
+ break;\r
+\r
+ case OPTEE_MESSAGE_ATTRIBUTE_TYPE_VALUE_INPUT:\r
+ case OPTEE_MESSAGE_ATTRIBUTE_TYPE_VALUE_OUTPUT:\r
+ case OPTEE_MESSAGE_ATTRIBUTE_TYPE_VALUE_INOUT:\r
+ OutParam->Attribute = Attribute;\r
+ OutParam->Union.Value.A = MessageParam->Union.Value.A;\r
+ OutParam->Union.Value.B = MessageParam->Union.Value.B;\r
+ OutParam->Union.Value.C = MessageParam->Union.Value.C;\r
+ break;\r
+\r
+ case OPTEE_MESSAGE_ATTRIBUTE_TYPE_MEMORY_INPUT:\r
+ case OPTEE_MESSAGE_ATTRIBUTE_TYPE_MEMORY_OUTPUT:\r
+ case OPTEE_MESSAGE_ATTRIBUTE_TYPE_MEMORY_INOUT:\r
+ OutParam->Attribute = Attribute;\r
+\r
+ if (MessageParam->Union.Memory.Size > OutParam->Union.Memory.Size) {\r
+ return EFI_BAD_BUFFER_SIZE;\r
+ }\r
+\r
+ CopyMem (\r
+ (VOID *)OutParam->Union.Memory.BufferAddress,\r
+ (VOID *)MessageParam->Union.Memory.BufferAddress,\r
+ MessageParam->Union.Memory.Size\r
+ );\r
+ OutParam->Union.Memory.Size = MessageParam->Union.Memory.Size;\r
+ break;\r
+\r
+ default:\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+OpteeInvokeFunction (\r
+ IN OUT OPTEE_INVOKE_FUNCTION_ARG *InvokeFunctionArg\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ OPTEE_MESSAGE_ARG *MessageArg;\r
+\r
+ MessageArg = NULL;\r
+\r
+ if (OpteeSharedMemoryInformation.Base == 0) {\r
+ DEBUG ((DEBUG_WARN, "OP-TEE not initialized\n"));\r
+ return EFI_NOT_STARTED;\r
+ }\r
+\r
+ MessageArg = (OPTEE_MESSAGE_ARG *)OpteeSharedMemoryInformation.Base;\r
+ ZeroMem (MessageArg, sizeof (OPTEE_MESSAGE_ARG));\r
+\r
+ MessageArg->Command = OPTEE_MESSAGE_COMMAND_INVOKE_FUNCTION;\r
+ MessageArg->Function = InvokeFunctionArg->Function;\r
+ MessageArg->Session = InvokeFunctionArg->Session;\r
+\r
+ Status = OpteeToMessageParam (\r
+ MessageArg->Params,\r
+ OPTEE_MAX_CALL_PARAMS,\r
+ InvokeFunctionArg->Params\r
+ );\r
+ if (Status) {\r
+ return Status;\r
+ }\r
+\r
+ MessageArg->NumParams = OPTEE_MAX_CALL_PARAMS;\r
+\r
+ if (OpteeCallWithArg ((EFI_PHYSICAL_ADDRESS)MessageArg)) {\r
+ MessageArg->Return = OPTEE_ERROR_COMMUNICATION;\r
+ MessageArg->ReturnOrigin = OPTEE_ORIGIN_COMMUNICATION;\r
+ }\r
+\r
+ if (OpteeFromMessageParam (\r
+ InvokeFunctionArg->Params,\r
+ OPTEE_MAX_CALL_PARAMS,\r
+ MessageArg->Params\r
+ )) {\r
+ MessageArg->Return = OPTEE_ERROR_COMMUNICATION;\r
+ MessageArg->ReturnOrigin = OPTEE_ORIGIN_COMMUNICATION;\r
+ }\r
+\r
+ InvokeFunctionArg->Return = MessageArg->Return;\r
+ InvokeFunctionArg->ReturnOrigin = MessageArg->ReturnOrigin;\r
+\r
+ return EFI_SUCCESS;\r
+}\r