Files
nuttx/drivers/misc/optee_rpc.c
chao an 87f134cfaa sched/sleep: replace all Signal-based sleep implement to Scheduled sleep
Nuttx currently has 2 types of sleep interfaces:

1. Signal-scheduled sleep: nxsig_sleep() / nxsig_usleep() / nxsig_nanosleep()
Weaknesses:
a. Signal-dependent: The signal-scheduled sleep method is bound to the signal framework, while some driver sleep operations do not depend on signals.
b. Timespec conversion: Signal-scheduled sleep involves timespec conversion, which has a significant impact on performance.

2. Busy sleep: up_mdelay() / up_udelay()
Weaknesses:
a. Does not actively trigger scheduling, occupy the CPU loading.

3. New interfaces: Scheduled sleep: nxsched_sleep() / nxsched_usleep() / nxsched_msleep() / nxsched_ticksleep()
Strengths:
a. Does not depend on the signal framework.
b. Tick-based, without additional computational overhead.

Currently, the Nuttx driver framework extensively uses nxsig_* interfaces. However, the driver does not need to rely on signals or timespec conversion.
Therefore, a new set of APIs is added to reduce dependencies on other modules.

(This PR also aims to make signals optional, further reducing the code size of Nuttx.)

Signed-off-by: chao an <anchao.archer@bytedance.com>
2025-10-17 14:05:02 +08:00

336 lines
10 KiB
C

