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 
00055     #define CPU_SAVED_REGS_CNT      7
00056     #define CPU_STACK_GROWS_UPWARD  0
00057     #define CPU_SP_ON_EMPTY_SLOT    0
00058 
00059 #elif CPU_ARM
00060 
00061     #define CPU_SAVED_REGS_CNT     10
00062     #define CPU_STACK_GROWS_UPWARD 0
00063     #define CPU_SP_ON_EMPTY_SLOT   0
00064 
00073     #define CPU_CREATE_NEW_STACK(stack, entry, exit) \
00074     do { \
00075         /* Process entry point */ \
00076         CPU_PUSH_CALL_FRAME(stack, entry); \
00077         /* LR (proc_exit) */ \
00078         CPU_PUSH_CALL_FRAME(stack, exit); \
00079         /* R11 */ \
00080         CPU_PUSH_WORD(stack, 0x11111111); \
00081         /* R10 */ \
00082         CPU_PUSH_WORD(stack, 0x10101010); \
00083         /* R9 */ \
00084         CPU_PUSH_WORD(stack, 0x09090909); \
00085         /* R8 */ \
00086         CPU_PUSH_WORD(stack, 0x08080808); \
00087         /* R7 */ \
00088         CPU_PUSH_WORD(stack, 0x07070707); \
00089         /* R6 */ \
00090         CPU_PUSH_WORD(stack, 0x06060606); \
00091         /* R5 */ \
00092         CPU_PUSH_WORD(stack, 0x05050505); \
00093         /* R4 */ \
00094         CPU_PUSH_WORD(stack, 0x04040404); \
00095         /* CPSR */ \
00096         CPU_PUSH_WORD(stack, 0x00000013); \
00097     } while (0)
00098 
00099 #elif CPU_PPC
00100 
00101     #define CPU_SAVED_REGS_CNT     1
00102     #define CPU_STACK_GROWS_UPWARD 0
00103     #define CPU_SP_ON_EMPTY_SLOT   1
00104 
00105 #elif CPU_DSP56K
00106 
00107     #define CPU_SAVED_REGS_CNT      8
00108     #define CPU_STACK_GROWS_UPWARD  1
00109     #define CPU_SP_ON_EMPTY_SLOT    0
00110 
00111 #elif CPU_AVR
00112 
00113     #define CPU_SAVED_REGS_CNT     19
00114     #define CPU_STACK_GROWS_UPWARD  0
00115     #define CPU_SP_ON_EMPTY_SLOT    1
00116 
00123     #define CPU_REG_INIT_VALUE(reg) (reg == 0 ? 0x80 : 0)
00124 
00125 #else
00126     #error No CPU_... defined.
00127 #endif
00128 
00129 #ifndef CPU_STACK_GROWS_UPWARD
00130     #error CPU_STACK_GROWS_UPWARD should have been defined to either 0 or 1
00131 #endif
00132 
00133 #ifndef CPU_SP_ON_EMPTY_SLOT
00134     #error CPU_SP_ON_EMPTY_SLOT should have been defined to either 0 or 1
00135 #endif
00136 
00138 #ifndef CPU_REG_INIT_VALUE
00139     #define CPU_REG_INIT_VALUE(reg)     0
00140 #endif
00141 
00142 /*
00143  * Support stack handling peculiarities of a few CPUs.
00144  *
00145  * Most processors let their stack grow downward and
00146  * keep SP pointing at the last pushed value.
00147  */
00148 #if !CPU_STACK_GROWS_UPWARD
00149     #if !CPU_SP_ON_EMPTY_SLOT
00150         /* Most microprocessors (x86, m68k...) */
00151         #define CPU_PUSH_WORD(sp, data) \
00152             do { *--(sp) = (data); } while (0)
00153         #define CPU_POP_WORD(sp) \
00154             (*(sp)++)
00155     #else
00156         /* AVR insanity */
00157         #define CPU_PUSH_WORD(sp, data) \
00158             do { *(sp)-- = (data); } while (0)
00159         #define CPU_POP_WORD(sp) \
00160             (*++(sp))
00161     #endif
00162 
00163 #else /* CPU_STACK_GROWS_UPWARD */
00164 
00165     #if !CPU_SP_ON_EMPTY_SLOT
00166         /* DSP56K and other weirdos */
00167         #define CPU_PUSH_WORD(sp, data) \
00168             do { *++(sp) = (cpu_stack_t)(data); } while (0)
00169         #define CPU_POP_WORD(sp) \
00170             (*(sp)--)
00171     #else
00172         #error I bet you cannot find a CPU like this
00173     #endif
00174 #endif
00175 
00176 
00177 #if CPU_DSP56K
00178     /*
00179      * DSP56k pushes both PC and SR to the stack in the JSR instruction, but
00180      * RTS discards SR while returning (it does not restore it). So we push
00181      * 0 to fake the same context.
00182      */
00183     #define CPU_PUSH_CALL_FRAME(sp, func) \
00184         do { \
00185             CPU_PUSH_WORD((sp), (func)); \
00186             CPU_PUSH_WORD((sp), 0x100); \
00187         } while (0);
00188 
00189 #elif CPU_AVR
00190     /*
00191      * On AVR, addresses are pushed into the stack as little-endian, while
00192      * memory accesses are big-endian (actually, it's a 8-bit CPU, so there is
00193      * no natural endianess).
00194      */
00195     #define CPU_PUSH_CALL_FRAME(sp, func) \
00196         do { \
00197             uint16_t funcaddr = (uint16_t)(func); \
00198             CPU_PUSH_WORD((sp), funcaddr); \
00199             CPU_PUSH_WORD((sp), funcaddr>>8); \
00200         } while (0)
00201 
00202     /*
00203      * If the kernel is in idle-spinning, the processor executes:
00204      *
00205      * IRQ_ENABLE;
00206      * CPU_IDLE;
00207      * IRQ_DISABLE;
00208      *
00209      * IRQ_ENABLE is translated in asm as "sei" and IRQ_DISABLE as "cli".
00210      * We could define CPU_IDLE to expand to none, so the resulting
00211      * asm code would be:
00212      *
00213      * sei;
00214      * cli;
00215      *
00216      * But Atmel datasheet states:
00217      * "When using the SEI instruction to enable interrupts,
00218      * the instruction following SEI will be executed *before*
00219      * any pending interrupts", so "cli" is executed before any
00220      * pending interrupt with the result that IRQs will *NOT*
00221      * be enabled!
00222      * To ensure that IRQ will run a NOP is required.
00223      */
00224     #define CPU_IDLE NOP
00225 
00226 #elif CPU_PPC
00227 
00228     #define CPU_PUSH_CALL_FRAME(sp, func) \
00229         do { \
00230             CPU_PUSH_WORD((sp), (cpu_stack_t)(func)); /* LR -> 8(SP) */ \
00231             CPU_PUSH_WORD((sp), 0);                  /* CR -> 4(SP) */ \
00232         } while (0)
00233 
00234 #else
00235     #define CPU_PUSH_CALL_FRAME(sp, func) \
00236         CPU_PUSH_WORD((sp), (cpu_stack_t)(func))
00237 #endif
00238 
00248 #ifndef CPU_IDLE
00249     #if defined(ARCH_QT) && (ARCH & ARCH_QT)
00250         /* This emulator hook should yield the CPU to the host.  */
00251         EXTERN_C_BEGIN
00252         void emul_idle(void);
00253         EXTERN_C_END
00254         #define CPU_IDLE emul_idle()
00255     #else /* !ARCH_EMUL */
00256         #define CPU_IDLE do { /* nothing */ } while (0)
00257     #endif /* !ARCH_EMUL */
00258 #endif /* !CPU_IDLE */
00259 
00263 #ifndef CPU_CREATE_NEW_STACK
00264 
00265     #define CPU_CREATE_NEW_STACK(stack, entry, exit) \
00266         do { \
00267             size_t i; \
00268             /* Initialize process stack frame */ \
00269             CPU_PUSH_CALL_FRAME(stack, exit); \
00270             CPU_PUSH_CALL_FRAME(stack, entry); \
00271             /* Push a clean set of CPU registers for asm_switch_context() */ \
00272             for (i = 0; i < CPU_SAVED_REGS_CNT; i++) \
00273                 CPU_PUSH_WORD(stack, CPU_REG_INIT_VALUE(i)); \
00274         } while (0)
00275 #endif
00276 
00277 #endif /* CPU_ATTR_H */