Skip to content

Commit 135ac03

Browse files
authored
Merge pull request #39 from JGoard/handle-task-errors
apply return guard and stack canary monitoring
2 parents f59b621 + ea24aa8 commit 135ac03

3 files changed

Lines changed: 38 additions & 12 deletions

File tree

jocktos/inc/os.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,9 +83,10 @@
8383
typedef struct {
8484
volatile bool pending;
8585
volatile uint32_t tick_count;
86-
volatile TaskControlBlock* running; ///< Currently running task
87-
volatile TaskControlBlock* ready; ///< Singly linked list of tasks ready to run, in decending order of priority
88-
volatile TaskControlBlock* suspended; ///< Singly linked list of suspended tasks, in decending order of priority
86+
volatile TaskControlBlock* terminated; ///< Currently running task
87+
volatile TaskControlBlock* running; ///< Currently running task
88+
volatile TaskControlBlock* ready; ///< Singly linked list of tasks ready to run, in decending order of priority
89+
volatile TaskControlBlock* suspended; ///< Singly linked list of suspended tasks, in decending order of priority
8990
} Scheduler;
9091

9192
/**

jocktos/inc/tcb.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,8 @@ typedef enum {
8888
RUNNING = 0, ///< The task is currently executing on the CPU with priority over others.
8989
READY = 1, ///< The task is ready and waiting for execution by the scheduler.
9090
BLOCKED = 2, ///< The task is waiting for a resource (e.g., semaphore, mutex) to become available.
91-
SUSPENDED = 3 ///< The task is temporarily inactive and can be reactivated by an event.
91+
SUSPENDED = 3, ///< The task is temporarily inactive and can be reactivated by an event.
92+
TERMINATED = 4 ///< The task has been terminated and is no longer executing.
9293
} TaskState;
9394

9495
/**

jocktos/src/os.c

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,20 @@
1818

1919
/* -- Defines ------------------------------------------------------------- */
2020

21+
#define FILL 0xBABEFACE // for task allocation debugging
22+
#define CANARY 0xDEADBEEF
23+
#define CANARY_SIZE 16
2124
#define TRIGGER_PendSV *(uintptr_t volatile *)0xE000ED04 = (1U << 28)
2225

2326
/* -- Types --------------------------------------------------------------- */
2427

2528
/* -- Private Function Declarations --------------------------------------- */
29+
/**
30+
* \details Safely catches an unexpected return from a task.
31+
* Any task that returns is marked as 'terminated' and moved accordingly.
32+
*
33+
*/
34+
void task_exit_guard(void);
2635

2736
/**
2837
* \brief Updates the task control blocks stack_usage
@@ -182,8 +191,7 @@ void initializeStack(TaskControlBlock* tcb) {
182191
// - non-critical registers are initialized to their index
183192
*(--stack_ptr) = (1U << 24); ///< Set thumb state bit in EPSR
184193
*(--stack_ptr) = (uintptr_t)tcb->task_handle; ///< Set PC to task function handle
185-
*(--stack_ptr) = 0xFFFFFFF9U; ///< Set LR register for MSP thread mode
186-
// *(--stack_ptr) = 0xFFFFFFFDU; ///< Set LR register for PSP thread mode
194+
*(--stack_ptr) = (uintptr_t)task_exit_guard; // LR: Return trap
187195
*(--stack_ptr) = 0x0000000CU; ///< Set R12 register deafult to its index
188196
*(--stack_ptr) = 0x00000003U; ///< Set R3 register deafult to its index
189197
*(--stack_ptr) = 0x00000002U; ///< Set R2 register deafult to its index
@@ -201,11 +209,11 @@ void initializeStack(TaskControlBlock* tcb) {
201209
*(--stack_ptr) = 0x00000004U; ///< Set R4 register deafult to its index
202210
tcb->stack_pointer = stack_ptr;
203211
// Fill unused process stack with known value
204-
while (stack_ptr > tcb->stack_overflow + 8) {
205-
*(--stack_ptr) = 0xBABEFACEU;
212+
while (stack_ptr > tcb->stack_overflow + CANARY_SIZE) {
213+
*(--stack_ptr) = FILL;
206214
}
207215
while (stack_ptr > tcb->stack_overflow) {
208-
*(--stack_ptr) = 0xDEADBEEFU; ///< set top 8 bytes to something else
216+
*(--stack_ptr) = CANARY; ///< set top 8 bytes to something else
209217
}
210218
}
211219

@@ -224,7 +232,17 @@ void SysTick_Handler(void) {
224232
uint32_t primask;
225233
primask = jock_os_enter_critical_section();
226234
JOCKTOSScheduler.tick_count++;
227-
jock_os_switch_running_task(&JOCKTOSScheduler.ready);
235+
TaskControlBlock** dest = &JOCKTOSScheduler.ready;
236+
TaskControlBlock* tcb = JOCKTOSScheduler.running;
237+
uint32_t* ptr = (uint32_t*)tcb->stack_overflow + CANARY_SIZE;
238+
for (int i = 0; i < CANARY_SIZE; i++) {
239+
if (*(--ptr) != CANARY) {
240+
if (tcb == &usr_main_tcb) break; // ignore stack canary for main [TODO]
241+
dest = &JOCKTOSScheduler.terminated;
242+
break;
243+
}
244+
}
245+
jock_os_switch_running_task(dest);
228246
jock_os_leave_critical_section(primask);
229247

230248
}
@@ -294,7 +312,7 @@ void monitorJOCKTOS(void* arg) {
294312
}
295313

296314

297-
void idleJOCKTOS(void* arg) {
315+
void idleJOCKTOS(void* arg __attribute__((unused))) {
298316
/* Disable interrupts to make sure that the busy flag does not get
299317
modified between the check in the while condition and the system
300318
sleep */
@@ -351,4 +369,10 @@ void idleJOCKTOS(void* arg) {
351369
// TODO: Figure out how to low power
352370
}
353371

354-
372+
__attribute__((noreturn))
373+
void task_exit_guard(void) {
374+
uint32_t primask = jock_os_enter_critical_section();
375+
JOCKTOSScheduler.running->state = TERMINATED;
376+
jock_os_switch_running_task(&JOCKTOSScheduler.terminated);
377+
jock_os_leave_critical_section(primask);
378+
}

0 commit comments

Comments
 (0)