From 874d1507ca93bb9cba9a12305286cd7ae2e58453 Mon Sep 17 00:00:00 2001 From: Randall Spangler Date: Fri, 7 Sep 2012 12:32:24 -0700 Subject: Allocate stacks separately from task context structs This is a precursor to supporting task-specific stack sizes. BUG=chrome-os-partner:13814 TEST=boot; taskinfo shouldn't print garbage BRANCH=all Original-Change-Id: Iff6cee8b5f292dd026244239c99ba2252e75cf12 Signed-off-by: Randall Spangler Reviewed-on: https://gerrit.chromium.org/gerrit/32592 Reviewed-by: Vincent Palatin (cherry picked from commit 22d13781dcd006f9305956d33bf1ce1581454d2e) Change-Id: I383f09df913e609f5f15edfbc80296c67d46ae54 Reviewed-on: https://gerrit.chromium.org/gerrit/32781 Tested-by: Randall Spangler Reviewed-by: Simon Glass Reviewed-by: Randall Spangler --- core/cortex-m/task.c | 105 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 63 insertions(+), 42 deletions(-) diff --git a/core/cortex-m/task.c b/core/cortex-m/task.c index e498301362..77573a3e14 100644 --- a/core/cortex-m/task.c +++ b/core/cortex-m/task.c @@ -21,21 +21,22 @@ */ #define TASK_SIZE 512 +/* Size of stack */ +#define STACK_SIZE 488 + typedef union { struct { - uint32_t sp; /* saved stack pointer for context switch */ - uint32_t events; /* bitmaps of received events */ + /* + * Note that sp must be the first element in the task struct + * for __switchto() to work. + */ + uint32_t sp; /* Saved stack pointer for context switch */ + uint32_t events; /* Bitmaps of received events */ uint64_t runtime; /* Time spent in task */ - uint32_t reserved; /* Reserved (for padding) */ - uint32_t guard; /* Guard value to detect stack overflow */ - uint32_t stack[0]; /* Task stack; must be 64-bit aligned */ + uint32_t *stack; /* Start of stack */ }; - uint32_t context[TASK_SIZE/4]; } task_; -/* Size of stack */ -#define STACK_SIZE (TASK_SIZE - OFFSET_OF(task_, stack)) - /* Value to store in unused stack */ #define STACK_UNUSED_VALUE 0xdeadd00d @@ -46,7 +47,7 @@ void __idle(void); CONFIG_TASK_LIST #undef TASK -/* store the task names for easier debugging */ +/* Task names for easier debugging */ #define TASK(n, r, d) #n, #include TASK_LIST static const char * const task_names[] = { @@ -55,7 +56,6 @@ static const char * const task_names[] = { }; #undef TASK - #ifdef CONFIG_TASK_PROFILING static uint64_t task_start_time; /* Time task scheduling started */ static uint64_t exc_start_time; /* Time of task->exception transition */ @@ -97,31 +97,39 @@ static void task_exit_trap(void) } -#define GUARD_VALUE 0x12345678 - /* Startup parameters for all tasks. */ #define TASK(n, r, d) { \ .r0 = (uint32_t)d, \ .pc = (uint32_t)r, \ + .stack_size = STACK_SIZE, \ }, #include TASK_LIST static const struct { uint32_t r0; uint32_t pc; + uint16_t stack_size; } const tasks_init[] = { TASK(IDLE, __idle, 0) CONFIG_TASK_LIST }; #undef TASK -/* Contexts and stacks for all tasks. */ -static task_ tasks[TASK_ID_COUNT] __attribute__((section(".bss.tasks"))) - __attribute__((aligned(TASK_SIZE))); -/* Reserve space to discard context on first context switch. This must - * immediately follow tasks, so that it is start-aligned to TASK_SIZE so that - * __get_current(scratchpad) == scratchpad. Note that aligned(TASK_SIZE) also - * size-aligns it, which wastes (512 - 17*4) bytes of RAM, so we simply put it - * in its own section which immediately follows .bss.tasks in ec.lds.S. */ -uint32_t scratchpad[17] __attribute__((section(".bss.task_scratchpad"))); + +/* Contexts for all tasks */ +static task_ tasks[TASK_ID_COUNT]; + +/* Stacks for all tasks */ +/* TODO: variable-size stacks */ +#define TASK(n, r, d) + STACK_SIZE +#include TASK_LIST +uint8_t task_stacks[ + STACK_SIZE + CONFIG_TASK_LIST +] __attribute__((aligned(8))); + +#undef TASK + +/* Reserve space to discard context on first context switch. */ +uint32_t scratchpad[17]; static task_ *current_task = (task_ *)scratchpad; @@ -222,7 +230,7 @@ void svc_handler(int desched, task_id_t resched) current = current_task; #ifdef CONFIG_OVERFLOW_DETECT - ASSERT(current->guard == GUARD_VALUE); + ASSERT(*current->stack == STACK_UNUSED_VALUE); #endif if (desched && !current->events) { @@ -474,17 +482,17 @@ void mutex_unlock(struct mutex *mtx) atomic_clear(&tsk->events, TASK_EVENT_MUTEX); } - void task_print_list(void) { int i; + ccputs("Task Ready Name Events Time (s) StkUsed\n"); for (i = 0; i < TASK_ID_COUNT; i++) { char is_ready = (tasks_ready & (1<guard = GUARD_VALUE; + /* + * Fill in guard value in scratchpad to prevent stack overflow + * detection failure on the first context switch. This works because + * the first word in the scratchpad is where the switcher will store + * sp, so it's ok to blow away. + */ + ((task_ *)scratchpad)->stack = (uint32_t *)scratchpad; + *(uint32_t *)scratchpad = STACK_UNUSED_VALUE; - /* sanity checks about static task invariants */ + /* Sanity checks about static task invariants */ BUILD_ASSERT(TASK_ID_COUNT <= sizeof(unsigned) * 8); BUILD_ASSERT(TASK_ID_COUNT < (1 << (sizeof(task_id_t) * 8))); -- cgit v1.2.1