/****************************************************************************
* drivers/misc/optee_rpc.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 <nuttx/signal.h>
#include <nuttx/kmalloc.h>
#include <stdint.h>
#include "optee.h"
#include "optee_msg.h"
#include "optee_rpc.h"
#ifdef CONFIG_DEV_OPTEE_SUPPLICANT
# include "optee_supplicant.h"
#endif
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: optee_rpc_cmd_get_time
*
* Description:
* Return REE wall-clock time (seconds + nanoseconds) to secure world.
*
* Parameters:
* arg - Pointer to the RPC message argument located in shared memory by
* the secure world. The answer will be placed in the same argument.
*
* Returned Value:
* The time is written to:
* arg->params[0].u.value.a containing seconds since epoch
* arg->params[0].u.value.b containing nanoseconds
* Result code is written to arg->ret.
*
****************************************************************************/
static void optee_rpc_cmd_get_time(FAR struct optee_msg_arg *arg)
{
struct timespec ts;
/* OP-TEE parameter validation. */
if (arg->num_params != 1 ||
(arg->params[0].attr & OPTEE_MSG_ATTR_TYPE_MASK)
!= OPTEE_MSG_ATTR_TYPE_VALUE_OUTPUT)
{
arg->ret = TEE_ERROR_BAD_PARAMETERS;
return;
}
if (clock_gettime(CLOCK_REALTIME, &ts) < 0)
{
/* Should not happen unless the RTC driver is missing */
arg->ret = TEE_ERROR_GENERIC;
return;
}
arg->params[0].u.value.a = (uint32_t)ts.tv_sec; /* Seconds since epoch. */
arg->params[0].u.value.b = (uint32_t)ts.tv_nsec; /* Nanoseconds. */
arg->ret = TEE_SUCCESS;
}
/****************************************************************************
* Name: optee_rpc_cmd_suspend
*
* Description:
* Request from OP-TEE to suspend the current nuttx process.
*
* Parameters:
* arg - Pointer to the RPC message argument, located in a shared page, by
* the secure world, containing the time in msec to sleep.
*
* Returned Value:
* None. Result codes are written into arg->ret.
*
****************************************************************************/
static void optee_rpc_cmd_suspend(FAR struct optee_msg_arg *arg)
{
useconds_t usec_to_wait;
/* OP-TEE parameter validation. */
if (arg->num_params != 1 ||
(arg->params[0].attr & OPTEE_MSG_ATTR_TYPE_MASK) !=
OPTEE_MSG_ATTR_TYPE_VALUE_INPUT)
{
arg->ret = TEE_ERROR_BAD_PARAMETERS;
return;
}
usec_to_wait = arg->params[0].u.value.a * 1000;
if (usec_to_wait)
{
nxsched_usleep(usec_to_wait);
}
arg->ret = TEE_SUCCESS;
}
/****************************************************************************
* Name: optee_rpc_cmd_shm_alloc
*
* Description:
* Handle OP-TEE's RPC to allocate shared memory.
*
* Parameters:
* priv - Pointer to the driver's optee_priv_data struct.
* arg - Pointer to the RPC message argument, located in a shared page
* by the secure world. A copy of this message might be sent to the
* supplicant process that runs in userspace for further processing.
* last_page_list - Passes by reference a pointer that will be updated with
* the virtual address of the page list.
*
* Returned Value:
* None. Result codes are written into arg->ret.
* Information about the shared memory is passed through arg->params
*
****************************************************************************/
static void optee_rpc_cmd_shm_alloc(FAR struct optee_priv_data *priv,
FAR struct optee_msg_arg *arg,
FAR void **last_page_list)
{
FAR struct optee_shm *shm;
size_t n;
size_t size;
int32_t ret = -EINVAL;
arg->ret_origin = TEE_ORIGIN_COMMS;
/* OP-TEE parameter validation. */
if (arg->num_params == 0 ||
arg->params[0].attr != OPTEE_MSG_ATTR_TYPE_VALUE_INPUT)
{
arg->ret = TEE_ERROR_BAD_PARAMETERS;
return;
}
for (n = 1; n < arg->num_params; n++)
{
if (arg->params[n].attr != OPTEE_MSG_ATTR_TYPE_NONE)
{
arg->ret = TEE_ERROR_BAD_PARAMETERS;
return;
}
}
size = arg->params[0].u.value.b;
switch (arg->params[0].u.value.a)
{
case OPTEE_MSG_RPC_SHM_TYPE_APPL:
#ifdef CONFIG_DEV_OPTEE_SUPPLICANT
ret = optee_supplicant_alloc(priv, size, &shm);
break;
#else
ret = -ENOTSUP;
#endif
case OPTEE_MSG_RPC_SHM_TYPE_KERNEL:
ret = optee_shm_alloc(priv, NULL, size, TEE_SHM_ALLOC, &shm);
break;
}
arg->ret = optee_convert_from_errno(ret);
if (arg->ret != TEE_SUCCESS)
{
return;
}
if (shm->flags & TEE_SHM_REGISTER)
{
arg->params[0].attr = OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT |
OPTEE_MSG_ATTR_NONCONTIG;
arg->params[0].u.tmem.buf_ptr = shm->paddr;
arg->params[0].u.tmem.size = shm->length;
arg->params[0].u.tmem.shm_ref = (unsigned long)shm;
*last_page_list = shm->page_list;
}
else
{
arg->params[0].attr = OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT;
arg->params[0].u.tmem.buf_ptr = shm->paddr;
arg->params[0].u.tmem.size = size;
arg->params[0].u.tmem.shm_ref = (unsigned long)shm;
}
}
/****************************************************************************
* Name: optee_rpc_cmd_shm_free
*
* Description:
* RPC Request from OP-TEE to free shared memory allocated by nuttx.
*
* Parameters:
* priv - Pointer to the driver's optee_priv_data struct.
* arg - Pointer to the RPC message argument, located in a shared page
* by the secure world. A copy of this message might be sent to the
* supplicant process that runs in userspace for further processing.
*
* Returned Value:
* None. Result codes are written into arg->ret.
*
****************************************************************************/
static void optee_rpc_cmd_shm_free(FAR struct optee_priv_data *priv,
FAR struct optee_msg_arg *arg)
{
FAR struct optee_shm *shm;
arg->ret_origin = TEE_ORIGIN_COMMS;
/* OP-TEE parameter validation. */
if (arg->num_params != 1 ||
arg->params[0].attr != OPTEE_MSG_ATTR_TYPE_VALUE_INPUT)
{
arg->ret = TEE_ERROR_BAD_PARAMETERS;
return;
}
shm = (FAR struct optee_shm *)(unsigned long)arg->params[0].u.value.b;
switch (arg->params[0].u.value.a)
{
case OPTEE_MSG_RPC_SHM_TYPE_APPL:
#ifdef CONFIG_DEV_OPTEE_SUPPLICANT
arg->ret = optee_supplicant_free(shm->id);
if (arg->ret)
{
/* The supplicant either failed or isn't running. */
return;
}
#else
arg->ret = TEE_ERROR_NOT_SUPPORTED;
return;
#endif
break;
case OPTEE_MSG_RPC_SHM_TYPE_KERNEL:
optee_shm_free(shm);
arg->ret = TEE_SUCCESS;
break;
default:
arg->ret = TEE_ERROR_BAD_PARAMETERS;
}
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: optee_rpc_handle_cmd
*
* Description:
* Handler of RPC requests.
*
* Parameters:
* priv - Pointer to the driver's optee_priv_data struct.
* shm - Contains a pointer to the RPC message argument, located in a
* shared page, by the secure world. A copy of this message
* might be sent to the supplicant process that runs in userspace
* for further processing.
* last_page_list - Passes by reference a pointer to the virtual address
* of a page list. The page list can be freed by a
* caller or by this function, depending on the response
* of the OP-TEE to the next SMC.
*
* Returned Value:
* None. The response to OP-TEE will passed through the shared memory.
*
****************************************************************************/
void optee_rpc_handle_cmd(FAR struct optee_priv_data *priv,
FAR struct optee_shm *shm,
FAR void **last_page_list)
{
FAR struct optee_msg_arg *arg;
DEBUGASSERT(shm != NULL);
arg = (FAR struct optee_msg_arg *)shm->vaddr;
switch (arg->cmd)
{
case OPTEE_MSG_RPC_CMD_GET_TIME:
optee_rpc_cmd_get_time(arg);
break;
case OPTEE_MSG_RPC_CMD_SUSPEND:
optee_rpc_cmd_suspend(arg);
break;
case OPTEE_MSG_RPC_CMD_SHM_ALLOC:
kmm_free(*last_page_list);
*last_page_list = NULL;
optee_rpc_cmd_shm_alloc(priv, arg, last_page_list);
break;
case OPTEE_MSG_RPC_CMD_SHM_FREE:
optee_rpc_cmd_shm_free(priv, arg);
break;
default:
#ifdef CONFIG_DEV_OPTEE_SUPPLICANT
optee_supplicant_cmd(priv, arg);
#else
arg->ret = TEE_ERROR_NOT_SUPPORTED;
#endif
}
}