frame.h

Go to the documentation of this file.
00001 
00045 #ifndef CPU_FRAME_H
00046 #define CPU_FRAME_H
00047 
00048 #include <cpu/detect.h>
00049 
00050 #include "cfg/cfg_arch.h"      /* ARCH_EMUL */
00051 #include <cfg/compiler.h>      /* for uintXX_t */
00052 
00053 #if CPU_X86
00054     #if CPU_X86_32
00055         #define CPU_SAVED_REGS_CNT      2
00056     #elif CPU_X86_64
00057         #define CPU_SAVED_REGS_CNT      8
00058     #else
00059         #error "unknown CPU"
00060     #endif
00061     #define CPU_STACK_GROWS_UPWARD  0
00062     #define CPU_SP_ON_EMPTY_SLOT    0
00063 
00064 #elif CPU_ARM
00065 
00066     #define CPU_SAVED_REGS_CNT     8
00067     #define CPU_STACK_GROWS_UPWARD 0
00068     #define CPU_SP_ON_EMPTY_SLOT   0
00069 
00070 #elif CPU_CM3
00071 
00072     #define CPU_SAVED_REGS_CNT     8
00073     #define CPU_STACK_GROWS_UPWARD 0
00074     #define CPU_SP_ON_EMPTY_SLOT   0
00075 
00076 #elif CPU_PPC
00077 
00078     #define CPU_SAVED_REGS_CNT     1
00079     #define CPU_STACK_GROWS_UPWARD 0
00080     #define CPU_SP_ON_EMPTY_SLOT   1
00081 
00082 #elif CPU_DSP56K
00083 
00084     #define CPU_SAVED_REGS_CNT      8
00085     #define CPU_STACK_GROWS_UPWARD  1
00086     #define CPU_SP_ON_EMPTY_SLOT    0
00087 
00088 #elif CPU_AVR
00089 
00090     #define CPU_SAVED_REGS_CNT     18
00091     #define CPU_STACK_GROWS_UPWARD  0
00092     #define CPU_SP_ON_EMPTY_SLOT    1
00093 
00094 #else
00095     #error No CPU_... defined.
00096 #endif
00097 
00098 #ifndef CPU_STACK_GROWS_UPWARD
00099     #error CPU_STACK_GROWS_UPWARD should have been defined to either 0 or 1
00100 #endif
00101 
00102 #ifndef CPU_SP_ON_EMPTY_SLOT
00103     #error CPU_SP_ON_EMPTY_SLOT should have been defined to either 0 or 1
00104 #endif
00105 
00107 #ifndef CPU_REG_INIT_VALUE
00108     #define CPU_REG_INIT_VALUE(reg)     (reg)
00109 #endif
00110 
00111 /*
00112  * Support stack handling peculiarities of a few CPUs.
00113  *
00114  * Most processors let their stack grow downward and
00115  * keep SP pointing at the last pushed value.
00116  */
00117 #if !CPU_STACK_GROWS_UPWARD
00118     #if !CPU_SP_ON_EMPTY_SLOT
00119         /* Most microprocessors (x86, m68k...) */
00120         #define CPU_PUSH_WORD(sp, data) \
00121             do { *--(sp) = (data); } while (0)
00122         #define CPU_POP_WORD(sp) \
00123             (*(sp)++)
00124     #else
00125         /* AVR insanity */
00126         #define CPU_PUSH_WORD(sp, data) \
00127             do { *(sp)-- = (data); } while (0)
00128         #define CPU_POP_WORD(sp) \
00129             (*++(sp))
00130     #endif
00131 
00132 #else /* CPU_STACK_GROWS_UPWARD */
00133 
00134     #if !CPU_SP_ON_EMPTY_SLOT
00135         /* DSP56K and other weirdos */
00136         #define CPU_PUSH_WORD(sp, data) \
00137             do { *++(sp) = (cpu_stack_t)(data); } while (0)
00138         #define CPU_POP_WORD(sp) \
00139             (*(sp)--)
00140     #else
00141         #error I bet you cannot find a CPU like this
00142     #endif
00143 #endif
00144 
00145 
00146 #if CPU_DSP56K
00147     /*
00148      * DSP56k pushes both PC and SR to the stack in the JSR instruction, but
00149      * RTS discards SR while returning (it does not restore it). So we push
00150      * 0 to fake the same context.
00151      */
00152     #define CPU_PUSH_CALL_FRAME(sp, func) \
00153         do { \
00154             CPU_PUSH_WORD((sp), (func)); \
00155             CPU_PUSH_WORD((sp), 0x100); \
00156         } while (0);
00157 
00158 #elif CPU_CM3
00159 
00160     #if CONFIG_KERN_PREEMPT
00161         INLINE void asm_switch_context(cpu_stack_t **new_sp, cpu_stack_t **old_sp)
00162         {
00163             register cpu_stack_t **__new_sp asm ("r0") = new_sp;
00164             register cpu_stack_t **__old_sp asm ("r1") = old_sp;
00165 
00166             asm volatile ("svc #0"
00167                 : : "r"(__new_sp), "r"(__old_sp) : "memory", "cc");
00168         }
00169         #define asm_switch_context asm_switch_context
00170 
00171         #define CPU_PUSH_CALL_FRAME(sp, func) \
00172             do { \
00173                 CPU_PUSH_WORD((sp), 0x01000000);        /* xPSR    */   \
00174                 CPU_PUSH_WORD((sp), (cpu_stack_t)(func));   /* pc      */   \
00175                 CPU_PUSH_WORD((sp), 0);             /* lr      */   \
00176                 CPU_PUSH_WORD((sp), 0);             /* ip      */   \
00177                 CPU_PUSH_WORD((sp), 0);             /* r3      */   \
00178                 CPU_PUSH_WORD((sp), 0);             /* r2      */   \
00179                 CPU_PUSH_WORD((sp), 0);             /* r1      */   \
00180                 CPU_PUSH_WORD((sp), 0);             /* r0      */   \
00181                 CPU_PUSH_WORD((sp), 0xfffffffd);        /* lr_exc  */   \
00182             } while (0);
00183 
00184         #define CPU_CREATE_NEW_STACK(stack) \
00185             do { \
00186                 size_t i; \
00187                 /* Initialize process stack frame */ \
00188                 CPU_PUSH_CALL_FRAME(stack, proc_entry); \
00189                 /* Push a clean set of CPU registers for asm_switch_context() */ \
00190                 for (i = 0; i < CPU_SAVED_REGS_CNT; i++) \
00191                     CPU_PUSH_WORD(stack, CPU_REG_INIT_VALUE(i)); \
00192                 CPU_PUSH_WORD(stack, IRQ_PRIO_DISABLED); \
00193             } while (0)
00194 
00195     #else /* !CONFIG_KERN_PREEMPT */
00196         #define CPU_PUSH_CALL_FRAME(sp, func) \
00197             do { \
00198                 CPU_PUSH_WORD((sp), 0x01000000);        /* xPSR    */   \
00199                 CPU_PUSH_WORD((sp), (cpu_stack_t)(func));   /* pc      */   \
00200             } while (0);
00201     #endif /* CONFIG_KERN_PREEMPT */
00202 
00203 #elif CPU_AVR
00204     /*
00205      * On AVR, addresses are pushed into the stack as little-endian, while
00206      * memory accesses are big-endian (actually, it's a 8-bit CPU, so there is
00207      * no natural endianess).
00208      */
00209     #define CPU_PUSH_CALL_FRAME(sp, func) \
00210         do { \
00211             uint16_t funcaddr = (uint16_t)(func); \
00212             CPU_PUSH_WORD((sp), funcaddr); \
00213             CPU_PUSH_WORD((sp), funcaddr>>8); \
00214         } while (0)
00215 
00216     /*
00217      * If the kernel is in idle-spinning, the processor executes:
00218      *
00219      * IRQ_ENABLE;
00220      * CPU_IDLE;
00221      * IRQ_DISABLE;
00222      *
00223      * IRQ_ENABLE is translated in asm as "sei" and IRQ_DISABLE as "cli".
00224      * We could define CPU_IDLE to expand to none, so the resulting
00225      * asm code would be:
00226      *
00227      * sei;
00228      * cli;
00229      *
00230      * But Atmel datasheet states:
00231      * "When using the SEI instruction to enable interrupts,
00232      * the instruction following SEI will be executed *before*
00233      * any pending interrupts", so "cli" is executed before any
00234      * pending interrupt with the result that IRQs will *NOT*
00235      * be enabled!
00236      * To ensure that IRQ will run a NOP is required.
00237      */
00238     #define CPU_IDLE NOP
00239 
00240 #elif CPU_PPC
00241 
00242     #define CPU_PUSH_CALL_FRAME(sp, func) \
00243         do { \
00244             CPU_PUSH_WORD((sp), (cpu_stack_t)(func)); /* LR -> 8(SP) */ \
00245             CPU_PUSH_WORD((sp), 0);                  /* CR -> 4(SP) */ \
00246         } while (0)
00247 
00248 #else
00249     #define CPU_PUSH_CALL_FRAME(sp, func) \
00250         CPU_PUSH_WORD((sp), (cpu_stack_t)(func))
00251 #endif
00252 
00262 #ifndef CPU_IDLE
00263     #define CPU_IDLE PAUSE
00264 #endif /* !CPU_IDLE */
00265 
00269 #ifndef CPU_CREATE_NEW_STACK
00270 
00271     #define CPU_CREATE_NEW_STACK(stack) \
00272         do { \
00273             size_t i; \
00274             /* Initialize process stack frame */ \
00275             CPU_PUSH_CALL_FRAME(stack, proc_entry); \
00276             /* Push a clean set of CPU registers for asm_switch_context() */ \
00277             for (i = 0; i < CPU_SAVED_REGS_CNT; i++) \
00278                 CPU_PUSH_WORD(stack, CPU_REG_INIT_VALUE(i)); \
00279         } while (0)
00280 #endif
00281 
00282 #endif /* CPU_ATTR_H */