/* * This file is part of the Trezor project, https://trezor.io/ * * Copyright (c) SatoshiLabs * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef TREZORHAL_SYSTASK_H #define TREZORHAL_SYSTASK_H #include #include #include #include "mpu.h" // Termination reason for the task typedef enum { TASK_TERM_REASON_EXIT = 0, TASK_TERM_REASON_ERROR, TASK_TERM_REASON_FATAL, TASK_TERM_REASON_FAULT, } systask_term_reason_t; typedef struct { // Fault/exception number (-15..-1) int irqn; // Configurable Fault Status Register // (combined UFSR/BFSR/MMFSR) uint32_t cfsr; // Hard Fault Status Register uint32_t hfsr; // Address associated with MemManage fault uint32_t mmfar; // Address associated with the BusFault uint32_t bfar; // Stack pointer at the time of the fault // (MSP or PSP depending on the privilege level) uint32_t sp; #if !(defined(__ARM_ARCH_8M_MAIN__) || defined(__ARM_ARCH_8M_BASE__)) // Stack pointer limit (for the stack overflow detection) uint32_t sp_lim; #endif } system_fault_t; // Task post-mortem information typedef struct { // Reason for the task termination systask_term_reason_t reason; // Whether the error occurred in privileged mode bool privileged; union { // Argument passed to `systask_exit()` struct { int code; } exit; // Fault information catched in `systask_exit_fault()` system_fault_t fault; // Arguments passed to `systask_exit_fatal()` struct { uint32_t line; char file[64]; char expr[64]; } fatal; // Arguments passed to `systask_exit_error()` struct { char title[64]; char message[64]; char footer[64]; } error; }; } systask_postmortem_t; // Error handler callback invoke when kernel task terminates. // // The purpose of this callbacks display RSOD (Red Screen of Death). // // The callback may be called from any context, including interrupt context. typedef void (*systask_error_handler_t)(const systask_postmortem_t* pminfo); #ifdef KERNEL_MODE // Task context used by the kernel to save the state of each task // when switching between them typedef struct { // `sp`, `sp_lim`, `exc_return` and `killed` should at the beginning // and in this order to be compatible with the PendSV_Handler // Stack pointer value uint32_t sp; // Stack pointer limit (ARMv8-M only) uint32_t sp_lim; // Exception return value uint32_t exc_return; // Set to nonzero, if the task is killed uint32_t killed; // MPU mode the task is running in mpu_mode_t mpu_mode; // Task post-mortem information systask_postmortem_t pminfo; } systask_t; // Initializes the scheduler for tasks // // No other task functions should be called before this function void systask_scheduler_init(systask_error_handler_t error_handler); // Returns the currently running task systask_t* systask_active(void); // Makes the given task the currently running task 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); // Pushes data onto the stack of the task // // The task must be not be running when the function is called uint32_t* systask_push_data(systask_t* task, const void* data, size_t size); // Pops data from the stack of the task // // The task must be not be running when the function is called void systask_pop_data(systask_t* task, size_t size); // Runs the task with the given entrypoint and arguments // // The task must be not be running when the function is called // Return `true` in case of success, `false` otherwise bool systask_push_call(systask_t* task, void* fn, uint32_t arg1, uint32_t arg2, uint32_t arg3); // Terminates the task with the given exit code // // If the task is not specified (NULL), it's automatically determined: // 1) If the function is called in thread mode, the active task will be // terminated. // 2) If the function is called in handler mode, the kernel task will be // terminated even if it is not the active task. // // If the terminated task is unprivileged, the kernel task will be scheduled // next. void systask_exit(systask_t* task, int exit_code); // Terminates the task with an error message // // (see `systask_exit()` for more details) void systask_exit_error(systask_t* task, const char* title, const char* message, const char* footer); // Terminates the task with a fatal error message // // (see `systask_exit()` for more details) void systask_exit_fatal(systask_t* task, const char* message, const char* file, int line); #endif // KERNEL_MODE #endif // TREZORHAL_SYSTASK_H