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     #ifdef __IAR_SYSTEMS_ICC__
00093         INLINE cpu_flags_t CPU_READ_FLAGS(void)
00094         {
00095             return __get_BASEPRI();
00096         }
00097
00098         INLINE void CPU_WRITE_FLAGS(cpu_flags_t flags)
00099         {
00100             __set_BASEPRI(flags);
00101         }
00102
00103         extern uint32_t CPU_READ_IPSR(void);
00104         extern bool irq_running(void);
00105
00106         #define IRQ_DISABLE CPU_WRITE_FLAGS(IRQ_PRIO_DISABLED)
00107 
00108         #define IRQ_ENABLE  CPU_WRITE_FLAGS(IRQ_PRIO_ENABLED)
00109 
00110         #define IRQ_SAVE_DISABLE(x)                 \
00111         do {                                \
00112             x = CPU_READ_FLAGS();                   \
00113             IRQ_DISABLE;                        \
00114         } while (0)
00115 
00116         #define IRQ_RESTORE(x)                      \
00117         do {                                \
00118             CPU_WRITE_FLAGS(x);                 \
00119         } while (0)
00120     #else /* !__IAR_SYSTEMS_ICC__ */
00121         #define IRQ_DISABLE                     \
00122         ({                              \
00123             register cpu_flags_t reg = IRQ_PRIO_DISABLED;       \
00124             asm volatile (                      \
00125                 "msr basepri, %0"               \
00126                 : : "r"(reg) : "memory", "cc");         \
00127         })
00128 
00129         #define IRQ_ENABLE                      \
00130         ({                              \
00131             register cpu_flags_t reg = IRQ_PRIO_ENABLED;        \
00132             asm volatile (                      \
00133                 "msr basepri, %0"               \
00134                 : : "r"(reg) : "memory", "cc");         \
00135         })
00136 
00137         #define CPU_READ_FLAGS()                    \
00138         ({                              \
00139             register cpu_flags_t reg;               \
00140             asm volatile (                      \
00141                 "mrs %0, basepri"               \
00142                  : "=r"(reg) : : "memory", "cc");       \
00143             reg;                            \
00144         })
00145 
00146         #define IRQ_SAVE_DISABLE(x)                 \
00147         ({                              \
00148             x = CPU_READ_FLAGS();                   \
00149             IRQ_DISABLE;                        \
00150         })
00151 
00152         #define IRQ_RESTORE(x)                      \
00153         ({                              \
00154             asm volatile (                      \
00155                 "msr basepri, %0"               \
00156                 : : "r"(x) : "memory", "cc");           \
00157         })
00158 
00159         INLINE bool irq_running(void)
00160         {
00161             register uint32_t ret;
00162
00163             /*
00164              * Check if the current stack pointer is the main stack or
00165              * process stack: we use the main stack only in Handler mode,
00166              * so this means we're running inside an ISR.
00167              */
00168             asm volatile (
00169                 "mrs %0, msp\n\t"
00170                 "cmp sp, %0\n\t"
00171                 "ite ne\n\t"
00172                 "movne %0, #0\n\t"
00173                 "moveq %0, #1\n\t" : "=r"(ret) : : "cc");
00174             return ret;
00175         }
00176     #endif /* __IAR_SYSTEMS_ICC__ */
00177
00178     #define IRQ_ENABLED() (CPU_READ_FLAGS() == IRQ_PRIO_ENABLED)
00179 
00180     #define IRQ_RUNNING() irq_running()
00181 
00182     #if (CONFIG_KERN && CONFIG_KERN_PREEMPT)
00183 
00184         #define DECLARE_ISR_CONTEXT_SWITCH(func)        \
00185         void func(void);                    \
00186         INLINE void __isr_##func(void);             \
00187         void func(void)                     \
00188         {                           \
00189             __isr_##func();                 \
00190             if (!proc_needPreempt())            \
00191                 return;                 \
00192             /*
00193              * Set a PendSV request.
00194              *
00195              * The preemption handler will be called immediately
00196              * after this ISR in tail-chaining mode (without the
00197              * overhead of hardware state saving and restoration
00198              * between interrupts).
00199              */                     \
00200             HWREG(NVIC_INT_CTRL) = NVIC_INT_CTRL_PEND_SV;   \
00201         }                           \
00202         INLINE void __isr_##func(void)
00203
00214         #if CONFIG_KERN_PRI
00215             #define DECLARE_ISR(func) \
00216                 DECLARE_ISR_CONTEXT_SWITCH(func)
00217 
00221             #define ISR_PROTO(func) \
00222                 ISR_PROTO_CONTEXT_SWITCH(func)
00223         #endif /* !CONFIG_KERN_PRI */
00224     #endif
00225 
00226     #ifndef ISR_PROTO
00227         #define ISR_PROTO(func) void func(void)
00228     #endif
00229     #ifndef DECLARE_ISR
00230         #define DECLARE_ISR(func) void func(void)
00231     #endif
00232     #ifndef DECLARE_ISR_CONTEXT_SWITCH
00233         #define DECLARE_ISR_CONTEXT_SWITCH(func) void func(void)
00234     #endif
00235     #ifndef ISR_PROTO_CONTEXT_SWITCH
00236         #define ISR_PROTO_CONTEXT_SWITCH(func) void func(void)
00237     #endif
00238 
00239 #elif CPU_ARM
00240 
00241     #ifdef __IAR_SYSTEMS_ICC__
00242 
00243         #include <inarm.h>
00244
00245         #if __CPU_MODE__ == 1 /* Thumb */
00246             /* Use stubs */
00247             extern cpu_flags_t get_CPSR(void);
00248             extern void set_CPSR(cpu_flags_t flags);
00249         #else
00250             #define get_CPSR __get_CPSR
00251             #define set_CPSR __set_CPSR
00252         #endif
00253 
00254         #define IRQ_DISABLE __disable_interrupt()
00255         #define IRQ_ENABLE  __enable_interrupt()
00256 
00257         #define IRQ_SAVE_DISABLE(x) \
00258         do { \
00259             (x) = get_CPSR(); \
00260             __disable_interrupt(); \
00261         } while (0)
00262 
00263         #define IRQ_RESTORE(x) \
00264         do { \
00265             set_CPSR(x); \
00266         } while (0)
00267 
00268         #define IRQ_ENABLED() \
00269             ((bool)(get_CPSR() & 0xb0))
00270 
00271     #else /* !__IAR_SYSTEMS_ICC__ */
00272
00273         #define IRQ_DISABLE                 \
00274         do {                            \
00275             cpu_flags_t sreg;               \
00276             asm volatile (                  \
00277                 "mrs %0, cpsr\n\t"          \
00278                 "orr %0, %0, #0xc0\n\t"         \
00279                 "msr cpsr_c, %0\n\t"            \
00280                 : "=r" (sreg) : : "memory", "cc");  \
00281         } while (0)
00282 
00283         #define IRQ_ENABLE                  \
00284         do {                            \
00285             cpu_flags_t sreg;               \
00286             asm volatile (                  \
00287                 "mrs %0, cpsr\n\t"          \
00288                 "bic %0, %0, #0xc0\n\t"         \
00289                 "msr cpsr_c, %0\n\t"            \
00290                 : "=r" (sreg) : : "memory", "cc");  \
00291         } while (0)
00292 
00293         #define IRQ_SAVE_DISABLE(x)             \
00294         do {                            \
00295             register cpu_flags_t sreg;          \
00296             asm volatile (                  \
00297                 "mrs %0, cpsr\n\t"          \
00298                 "orr %1, %0, #0xc0\n\t"         \
00299                 "msr cpsr_c, %1\n\t"            \
00300                 : "=r" (x), "=r" (sreg)         \
00301                 : : "memory", "cc");            \
00302         } while (0)
00303 
00304         #define IRQ_RESTORE(x)                  \
00305         do {                            \
00306             asm volatile (                  \
00307                 "msr cpsr_c, %0\n\t"            \
00308                 : : "r" (x) : "memory", "cc");      \
00309         } while (0)
00310 
00311         #define CPU_READ_FLAGS()                \
00312         ({                          \
00313             cpu_flags_t sreg;               \
00314             asm volatile (                  \
00315                 "mrs %0, cpsr\n\t"          \
00316                 : "=r" (sreg) : : "memory", "cc");  \
00317             sreg;                       \
00318         })
00319 
00320         #define IRQ_ENABLED() ((CPU_READ_FLAGS() & 0xc0) != 0xc0)
00321 
00322         #define IRQ_RUNNING() ((CPU_READ_FLAGS() & 0x0F) == 0x02)
00323 
00324         #if (CONFIG_KERN && CONFIG_KERN_PREEMPT)
00325             EXTERN_C void asm_irq_switch_context(void);
00326
00333             #define IRQ_ENTRY() asm volatile ( \
00334                         "sub    lr, lr, #4\n\t" \
00335                         "stmfd  sp!, {r0-r3, ip, lr}\n\t")
00336             #define IRQ_EXIT()  asm volatile ( \
00337                         "b  asm_irq_switch_context\n\t")
00338 
00348             #define ISR_FUNC __attribute__((naked))
00349 
00376             #define DECLARE_ISR_CONTEXT_SWITCH(func)        \
00377                 void ISR_FUNC func(void);           \
00378                 static NOINLINE void __isr_##func(void);    \
00379                 void ISR_FUNC func(void)            \
00380                 {                       \
00381                     IRQ_ENTRY();                \
00382                     IRQ_DISABLE;                \
00383                     __isr_##func();             \
00384                     IRQ_EXIT();             \
00385                 }                       \
00386                 static NOINLINE void __isr_##func(void)
00387 
00391             #define ISR_PROTO_CONTEXT_SWITCH(func)  \
00392                 void ISR_FUNC func(void)
00393 
00403             #if CONFIG_KERN_PRI
00404                 #define DECLARE_ISR(func) \
00405                     DECLARE_ISR_CONTEXT_SWITCH(func)
00406 
00407                 #define ISR_PROTO(func) \
00408                     ISR_PROTO_CONTEXT_SWITCH(func)
00409             #endif /* !CONFIG_KERN_PRI */
00410         #endif /* CONFIG_KERN_PREEMPT */
00411
00412         #ifndef ISR_FUNC
00413             #define ISR_FUNC __attribute__((naked))
00414         #endif
00415         #ifndef DECLARE_ISR
00416             #define DECLARE_ISR(func) \
00417                 void ISR_FUNC func(void);               \
00418                 /*                          \
00419                  * FIXME: avoid the inlining of this function.      \
00420                  *                          \
00421                  * This is terribly inefficient, but it's a     \
00422                  * reliable workaround to avoid gcc blowing     \
00423                  * away the stack (see the bug below):          \
00424                  *                          \
00425                  * http://gcc.gnu.org/bugzilla/show_bug.cgi?id=41999    \
00426                  */                         \
00427                 static NOINLINE void __isr_##func(void);        \
00428                 void ISR_FUNC func(void)                \
00429                 {                           \
00430                     asm volatile (                  \
00431                         "sub    lr, lr, #4\n\t"         \
00432                         "stmfd  sp!, {r0-r3, ip, lr}\n\t"); \
00433                     __isr_##func();                 \
00434                     asm volatile (                  \
00435                         "ldmfd sp!, {r0-r3, ip, pc}^\n\t"); \
00436                 }                           \
00437                 static NOINLINE void __isr_##func(void)
00438         #endif
00439         #ifndef DECLARE_ISR_CONTEXT_SWITCH
00440             #define DECLARE_ISR_CONTEXT_SWITCH(func) DECLARE_ISR(func)
00441         #endif
00442         #ifndef ISR_PROTO
00443             #define ISR_PROTO(func) void ISR_FUNC func(void)
00444         #endif
00445         #ifndef ISR_PROTO_CONTEXT_SWITCH
00446             #define ISR_PROTO_CONTEXT_SWITCH(func) ISR_PROTO(func)
00447         #endif
00448 
00449     #endif /* !__IAR_SYSTEMS_ICC_ */
00450
00451 #elif CPU_PPC
00452 
00453     /* Get IRQ_* definitions from the hosting environment. */
00454     #include <cfg/os.h>
00455     #if OS_EMBEDDED
00456         #define IRQ_DISABLE         FIXME
00457         #define IRQ_ENABLE          FIXME
00458         #define IRQ_SAVE_DISABLE(x) FIXME
00459         #define IRQ_RESTORE(x)      FIXME
00460         #define IRQ_ENABLED()       FIXME
00461     #endif /* OS_EMBEDDED */
00462
00463 #elif CPU_DSP56K
00464 
00465     #define IRQ_DISABLE             do { asm(bfset #0x0200,SR); asm(nop); } while (0)
00466     #define IRQ_ENABLE              do { asm(bfclr #0x0200,SR); asm(nop); } while (0)
00467 
00468     #define IRQ_SAVE_DISABLE(x)  \
00469         do { (void)x; asm(move SR,x); asm(bfset #0x0200,SR); } while (0)
00470     #define IRQ_RESTORE(x)  \
00471         do { (void)x; asm(move x,SR); } while (0)
00472 
00473     static inline bool irq_running(void)
00474     {
00475         extern void *user_sp;
00476         return !!user_sp;
00477     }
00478     #define IRQ_RUNNING() irq_running()
00479 
00480     static inline bool irq_enabled(void)
00481     {
00482         uint16_t x;
00483         asm(move SR,x);
00484         return !(x & 0x0200);
00485     }
00486     #define IRQ_ENABLED() irq_enabled()
00487 
00488 #elif CPU_AVR
00489 
00490     #define IRQ_DISABLE   asm volatile ("cli" ::)
00491     #define IRQ_ENABLE    asm volatile ("sei" ::)
00492 
00493     #define IRQ_SAVE_DISABLE(x) \
00494     do { \
00495         __asm__ __volatile__( \
00496             "in %0,__SREG__\n\t" \
00497             "cli" \
00498             : "=r" (x) : /* no inputs */ : "cc" \
00499         ); \
00500     } while (0)
00501
00502     #define IRQ_RESTORE(x) \
00503     do { \
00504         __asm__ __volatile__( \
00505             "out __SREG__,%0" : /* no outputs */ : "r" (x) : "cc" \
00506         ); \
00507     } while (0)
00508
00509     #define IRQ_ENABLED() \
00510     ({ \
00511         uint8_t sreg; \
00512         __asm__ __volatile__( \
00513             "in %0,__SREG__\n\t" \
00514             : "=r" (sreg)  /* no inputs & no clobbers */ \
00515         ); \
00516         (bool)(sreg & 0x80); \
00517     })
00518     #if (CONFIG_KERN && CONFIG_KERN_PREEMPT)
00519         #define DECLARE_ISR_CONTEXT_SWITCH(vect)        \
00520             INLINE void __isr_##vect(void);         \
00521             ISR(vect)                   \
00522             {                       \
00523                 __isr_##vect();             \
00524                 IRQ_PREEMPT_HANDLER();          \
00525             }                       \
00526             INLINE void __isr_##vect(void)
00527 
00538         #if CONFIG_KERN_PRI
00539             #define DECLARE_ISR(func) \
00540                 DECLARE_ISR_CONTEXT_SWITCH(func)
00541 
00545             #define ISR_PROTO(func) \
00546                 ISR_PROTO_CONTEXT_SWITCH(func)
00547         #endif /* !CONFIG_KERN_PRI */
00548     #endif
00549 
00550     #ifndef ISR_PROTO
00551         #define ISR_PROTO(vect) ISR(vect)
00552     #endif
00553     #ifndef DECLARE_ISR
00554         #define DECLARE_ISR(vect) ISR(vect)
00555     #endif
00556     #ifndef DECLARE_ISR_CONTEXT_SWITCH
00557         #define DECLARE_ISR_CONTEXT_SWITCH(vect) ISR(vect)
00558     #endif
00559     #ifndef ISR_PROTO_CONTEXT_SWITCH
00560         #define ISR_PROTO_CONTEXT_SWITCH(vect) ISR(vect)
00561     #endif
00562 
00563 #elif CPU_MSP430
00564 
00565     /* Get the compiler defined macros */
00566     #include <signal.h>
00567     #define IRQ_DISABLE         dint()
00568     #define IRQ_ENABLE          eint()
00569 
00570 #else
00571     #error No CPU_... defined.
00572 #endif
00573 
00574 #ifdef IRQ_RUNNING
00575 
00576     #define ASSERT_IRQ_CONTEXT()  ASSERT(IRQ_RUNNING())
00577 
00579     #define ASSERT_USER_CONTEXT() ASSERT(!IRQ_RUNNING())
00580 #else
00581     #define IRQ_RUNNING()   false
00582     #define ASSERT_USER_CONTEXT()  do {} while(0)
00583     #define ASSERT_IRQ_CONTEXT()   do {} while(0)
00584 #endif
00585 
00586 #ifdef IRQ_ENABLED
00587 
00588     #define IRQ_ASSERT_ENABLED()  ASSERT(IRQ_ENABLED())
00589 
00591     #define IRQ_ASSERT_DISABLED() ASSERT(!IRQ_ENABLED())
00592 #else
00593     #define IRQ_ASSERT_ENABLED() do {} while(0)
00594     #define IRQ_ASSERT_DISABLED() do {} while(0)
00595 #endif
00596 
00597
00598 #ifndef IRQ_PREEMPT_HANDLER
00599     #if (CONFIG_KERN && CONFIG_KERN_PREEMPT)
00600 
00603         INLINE void IRQ_PREEMPT_HANDLER(void)
00604         {
00605             if (proc_needPreempt())
00606                 proc_preempt();
00607         }
00608     #else
00609         #define IRQ_PREEMPT_HANDLER() /* Nothing */
00610     #endif
00611 #endif
00612 
00618 #define ATOMIC(CODE) \
00619     do { \
00620         cpu_flags_t __flags; \
00621         IRQ_SAVE_DISABLE(__flags); \
00622         CODE; \
00623         IRQ_RESTORE(__flags); \
00624     } while (0)
00625 
00626 #endif /* CPU_IRQ_H */