]> git.proxmox.com Git - mirror_edk2.git/blobdiff - ArmPkg/Library/OpteeLib/Optee.c
ArmPkg/OpteeLib: Add APIs to communicate with OP-TEE
[mirror_edk2.git] / ArmPkg / Library / OpteeLib / Optee.c
index 574527f8b5ea7f97a65ceafb2fb425f8a0910caf..8ac31cb282663f2a1dd3c99acbf9ffe434573e2c 100644 (file)
 \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
@@ -31,6 +38,7 @@ IsOpteePresent (
 {\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
@@ -44,3 +52,387 @@ IsOpteePresent (
     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