mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-05-29 12:18:51 +00:00
feat(core): introduce systask id & task count limit
[no changelog]
This commit is contained in:
parent
24048d7094
commit
6b045dd43d
@ -17,8 +17,7 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef TREZORHAL_SYSTASK_H
|
#pragma once
|
||||||
#define TREZORHAL_SYSTASK_H
|
|
||||||
|
|
||||||
#include <trezor_types.h>
|
#include <trezor_types.h>
|
||||||
|
|
||||||
@ -97,6 +96,12 @@ typedef void (*systask_error_handler_t)(const systask_postmortem_t* pminfo);
|
|||||||
|
|
||||||
#ifdef KERNEL_MODE
|
#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
|
// Task context used by the kernel to save the state of each task
|
||||||
// when switching between them
|
// when switching between them
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -111,6 +116,8 @@ typedef struct {
|
|||||||
// Set to nonzero, if the task is killed
|
// Set to nonzero, if the task is killed
|
||||||
uint32_t killed;
|
uint32_t killed;
|
||||||
|
|
||||||
|
// Task id
|
||||||
|
systask_id_t id;
|
||||||
// MPU mode the task is running in
|
// MPU mode the task is running in
|
||||||
mpu_mode_t mpu_mode;
|
mpu_mode_t mpu_mode;
|
||||||
// Task post-mortem information
|
// 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
|
// Initializes a task with the given stack pointer, stack size
|
||||||
//
|
//
|
||||||
// The task must be not be running when the function is called
|
// 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);
|
void* context);
|
||||||
|
|
||||||
// Pushes data onto the stack of the task
|
// 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,
|
bool systask_push_call(systask_t* task, void* fn, uint32_t arg1, uint32_t arg2,
|
||||||
uint32_t arg3);
|
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
|
// Terminates the task with the given exit code
|
||||||
//
|
//
|
||||||
// If the task is not specified (NULL), it's automatically determined:
|
// 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);
|
int line);
|
||||||
|
|
||||||
#endif // KERNEL_MODE
|
#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);
|
applet_clear_memory(applet);
|
||||||
|
|
||||||
// Reset the applet task (stack pointer, etc.)
|
// Reset the applet task (stack pointer, etc.)
|
||||||
systask_init(&applet->task, applet->header->stack.start,
|
if (!systask_init(&applet->task, applet->header->stack.start,
|
||||||
applet->header->stack.size, applet);
|
applet->header->stack.size, applet)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Copy the arguments onto the applet stack
|
// Copy the arguments onto the applet stack
|
||||||
void* arg_copy = NULL;
|
void* arg_copy = NULL;
|
||||||
|
@ -53,6 +53,8 @@ typedef struct {
|
|||||||
systask_t* active_task;
|
systask_t* active_task;
|
||||||
// Task to be scheduled next
|
// Task to be scheduled next
|
||||||
systask_t* waiting_task;
|
systask_t* waiting_task;
|
||||||
|
// Bitmap of used task IDs
|
||||||
|
uint32_t task_id_map;
|
||||||
} systask_scheduler_t;
|
} systask_scheduler_t;
|
||||||
|
|
||||||
// Global task manager state
|
// Global task manager state
|
||||||
@ -61,8 +63,10 @@ static systask_scheduler_t g_systask_scheduler = {
|
|||||||
// to function correctly before the scheduler is initialized.
|
// to function correctly before the scheduler is initialized.
|
||||||
.active_task = &g_systask_scheduler.kernel_task,
|
.active_task = &g_systask_scheduler.kernel_task,
|
||||||
.waiting_task = &g_systask_scheduler.kernel_task,
|
.waiting_task = &g_systask_scheduler.kernel_task,
|
||||||
|
.task_id_map = 0x00000001, // Kernel task is always present
|
||||||
.kernel_task = {
|
.kernel_task = {
|
||||||
.sp_lim = (uint32_t)&_stack_section_start,
|
.sp_lim = (uint32_t)&_stack_section_start,
|
||||||
|
.id = 0, // Kernel task ID == 0
|
||||||
}};
|
}};
|
||||||
|
|
||||||
void systask_scheduler_init(systask_error_handler_t error_handler) {
|
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->error_handler = error_handler;
|
||||||
scheduler->active_task = &scheduler->kernel_task;
|
scheduler->active_task = &scheduler->kernel_task;
|
||||||
scheduler->waiting_task = scheduler->active_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;
|
scheduler->kernel_task.sp_lim = (uint32_t)&_stack_section_start;
|
||||||
|
|
||||||
@ -117,16 +122,36 @@ void systask_yield_to(systask_t* task) {
|
|||||||
systask_yield();
|
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) {
|
void* applet) {
|
||||||
|
systask_id_t id = systask_get_unused_id();
|
||||||
|
if (id >= SYSTASK_MAX_TASKS) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
memset(task, 0, sizeof(systask_t));
|
memset(task, 0, sizeof(systask_t));
|
||||||
task->sp = stack_ptr + stack_size;
|
task->sp = stack_ptr + stack_size;
|
||||||
task->sp_lim = stack_ptr + 256;
|
task->sp_lim = stack_ptr + 256;
|
||||||
task->exc_return = 0xFFFFFFED; // Thread mode, use PSP, pop FP context
|
task->exc_return = 0xFFFFFFED; // Thread mode, use PSP, pop FP context
|
||||||
|
task->id = id;
|
||||||
task->mpu_mode = MPU_MODE_APP;
|
task->mpu_mode = MPU_MODE_APP;
|
||||||
task->applet = applet;
|
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) {
|
uint32_t* systask_push_data(systask_t* task, const void* data, size_t size) {
|
||||||
if (task->sp < task->sp_lim) {
|
if (task->sp < task->sp_lim) {
|
||||||
// Stack overflow
|
// Stack overflow
|
||||||
@ -211,6 +236,9 @@ static void systask_kill(systask_t* task) {
|
|||||||
// if it returns. Neither is expected to happen.
|
// if it returns. Neither is expected to happen.
|
||||||
reboot_device();
|
reboot_device();
|
||||||
} else if (task == scheduler->active_task) {
|
} else if (task == scheduler->active_task) {
|
||||||
|
// Free task ID
|
||||||
|
scheduler->task_id_map &= ~(1 << task->id);
|
||||||
|
|
||||||
// Switch to the kernel task
|
// Switch to the kernel task
|
||||||
systask_yield_to(&scheduler->kernel_task);
|
systask_yield_to(&scheduler->kernel_task);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user