cpu/irq.h

Go to the documentation of this file.
00001 
00041 #ifndef CPU_IRQ_H
00042 #define CPU_IRQ_H
00043 
00044 #include "detect.h"
00045 #include "types.h"
00046 
00047 #include <kern/proc.h> /* proc_needPreempt() / proc_preempt() */
00048 
00049 #include <cfg/compiler.h> /* for uintXX_t */
00050 #include "cfg/cfg_proc.h" /* CONFIG_KERN_PREEMPT */
00051 
00052 #if CPU_I196
00053     #define IRQ_DISABLE             disable_interrupt()
00054     #define IRQ_ENABLE              enable_interrupt()
00055 #elif CPU_X86
00056 
00057     /* Get IRQ_* definitions from the hosting environment. */
00058     #include <cfg/os.h>
00059     #if OS_EMBEDDED
00060         #define IRQ_DISABLE             FIXME
00061         #define IRQ_ENABLE              FIXME
00062         #define IRQ_SAVE_DISABLE(x)     FIXME
00063         #define IRQ_RESTORE(x)          FIXME
00064     #endif /* OS_EMBEDDED */
00065 
00066 #elif CPU_CM3
00067     /* Cortex-M3 */
00068 
00069     /*
00070      * Interrupt priority.
00071      *
00072      * NOTE: 0 means that an interrupt is not affected by the global IRQ
00073      * priority settings.
00074      */
00075     #define IRQ_PRIO        0x80
00076     #define IRQ_PRIO_MIN        0xf0
00077     #define IRQ_PRIO_MAX        0
00078     /*
00079      * To disable interrupts we just raise the system base priority to a
00080      * number lower than the default IRQ priority. In this way, all the
00081      * "normal" interrupt can't be triggered. High-priority interrupt can
00082      * still happen (at the moment only the soft-interrupt svcall uses a
00083      * priority greater than the default IRQ priority).
00084      *
00085      * To enable interrupts we set the system base priority to 0, that
00086      * means IRQ priority mechanism is disabled, and any interrupt can
00087      * happen.
00088      */
00089     #define IRQ_PRIO_DISABLED   0x40
00090     #define IRQ_PRIO_ENABLED    0
00091 
00092     #define IRQ_DISABLE                     \
00093     ({                              \
00094         register cpu_flags_t reg = IRQ_PRIO_DISABLED;       \
00095         asm volatile (                      \
00096             "msr basepri, %0"               \
00097             : : "r"(reg) : "memory", "cc");         \
00098     })
00099 
00100     #define IRQ_ENABLE                      \
00101     ({                              \
00102         register cpu_flags_t reg = IRQ_PRIO_ENABLED;        \
00103         asm volatile (                      \
00104             "msr basepri, %0"               \
00105             : : "r"(reg) : "memory", "cc");         \
00106     })
00107 
00108     #define CPU_READ_FLAGS()                    \
00109     ({                              \
00110         register cpu_flags_t reg;               \
00111         asm volatile (                      \
00112             "mrs %0, basepri"               \
00113              : "=r"(reg) : : "memory", "cc");       \
00114         reg;                            \
00115     })
00116 
00117     #define IRQ_SAVE_DISABLE(x)                 \
00118     ({                              \
00119         x = CPU_READ_FLAGS();                   \
00120         IRQ_DISABLE;                        \
00121     })
00122 
00123     #define IRQ_RESTORE(x)                      \
00124     ({                              \
00125         asm volatile (                      \
00126             "msr basepri, %0"               \
00127             : : "r"(x) : "memory", "cc");           \
00128     })
00129 
00130     #define IRQ_ENABLED() (CPU_READ_FLAGS() == IRQ_PRIO_ENABLED)
00131 
00132     INLINE bool irq_running(void)
00133     {
00134         register uint32_t ret;
00135 
00136         /*
00137          * Check if the current stack pointer is the main stack or
00138          * process stack: we use the main stack only in Handler mode,
00139          * so this means we're running inside an ISR.
00140          */
00141         asm volatile (
00142             "mrs %0, msp\n\t"
00143             "cmp sp, %0\n\t"
00144             "ite ne\n\t"
00145             "movne %0, #0\n\t"
00146             "moveq %0, #1\n\t" : "=r"(ret) : : "cc");
00147         return ret;
00148     }
00149     #define IRQ_RUNNING() irq_running()
00150 
00151     #if (CONFIG_KERN && CONFIG_KERN_PREEMPT)
00152 
00153         #define DECLARE_ISR_CONTEXT_SWITCH(func)        \
00154         void func(void);                    \
00155         INLINE void __isr_##func(void);             \
00156         void func(void)                     \
00157         {                           \
00158             __isr_##func();                 \
00159             if (!proc_needPreempt())            \
00160                 return;                 \
00161             /*
00162              * Set a PendSV request.
00163              *
00164              * The preemption handler will be called immediately
00165              * after this ISR in tail-chaining mode (without the
00166              * overhead of hardware state saving and restoration
00167              * between interrupts).
00168              */                     \
00169             HWREG(NVIC_INT_CTRL) = NVIC_INT_CTRL_PEND_SV;   \
00170         }                           \
00171         INLINE void __isr_##func(void)
00172 
00183         #if CONFIG_KERN_PRI
00184             #define DECLARE_ISR(func) \
00185                 DECLARE_ISR_CONTEXT_SWITCH(func)
00186 
00190             #define ISR_PROTO(func) \
00191                 ISR_PROTO_CONTEXT_SWITCH(func)
00192         #endif /* !CONFIG_KERN_PRI */
00193     #endif
00194 
00195     #ifndef ISR_PROTO
00196         #define ISR_PROTO(func) void func(void)
00197     #endif
00198     #ifndef DECLARE_ISR
00199         #define DECLARE_ISR(func) void func(void)
00200     #endif
00201     #ifndef DECLARE_ISR_CONTEXT_SWITCH
00202         #define DECLARE_ISR_CONTEXT_SWITCH(func) void func(void)
00203     #endif
00204     #ifndef ISR_PROTO_CONTEXT_SWITCH
00205         #define ISR_PROTO_CONTEXT_SWITCH(func) void func(void)
00206     #endif
00207 
00208 #elif CPU_ARM
00209 
00210     #ifdef __IAR_SYSTEMS_ICC__
00211 
00212         #include <inarm.h>
00213 
00214         #if __CPU_MODE__ == 1 /* Thumb */
00215             /* Use stubs */
00216             extern cpu_flags_t get_CPSR(void);
00217             extern void set_CPSR(cpu_flags_t flags);
00218         #else
00219             #define get_CPSR __get_CPSR
00220             #define set_CPSR __set_CPSR
00221         #endif
00222 
00223         #define IRQ_DISABLE __disable_interrupt()
00224         #define IRQ_ENABLE  __enable_interrupt()
00225 
00226         #define IRQ_SAVE_DISABLE(x) \
00227         do { \
00228             (x) = get_CPSR(); \
00229             __disable_interrupt(); \
00230         } while (0)
00231 
00232         #define IRQ_RESTORE(x) \
00233         do { \
00234             set_CPSR(x); \
00235         } while (0)
00236 
00237         #define IRQ_ENABLED() \
00238             ((bool)(get_CPSR() & 0xb0))
00239 
00240     #else /* !__IAR_SYSTEMS_ICC__ */
00241 
00242         #define IRQ_DISABLE                 \
00243         do {                            \
00244             cpu_flags_t sreg;               \
00245             asm volatile (                  \
00246                 "mrs %0, cpsr\n\t"          \
00247                 "orr %0, %0, #0xc0\n\t"         \
00248                 "msr cpsr_c, %0\n\t"            \
00249                 : "=r" (sreg) : : "memory", "cc");  \
00250         } while (0)
00251 
00252         #define IRQ_ENABLE                  \
00253         do {                            \
00254             cpu_flags_t sreg;               \
00255             asm volatile (                  \
00256                 "mrs %0, cpsr\n\t"          \
00257                 "bic %0, %0, #0xc0\n\t"         \
00258                 "msr cpsr_c, %0\n\t"            \
00259                 : "=r" (sreg) : : "memory", "cc");  \
00260         } while (0)
00261 
00262         #define IRQ_SAVE_DISABLE(x)             \
00263         do {                            \
00264             register cpu_flags_t sreg;          \
00265             asm volatile (                  \
00266                 "mrs %0, cpsr\n\t"          \
00267                 "orr %1, %0, #0xc0\n\t"         \
00268                 "msr cpsr_c, %1\n\t"            \
00269                 : "=r" (x), "=r" (sreg)         \
00270                 : : "memory", "cc");            \
00271         } while (0)
00272 
00273         #define IRQ_RESTORE(x)                  \
00274         do {                            \
00275             asm volatile (                  \
00276                 "msr cpsr_c, %0\n\t"            \
00277                 : : "r" (x) : "memory", "cc");      \
00278         } while (0)
00279 
00280         #define CPU_READ_FLAGS()                \
00281         ({                          \
00282             cpu_flags_t sreg;               \
00283             asm volatile (                  \
00284                 "mrs %0, cpsr\n\t"          \
00285                 : "=r" (sreg) : : "memory", "cc");  \
00286             sreg;                       \
00287         })
00288 
00289         #define IRQ_ENABLED() ((CPU_READ_FLAGS() & 0xc0) != 0xc0)
00290 
00291         #if (CONFIG_KERN && CONFIG_KERN_PREEMPT)
00292             EXTERN_C void asm_irq_switch_context(void);
00293 
00300             #define IRQ_ENTRY() asm volatile ( \
00301                         "sub    lr, lr, #4\n\t" \
00302                         "stmfd  sp!, {r0-r3, ip, lr}\n\t")
00303             #define IRQ_EXIT()  asm volatile ( \
00304                         "b  asm_irq_switch_context\n\t")
00305 
00315             #define ISR_FUNC __attribute__((naked))
00316 
00343             #define DECLARE_ISR_CONTEXT_SWITCH(func)        \
00344                 void ISR_FUNC func(void);           \
00345                 static NOINLINE void __isr_##func(void);    \
00346                 void ISR_FUNC func(void)            \
00347                 {                       \
00348                     IRQ_ENTRY();                \
00349                     IRQ_DISABLE;                \
00350                     __isr_##func();             \
00351                     IRQ_EXIT();             \
00352                 }                       \
00353                 static NOINLINE void __isr_##func(void)
00354 
00358             #define ISR_PROTO_CONTEXT_SWITCH(func)  \
00359                 void ISR_FUNC func(void)
00360 
00370             #if CONFIG_KERN_PRI
00371                 #define DECLARE_ISR(func) \
00372                     DECLARE_ISR_CONTEXT_SWITCH(func)
00373 
00374                 #define ISR_PROTO(func) \
00375                     ISR_PROTO_CONTEXT_SWITCH(func)
00376             #endif /* !CONFIG_KERN_PRI */
00377         #endif /* CONFIG_KERN_PREEMPT */
00378 
00379         #ifndef ISR_FUNC
00380             #define ISR_FUNC __attribute__((naked))
00381         #endif
00382         #ifndef DECLARE_ISR
00383             #define DECLARE_ISR(func) \
00384                 void ISR_FUNC func(void);               \
00385                 /*                          \
00386                  * FIXME: avoid the inlining of this function.      \
00387                  *                          \
00388                  * This is terribly inefficient, but it's a     \
00389                  * reliable workaround to avoid gcc blowing     \
00390                  * away the stack (see the bug below):          \
00391                  *                          \
00392                  * http://gcc.gnu.org/bugzilla/show_bug.cgi?id=41999    \
00393                  */                         \
00394                 static NOINLINE void __isr_##func(void);        \
00395                 void ISR_FUNC func(void)                \
00396                 {                           \
00397                     asm volatile (                  \
00398                         "sub    lr, lr, #4\n\t"         \
00399                         "stmfd  sp!, {r0-r3, ip, lr}\n\t"); \
00400                     __isr_##func();                 \
00401                     asm volatile (                  \
00402                         "ldmfd sp!, {r0-r3, ip, pc}^\n\t"); \
00403                 }                           \
00404                 static NOINLINE void __isr_##func(void)
00405         #endif
00406         #ifndef DECLARE_ISR_CONTEXT_SWITCH
00407             #define DECLARE_ISR_CONTEXT_SWITCH(func) DECLARE_ISR(func)
00408         #endif
00409         #ifndef ISR_PROTO
00410             #define ISR_PROTO(func) void ISR_FUNC func(void)
00411         #endif
00412         #ifndef ISR_PROTO_CONTEXT_SWITCH
00413             #define ISR_PROTO_CONTEXT_SWITCH(func) ISR_PROTO(func)
00414         #endif
00415 
00416     #endif /* !__IAR_SYSTEMS_ICC_ */
00417 
00418 #elif CPU_PPC
00419 
00420     /* Get IRQ_* definitions from the hosting environment. */
00421     #include <cfg/os.h>
00422     #if OS_EMBEDDED
00423         #define IRQ_DISABLE         FIXME
00424         #define IRQ_ENABLE          FIXME
00425         #define IRQ_SAVE_DISABLE(x) FIXME
00426         #define IRQ_RESTORE(x)      FIXME
00427         #define IRQ_ENABLED()       FIXME
00428     #endif /* OS_EMBEDDED */
00429 
00430 #elif CPU_DSP56K
00431 
00432     #define IRQ_DISABLE             do { asm(bfset #0x0200,SR); asm(nop); } while (0)
00433     #define IRQ_ENABLE              do { asm(bfclr #0x0200,SR); asm(nop); } while (0)
00434 
00435     #define IRQ_SAVE_DISABLE(x)  \
00436         do { (void)x; asm(move SR,x); asm(bfset #0x0200,SR); } while (0)
00437     #define IRQ_RESTORE(x)  \
00438         do { (void)x; asm(move x,SR); } while (0)
00439 
00440     static inline bool irq_running(void)
00441     {
00442         extern void *user_sp;
00443         return !!user_sp;
00444     }
00445     #define IRQ_RUNNING() irq_running()
00446 
00447     static inline bool irq_enabled(void)
00448     {
00449         uint16_t x;
00450         asm(move SR,x);
00451         return !(x & 0x0200);
00452     }
00453     #define IRQ_ENABLED() irq_enabled()
00454 
00455 #elif CPU_AVR
00456 
00457     #define IRQ_DISABLE   asm volatile ("cli" ::)
00458     #define IRQ_ENABLE    asm volatile ("sei" ::)
00459 
00460     #define IRQ_SAVE_DISABLE(x) \
00461     do { \
00462         __asm__ __volatile__( \
00463             "in %0,__SREG__\n\t" \
00464             "cli" \
00465             : "=r" (x) : /* no inputs */ : "cc" \
00466         ); \
00467     } while (0)
00468 
00469     #define IRQ_RESTORE(x) \
00470     do { \
00471         __asm__ __volatile__( \
00472             "out __SREG__,%0" : /* no outputs */ : "r" (x) : "cc" \
00473         ); \
00474     } while (0)
00475 
00476     #define IRQ_ENABLED() \
00477     ({ \
00478         uint8_t sreg; \
00479         __asm__ __volatile__( \
00480             "in %0,__SREG__\n\t" \
00481             : "=r" (sreg)  /* no inputs & no clobbers */ \
00482         ); \
00483         (bool)(sreg & 0x80); \
00484     })
00485     #if (CONFIG_KERN && CONFIG_KERN_PREEMPT)
00486         #define DECLARE_ISR_CONTEXT_SWITCH(vect)        \
00487             INLINE void __isr_##vect(void);         \
00488             ISR(vect)                   \
00489             {                       \
00490                 __isr_##vect();             \
00491                 IRQ_PREEMPT_HANDLER();          \
00492             }                       \
00493             INLINE void __isr_##vect(void)
00494 
00505         #if CONFIG_KERN_PRI
00506             #define DECLARE_ISR(func) \
00507                 DECLARE_ISR_CONTEXT_SWITCH(func)
00508 
00512             #define ISR_PROTO(func) \
00513                 ISR_PROTO_CONTEXT_SWITCH(func)
00514         #endif /* !CONFIG_KERN_PRI */
00515     #endif
00516 
00517     #ifndef ISR_PROTO
00518         #define ISR_PROTO(vect) ISR(vect)
00519     #endif
00520     #ifndef DECLARE_ISR
00521         #define DECLARE_ISR(vect) ISR(vect)
00522     #endif
00523     #ifndef DECLARE_ISR_CONTEXT_SWITCH
00524         #define DECLARE_ISR_CONTEXT_SWITCH(vect) ISR(vect)
00525     #endif
00526     #ifndef ISR_PROTO_CONTEXT_SWITCH
00527         #define ISR_PROTO_CONTEXT_SWITCH(vect) ISR(vect)
00528     #endif
00529 
00530 #else
00531     #error No CPU_... defined.
00532 #endif
00533 
00534 #ifdef IRQ_RUNNING
00535 
00536     #define ASSERT_IRQ_CONTEXT()  ASSERT(IRQ_RUNNING())
00537 
00539     #define ASSERT_USER_CONTEXT() ASSERT(!IRQ_RUNNING())
00540 #else
00541     #define IRQ_RUNNING()   false
00542     #define ASSERT_USER_CONTEXT()  do {} while(0)
00543     #define ASSERT_IRQ_CONTEXT()   do {} while(0)
00544 #endif
00545 
00546 #ifdef IRQ_ENABLED
00547 
00548     #define IRQ_ASSERT_ENABLED()  ASSERT(IRQ_ENABLED())
00549 
00551     #define IRQ_ASSERT_DISABLED() ASSERT(!IRQ_ENABLED())
00552 #else
00553     #define IRQ_ASSERT_ENABLED() do {} while(0)
00554     #define IRQ_ASSERT_DISABLED() do {} while(0)
00555 #endif
00556 
00557 
00558 #ifndef IRQ_PREEMPT_HANDLER
00559     #if (CONFIG_KERN && CONFIG_KERN_PREEMPT)
00560 
00563         INLINE void IRQ_PREEMPT_HANDLER(void)
00564         {
00565             if (proc_needPreempt())
00566                 proc_preempt();
00567         }
00568     #else
00569         #define IRQ_PREEMPT_HANDLER() /* Nothing */
00570     #endif
00571 #endif
00572 
00578 #define ATOMIC(CODE) \
00579     do { \
00580         cpu_flags_t __flags; \
00581         IRQ_SAVE_DISABLE(__flags); \
00582         CODE; \
00583         IRQ_RESTORE(__flags); \
00584     } while (0)
00585 
00586 #endif /* CPU_IRQ_H */