Hi, i have discovered a bug in portRESTORE_CONTEXT() in the AVR32 port of FreeRTOS. The issue relates to both the official port and the one in ‘atmel software framework’.
Problem: The portRESTORE_CONTEXT() call does not restore the status register and PC in one atomic operation. It first restores SR, then the PC. When restoring the SR, the interrupts will be enabled before the correct program counter has been set. This will allow any pending interrupt to be processed, and when the interrupt routine finishes the stack have been altered, which eventually will cause the call to set the program counter to crash the CPU.
Solution: By using the ‘rets’ instruction, the processor will pop both the SR and PC off the stack in one operation. And the pending interrupt will first be allowed to run after the PC have been set.
Here’s a patch:
--- a/thirdparty/freertos/freertos-8.0.0/Source/portable/GCC/AVR32_UC3/portmacro.h +++ b/thirdparty/freertos/freertos-8.0.0/Source/portable/GCC/AVR32_UC3/portmacro.h @@ -215,18 +215,7 @@ extern void *pvPortRealloc( void *pv, size_t xSize ); /* Restore R0..R7 */ "ldm sp++, r0-r7 - /* R0-R7 should not be used below this line */ - /* Skip PC and SR (will do it at the end) */ - "sub sp, -2*4 - /* Restore R8..R12 and LR */ - "ldm sp++, r8-r12, lr - /* Restore SR */ - "ld.w r0, sp[-8*4]\n\t" /* R0 is modified, is restored later. */ - "mtsr %[SR], r0 - /* Restore r0 */ - "ld.w r0, sp[-9*4] - /* Restore PC */ - "ld.w pc, sp[-7*4]" /* Get PC from stack - PC is the 7th register saved */ + "rets" : : [ulCriticalNesting] "i" (&ulCriticalNesting), [pxCurrentTCB] "i" (&pxCurrentTCB),
Note: I know that this will also not set the R8…R12 and LR, but doing so would require a change of the initialStackLayout to set SR and PC at the top, not in the middle. But it proves the issue.
Steps to reproduce:
- Setup freertos on avr32 target
- Setup a perihperal interrupt in main.c. Do not enable the global interrupt.
- Trigger the interrupt source, thus causing an interrupt to be pending.
- call vTaskStartScheduler()
5) The system executes the ISR, then hangs.
5) The system executes the ISR, then continues to the highest priority task.