mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-04-13 13:55:50 +00:00
feat(core): introduce systask id & task count limit
[no changelog]
This commit is contained in:
parent
7cbbfb2adc
commit
604a8cbba7
@ -17,8 +17,7 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TREZORHAL_SYSTASK_H
|
||||
#define TREZORHAL_SYSTASK_H
|
||||
#pragma once
|
||||
|
||||
#include <trezor_types.h>
|
||||
|
||||
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user