Skip to content

Commit

Permalink
core: arm: entry for system thread
Browse files Browse the repository at this point in the history
Adds provisioned system threads among the OP-TEE provisioned threads.
New config switch CFG_NUM_SYSTEM_THREADS defines a number of thread
contexts reserved for system function invocations. The feature is
reported by TEE during capabilities exchange.

This is needed for platforms where specific OP-TEE yielded services
are dedicated to system management that can be indirectly invoked from
an RPC sequence and hence cannot wait clients complete their invocation
to release their TEE thread context unless what system can deadlock.
SCMI services for clocks, regulators and more, exposed by the SCMI PTA,
are examples of such system services.

Adds a new SMC function ID OPTEE_SMC_CALL_SYSTEM_WITH_REGD_ARG, defined
for yielded system calls expecting using system provisioned resources.

The implementation uses a best effort strategy when allocating a system
thread. If all system thread contexts are already in use, allocate from
the common pool.

Signed-off-by: Etienne Carriere <[email protected]>
  • Loading branch information
etienne-lms committed Jan 27, 2023
1 parent 9e7f74c commit 699f930
Show file tree
Hide file tree
Showing 7 changed files with 72 additions and 33 deletions.
4 changes: 2 additions & 2 deletions core/arch/arm/include/kernel/thread_private_arch.h
Original file line number Diff line number Diff line change
Expand Up @@ -185,8 +185,8 @@ uint32_t thread_get_usr_lr(void);
void thread_set_usr_lr(uint32_t usr_lr);
#endif /*ARM32*/

void thread_alloc_and_run(uint32_t a0, uint32_t a1, uint32_t a2, uint32_t a3,
uint32_t a4, uint32_t a5);
void thread_alloc_and_run(bool sys_thread, uint32_t a0, uint32_t a1,
uint32_t a2, uint32_t a3, uint32_t a4, uint32_t a5);
void thread_resume_from_rpc(uint32_t thread_id, uint32_t a0, uint32_t a1,
uint32_t a2, uint32_t a3);

Expand Down
24 changes: 20 additions & 4 deletions core/arch/arm/include/sm/optee_smc.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* Copyright (c) 2015-2021, Linaro Limited
* Copyright (c) 2015-2023, Linaro Limited
*/
#ifndef OPTEE_SMC_H
#define OPTEE_SMC_H
Expand Down Expand Up @@ -136,11 +136,15 @@
* Call with struct optee_msg_arg as argument
*
* When called with OPTEE_SMC_CALL_WITH_RPC_ARG or
* OPTEE_SMC_CALL_WITH_REGD_ARG in a0 there is one RPC struct optee_msg_arg
* OPTEE_SMC_CALL_WITH_REGD_ARG or OPTEE_SMC_CALL_SYSTEM_WITH_REGD_ARG
* in a0 there is one RPC struct optee_msg_arg
* following after the first struct optee_msg_arg. The RPC struct
* optee_msg_arg has reserved space for the number of RPC parameters as
* returned by OPTEE_SMC_EXCHANGE_CAPABILITIES.
*
* When called with OPTEE_SMC_CALL_SYSTEM_WITH_REGD_ARG in a0 secure world
* will use provisioned system resource for the call execution.
*
* When calling these functions normal world has a few responsibilities:
* 1. It must be able to handle eventual RPCs
* 2. Non-secure interrupts should not be masked
Expand All @@ -158,8 +162,10 @@
* a4-6 Not used
* a7 Hypervisor Client ID register
*
* Call register usage, OPTEE_SMC_CALL_WITH_REGD_ARG:
* a0 SMC Function ID, OPTEE_SMC_CALL_WITH_REGD_ARG
* Call register usage, OPTEE_SMC_CALL_WITH_REGD_ARG and
* OPTEE_SMC_CALL_SYSTEM_WITH_REGD_ARG:
* a0 SMC Function ID, OPTEE_SMC_CALL_WITH_REGD_ARG or
* OPTEE_SMC_CALL_SYSTEM_WITH_REGD_ARG
* a1 Upper 32 bits of a 64-bit shared memory cookie
* a2 Lower 32 bits of a 64-bit shared memory cookie
* a3 Offset of the struct optee_msg_arg in the shared memory with the
Expand Down Expand Up @@ -203,6 +209,8 @@
OPTEE_SMC_STD_CALL_VAL(OPTEE_SMC_FUNCID_CALL_WITH_RPC_ARG)
#define OPTEE_SMC_CALL_WITH_REGD_ARG \
OPTEE_SMC_STD_CALL_VAL(OPTEE_SMC_FUNCID_CALL_WITH_REGD_ARG)
#define OPTEE_SMC_CALL_SYSTEM_WITH_REGD_ARG \
OPTEE_SMC_STD_CALL_VAL(OPTEE_SMC_FUNCID_CALL_SYSTEM_WITH_REGD_ARG)

