From 2bc6f5ca08f94499103d3165d45b9a11ec8290ba Mon Sep 17 00:00:00 2001 From: Etienne Carriere Date: Fri, 13 Jan 2023 08:20:29 +0100 Subject: [PATCH 1/7] core: arm: entry for system thread 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. Reviewed-by: Jens Wiklander Signed-off-by: Etienne Carriere --- .../arm/include/kernel/thread_private_arch.h | 4 +- core/arch/arm/include/sm/optee_smc.h | 24 ++++++-- core/arch/arm/kernel/thread.c | 61 +++++++++++-------- core/arch/arm/kernel/thread_optee_smc.c | 5 +- core/arch/arm/kernel/thread_spmc.c | 4 +- core/arch/arm/tee/entry_fast.c | 3 + mk/config.mk | 4 ++ 7 files changed, 72 insertions(+), 33 deletions(-) diff --git a/core/arch/arm/include/kernel/thread_private_arch.h b/core/arch/arm/include/kernel/thread_private_arch.h index 450d4171fae..9b6b1feb551 100644 --- a/core/arch/arm/include/kernel/thread_private_arch.h +++ b/core/arch/arm/include/kernel/thread_private_arch.h @@ -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); diff --git a/core/arch/arm/include/sm/optee_smc.h b/core/arch/arm/include/sm/optee_smc.h index cd45917d776..d165372f3cf 100644 --- a/core/arch/arm/include/sm/optee_smc.h +++ b/core/arch/arm/include/sm/optee_smc.h @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 \ @@ -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(20) + /* * Resume from RPC (for example after processing a foreign interrupt) * diff --git a/core/arch/arm/kernel/thread.c b/core/arch/arm/kernel/thread.c index f4356b3816a..558635b6d62 100644 --- a/core/arch/arm/kernel/thread.c +++ b/core/arch/arm/kernel/thread.c @@ -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 diff --git a/core/arch/arm/kernel/thread_optee_smc.c b/core/arch/arm/kernel/thread_optee_smc.c index e4b803e0169..723cf326e43 100644 --- a/core/arch/arm/kernel/thread_optee_smc.c +++ b/core/arch/arm/kernel/thread_optee_smc.c @@ -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; } @@ -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); diff --git a/core/arch/arm/kernel/thread_spmc.c b/core/arch/arm/kernel/thread_spmc.c index 3b4ac0b4e35..41f197ebde6 100644 --- a/core/arch/arm/kernel/thread_spmc.c +++ b/core/arch/arm/kernel/thread_spmc.c @@ -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, diff --git a/core/arch/arm/tee/entry_fast.c b/core/arch/arm/tee/entry_fast.c index 5198cae44ae..dc1d10b73e4 100644 --- a/core/arch/arm/tee/entry_fast.c +++ b/core/arch/arm/tee/entry_fast.c @@ -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) diff --git a/mk/config.mk b/mk/config.mk index ebd99160140..1ac3c9dec83 100644 --- a/mk/config.mk +++ b/mk/config.mk @@ -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 From 687e777cd0121f7e82e8229228c58e192891670d Mon Sep 17 00:00:00 2001 From: Etienne Carriere Date: Fri, 27 Jan 2023 12:12:05 +0100 Subject: [PATCH 2/7] plat-stm32mp1: provision system thread for SCMI support Provision a system thread for SCMI support on platform STM32MP1 Acked-by: Jens Wiklander Signed-off-by: Etienne Carriere --- core/arch/arm/plat-stm32mp1/conf.mk | 1 + 1 file changed, 1 insertion(+) diff --git a/core/arch/arm/plat-stm32mp1/conf.mk b/core/arch/arm/plat-stm32mp1/conf.mk index 94b104b9c90..17381082255 100644 --- a/core/arch/arm/plat-stm32mp1/conf.mk +++ b/core/arch/arm/plat-stm32mp1/conf.mk @@ -235,6 +235,7 @@ endif # Provision enough threads to pass xtest ifneq (,$(filter y,$(CFG_SCMI_PTA) $(CFG_STM32MP1_SCMI_SIP))) +CFG_NUM_SYSTEM_THREADS ?= 1 ifeq ($(CFG_WITH_PAGER),y) CFG_NUM_THREADS ?= 3 else From d3f22554e368e76aa36d333f1ca5cb41b453eb99 Mon Sep 17 00:00:00 2001 From: Etienne Carriere Date: Tue, 14 Feb 2023 09:13:53 +0100 Subject: [PATCH 3/7] [review] core: arm: entry for system thread From Linux optee driver discussion, REE should call OP-TEE to reserve system contexts when needed. This change modifies how threads are allocated (check counters instead of finding a free cell). Adds 2 fastcall SMC functions for REE to reserve/release system contexts that is thread_counts.sys_reserved. The policy allows context reservation as far as there remains at least 1 generic purpose thread context. Signed-off-by: Etienne Carriere --- .../arm/include/kernel/thread_private_arch.h | 5 + core/arch/arm/include/sm/optee_smc.h | 46 +++++++++ core/arch/arm/kernel/thread.c | 97 +++++++++++++++---- core/arch/arm/tee/entry_fast.c | 36 ++++++- core/include/kernel/thread.h | 1 + mk/config.mk | 7 +- 6 files changed, 171 insertions(+), 21 deletions(-) diff --git a/core/arch/arm/include/kernel/thread_private_arch.h b/core/arch/arm/include/kernel/thread_private_arch.h index 9b6b1feb551..65143745654 100644 --- a/core/arch/arm/include/kernel/thread_private_arch.h +++ b/core/arch/arm/include/kernel/thread_private_arch.h @@ -239,5 +239,10 @@ uint32_t thread_handle_std_smc(uint32_t a0, uint32_t a1, uint32_t a2, void thread_scall_handler(struct thread_scall_regs *regs); void thread_spmc_register_secondary_ep(vaddr_t ep); + +/* Reservation of system thread context */ +TEE_Result reserve_sys_thread(void); +TEE_Result unreserve_sys_thread(void); + #endif /*__ASSEMBLER__*/ #endif /*__KERNEL_THREAD_PRIVATE_ARCH_H*/ diff --git a/core/arch/arm/include/sm/optee_smc.h b/core/arch/arm/include/sm/optee_smc.h index d165372f3cf..a4b8ae45db1 100644 --- a/core/arch/arm/include/sm/optee_smc.h +++ b/core/arch/arm/include/sm/optee_smc.h @@ -575,6 +575,52 @@ /* See OPTEE_SMC_CALL_SYSTEM_WITH_REGD_ARG above */ #define OPTEE_SMC_FUNCID_CALL_SYSTEM_WITH_REGD_ARG U(20) +/* + * Request reservation of a system invocation thread context in OP-TEE + * + * Call register usage: + * a0 SMC Function ID: OPTEE_SMC_CALL_RESERVE_SYS_THREAD + * a1-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 + * + * Possible return values: + * OPTEE_SMC_RETURN_UNKNOWN_FUNCTION Trusted OS does not recognize this + * function. + * OPTEE_SMC_RETURN_OK Call successfully completed. + * OPTEE_SMC_RETURN_ETHREAD_LIMIT Number of Trusted OS threads exceeded + * for the request. + */ +#define OPTEE_SMC_FUNCID_CALL_RESERVE_SYS_THREAD U(21) +#define OPTEE_SMC_CALL_RESERVE_SYS_THREAD \ + OPTEE_SMC_STD_CALL_VAL(OPTEE_SMC_FUNCID_CALL_RESERVE_SYS_THREAD) + +/* + * Unregister reservation of a system invocation thread context in OP-TEE + * + * Call register usage: + * a0 SMC Function ID: OPTEE_SMC_CALL_UNRESERVE_SYS_THREAD + * a1-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 + * + * Possible return values: + * OPTEE_SMC_RETURN_UNKNOWN_FUNCTION Trusted OS does not recognize this + * function. + * OPTEE_SMC_RETURN_OK Call successfully completed. + */ +#define OPTEE_SMC_FUNCID_CALL_UNRESERVE_SYS_THREAD U(22) +#define OPTEE_SMC_CALL_UNRESERVE_SYS_THREAD \ + OPTEE_SMC_STD_CALL_VAL(OPTEE_SMC_FUNCID_CALL_UNRESERVE_SYS_THREAD) + /* * Resume from RPC (for example after processing a foreign interrupt) * diff --git a/core/arch/arm/kernel/thread.c b/core/arch/arm/kernel/thread.c index 558635b6d62..0b33ccf5c52 100644 --- a/core/arch/arm/kernel/thread.c +++ b/core/arch/arm/kernel/thread.c @@ -35,6 +35,22 @@ #include #include +/* + * struct thread_counts - Cached count of allocated threads + * @free Number of free thread context in the pool + * @sys_free Number of free reserved system thread context + * @sys_reserved Number of contexts reserved system thread + */ +struct thread_counts { + size_t free; + size_t sys_free; + size_t sys_reserved; +}; + +static struct thread_counts thread_counts = { + .free = CFG_NUM_THREADS, +}; + #ifdef CFG_CORE_UNMAP_CORE_AT_EL0 static vaddr_t thread_user_kcode_va __nex_bss; long thread_user_kcode_offset __nex_bss; @@ -215,15 +231,42 @@ static void init_regs(struct thread_ctx *thread, uint32_t a0, uint32_t a1, } #endif /*ARM64*/ -static int find_free_thread(size_t start_idx, size_t count) +TEE_Result reserve_sys_thread(void) { - size_t n = 0; + TEE_Result res = TEE_ERROR_GENERIC; + + thread_lock_global(); - for (n = start_idx; n < start_idx + count; n++) - if (threads[n].state == THREAD_STATE_FREE) - return n; + /* Add a reserved context if at least 1 generic context remains */ + if (IS_ENABLED(CFG_RESERVED_SYSTEM_THREAD) && + (thread_counts.free - thread_counts.sys_free) > 1 && + thread_counts.sys_reserved < UINT_MAX) { + thread_counts.sys_reserved++; + thread_counts.sys_free++; + res = TEE_SUCCESS; + } - return -1; + thread_unlock_global(); + + return res; +} + +TEE_Result unreserve_sys_thread(void) +{ + TEE_Result res = TEE_ERROR_GENERIC; + + thread_lock_global(); + + if (IS_ENABLED(CFG_RESERVED_SYSTEM_THREAD) && + thread_counts.sys_reserved && thread_counts.sys_free) { + thread_counts.sys_reserved--; + thread_counts.sys_free--; + res = TEE_SUCCESS; + } + + thread_unlock_global(); + + return res; } static void __thread_alloc_and_run(bool sys_thread, uint32_t a0, uint32_t a1, @@ -232,31 +275,46 @@ static void __thread_alloc_and_run(bool sys_thread, uint32_t a0, uint32_t a1, void *pc) { struct thread_core_local *l = thread_get_core_local(); + bool find_sys_thread = false; + bool find_thread = false; int i = -1; assert(l->curr_thread == THREAD_ID_INVALID); thread_lock_global(); - 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; + if (IS_ENABLED(CFG_RESERVED_SYSTEM_THREAD)) { + if (sys_thread && thread_counts.sys_free) { + thread_counts.sys_free--; + thread_counts.free--; + find_sys_thread = true; + } else if (thread_counts.free > thread_counts.sys_free) { + thread_counts.free--; + find_thread = true; + } + } else if (thread_counts.free) { + thread_counts.free--; + find_thread = true; + } thread_unlock_global(); - if (i < 0) + if (!find_thread && !find_sys_thread) return; + for (i = 0; i < CFG_NUM_THREADS; i++) + if (threads[i].state == THREAD_STATE_FREE) + break; + + assert(i < CFG_NUM_THREADS); + l->curr_thread = i; + threads[i].state = THREAD_STATE_ACTIVE; threads[i].flags = 0; + if (find_sys_thread) + threads[i].flags |= THREAD_FLAGS_SYSTEM_CONTEXT; + init_regs(threads + i, a0, a1, a2, a3, a4, a5, a6, a7, pc); #ifdef CFG_CORE_PAUTH /* @@ -456,6 +514,11 @@ void thread_state_free(void) thread_lock_global(); assert(threads[ct].state == THREAD_STATE_ACTIVE); + + thread_counts.free++; + if (threads[ct].flags & THREAD_FLAGS_SYSTEM_CONTEXT) + thread_counts.sys_free++; + threads[ct].state = THREAD_STATE_FREE; threads[ct].flags = 0; l->curr_thread = THREAD_ID_INVALID; diff --git a/core/arch/arm/tee/entry_fast.c b/core/arch/arm/tee/entry_fast.c index dc1d10b73e4..0271cd3cd72 100644 --- a/core/arch/arm/tee/entry_fast.c +++ b/core/arch/arm/tee/entry_fast.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -117,7 +118,7 @@ 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) + if (IS_ENABLED(CFG_RESERVED_SYSTEM_THREAD)) args->a1 |= OPTEE_SMC_SEC_CAP_SYSTEM_THREAD; } @@ -220,6 +221,32 @@ static void get_async_notif_value(struct thread_smc_args *args) args->a2 |= OPTEE_SMC_ASYNC_NOTIF_PENDING; } +static void request_system_thread_context(struct thread_smc_args *args) +{ + if (IS_ENABLED(CFG_RESERVED_SYSTEM_THREAD)) { + if (reserve_sys_thread()) + args->a0 = OPTEE_SMC_RETURN_ETHREAD_LIMIT; + else + args->a0 = OPTEE_SMC_RETURN_OK; + + } else { + args->a0 = OPTEE_SMC_RETURN_OK; + } +} + +static void release_system_thread_context(struct thread_smc_args *args) +{ + if (IS_ENABLED(CFG_RESERVED_SYSTEM_THREAD)) { + if (unreserve_sys_thread()) + args->a0 = OPTEE_SMC_RETURN_ETHREAD_LIMIT; + else + args->a0 = OPTEE_SMC_RETURN_OK; + + } else { + args->a0 = OPTEE_SMC_RETURN_OK; + } +} + /* * If tee_entry_fast() is overridden, it's still supposed to call this * function. @@ -294,6 +321,13 @@ void __tee_entry_fast(struct thread_smc_args *args) args->a0 = OPTEE_SMC_RETURN_UNKNOWN_FUNCTION; break; + case OPTEE_SMC_FUNCID_CALL_RESERVE_SYS_THREAD: + request_system_thread_context(args); + break; + case OPTEE_SMC_FUNCID_CALL_UNRESERVE_SYS_THREAD: + release_system_thread_context(args); + break; + default: args->a0 = OPTEE_SMC_RETURN_UNKNOWN_FUNCTION; break; diff --git a/core/include/kernel/thread.h b/core/include/kernel/thread.h index d0d0995fa65..8b1f96e5855 100644 --- a/core/include/kernel/thread.h +++ b/core/include/kernel/thread.h @@ -19,6 +19,7 @@ #define THREAD_FLAGS_COPY_ARGS_ON_RETURN BIT(0) #define THREAD_FLAGS_FOREIGN_INTR_ENABLE BIT(1) #define THREAD_FLAGS_EXIT_ON_FOREIGN_INTR BIT(2) +#define THREAD_FLAGS_SYSTEM_CONTEXT BIT(3) #define THREAD_ID_0 0 #define THREAD_ID_INVALID -1 diff --git a/mk/config.mk b/mk/config.mk index 1ac3c9dec83..ea34dbf3d81 100644 --- a/mk/config.mk +++ b/mk/config.mk @@ -112,9 +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 +# CFG_RESERVED_SYSTEM_THREAD when enabled, allows normal world to reservation +# system thread contexts reached with a specific invocation, as needed by +# OP-TEE SCMI services. +CFG_RESERVED_SYSTEM_THREAD ?= n # API implementation version CFG_TEE_API_VERSION ?= GPD-1.1-dev From b6409125bec1c168dd4e18a9723b521143ca2f6b Mon Sep 17 00:00:00 2001 From: Etienne Carriere Date: Tue, 14 Feb 2023 16:04:06 +0100 Subject: [PATCH 4/7] [review] plat-stm32mp1: provision system thread for SCMI support Enable CFG_RESERVED_SYSTEM_THREAD. Signed-off-by: Etienne Carriere --- core/arch/arm/plat-stm32mp1/conf.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/arch/arm/plat-stm32mp1/conf.mk b/core/arch/arm/plat-stm32mp1/conf.mk index 17381082255..c3a92c4d0f3 100644 --- a/core/arch/arm/plat-stm32mp1/conf.mk +++ b/core/arch/arm/plat-stm32mp1/conf.mk @@ -235,7 +235,7 @@ endif # Provision enough threads to pass xtest ifneq (,$(filter y,$(CFG_SCMI_PTA) $(CFG_STM32MP1_SCMI_SIP))) -CFG_NUM_SYSTEM_THREADS ?= 1 +CFG_RESERVED_SYSTEM_THREAD ?= y ifeq ($(CFG_WITH_PAGER),y) CFG_NUM_THREADS ?= 3 else From 41a4aa8e8e4f7a1f1d484cf82657a12a537bba33 Mon Sep 17 00:00:00 2001 From: Etienne Carriere Date: Wed, 15 Feb 2023 14:08:44 +0100 Subject: [PATCH 5/7] [review] core: arm: entry for system thread Fixes SMC funcIDs RESERVE_SYS_THREAD/UNRESERVE_SYS_THREAD: fastcall IDs not standard + minor renaing (drop CALL_ in macros name). Signed-off-by: Etienne Carriere --- core/arch/arm/include/sm/optee_smc.h | 16 ++++++++-------- core/arch/arm/tee/entry_fast.c | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/core/arch/arm/include/sm/optee_smc.h b/core/arch/arm/include/sm/optee_smc.h index a4b8ae45db1..b199d35b284 100644 --- a/core/arch/arm/include/sm/optee_smc.h +++ b/core/arch/arm/include/sm/optee_smc.h @@ -579,7 +579,7 @@ * Request reservation of a system invocation thread context in OP-TEE * * Call register usage: - * a0 SMC Function ID: OPTEE_SMC_CALL_RESERVE_SYS_THREAD + * a0 SMC Function ID: OPTEE_SMC_RESERVE_SYS_THREAD * a1-6 Not used * a7 Hypervisor Client ID register * @@ -595,15 +595,15 @@ * OPTEE_SMC_RETURN_ETHREAD_LIMIT Number of Trusted OS threads exceeded * for the request. */ -#define OPTEE_SMC_FUNCID_CALL_RESERVE_SYS_THREAD U(21) -#define OPTEE_SMC_CALL_RESERVE_SYS_THREAD \ - OPTEE_SMC_STD_CALL_VAL(OPTEE_SMC_FUNCID_CALL_RESERVE_SYS_THREAD) +#define OPTEE_SMC_FUNCID_RESERVE_SYS_THREAD U(21) +#define OPTEE_SMC_RESERVE_SYS_THREAD \ + OPTEE_SMC_FAST_CALL_VAL(OPTEE_SMC_FUNCID_RESERVE_SYS_THREAD) /* * Unregister reservation of a system invocation thread context in OP-TEE * * Call register usage: - * a0 SMC Function ID: OPTEE_SMC_CALL_UNRESERVE_SYS_THREAD + * a0 SMC Function ID: OPTEE_SMC_UNRESERVE_SYS_THREAD * a1-6 Not used * a7 Hypervisor Client ID register * @@ -617,9 +617,9 @@ * function. * OPTEE_SMC_RETURN_OK Call successfully completed. */ -#define OPTEE_SMC_FUNCID_CALL_UNRESERVE_SYS_THREAD U(22) -#define OPTEE_SMC_CALL_UNRESERVE_SYS_THREAD \ - OPTEE_SMC_STD_CALL_VAL(OPTEE_SMC_FUNCID_CALL_UNRESERVE_SYS_THREAD) +#define OPTEE_SMC_FUNCID_UNRESERVE_SYS_THREAD U(22) +#define OPTEE_SMC_UNRESERVE_SYS_THREAD \ + OPTEE_SMC_FAST_CALL_VAL(OPTEE_SMC_FUNCID_UNRESERVE_SYS_THREAD) /* * Resume from RPC (for example after processing a foreign interrupt) diff --git a/core/arch/arm/tee/entry_fast.c b/core/arch/arm/tee/entry_fast.c index 0271cd3cd72..5ccde3dc361 100644 --- a/core/arch/arm/tee/entry_fast.c +++ b/core/arch/arm/tee/entry_fast.c @@ -321,10 +321,10 @@ void __tee_entry_fast(struct thread_smc_args *args) args->a0 = OPTEE_SMC_RETURN_UNKNOWN_FUNCTION; break; - case OPTEE_SMC_FUNCID_CALL_RESERVE_SYS_THREAD: + case OPTEE_SMC_RESERVE_SYS_THREAD: request_system_thread_context(args); break; - case OPTEE_SMC_FUNCID_CALL_UNRESERVE_SYS_THREAD: + case OPTEE_SMC_UNRESERVE_SYS_THREAD: release_system_thread_context(args); break; From 4fa2469d36937250309f4b4fce127599d30122fc Mon Sep 17 00:00:00 2001 From: Etienne Carriere Date: Tue, 14 Feb 2023 09:13:53 +0100 Subject: [PATCH 6/7] [review] core: arm: entry for system thread System invocation contexts are reserved from context pool high indices, simplifies lookup for a free thread. Signed-off-by: Etienne Carriere --- core/arch/arm/kernel/thread.c | 84 ++++++++++++----------------------- core/include/kernel/thread.h | 1 - 2 files changed, 28 insertions(+), 57 deletions(-) diff --git a/core/arch/arm/kernel/thread.c b/core/arch/arm/kernel/thread.c index 0b33ccf5c52..73a96bbb367 100644 --- a/core/arch/arm/kernel/thread.c +++ b/core/arch/arm/kernel/thread.c @@ -35,28 +35,14 @@ #include #include -/* - * struct thread_counts - Cached count of allocated threads - * @free Number of free thread context in the pool - * @sys_free Number of free reserved system thread context - * @sys_reserved Number of contexts reserved system thread - */ -struct thread_counts { - size_t free; - size_t sys_free; - size_t sys_reserved; -}; - -static struct thread_counts thread_counts = { - .free = CFG_NUM_THREADS, -}; - #ifdef CFG_CORE_UNMAP_CORE_AT_EL0 static vaddr_t thread_user_kcode_va __nex_bss; long thread_user_kcode_offset __nex_bss; static size_t thread_user_kcode_size __nex_bss; #endif +static size_t __maybe_unused reserved_sys_thread; + #if defined(CFG_CORE_UNMAP_CORE_AT_EL0) && \ defined(CFG_CORE_WORKAROUND_SPECTRE_BP_SEC) && defined(ARM64) long thread_user_kdata_sp_offset __nex_bss; @@ -237,12 +223,10 @@ TEE_Result reserve_sys_thread(void) thread_lock_global(); - /* Add a reserved context if at least 1 generic context remains */ + /* Reserved a context if at least 1 generic context remains */ if (IS_ENABLED(CFG_RESERVED_SYSTEM_THREAD) && - (thread_counts.free - thread_counts.sys_free) > 1 && - thread_counts.sys_reserved < UINT_MAX) { - thread_counts.sys_reserved++; - thread_counts.sys_free++; + (CFG_NUM_THREADS - reserved_sys_thread) > 1) { + reserved_sys_thread++; res = TEE_SUCCESS; } @@ -257,10 +241,8 @@ TEE_Result unreserve_sys_thread(void) thread_lock_global(); - if (IS_ENABLED(CFG_RESERVED_SYSTEM_THREAD) && - thread_counts.sys_reserved && thread_counts.sys_free) { - thread_counts.sys_reserved--; - thread_counts.sys_free--; + if (IS_ENABLED(CFG_RESERVED_SYSTEM_THREAD) && reserved_sys_thread) { + reserved_sys_thread--; res = TEE_SUCCESS; } @@ -269,52 +251,47 @@ TEE_Result unreserve_sys_thread(void) return res; } +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 find_sys_thread = false; - bool find_thread = false; int i = -1; assert(l->curr_thread == THREAD_ID_INVALID); thread_lock_global(); - if (IS_ENABLED(CFG_RESERVED_SYSTEM_THREAD)) { - if (sys_thread && thread_counts.sys_free) { - thread_counts.sys_free--; - thread_counts.free--; - find_sys_thread = true; - } else if (thread_counts.free > thread_counts.sys_free) { - thread_counts.free--; - find_thread = true; - } - } else if (thread_counts.free) { - thread_counts.free--; - find_thread = true; - } + if (sys_thread) + i = find_free_thread(CFG_NUM_THREADS - reserved_sys_thread, + reserved_sys_thread); - thread_unlock_global(); + if (i < 0) + i = find_free_thread(0, CFG_NUM_THREADS - reserved_sys_thread); - if (!find_thread && !find_sys_thread) - return; + if (i >= 0) + threads[i].state = THREAD_STATE_ACTIVE; - for (i = 0; i < CFG_NUM_THREADS; i++) - if (threads[i].state == THREAD_STATE_FREE) - break; + thread_unlock_global(); - assert(i < CFG_NUM_THREADS); + if (i < 0) + return; l->curr_thread = i; - threads[i].state = THREAD_STATE_ACTIVE; threads[i].flags = 0; - if (find_sys_thread) - threads[i].flags |= THREAD_FLAGS_SYSTEM_CONTEXT; - init_regs(threads + i, a0, a1, a2, a3, a4, a5, a6, a7, pc); #ifdef CFG_CORE_PAUTH /* @@ -514,11 +491,6 @@ void thread_state_free(void) thread_lock_global(); assert(threads[ct].state == THREAD_STATE_ACTIVE); - - thread_counts.free++; - if (threads[ct].flags & THREAD_FLAGS_SYSTEM_CONTEXT) - thread_counts.sys_free++; - threads[ct].state = THREAD_STATE_FREE; threads[ct].flags = 0; l->curr_thread = THREAD_ID_INVALID; diff --git a/core/include/kernel/thread.h b/core/include/kernel/thread.h index 8b1f96e5855..d0d0995fa65 100644 --- a/core/include/kernel/thread.h +++ b/core/include/kernel/thread.h @@ -19,7 +19,6 @@ #define THREAD_FLAGS_COPY_ARGS_ON_RETURN BIT(0) #define THREAD_FLAGS_FOREIGN_INTR_ENABLE BIT(1) #define THREAD_FLAGS_EXIT_ON_FOREIGN_INTR BIT(2) -#define THREAD_FLAGS_SYSTEM_CONTEXT BIT(3) #define THREAD_ID_0 0 #define THREAD_ID_INVALID -1 From 934983a6476c745df3406c54aa198980de45e674 Mon Sep 17 00:00:00 2001 From: Etienne Carriere Date: Wed, 15 Feb 2023 18:10:57 +0100 Subject: [PATCH 7/7] [review] core: arm: entry for system thread request_system_thread_context() and release_system_thread_context() to return an error code when CFG_RESERVED_SYSTEM_THREAD is disabled. Rename [un]eserve_sys_thread() to thread_[un]reserve_sys_ctx(). Signed-off-by: Etienne Carriere --- core/arch/arm/include/kernel/thread_private_arch.h | 4 ++-- core/arch/arm/kernel/thread.c | 4 ++-- core/arch/arm/tee/entry_fast.c | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/core/arch/arm/include/kernel/thread_private_arch.h b/core/arch/arm/include/kernel/thread_private_arch.h index 65143745654..2238cb99179 100644 --- a/core/arch/arm/include/kernel/thread_private_arch.h +++ b/core/arch/arm/include/kernel/thread_private_arch.h @@ -241,8 +241,8 @@ void thread_scall_handler(struct thread_scall_regs *regs); void thread_spmc_register_secondary_ep(vaddr_t ep); /* Reservation of system thread context */ -TEE_Result reserve_sys_thread(void); -TEE_Result unreserve_sys_thread(void); +TEE_Result thread_reserve_sys_ctx(void); +TEE_Result thread_unreserve_sys_ctx(void); #endif /*__ASSEMBLER__*/ #endif /*__KERNEL_THREAD_PRIVATE_ARCH_H*/ diff --git a/core/arch/arm/kernel/thread.c b/core/arch/arm/kernel/thread.c index 73a96bbb367..44cfdfa4150 100644 --- a/core/arch/arm/kernel/thread.c +++ b/core/arch/arm/kernel/thread.c @@ -217,7 +217,7 @@ static void init_regs(struct thread_ctx *thread, uint32_t a0, uint32_t a1, } #endif /*ARM64*/ -TEE_Result reserve_sys_thread(void) +TEE_Result thread_reserve_sys_ctx(void) { TEE_Result res = TEE_ERROR_GENERIC; @@ -235,7 +235,7 @@ TEE_Result reserve_sys_thread(void) return res; } -TEE_Result unreserve_sys_thread(void) +TEE_Result thread_unreserve_sys_ctx(void) { TEE_Result res = TEE_ERROR_GENERIC; diff --git a/core/arch/arm/tee/entry_fast.c b/core/arch/arm/tee/entry_fast.c index 5ccde3dc361..902fc58064a 100644 --- a/core/arch/arm/tee/entry_fast.c +++ b/core/arch/arm/tee/entry_fast.c @@ -224,26 +224,26 @@ static void get_async_notif_value(struct thread_smc_args *args) static void request_system_thread_context(struct thread_smc_args *args) { if (IS_ENABLED(CFG_RESERVED_SYSTEM_THREAD)) { - if (reserve_sys_thread()) + if (thread_reserve_sys_ctx()) args->a0 = OPTEE_SMC_RETURN_ETHREAD_LIMIT; else args->a0 = OPTEE_SMC_RETURN_OK; } else { - args->a0 = OPTEE_SMC_RETURN_OK; + args->a0 = OPTEE_SMC_RETURN_EBADCMD; } } static void release_system_thread_context(struct thread_smc_args *args) { if (IS_ENABLED(CFG_RESERVED_SYSTEM_THREAD)) { - if (unreserve_sys_thread()) + if (thread_unreserve_sys_ctx()) args->a0 = OPTEE_SMC_RETURN_ETHREAD_LIMIT; else args->a0 = OPTEE_SMC_RETURN_OK; } else { - args->a0 = OPTEE_SMC_RETURN_OK; + args->a0 = OPTEE_SMC_RETURN_EBADCMD; } }