Minimum bound for stack sizes

deckard26354 wrote on Sunday, November 23, 2008:

Greetings.

I’ve been working with FreeRTOS on the SAM7S32.

I ended up chasing down a nasty funny, in that, I had an application which was calling vTaskDelay(10); but was never being re-scheduled.

I ended up instruction stepping

xTaskDelay(); To cut a long story short - FreeRTOS’ practice of saving context on the user’s stack in portSAVE_CONTEXT(); - rather than on the ISR’s stack - I believe - with respect - is a bit backwards.

Reason being the following - the pvOwner - which is a pointer to the TCB of the task that did the xTaskDelay(); is at 0x2006c0.

At this point in time the task calling xTaskDelay(); has been configured with a stack of 0x18 * 4 words - or 96 bytes, which I was thinking was generous on 8k of SRAM.

However at vPortYieldProcessor+44 - you’ll see that the ARM assembler is subtracting 60 bytes from the link register.

The link registers is in fact the stack pointer - plus or minus a few words of the CALLING task - not the ISR context we are in a this point.

Hence : if the stack size of the calling task is below a certain size ~ 1xx bytes the context switching code of the ISR will overflow the tasks stack.

I was loathe to go changing the context switching code - without a full understanding of all aspects of it - however - I think it would be a good idea to have at the very least an

#if configMINIMAL_STACK_SIZE < SOME_MINIMUM_SIZE_FOR_CONTEXT_SWITCHING
    #error "Your stack will overflow me auld flower"
#endif

just to ATTEMPT to idot proof - even against sufficiently talented idots such as myself !

Cheers,
Bryan

[code]