/*
* Get Shared Memory Config
Expand Down Expand Up @@ -316,6 +324,11 @@
#define OPTEE_SMC_SEC_CAP_ASYNC_NOTIF BIT(5)
/* Secure world supports pre-allocating RPC arg struct */
#define OPTEE_SMC_SEC_CAP_RPC_ARG BIT(6)
/*
* Secure world provisions resources for system calls using SMC Function ID
* OPTEE_SMC_CALL_SYSTEM_WITH_REGD_ARG.
*/
#define OPTEE_SMC_SEC_CAP_SYSTEM_THREAD BIT(7)

#define OPTEE_SMC_FUNCID_EXCHANGE_CAPABILITIES U(9)
#define OPTEE_SMC_EXCHANGE_CAPABILITIES \
Expand Down Expand Up @@ -559,6 +572,9 @@
/* See OPTEE_SMC_CALL_WITH_REGD_ARG above */
#define OPTEE_SMC_FUNCID_CALL_WITH_REGD_ARG U(19)

/* See OPTEE_SMC_CALL_SYSTEM_WITH_REGD_ARG above */
#define OPTEE_SMC_FUNCID_CALL_SYSTEM_WITH_REGD_ARG U(22)

/*
* Resume from RPC (for example after processing a foreign interrupt)
*
Expand Down
61 changes: 37 additions & 24 deletions core/arch/arm/kernel/thread.c
Original file line number Diff line number Diff line change
Expand Up @@ -215,65 +215,78 @@ static void init_regs(struct thread_ctx *thread, uint32_t a0, uint32_t a1,
}
#endif /*ARM64*/

