From 6b045dd43d5cdaae8b2e0cb1978709b625762f9f Mon Sep 17 00:00:00 2001 From: cepetr Date: Tue, 1 Apr 2025 09:06:10 +0200 Subject: [PATCH] feat(core): introduce systask id & task count limit [no changelog] --- core/embed/sys/task/inc/sys/systask.h | 18 +++++++++++----- core/embed/sys/task/stm32/applet.c | 6 ++++-- core/embed/sys/task/stm32/systask.c | 30 ++++++++++++++++++++++++++- 3 files changed, 46 insertions(+), 8 deletions(-) diff --git a/core/embed/sys/task/inc/sys/systask.h b/core/embed/sys/task/inc/sys/systask.h index ef0f39eeb8..72f72e6501 100644 --- a/core/embed/sys/task/inc/sys/systask.h +++ b/core/embed/sys/task/inc/sys/systask.h @@ -17,8 +17,7 @@ * along with this program. If not, see . */ -#ifndef TREZORHAL_SYSTASK_H -#define TREZORHAL_SYSTASK_H +#pragma once #include @@ -97,6 +96,12 @@ typedef void (*systask_error_handler_t)(const systask_postmortem_t* pminfo); #ifdef KERNEL_MODE +// Maximum number of tasks that can be created +#define SYSTASK_MAX_TASKS 2 + +// Zero-based task ID (up SYSTASK_MAX_TASKS - 1) +typedef uint8_t systask_id_t; + // Task context used by the kernel to save the state of each task // when switching between them typedef struct { @@ -111,6 +116,8 @@ typedef struct { // Set to nonzero, if the task is killed uint32_t killed; + // Task id + systask_id_t id; // MPU mode the task is running in mpu_mode_t mpu_mode; // Task post-mortem information @@ -134,7 +141,7 @@ void systask_yield_to(systask_t* task); // Initializes a task with the given stack pointer, stack size // // The task must be not be running when the function is called -void systask_init(systask_t* task, uint32_t stack_ptr, uint32_t stack_size, +bool systask_init(systask_t* task, uint32_t stack_ptr, uint32_t stack_size, void* context); // Pushes data onto the stack of the task @@ -154,6 +161,9 @@ void systask_pop_data(systask_t* task, size_t size); bool systask_push_call(systask_t* task, void* fn, uint32_t arg1, uint32_t arg2, uint32_t arg3); +// Gets the Id (zero-based index up SYSTASK_MAX_TASKS - 1) of the given task +systask_id_t systask_id(systask_t* task); + // Terminates the task with the given exit code // // If the task is not specified (NULL), it's automatically determined: @@ -181,5 +191,3 @@ void systask_exit_fatal(systask_t* task, const char* message, int line); #endif // KERNEL_MODE - -#endif // TREZORHAL_SYSTASK_H diff --git a/core/embed/sys/task/stm32/applet.c b/core/embed/sys/task/stm32/applet.c index 3d03d0f7cb..fdd42c9c53 100644 --- a/core/embed/sys/task/stm32/applet.c +++ b/core/embed/sys/task/stm32/applet.c @@ -56,8 +56,10 @@ bool applet_reset(applet_t* applet, uint32_t cmd, const void* arg, applet_clear_memory(applet); // Reset the applet task (stack pointer, etc.) - systask_init(&applet->task, applet->header->stack.start, - applet->header->stack.size, applet); + if (!systask_init(&applet->task, applet->header->stack.start, + applet->header->stack.size, applet)) { + return false; + } // Copy the arguments onto the applet stack void* arg_copy = NULL; diff --git a/core/embed/sys/task/stm32/systask.c b/core/embed/sys/task/stm32/systask.c index 852b53a415..d6ddddae45 100644 --- a/core/embed/sys/task/stm32/systask.c +++ b/core/embed/sys/task/stm32/systask.c @@ -53,6 +53,8 @@ typedef struct { systask_t* active_task; // Task to be scheduled next systask_t* waiting_task; + // Bitmap of used task IDs + uint32_t task_id_map; } systask_scheduler_t; // Global task manager state @@ -61,8 +63,10 @@ static systask_scheduler_t g_systask_scheduler = { // to function correctly before the scheduler is initialized. .active_task = &g_systask_scheduler.kernel_task, .waiting_task = &g_systask_scheduler.kernel_task, + .task_id_map = 0x00000001, // Kernel task is always present .kernel_task = { .sp_lim = (uint32_t)&_stack_section_start, + .id = 0, // Kernel task ID == 0 }}; void systask_scheduler_init(systask_error_handler_t error_handler) { @@ -73,6 +77,7 @@ void systask_scheduler_init(systask_error_handler_t error_handler) { scheduler->error_handler = error_handler; scheduler->active_task = &scheduler->kernel_task; scheduler->waiting_task = scheduler->active_task; + scheduler->task_id_map = 0x00000001; // Kernel task is always present scheduler->kernel_task.sp_lim = (uint32_t)&_stack_section_start; @@ -117,16 +122,36 @@ void systask_yield_to(systask_t* task) { systask_yield(); } -void systask_init(systask_t* task, uint32_t stack_ptr, uint32_t stack_size, +static systask_id_t systask_get_unused_id(void) { + systask_id_t id = 0; + while (++id < SYSTASK_MAX_TASKS) { + if ((g_systask_scheduler.task_id_map & (1 << id)) == 0) { + break; + } + } + return id; +} + +bool systask_init(systask_t* task, uint32_t stack_ptr, uint32_t stack_size, void* applet) { + systask_id_t id = systask_get_unused_id(); + if (id >= SYSTASK_MAX_TASKS) { + return false; + } + memset(task, 0, sizeof(systask_t)); task->sp = stack_ptr + stack_size; task->sp_lim = stack_ptr + 256; task->exc_return = 0xFFFFFFED; // Thread mode, use PSP, pop FP context + task->id = id; task->mpu_mode = MPU_MODE_APP; task->applet = applet; + + return true; } +systask_id_t systask_id(const systask_t* task) { return task->id; } + uint32_t* systask_push_data(systask_t* task, const void* data, size_t size) { if (task->sp < task->sp_lim) { // Stack overflow @@ -211,6 +236,9 @@ static void systask_kill(systask_t* task) { // if it returns. Neither is expected to happen. reboot_device(); } else if (task == scheduler->active_task) { + // Free task ID + scheduler->task_id_map &= ~(1 << task->id); + // Switch to the kernel task systask_yield_to(&scheduler->kernel_task); }