ARM7TDMI: gcc stack corruption workaround.
authorarighi <arighi@38d2e660-2303-0410-9eaa-f027e97ec537>
Tue, 18 May 2010 12:22:06 +0000 (12:22 +0000)
committerarighi <arighi@38d2e660-2303-0410-9eaa-f027e97ec537>
Tue, 18 May 2010 12:22:06 +0000 (12:22 +0000)
GCC corrupts the stack pointer and the frame pointer when calling
functions with at least one parameter inside ISR functions, declared
with __attribute__((interrupt)):

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=41999

As a workaround, we redefine all the ISRs to call only a single
"void isr(void)" function. In this way, inside the actual isr() we can
use any function call as usual.

NOTE: this is inefficient, because it forces a totally unnecessary
additional function call, but it is a reliable way to avoid the
propagation of this bug to any project or architecture port that defines
interrupt routines.

When the bug will be fixed we will add an appropriate #ifdef to apply
the workaround only when old versions of gcc are used.

git-svn-id: https://src.develer.com/svnoss/bertos/trunk@3708 38d2e660-2303-0410-9eaa-f027e97ec537

bertos/cpu/irq.h

index f4cd21ee32d4f90d4b7d93db085a166a6b250f55..40571142bc33d3bb7be821c185b18099dafa4728 100644 (file)
                         * IRQs will be automatically re-enabled when restoring
                         * the context of the user task.
                         */
-                       #define DECLARE_ISR_CONTEXT_SWITCH(func)        \
-                               void ISR_FUNC func(void);               \
-                               static void __isr_##func(void);         \
-                               void ISR_FUNC func(void)                \
-                               {                                       \
-                                       IRQ_ENTRY();                    \
-                                       IRQ_DISABLE;                    \
-                                       __isr_##func();                 \
-                                       IRQ_EXIT();                     \
-                               }                                       \
+                       #define DECLARE_ISR_CONTEXT_SWITCH(func)                \
+                               void ISR_FUNC func(void);                       \
+                               static NOINLINE void __isr_##func(void);        \
+                               void ISR_FUNC func(void)                        \
+                               {                                               \
+                                       IRQ_ENTRY();                            \
+                                       IRQ_DISABLE;                            \
+                                       __isr_##func();                         \
+                                       IRQ_EXIT();                             \
+                               }                                               \
                                static void __isr_##func(void)
                        /**
                         * Interrupt service routine prototype: can be used for
                        #endif /* !CONFIG_KERN_PRI */
                #endif /* CONFIG_KERN_PREEMPT */
 
+               #ifndef ISR_FUNC
+                       #define ISR_FUNC  __attribute__((interrupt))
+               #endif
                #ifndef DECLARE_ISR
                        #define DECLARE_ISR(func) \
-                               void __attribute__((interrupt)) func(void)
+                               void ISR_FUNC func(void);                               \
+                               /*                                                      \
+                                * FIXME: avoid the inlining of this function.          \
+                                *                                                      \
+                                * This is terribly inefficient, but it's a             \
+                                * reliable workaround to avoid gcc blowing             \
+                                * away the stack (see the bug below):                  \
+                                *                                                      \
+                                * http://gcc.gnu.org/bugzilla/show_bug.cgi?id=41999    \
+                                */                                                     \
+                               static NOINLINE void __isr_##func(void);                \
+                               void ISR_FUNC func(void)                                \
+                               {                                                       \
+                                       __isr_##func();                                 \
+                               }                                                       \
+                               static void __isr_##func(void)
                #endif
                #ifndef DECLARE_ISR_CONTEXT_SWITCH
-                       #define DECLARE_ISR_CONTEXT_SWITCH(func) \
-                               void __attribute__((interrupt)) func(void)
+                       #define DECLARE_ISR_CONTEXT_SWITCH(func) DECLARE_ISR(func)
                #endif
                #ifndef ISR_PROTO
-                       #define ISR_PROTO(func) \
-                               void __attribute__((interrupt)) func(void)
+                       #define ISR_PROTO(func) void ISR_FUNC func(void)
                #endif
                #ifndef ISR_PROTO_CONTEXT_SWITCH
-                       #define ISR_PROTO_CONTEXT_SWITCH(func)  \
-                               void __attribute__((interrupt)) func(void)
+                       #define ISR_PROTO_CONTEXT_SWITCH(func) ISR_PROTO(func)
                #endif
 
        #endif /* !__IAR_SYSTEMS_ICC_ */