static void __thread_alloc_and_run(uint32_t a0, uint32_t a1, uint32_t a2,
uint32_t a3, uint32_t a4, uint32_t a5,
uint32_t a6, uint32_t a7,
static int find_free_thread(size_t start_idx, size_t count)
{
size_t n = 0;

for (n = start_idx; n < start_idx + count; n++)
if (threads[n].state == THREAD_STATE_FREE)
return n;

return -1;
}

static void __thread_alloc_and_run(bool sys_thread, uint32_t a0, uint32_t a1,
uint32_t a2, uint32_t a3, uint32_t a4,
uint32_t a5, uint32_t a6, uint32_t a7,
void *pc)
{
struct thread_core_local *l = thread_get_core_local();
bool found_thread = false;
size_t n = 0;
int i = -1;

assert(l->curr_thread == THREAD_ID_INVALID);

thread_lock_global();

for (n = 0; n < CFG_NUM_THREADS; n++) {
if (threads[n].state == THREAD_STATE_FREE) {
threads[n].state = THREAD_STATE_ACTIVE;
found_thread = true;
break;
}
}
if (sys_thread)
i = find_free_thread(CFG_NUM_THREADS - CFG_NUM_SYSTEM_THREADS,
CFG_NUM_SYSTEM_THREADS);

if (i < 0)
i = find_free_thread(0,
CFG_NUM_THREADS - CFG_NUM_SYSTEM_THREADS);

if (i >= 0)
threads[i].state = THREAD_STATE_ACTIVE;

thread_unlock_global();

if (!found_thread)
if (i < 0)
return;

l->curr_thread = n;
l->curr_thread = i;

threads[n].flags = 0;
init_regs(threads + n, a0, a1, a2, a3, a4, a5, a6, a7, pc);
threads[i].flags = 0;
init_regs(threads + i, a0, a1, a2, a3, a4, a5, a6, a7, pc);
#ifdef CFG_CORE_PAUTH
/*
* Copy the APIA key into the registers to be restored with
* thread_resume().
*/
threads[n].regs.apiakey_hi = threads[n].keys.apia_hi;
threads[n].regs.apiakey_lo = threads[n].keys.apia_lo;
threads[i].regs.apiakey_hi = threads[i].keys.apia_hi;
threads[i].regs.apiakey_lo = threads[i].keys.apia_lo;
#endif

thread_lazy_save_ns_vfp();

l->flags &= ~THREAD_CLF_TMP;
thread_resume(&threads[n].regs);
thread_resume(&threads[i].regs);
/*NOTREACHED*/
panic();
}

void thread_alloc_and_run(uint32_t a0, uint32_t a1, uint32_t a2, uint32_t a3,
uint32_t a4, uint32_t a5)
void thread_alloc_and_run(bool sys_thread, uint32_t a0, uint32_t a1,
uint32_t a2, uint32_t a3, uint32_t a4, uint32_t a5)
{
__thread_alloc_and_run(a0, a1, a2, a3, a4, a5, 0, 0,
__thread_alloc_and_run(sys_thread, a0, a1, a2, a3, a4, a5, 0, 0,
thread_std_smc_entry);
}

#ifdef CFG_SECURE_PARTITION
void thread_sp_alloc_and_run(struct thread_smc_args *args __maybe_unused)
{
__thread_alloc_and_run(args->a0, args->a1, args->a2, args->a3, args->a4,
args->a5, args->a6, args->a7,
__thread_alloc_and_run(false, args->a0, args->a1, args->a2, args->a3,
args->a4, args->a5, args->a6, args->a7,
spmc_sp_thread_entry);
}
#endif
Expand Down
5 changes: 4 additions & 1 deletion core/arch/arm/kernel/thread_optee_smc.c
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,9 @@ uint32_t thread_handle_std_smc(uint32_t a0, uint32_t a1, uint32_t a2,
thread_resume_from_rpc(a3, a1, a2, a4, a5);
rv = OPTEE_SMC_RETURN_ERESUME;
} else {
thread_alloc_and_run(a0, a1, a2, a3, 0, 0);
bool sys_thread = (a0 == OPTEE_SMC_CALL_SYSTEM_WITH_REGD_ARG);

thread_alloc_and_run(sys_thread, a0, a1, a2, a3, 0, 0);
rv = OPTEE_SMC_RETURN_ETHREAD_LIMIT;
}

Expand Down Expand Up @@ -279,6 +281,7 @@ static uint32_t std_smc_entry(uint32_t a0, uint32_t a1, uint32_t a2,
return std_entry_with_parg(reg_pair_to_64(a1, a2),
with_rpc_arg);
case OPTEE_SMC_CALL_WITH_REGD_ARG:
case OPTEE_SMC_CALL_SYSTEM_WITH_REGD_ARG:
return std_entry_with_regd_arg(reg_pair_to_64(a1, a2), a3);
default:
EMSG("Unknown SMC 0x%"PRIx32, a0);
Expand Down
4 changes: 2 additions & 2 deletions core/arch/arm/kernel/thread_spmc.c
Original file line number Diff line number Diff line change
Expand Up @@ -451,8 +451,8 @@ static void handle_yielding_call(struct thread_smc_args *args)
0);
res = TEE_ERROR_BAD_PARAMETERS;
} else {
thread_alloc_and_run(args->a1, args->a3, args->a4, args->a5,
args->a6, args->a7);
thread_alloc_and_run(false, args->a1, args->a3, args->a4,
args->a5, args->a6, args->a7);
res = TEE_ERROR_BUSY;
}
spmc_set_args(args, FFA_MSG_SEND_DIRECT_RESP_32,
Expand Down
3 changes: 3 additions & 0 deletions core/arch/arm/tee/entry_fast.c
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,9 @@ static void tee_entry_exchange_capabilities(struct thread_smc_args *args)

args->a1 |= OPTEE_SMC_SEC_CAP_RPC_ARG;
args->a3 = THREAD_RPC_MAX_NUM_PARAMS;

if (CFG_NUM_SYSTEM_THREADS)
args->a1 |= OPTEE_SMC_SEC_CAP_SYSTEM_THREAD;
}

static void tee_entry_disable_shm_cache(struct thread_smc_args *args)
Expand Down
4 changes: 4 additions & 0 deletions mk/config.mk
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,10 @@ CFG_WITH_SOFTWARE_PRNG ?= y
# Number of threads
CFG_NUM_THREADS ?= 2

# Number of threads among CFG_NUM_THREADS provisioned for system invocation
# as for an SCMI service.
CFG_NUM_SYSTEM_THREADS ?= 0

# API implementation version
CFG_TEE_API_VERSION ?= GPD-1.1-dev

Expand Down

0 comments on commit 699f930

Please sign in to comment.