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_PPC
00071 
00072     #define CPU_SAVED_REGS_CNT     1
00073     #define CPU_STACK_GROWS_UPWARD 0
00074     #define CPU_SP_ON_EMPTY_SLOT   1
00075 
00076 #elif CPU_DSP56K
00077 
00078     #define CPU_SAVED_REGS_CNT      8
00079     #define CPU_STACK_GROWS_UPWARD  1
00080     #define CPU_SP_ON_EMPTY_SLOT    0
00081 
00082 #elif CPU_AVR
00083 
00084     #define CPU_SAVED_REGS_CNT     18
00085     #define CPU_STACK_GROWS_UPWARD  0
00086     #define CPU_SP_ON_EMPTY_SLOT    1
00087 
00088 #else
00089     #error No CPU_... defined.
00090 #endif
00091 
00092 #ifndef CPU_STACK_GROWS_UPWARD
00093     #error CPU_STACK_GROWS_UPWARD should have been defined to either 0 or 1
00094 #endif
00095 
00096 #ifndef CPU_SP_ON_EMPTY_SLOT
00097     #error CPU_SP_ON_EMPTY_SLOT should have been defined to either 0 or 1
00098 #endif
00099 
00101 #ifndef CPU_REG_INIT_VALUE
00102     #define CPU_REG_INIT_VALUE(reg)     (reg)
00103 #endif
00104 
00105 /*
00106  * Support stack handling peculiarities of a few CPUs.
00107  *
00108  * Most processors let their stack grow downward and
00109  * keep SP pointing at the last pushed value.
00110  */
00111 #if !CPU_STACK_GROWS_UPWARD
00112     #if !CPU_SP_ON_EMPTY_SLOT
00113         /* Most microprocessors (x86, m68k...) */
00114         #define CPU_PUSH_WORD(sp, data) \
00115             do { *--(sp) = (data); } while (0)
00116         #define CPU_POP_WORD(sp) \
00117             (*(sp)++)
00118     #else
00119         /* AVR insanity */
00120         #define CPU_PUSH_WORD(sp, data) \
00121             do { *(sp)-- = (data); } while (0)
00122         #define CPU_POP_WORD(sp) \
00123             (*++(sp))
00124     #endif
00125 
00126 #else /* CPU_STACK_GROWS_UPWARD */
00127 
00128     #if !CPU_SP_ON_EMPTY_SLOT
00129         /* DSP56K and other weirdos */
00130         #define CPU_PUSH_WORD(sp, data) \
00131             do { *++(sp) = (cpu_stack_t)(data); } while (0)
00132         #define CPU_POP_WORD(sp) \
00133             (*(sp)--)
00134     #else
00135         #error I bet you cannot find a CPU like this
00136     #endif
00137 #endif
00138 
00139 
00140 #if CPU_DSP56K
00141     /*
00142      * DSP56k pushes both PC and SR to the stack in the JSR instruction, but
00143      * RTS discards SR while returning (it does not restore it). So we push
00144      * 0 to fake the same context.
00145      */
00146     #define CPU_PUSH_CALL_FRAME(sp, func) \
00147         do { \
00148             CPU_PUSH_WORD((sp), (func)); \
00149             CPU_PUSH_WORD((sp), 0x100); \
00150         } while (0);
00151 
00152 #elif CPU_AVR
00153     /*
00154      * On AVR, addresses are pushed into the stack as little-endian, while
00155      * memory accesses are big-endian (actually, it's a 8-bit CPU, so there is
00156      * no natural endianess).
00157      */
00158     #define CPU_PUSH_CALL_FRAME(sp, func) \
00159         do { \
00160             uint16_t funcaddr = (uint16_t)(func); \
00161             CPU_PUSH_WORD((sp), funcaddr); \
00162             CPU_PUSH_WORD((sp), funcaddr>>8); \
00163         } while (0)
00164 
00165     /*
00166      * If the kernel is in idle-spinning, the processor executes:
00167      *
00168      * IRQ_ENABLE;
00169      * CPU_IDLE;
00170      * IRQ_DISABLE;
00171      *
00172      * IRQ_ENABLE is translated in asm as "sei" and IRQ_DISABLE as "cli".
00173      * We could define CPU_IDLE to expand to none, so the resulting
00174      * asm code would be:
00175      *
00176      * sei;
00177      * cli;
00178      *
00179      * But Atmel datasheet states:
00180      * "When using the SEI instruction to enable interrupts,
00181      * the instruction following SEI will be executed *before*
00182      * any pending interrupts", so "cli" is executed before any
00183      * pending interrupt with the result that IRQs will *NOT*
00184      * be enabled!
00185      * To ensure that IRQ will run a NOP is required.
00186      */
00187     #define CPU_IDLE NOP
00188 
00189 #elif CPU_PPC
00190 
00191     #define CPU_PUSH_CALL_FRAME(sp, func) \
00192         do { \
00193             CPU_PUSH_WORD((sp), (cpu_stack_t)(func)); /* LR -> 8(SP) */ \
00194             CPU_PUSH_WORD((sp), 0);                  /* CR -> 4(SP) */ \
00195         } while (0)
00196 
00197 #else
00198     #define CPU_PUSH_CALL_FRAME(sp, func) \
00199         CPU_PUSH_WORD((sp), (cpu_stack_t)(func))
00200 #endif
00201 
00211 #ifndef CPU_IDLE
00212     #define CPU_IDLE PAUSE
00213 #endif /* !CPU_IDLE */
00214 
00218 #ifndef CPU_CREATE_NEW_STACK
00219 
00220     #define CPU_CREATE_NEW_STACK(stack) \
00221         do { \
00222             size_t i; \
00223             /* Initialize process stack frame */ \
00224             CPU_PUSH_CALL_FRAME(stack, proc_entry); \
00225             /* Push a clean set of CPU registers for asm_switch_context() */ \
00226             for (i = 0; i < CPU_SAVED_REGS_CNT; i++) \
00227                 CPU_PUSH_WORD(stack, CPU_REG_INIT_VALUE(i)); \
00228         } while (0)
00229 #endif
00230 
00231 #endif /* CPU_ATTR_H */