$7 = (volatile struct xLIST_ITEM *) 0x2006c0
(gdb) print &pxDelayedTaskList->xListEnd->pxNext->pvOwner
$8 = (void **) 0x2006cc
(gdb) disass
Dump of assembler code for function vPortYieldProcessor:
0x0010432c <vPortYieldProcessor+0>:     add     lr, lr, #4      ; 0x4
0x00104330 <vPortYieldProcessor+4>:     push    {r0}
0x00104334 <vPortYieldProcessor+8>:     stmdb   sp, {sp}^
0x00104338 <vPortYieldProcessor+12>:    nop                     (mov r0,r0)
0x0010433c <vPortYieldProcessor+16>:    sub     sp, sp, #4      ; 0x4
0x00104340 <vPortYieldProcessor+20>:    pop     {r0}
0x00104344 <vPortYieldProcessor+24>:    stmdb   r0!, {lr}
0x00104348 <vPortYieldProcessor+28>:    mov     lr, r0
0x0010434c <vPortYieldProcessor+32>:    pop     {r0}
0x00104350 <vPortYieldProcessor+36>:    stmdb   lr, {r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r1
1, r12, sp, lr}^
0x00104354 <vPortYieldProcessor+40>:    nop                     (mov r0,r0)
0x00104358 <vPortYieldProcessor+44>:    sub     lr, lr, #60     ; 0x3c
0x0010435c <vPortYieldProcessor+48>:    mrs     r0, SPSR
0x00104360 <vPortYieldProcessor+52>:    stmdb   lr!, {r0}
0x00104364 <vPortYieldProcessor+56>:    ldr     r0, [pc, #404]  ; 0x104500
0x00104368 <vPortYieldProcessor+60>:    ldr     r0, [r0]
0x0010436c <vPortYieldProcessor+64>:    stmdb   lr!, {r0}
0x00104370 <vPortYieldProcessor+68>:    ldr     r0, [pc, #388]  ; 0x1044fc
0x00104374 <vPortYieldProcessor+72>:    ldr     r0, [r0]
0x00104378 <vPortYieldProcessor+76>:    str     lr, [r0]
0x0010437c <vPortYieldProcessor+80>:    ldr     r3, [pc, #76]   ; 0x1043d0 <vPortYieldProcessor+164>

0x00104380 <vPortYieldProcessor+84>:    ldr     r3, [r3]
0x00104384 <vPortYieldProcessor+88>:    ldr     r3, [pc, #72]   ; 0x1043d4 <vPortYieldProcessor+168>

0x00104388 <vPortYieldProcessor+92>:    ldr     r3, [r3]
0x0010438c <vPortYieldProcessor+96>:    bl      0x102d9c <vTaskSwitchContext>
0x00104390 <vPortYieldProcessor+100>:   ldr     r0, [pc, #356]  ; 0x1044fc
0x00104394 <vPortYieldProcessor+104>:   ldr     r0, [r0]
0x00104398 <vPortYieldProcessor+108>:   ldr     lr, [r0]
0x0010439c <vPortYieldProcessor+112>:   ldr     r0, [pc, #348]  ; 0x104500
0x001043a0 <vPortYieldProcessor+116>:   ldm     lr!, {r1}
0x001043a4 <vPortYieldProcessor+120>:   str     r1, [r0]
0x001043a8 <vPortYieldProcessor+124>:   ldm     lr!, {r0}
0x001043ac <vPortYieldProcessor+128>:   msr     SPSR_fc, r0
0x001043b0 <vPortYieldProcessor+132>:   ldm     lr, {r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r1
1, r12, sp, lr}^
0x001043b4 <vPortYieldProcessor+136>:   nop                     (mov r0,r0)
0x001043b8 <vPortYieldProcessor+140>:   ldr     lr, [lr, #60]
0x001043bc <vPortYieldProcessor+144>:   subs    pc, lr, #4      ; 0x4
0x001043c0 <vPortYieldProcessor+148>:   ldr     r3, [pc, #8]    ; 0x1043d0 <vPortYieldProcessor+164>

0x001043c4 <vPortYieldProcessor+152>:   ldr     r3, [r3]
0x001043c8 <vPortYieldProcessor+156>:   ldr     r3, [pc, #4]    ; 0x1043d4 <vPortYieldProcessor+168>

0x001043cc <vPortYieldProcessor+160>:   ldr     r3, [r3]
0x001043d0 <vPortYieldProcessor+164>:   eoreq   r0, r0, r4
0x001043d4 <vPortYieldProcessor+168>:   eoreq   r0, r0, r0, asr r4
End of assembler dump.
(gdb) info registers
r0             0x0      0
r1             0x0      0
r2             0x0      0
r3             0x0      0
r4             0x4040404        67372036
r5             0x5050505        84215045
r6             0x6060606        101058054
r7             0x7070707        117901063
r8             0x8080808        134744072
r9             0x9090909        151587081
r10            0x10101010       269488144
r11            0x11111111       286331153
r12            0x12121212       303174162
sp             0x200ed8 0x200ed8
lr             0x2006d0 2098896
pc             0x10436c 0x10436c <vPortYieldProcessor+64>
fps            0x0      0
cpsr           0x60000093       1610612883
(gdb) print &pxDelayedTaskList->xListEnd->pxNext->pvOwner
$9 = (void **) 0x2006cc
(gdb) print pxDelayedTaskList->xListEnd->pxNext->pvOwner
$10 = (void *) 0x2006bc
(gdb) stepi
0x00104370      186        portSAVE_CONTEXT();
(gdb) print pxDelayedTaskList->xListEnd->pxNext->pvOwner
$11 = (void *) 0x0
(gdb) print &pxDelayedTaskList->xListEnd->pxNext->pvOwner
$12 = (void **) 0x2006cc
(gdb) q
The program is running.  Exit anyway? (y or n) y

[/code]

davedoors wrote on Sunday, November 23, 2008:

The context cannot be saved on the IRQ stack because the stack frame has to exist until the task next runs, the IRQ stack frame will be clobbered the next time a task runs.

Take a look at number 1 on this page, including the links. These should help.
http://www.freertos.org/FAQHelp.html