From b103a64a87e4cce93039294e40f09b335be034d4 Mon Sep 17 00:00:00 2001 From: George Poulios Date: Mon, 5 May 2025 17:32:33 +0300 Subject: [PATCH] drivers/misc/optee: Add SMC backend for arm archs So far NuttX has supported OP-TEE interfacing over local and RPMsg sockets. This commit introduces support for direct invocation of OP-TEE through arm SMCs. The SMC transport is enabled through CONFIG_DEV_OPTEE_SMC. This SMC implementation has been tested only with arm64, OP-TEE rev 4.4. Note that it does not support reverse direction RPCs, i.e. from the Secure World to the Normal World to something like optee supplicant. A basic RPC handling skeleton is provided with implementation for some basic functions (alloc/free mem, and foreign interrupts) but no supplicant command handling. (+one minor change s/parm/param in arch/arm64/include/syscall to satisfy the spellchecker during PR) Signed-off-by: George Poulios --- arch/arm64/include/syscall.h | 48 +++- drivers/misc/CMakeLists.txt | 6 +- drivers/misc/Kconfig | 26 ++ drivers/misc/Make.defs | 6 +- drivers/misc/optee_smc.c | 343 +++++++++++++++++++++++++++ drivers/misc/optee_smc.h | 448 +++++++++++++++++++++++++++++++++++ 6 files changed, 873 insertions(+), 4 deletions(-) create mode 100644 drivers/misc/optee_smc.c create mode 100644 drivers/misc/optee_smc.h diff --git a/arch/arm64/include/syscall.h b/arch/arm64/include/syscall.h index 6d360bf820..4814ed79c7 100644 --- a/arch/arm64/include/syscall.h +++ b/arch/arm64/include/syscall.h @@ -110,6 +110,50 @@ #define ARM_SMCC_RES_A6 (6) #define ARM_SMCC_RES_A7 (7) +#define ARM_SMCCC_STD_CALL 0UL +#define ARM_SMCCC_FAST_CALL 1UL +#define ARM_SMCCC_TYPE_SHIFT 31 + +#define ARM_SMCCC_SMC_32 0 +#define ARM_SMCCC_SMC_64 1 +#define ARM_SMCCC_CALL_CONV_SHIFT 30 + +#define ARM_SMCCC_OWNER_MASK 0x3F +#define ARM_SMCCC_OWNER_SHIFT 24 + +#define ARM_SMCCC_FUNC_MASK 0xFFFF + +#define ARM_SMCCC_IS_FAST_CALL(smc_val) \ + ((smc_val) & (ARM_SMCCC_FAST_CALL << ARM_SMCCC_TYPE_SHIFT)) +#define ARM_SMCCC_IS_64(smc_val) \ + ((smc_val) & (ARM_SMCCC_SMC_64 << ARM_SMCCC_CALL_CONV_SHIFT)) +#define ARM_SMCCC_FUNC_NUM(smc_val) ((smc_val) & ARM_SMCCC_FUNC_MASK) +#define ARM_SMCCC_OWNER_NUM(smc_val) \ + (((smc_val) >> ARM_SMCCC_OWNER_SHIFT) & ARM_SMCCC_OWNER_MASK) + +#define ARM_SMCCC_CALL_VAL(type, calling_convention, owner, func_num) \ + (((type) << ARM_SMCCC_TYPE_SHIFT) | \ + ((calling_convention) << ARM_SMCCC_CALL_CONV_SHIFT) | \ + (((owner) & ARM_SMCCC_OWNER_MASK) << ARM_SMCCC_OWNER_SHIFT) | \ + ((func_num) & ARM_SMCCC_FUNC_MASK)) + +#define ARM_SMCCC_OWNER_ARCH 0 +#define ARM_SMCCC_OWNER_CPU 1 +#define ARM_SMCCC_OWNER_SIP 2 +#define ARM_SMCCC_OWNER_OEM 3 +#define ARM_SMCCC_OWNER_STANDARD 4 +#define ARM_SMCCC_OWNER_TRUSTED_APP 48 +#define ARM_SMCCC_OWNER_TRUSTED_APP_END 49 +#define ARM_SMCCC_OWNER_TRUSTED_OS 50 +#define ARM_SMCCC_OWNER_TRUSTED_OS_END 63 + +#define ARM_SMCCC_QUIRK_NONE 0 +#define ARM_SMCCC_QUIRK_QCOM_A6 1 /* Save/restore register a6 */ + +#define ARM_SMCCC_ARCH_FEATURES 0x80000001 + +#define ARM_SMCCC_RET_NOT_SUPPORTED ((unsigned long)-1) + #ifndef __ASSEMBLY__ /**************************************************************************** @@ -300,10 +344,10 @@ static inline uintptr_t sys_call6(unsigned int nbr, uintptr_t parm1, /* semihosting(SMH) call with call number and one parameter */ -static inline long smh_call(unsigned int nbr, void *parm) +static inline long smh_call(unsigned int nbr, void *param) { register uint64_t reg0 __asm__("x0") = (uint64_t)(nbr); - register uint64_t reg1 __asm__("x1") = (uint64_t)(parm); + register uint64_t reg1 __asm__("x1") = (uint64_t)(param); __asm__ __volatile__ ( diff --git a/drivers/misc/CMakeLists.txt b/drivers/misc/CMakeLists.txt index c82143bb28..3c3a3b28d9 100644 --- a/drivers/misc/CMakeLists.txt +++ b/drivers/misc/CMakeLists.txt @@ -80,7 +80,11 @@ endif() if(NOT CONFIG_DEV_OPTEE_NONE) list(APPEND SRCS optee.c) - list(APPEND SRCS optee_socket.c) + if(CONFIG_DEV_OPTEE_SMC) + list(APPEND SRCS optee_smc.c) + else() + list(APPEND SRCS optee_socket.c) + endif() endif() if(CONFIG_GOLDFISH_PIPE) diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index c4d25662ef..1892f84e31 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -62,6 +62,12 @@ config DEV_OPTEE_RPMSG depends on LIBC_MEMFD_SHMFS depends on ALLOW_BSD_COMPONENTS +config DEV_OPTEE_SMC + bool "OP-TEE SMC CC Support" + depends on ARCH_ARM || ARCH_ARM64 + depends on LIBC_MEMFD_SHMFS + depends on ALLOW_BSD_COMPONENTS + config DEV_OPTEE_NONE bool "Disable OP-TEE driver" @@ -75,6 +81,26 @@ config OPTEE_REMOTE_CPU_NAME endif # DEV_OPTEE_RPMSG +if DEV_OPTEE_SMC + +choice + prompt "Select OP-TEE conduit method" + default DEV_OPTEE_SMC_CONDUIT_SMC + ---help--- + Select between the 2 supported conduit methods for invoking the secure + world: SMC (when running at EL1) and HVC (when running at EL2, which is + not supported by NuttX yet). + +config DEV_OPTEE_SMC_CONDUIT_SMC + bool "Use SMC calls to invoke OP-TEE" + +config DEV_OPTEE_SMC_CONDUIT_HVC + bool "Use HVC calls to invoke OP-TEE" + +endchoice + +endif # DEV_OPTEE_SMC + config DRVR_MKRD bool "RAM disk wrapper (mkrd)" default n diff --git a/drivers/misc/Make.defs b/drivers/misc/Make.defs index c46fad48dc..3d2b45a95c 100644 --- a/drivers/misc/Make.defs +++ b/drivers/misc/Make.defs @@ -77,7 +77,11 @@ endif ifneq ($(CONFIG_DEV_OPTEE_NONE),y) CSRCS += optee.c - CSRCS += optee_socket.c + ifeq ($(CONFIG_DEV_OPTEE_SMC),y) + CSRCS += optee_smc.c + else + CSRCS += optee_socket.c + endif endif ifeq ($(CONFIG_GOLDFISH_PIPE),y) diff --git a/drivers/misc/optee_smc.c b/drivers/misc/optee_smc.c new file mode 100644 index 0000000000..b4886a644a --- /dev/null +++ b/drivers/misc/optee_smc.c @@ -0,0 +1,343 @@ +/**************************************************************************** + * drivers/misc/optee_smc.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include + +#include "optee.h" +#include "optee_smc.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#if defined(CONFIG_ARCH_ARM) +# define smccc_smc arm_smccc_smc +# define smccc_hvc arm_smccc_hvc +# define smccc_res_t arm_smccc_res_t +#elif defined(CONFIG_ARCH_ARM64) +# define smccc_smc arm64_smccc_smc +# define smccc_hvc arm64_smccc_hvc +# define smccc_res_t arm64_smccc_res_t +#else +# error "CONFIG_DEV_OPTEE_SMC is only supported on arm and arm64" +#endif + +#ifdef CONFIG_DEV_OPTEE_SMC_CONDUIT_SMC +# define smc_conduit smccc_smc +#else +# define smc_conduit smccc_hvc +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +typedef void (*optee_smc_fn)(unsigned long, unsigned long, unsigned long, + unsigned long, unsigned long, unsigned long, + unsigned long, unsigned long, + FAR smccc_res_t *); + +struct optee_smc_priv_data +{ + struct optee_priv_data base; + optee_smc_fn smc_fn; +}; + +union optee_smc_os_revision +{ + smccc_res_t smccc; + struct optee_smc_call_get_os_revision_result result; +}; + +union optee_smc_calls_revision +{ + smccc_res_t smccc; + struct optee_smc_calls_revision_result result; +}; + +union optee_smc_exchg_caps +{ + smccc_res_t smccc; + struct optee_smc_exchange_capabilities_result result; +}; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static inline uintptr_t reg_pair_to_uintptr(uint64_t reg0, uint64_t reg1) +{ + return (uintptr_t)(reg0 << 32 | (reg1 & UINT32_MAX)); +} + +static inline void reg_pair_from_64(uint64_t val, uint64_t *reg0, + uint64_t *reg1) +{ + *reg0 = val >> 32; + *reg1 = val & UINT32_MAX; +} + +static bool optee_smc_is_compatible(optee_smc_fn smc_fn) +{ + union optee_smc_os_revision osrev; + union optee_smc_calls_revision callsrev; + union optee_smc_exchg_caps xchgcaps; + smccc_res_t callsuid; + + /* Print the OS revision and build ID (if reported) */ + + osrev.result.build_id = 0; + + smc_fn(OPTEE_SMC_CALL_GET_OS_REVISION, 0, 0, 0, 0, 0, 0, 0, &osrev.smccc); + + if (osrev.result.build_id) + { + syslog(LOG_INFO, "OP-TEE: OS revision %lu.%lu (%08lx)\n", + osrev.result.major, osrev.result.minor, + osrev.result.build_id); + } + else + { + syslog(LOG_INFO, "OP-TEE: OS revision %lu.%lu\n", + osrev.result.major, osrev.result.minor); + } + + /* Check the API UID */ + + smc_fn(OPTEE_SMC_CALLS_UID, 0, 0, 0, 0, 0, 0, 0, &callsuid); + + if (callsuid.a0 != OPTEE_MSG_UID_0 || callsuid.a1 != OPTEE_MSG_UID_1 || + callsuid.a2 != OPTEE_MSG_UID_2 || callsuid.a3 != OPTEE_MSG_UID_3) + { + syslog(LOG_ERR, "OP-TEE: API UID mismatch\n"); + return false; + } + + /* Check the API revision */ + + smc_fn(OPTEE_SMC_CALLS_REVISION, 0, 0, 0, 0, 0, 0, 0, &callsrev.smccc); + + if (callsrev.result.major != OPTEE_MSG_REVISION_MAJOR || + callsrev.result.minor < OPTEE_MSG_REVISION_MINOR) + { + syslog(LOG_ERR, "OP-TEE: API revision incompatible\n"); + return false; + } + + /* Check the capabilities */ + + smc_fn(OPTEE_SMC_EXCHANGE_CAPABILITIES, OPTEE_SMC_NSEC_CAP_UNIPROCESSOR, + 0, 0, 0, 0, 0, 0, &xchgcaps.smccc); + + if (xchgcaps.result.status != OPTEE_SMC_RETURN_OK) + { + syslog(LOG_ERR, "OP-TEE: Failed to exchange capabilities\n"); + return false; + } + + if (!(xchgcaps.result.capabilities & OPTEE_SMC_SEC_CAP_DYNAMIC_SHM)) + { + syslog(LOG_ERR, "OP-TEE: Does not support dynamic shared mem\n"); + return false; + } + + return true; +} + +static void optee_smc_handle_rpc(FAR struct optee_priv_data *priv_, + FAR smccc_res_t *par) +{ + FAR struct optee_shm_entry *shme; + uintptr_t shme_pa; + uint32_t rpc_func; + + rpc_func = OPTEE_SMC_RETURN_GET_RPC_FUNC(par->a0); + par->a0 = OPTEE_SMC_CALL_RETURN_FROM_RPC; + + switch (rpc_func) + { + case OPTEE_SMC_RPC_FUNC_ALLOC: + if (!optee_shm_alloc(priv_, NULL, par->a1, + TEE_SHM_ALLOC | TEE_SHM_REGISTER, &shme)) + { + shme_pa = optee_va_to_pa((FAR void *)(uintptr_t)shme->shm.addr); + reg_pair_from_64(shme_pa, &par->a1, &par->a2); + reg_pair_from_64((uintptr_t)shme, &par->a4, &par->a5); + } + else + { + reg_pair_from_64(0, &par->a1, &par->a2); + reg_pair_from_64(0, &par->a4, &par->a5); + } + break; + + case OPTEE_SMC_RPC_FUNC_FREE: + shme = (FAR struct optee_shm_entry *) + reg_pair_to_uintptr(par->a1, par->a2); + optee_shm_free(priv_, shme); + break; + + case OPTEE_SMC_RPC_FUNC_FOREIGN_INTR: + break; + + default: + syslog(LOG_ERR, "OP-TEE: RPC 0x%04x not implemented\n", rpc_func); + break; + } +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: optee_transport_init + * + * Description: + * Perform any initialization actions specific to the transport used + * right before the driver is registered. + * + * Returned Values: + * 0 on success; A negated errno value is returned on any failure. + * + ****************************************************************************/ + +int optee_transport_init(void) +{ + if (!optee_smc_is_compatible(smc_conduit)) + { + return -ENOENT; + } + + return 0; +} + +/**************************************************************************** + * Name: optee_transport_open + * + * Description: + * Perform any transport-specific actions upon driver character device + * open. + * + * Parameters: + * priv_ - the optee_priv_data struct to allocate and return by + * reference. + * + * Returned Values: + * 0 on success; A negated errno value is returned on any failure. + * + ****************************************************************************/ + +int optee_transport_open(FAR struct optee_priv_data **priv_) +{ + FAR struct optee_smc_priv_data *priv; + + priv = kmm_zalloc(sizeof(struct optee_smc_priv_data)); + if (priv == NULL) + { + return -ENOMEM; + } + + priv->base.alignment = OPTEE_MSG_NONCONTIG_PAGE_SIZE; + priv->smc_fn = smc_conduit; + *priv_ = (FAR struct optee_priv_data *)priv; + return 0; +} + +/**************************************************************************** + * Name: optee_transport_close + * + * Description: + * Perform any transport-specific actions upon driver character device + * close. + * + * Parameters: + * priv_ - the optee_priv_data struct to close and de-allocate. + * + * Returned Values: + * None + * + ****************************************************************************/ + +void optee_transport_close(FAR struct optee_priv_data *priv_) +{ + kmm_free(priv_); +} + +/**************************************************************************** + * Name: optee_transport_call + * + * Description: + * Call OP-TEE OS using SMCs. + * + * Parameters: + * priv_ - the optee_priv_data struct to use + * + * Returned Values: + * 0 on success; A negated errno value is returned on any failure. + * + ****************************************************************************/ + +int optee_transport_call(FAR struct optee_priv_data *priv_, + FAR struct optee_msg_arg *arg) +{ + FAR struct optee_smc_priv_data *priv = + (FAR struct optee_smc_priv_data *)priv_; + smccc_res_t res; + smccc_res_t par; + uintptr_t arg_pa; + + memset(&par, 0, sizeof(smccc_res_t)); + + par.a0 = OPTEE_SMC_CALL_WITH_ARG; + arg_pa = optee_va_to_pa(arg); + reg_pair_from_64(arg_pa, &par.a1, &par.a2); + + for (; ; ) + { + memset(&res, 0, sizeof(smccc_res_t)); + + priv->smc_fn(par.a0, par.a1, par.a2, par.a3, + par.a4, par.a5, par.a6, par.a7, &res); + + if (OPTEE_SMC_RETURN_IS_RPC(res.a0)) + { + memcpy(&par, &res, 4 * sizeof(unsigned long)); + optee_smc_handle_rpc(priv_, &par); + } + else + { + return (int)res.a0; + } + } +} diff --git a/drivers/misc/optee_smc.h b/drivers/misc/optee_smc.h new file mode 100644 index 0000000000..c9237dd24b --- /dev/null +++ b/drivers/misc/optee_smc.h @@ -0,0 +1,448 @@ +/**************************************************************************** + * drivers/misc/optee_smc.h + * + * SPDX-License-Identifier: BSD-2-Clause + * Copyright (c) 2015-2018, Linaro Limited + * + ****************************************************************************/ + +#ifndef __DRIVERS_MISC_OPTEE_SMC_H +#define __DRIVERS_MISC_OPTEE_SMC_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include + +/* This file is based on + * https://github.com + * /OP-TEE/optee_os/blob/master/core/arch/arm/include/sm/optee_smc.h + * and may need to be updated when introducing new features. + */ + +#define OPTEE_SMC_STD_CALL_VAL(func_num) \ + ARM_SMCCC_CALL_VAL(ARM_SMCCC_STD_CALL, ARM_SMCCC_SMC_32, \ + ARM_SMCCC_OWNER_TRUSTED_OS, (func_num)) +#define OPTEE_SMC_FAST_CALL_VAL(func_num) \ + ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, ARM_SMCCC_SMC_32, \ + ARM_SMCCC_OWNER_TRUSTED_OS, (func_num)) + +/* Function specified by SMC Calling convention. + */ +#define OPTEE_SMC_FUNCID_CALLS_COUNT 0xFF00 +#define OPTEE_SMC_CALLS_COUNT \ + ARM_SMCCC_CALL_VAL(OPTEE_SMC_FAST_CALL, SMCCC_SMC_32, \ + SMCCC_OWNER_TRUSTED_OS_END, \ + OPTEE_SMC_FUNCID_CALLS_COUNT) + +/* Normal cached memory (write-back), shareable for SMP systems and not + * shareable for UP systems. + */ +#define OPTEE_SMC_SHM_CACHED 1 + +/* a0..a7 is used as register names in the descriptions below, on arm32 + * that translates to r0..r7 and on arm64 to w0..w7. In both cases it's + * 32-bit registers. + */ + +/* Function specified by SMC Calling convention + * + * Return one of the following UIDs if using API specified in this file + * without further extensions: + * 65cb6b93-af0c-4617-8ed6-644a8d1140f8 + * see also OPTEE_SMC_UID_* in optee_msg.h + */ +#define OPTEE_SMC_FUNCID_CALLS_UID OPTEE_MSG_FUNCID_CALLS_UID +#define OPTEE_SMC_CALLS_UID \ + ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, ARM_SMCCC_SMC_32, \ + ARM_SMCCC_OWNER_TRUSTED_OS_END, \ + OPTEE_SMC_FUNCID_CALLS_UID) + +/* Function specified by SMC Calling convention + * + * Returns 2.0 if using API specified in this file without further + * extensions. See also OPTEE_MSG_REVISION_* in optee_msg.h + */ +#define OPTEE_SMC_FUNCID_CALLS_REVISION OPTEE_MSG_FUNCID_CALLS_REVISION +#define OPTEE_SMC_CALLS_REVISION \ + ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, ARM_SMCCC_SMC_32, \ + ARM_SMCCC_OWNER_TRUSTED_OS_END, \ + OPTEE_SMC_FUNCID_CALLS_REVISION) + +struct optee_smc_calls_revision_result +{ + unsigned long major; + unsigned long minor; + unsigned long reserved0; + unsigned long reserved1; +}; + +/* Get UUID of Trusted OS. + * + * Used by non-secure world to figure out which Trusted OS is installed. + * Note that returned UUID is the UUID of the Trusted OS, not of the API. + * + * Returns UUID in a0-4 in the same way as OPTEE_SMC_CALLS_UID + * described above. + */ +#define OPTEE_SMC_FUNCID_GET_OS_UUID OPTEE_MSG_FUNCID_GET_OS_UUID +#define OPTEE_SMC_CALL_GET_OS_UUID \ + OPTEE_SMC_FAST_CALL_VAL(OPTEE_SMC_FUNCID_GET_OS_UUID) + +/* Get revision of Trusted OS. + * + * Used by non-secure world to figure out which version of the Trusted OS + * is installed. Note that the returned revision is the revision of the + * Trusted OS, not of the API. + * + * Returns revision in a0-1 in the same way as OPTEE_SMC_CALLS_REVISION + * described above. May optionally return a 32-bit build identifier in a2, + * with zero meaning unspecified. + */ +#define OPTEE_SMC_FUNCID_GET_OS_REVISION OPTEE_MSG_FUNCID_GET_OS_REVISION +#define OPTEE_SMC_CALL_GET_OS_REVISION \ + OPTEE_SMC_FAST_CALL_VAL(OPTEE_SMC_FUNCID_GET_OS_REVISION) + +struct optee_smc_call_get_os_revision_result +{ + unsigned long major; + unsigned long minor; + unsigned long build_id; + unsigned long reserved1; +}; + +/* Call with struct optee_msg_arg as argument + * + * Call register usage: + * a0 SMC Function ID, OPTEE_SMC*CALL_WITH_ARG + * a1 Upper 32bit of a 64bit physical pointer to a struct optee_msg_arg + * a2 Lower 32bit of a 64bit physical pointer to a struct optee_msg_arg + * a3 Cache settings, not used if physical pointer is in a predefined shared + * memory area else per OPTEE_SMC_SHM_* + * a4-6 Not used + * a7 Hypervisor Client ID register + * + * Normal return register usage: + * a0 Return value, OPTEE_SMC_RETURN_* + * a1-3 Not used + * a4-7 Preserved + * + * OPTEE_SMC_RETURN_ETHREAD_LIMIT return register usage: + * a0 Return value, OPTEE_SMC_RETURN_ETHREAD_LIMIT + * a1-3 Preserved + * a4-7 Preserved + * + * RPC return register usage: + * a0 Return value, OPTEE_SMC_RETURN_IS_RPC(val) + * a1-2 RPC parameters + * a3-7 Resume information, must be preserved + * + * Possible return values: + * OPTEE_SMC_RETURN_UNKNOWN_FUNCTION Trusted OS does not recognize this + * function. + * OPTEE_SMC_RETURN_OK Call completed, result updated in + * the previously supplied struct + * optee_msg_arg. + * OPTEE_SMC_RETURN_ETHREAD_LIMIT Number of Trusted OS threads exceeded, + * try again later. + * OPTEE_SMC_RETURN_EBADADDR Bad physical pointer to struct + * optee_msg_arg. + * OPTEE_SMC_RETURN_EBADCMD Bad/unknown cmd in struct optee_msg_arg + * OPTEE_SMC_RETURN_IS_RPC() Call suspended by RPC call to normal + * world. + */ +#define OPTEE_SMC_FUNCID_CALL_WITH_ARG OPTEE_MSG_FUNCID_CALL_WITH_ARG +#define OPTEE_SMC_CALL_WITH_ARG \ + OPTEE_SMC_STD_CALL_VAL(OPTEE_SMC_FUNCID_CALL_WITH_ARG) + +/* Get Shared Memory Config + * + * Returns the Secure/Non-secure shared memory config. + * + * Call register usage: + * a0 SMC Function ID, OPTEE_SMC_GET_SHM_CONFIG + * a1-6 Not used + * a7 Hypervisor Client ID register + * + * Have config return register usage: + * a0 OPTEE_SMC_RETURN_OK + * a1 Physical address of start of SHM + * a2 Size of of SHM + * a3 Cache settings of memory, as defined by the + * OPTEE_SMC_SHM_* values above + * a4-7 Preserved + * + * Not available register usage: + * a0 OPTEE_SMC_RETURN_ENOTAVAIL + * a1-3 Not used + * a4-7 Preserved + */ +#define OPTEE_SMC_FUNCID_GET_SHM_CONFIG 7 +#define OPTEE_SMC_GET_SHM_CONFIG \ + OPTEE_SMC_FAST_CALL_VAL(OPTEE_SMC_FUNCID_GET_SHM_CONFIG) + +struct optee_smc_get_shm_config_result +{ + unsigned long status; + unsigned long start; + unsigned long size; + unsigned long settings; +}; + +/* Exchanges capabilities between normal world and secure world + * + * Call register usage: + * a0 SMC Function ID, OPTEE_SMC_EXCHANGE_CAPABILITIES + * a1 bitfield of normal world capabilities OPTEE_SMC_NSEC_CAP_* + * a2-6 Not used + * a7 Hypervisor Client ID register + * + * Normal return register usage: + * a0 OPTEE_SMC_RETURN_OK + * a1 bitfield of secure world capabilities OPTEE_SMC_SEC_CAP_* + * a2-7 Preserved + * + * Error return register usage: + * a0 OPTEE_SMC_RETURN_ENOTAVAIL, can't use the capabilities from normal + * world + * a1 bitfield of secure world capabilities OPTEE_SMC_SEC_CAP_* + * a2-7 Preserved + */ + +/* Normal world works as a uniprocessor system */ +#define OPTEE_SMC_NSEC_CAP_UNIPROCESSOR BIT(0) +/* Secure world has reserved shared memory for normal world to use */ +#define OPTEE_SMC_SEC_CAP_HAVE_RESERVED_SHM BIT(0) +/* Secure world can communicate via previously unregistered shared memory */ +#define OPTEE_SMC_SEC_CAP_UNREGISTERED_SHM BIT(1) + +/* Secure world supports commands "register/unregister shared memory", + * secure world accepts command buffers located in any parts of non-secure + * RAM + */ +#define OPTEE_SMC_SEC_CAP_DYNAMIC_SHM BIT(2) + +#define OPTEE_SMC_FUNCID_EXCHANGE_CAPABILITIES 9 +#define OPTEE_SMC_EXCHANGE_CAPABILITIES \ + OPTEE_SMC_FAST_CALL_VAL(OPTEE_SMC_FUNCID_EXCHANGE_CAPABILITIES) + +struct optee_smc_exchange_capabilities_result +{ + unsigned long status; + unsigned long capabilities; + unsigned long reserved0; + unsigned long reserved1; +}; + +/* Disable and empties cache of shared memory objects + * + * Secure world can cache frequently used shared memory objects, for + * example objects used as RPC arguments. When secure world is idle this + * function returns one shared memory reference to free. To disable the + * cache and free all cached objects this function has to be called until + * it returns OPTEE_SMC_RETURN_ENOTAVAIL. + * + * Call register usage: + * a0 SMC Function ID, OPTEE_SMC_DISABLE_SHM_CACHE + * a1-6 Not used + * a7 Hypervisor Client ID register + * + * Normal return register usage: + * a0 OPTEE_SMC_RETURN_OK + * a1 Upper 32bit of a 64bit Shared memory cookie + * a2 Lower 32bit of a 64bit Shared memory cookie + * a3-7 Preserved + * + * Cache empty return register usage: + * a0 OPTEE_SMC_RETURN_ENOTAVAIL + * a1-7 Preserved + * + * Not idle return register usage: + * a0 OPTEE_SMC_RETURN_EBUSY + * a1-7 Preserved + */ +#define OPTEE_SMC_FUNCID_DISABLE_SHM_CACHE 10 +#define OPTEE_SMC_DISABLE_SHM_CACHE \ + OPTEE_SMC_FAST_CALL_VAL(OPTEE_SMC_FUNCID_DISABLE_SHM_CACHE) + +struct optee_smc_disable_shm_cache_result +{ + unsigned long status; + unsigned long shm_upper32; + unsigned long shm_lower32; + unsigned long reserved0; +}; + +/* Enable cache of shared memory objects + * + * Secure world can cache frequently used shared memory objects, for + * example objects used as RPC arguments. When secure world is idle this + * function returns OPTEE_SMC_RETURN_OK and the cache is enabled. If + * secure world isn't idle OPTEE_SMC_RETURN_EBUSY is returned. + * + * Call register usage: + * a0 SMC Function ID, OPTEE_SMC_ENABLE_SHM_CACHE + * a1-6 Not used + * a7 Hypervisor Client ID register + * + * Normal return register usage: + * a0 OPTEE_SMC_RETURN_OK + * a1-7 Preserved + * + * Not idle return register usage: + * a0 OPTEE_SMC_RETURN_EBUSY + * a1-7 Preserved + */ +#define OPTEE_SMC_FUNCID_ENABLE_SHM_CACHE 11 +#define OPTEE_SMC_ENABLE_SHM_CACHE \ + OPTEE_SMC_FAST_CALL_VAL(OPTEE_SMC_FUNCID_ENABLE_SHM_CACHE) + +/* Resume from RPC (for example after processing a foreign interrupt) + * + * Call register usage: + * a0 SMC Function ID, OPTEE_SMC_CALL_RETURN_FROM_RPC + * a1-3 Value of a1-3 when OPTEE_SMC_CALL_WITH_ARG returned + * OPTEE_SMC_RETURN_RPC in a0 + * + * Return register usage is the same as for OPTEE_SMC_*CALL_WITH_ARG above. + * + * Possible return values + * OPTEE_SMC_RETURN_UNKNOWN_FUNCTION Trusted OS does not recognize this + * function. + * OPTEE_SMC_RETURN_OK Original call completed, result + * updated in the previously supplied. + * struct optee_msg_arg + * OPTEE_SMC_RETURN_RPC Call suspended by RPC call to normal + * world. + * OPTEE_SMC_RETURN_ERESUME Resume failed, the opaque resume + * information was corrupt. + */ +#define OPTEE_SMC_FUNCID_RETURN_FROM_RPC 3 +#define OPTEE_SMC_CALL_RETURN_FROM_RPC \ + OPTEE_SMC_STD_CALL_VAL(OPTEE_SMC_FUNCID_RETURN_FROM_RPC) + +#define OPTEE_SMC_RETURN_RPC_PREFIX_MASK 0xFFFF0000 +#define OPTEE_SMC_RETURN_RPC_PREFIX 0xFFFF0000 +#define OPTEE_SMC_RETURN_RPC_FUNC_MASK 0x0000FFFF + +#define OPTEE_SMC_RETURN_GET_RPC_FUNC(ret) \ + ((ret) & OPTEE_SMC_RETURN_RPC_FUNC_MASK) + +#define OPTEE_SMC_RPC_VAL(func) ((func) | OPTEE_SMC_RETURN_RPC_PREFIX) + +/* Allocate memory for RPC parameter passing. The memory is used to hold a + * struct optee_msg_arg. + * + * "Call" register usage: + * a0 This value, OPTEE_SMC_RETURN_RPC_ALLOC + * a1 Size in bytes of required argument memory + * a2 Not used + * a3 Resume information, must be preserved + * a4-5 Not used + * a6-7 Resume information, must be preserved + * + * "Return" register usage: + * a0 SMC Function ID, OPTEE_SMC_CALL_RETURN_FROM_RPC. + * a1 Upper 32bits of 64bit physical pointer to allocated + * memory, (a1 == 0 && a2 == 0) if size was 0 or if memory can't + * be allocated. + * a2 Lower 32bits of 64bit physical pointer to allocated + * memory, (a1 == 0 && a2 == 0) if size was 0 or if memory can't + * be allocated + * a3 Preserved + * a4 Upper 32bits of 64bit Shared memory cookie used when freeing + * the memory or doing an RPC + * a5 Lower 32bits of 64bit Shared memory cookie used when freeing + * the memory or doing an RPC + * a6-7 Preserved + */ +#define OPTEE_SMC_RPC_FUNC_ALLOC 0 +#define OPTEE_SMC_RETURN_RPC_ALLOC \ + OPTEE_SMC_RPC_VAL(OPTEE_SMC_RPC_FUNC_ALLOC) + +/* Free memory previously allocated by OPTEE_SMC_RETURN_RPC_ALLOC + * + * "Call" register usage: + * a0 This value, OPTEE_SMC_RETURN_RPC_FREE + * a1 Upper 32bits of 64bit shared memory cookie belonging to this + * argument memory + * a2 Lower 32bits of 64bit shared memory cookie belonging to this + * argument memory + * a3-7 Resume information, must be preserved + * + * "Return" register usage: + * a0 SMC Function ID, OPTEE_SMC_CALL_RETURN_FROM_RPC. + * a1-2 Not used + * a3-7 Preserved + */ +#define OPTEE_SMC_RPC_FUNC_FREE 2 +#define OPTEE_SMC_RETURN_RPC_FREE \ + OPTEE_SMC_RPC_VAL(OPTEE_SMC_RPC_FUNC_FREE) + +/* Deliver foreign interrupt to normal world. + * + * "Call" register usage: + * a0 OPTEE_SMC_RETURN_RPC_FOREIGN_INTR + * a1-7 Resume information, must be preserved + * + * "Return" register usage: + * a0 SMC Function ID, OPTEE_SMC_CALL_RETURN_FROM_RPC. + * a1-7 Preserved + */ +#define OPTEE_SMC_RPC_FUNC_FOREIGN_INTR 4 +#define OPTEE_SMC_RETURN_RPC_FOREIGN_INTR \ + OPTEE_SMC_RPC_VAL(OPTEE_SMC_RPC_FUNC_FOREIGN_INTR) + +/* Do an RPC request. The supplied struct optee_msg_arg tells which + * request to do and the parameters for the request. The following fields + * are used (the rest are unused): + * - cmd the Request ID + * - ret return value of the request, filled in by normal world + * - num_params number of parameters for the request + * - params the parameters + * - param_attrs attributes of the parameters + * + * "Call" register usage: + * a0 OPTEE_SMC_RETURN_RPC_CMD + * a1 Upper 32bit of a 64bit Shared memory cookie holding a + * struct optee_msg_arg, must be preserved, only the data should + * be updated + * a2 Lower 32bit of a 64bit Shared memory cookie holding a + * struct optee_msg_arg, must be preserved, only the data should + * be updated + * a3-7 Resume information, must be preserved + * + * "Return" register usage: + * a0 SMC Function ID, OPTEE_SMC_CALL_RETURN_FROM_RPC. + * a1-2 Not used + * a3-7 Preserved + */ +#define OPTEE_SMC_RPC_FUNC_CMD 5 +#define OPTEE_SMC_RETURN_RPC_CMD \ + OPTEE_SMC_RPC_VAL(OPTEE_SMC_RPC_FUNC_CMD) + +/* Returned in a0 */ +#define OPTEE_SMC_RETURN_UNKNOWN_FUNCTION 0xFFFFFFFF + +/* Returned in a0 only from Trusted OS functions */ +#define OPTEE_SMC_RETURN_OK 0x0 +#define OPTEE_SMC_RETURN_ETHREAD_LIMIT 0x1 +#define OPTEE_SMC_RETURN_EBUSY 0x2 +#define OPTEE_SMC_RETURN_ERESUME 0x3 +#define OPTEE_SMC_RETURN_EBADADDR 0x4 +#define OPTEE_SMC_RETURN_EBADCMD 0x5 +#define OPTEE_SMC_RETURN_ENOMEM 0x6 +#define OPTEE_SMC_RETURN_ENOTAVAIL 0x7 +#define OPTEE_SMC_RETURN_IS_RPC(ret) optee_smc_return_is_rpc((ret)) + +static inline bool optee_smc_return_is_rpc(uint32_t ret) +{ + return ret != OPTEE_SMC_RETURN_UNKNOWN_FUNCTION && + (ret & OPTEE_SMC_RETURN_RPC_PREFIX_MASK) == + OPTEE_SMC_RETURN_RPC_PREFIX; +} + +#endif /* __DRIVERS_MISC_OPTEE_SMC_H */