summaryrefslogtreecommitdiffstats
path: root/cpukit/score/cpu/i386
diff options
context:
space:
mode:
authorTill Straumann <strauman@slac.stanford.edu>2009-10-29 03:15:03 +0000
committerTill Straumann <strauman@slac.stanford.edu>2009-10-29 03:15:03 +0000
commita6d48e3941123189084882866361ff009de1ee04 (patch)
tree96e033d504c0da7aeb1a0ac0185cb80a802db847 /cpukit/score/cpu/i386
parent2009-10-28 Till Straumann <strauman@slac.stanford.edu> (diff)
downloadrtems-a6d48e3941123189084882866361ff009de1ee04.tar.bz2
2009-10-28 Till Straumann <strauman@slac.stanford.edu>
* score/cpu/i386/rtems/score/cpu.h: Added #ifdef ASM constructs so that this header can be included from assembly code. Increased CPU_STACK_ALIGNMENT to 16 bytes. Gcc maintains 16-byte alignment and it may be a advantageous to provide initial 16-byte alignment. When using SSE some gcc versions may produce code that crashes if the stack is not 16-byte aligned. Make sure _CPU_Context_Initialize() sets the thread stack up so that it is aligned to CPU_CACHE_ALIGNMENT. * score/cpu/i386/cpu_asm.S: Align stack to CPU_CACHE_ALIGNMENT before calling C-code.
Diffstat (limited to 'cpukit/score/cpu/i386')
-rw-r--r--cpukit/score/cpu/i386/cpu_asm.S21
-rw-r--r--cpukit/score/cpu/i386/rtems/score/cpu.h58
2 files changed, 69 insertions, 10 deletions
diff --git a/cpukit/score/cpu/i386/cpu_asm.S b/cpukit/score/cpu/i386/cpu_asm.S
index 7630aa3b35..4084e03fb8 100644
--- a/cpukit/score/cpu/i386/cpu_asm.S
+++ b/cpukit/score/cpu/i386/cpu_asm.S
@@ -14,6 +14,11 @@
*/
#include <rtems/asm.h>
+#include <rtems/score/cpu.h>
+
+#ifndef CPU_STACK_ALIGNMENT
+#error "Missing header? CPU_STACK_ALIGNMENT not defined"
+#endif
/*
* Format of i386 Register structure
@@ -110,13 +115,17 @@ SYM (_CPU_Context_restore_fp):
PUBLIC (_Exception_Handler)
SYM (_Exception_Handler):
- pusha /* Push general purpose registers */
- pushl esp /* Push exception frame address */
- movl _currentExcHandler, eax /* Call function storead in _currentExcHandler */
+ pusha /* Push general purpose registers */
+ movl esp, ebp /* Save original SP */
+ subl $4, esp /* Reserve space for argument */
+ /* Align stack (courtesy for C/gcc) */
+ andl $ - CPU_STACK_ALIGNMENT, esp
+ movl ebp, (esp) /* Store argument */
+ movl _currentExcHandler, eax /* Call function stored in _currentExcHandler */
call * eax
- addl $4, esp
- popa /* restore general purpose registers */
- addl $8, esp /* skill vector number and faultCode */
+ movl ebp, esp /* Restore original SP */
+ popa /* Restore general purpose registers */
+ addl $8, esp /* Skill vector number and faultCode */
iret
#define DISTINCT_EXCEPTION_WITH_FAULTCODE_ENTRY(_vector) \
diff --git a/cpukit/score/cpu/i386/rtems/score/cpu.h b/cpukit/score/cpu/i386/rtems/score/cpu.h
index d91a9474f1..7e2b086914 100644
--- a/cpukit/score/cpu/i386/rtems/score/cpu.h
+++ b/cpukit/score/cpu/i386/rtems/score/cpu.h
@@ -19,7 +19,9 @@
#ifndef _RTEMS_SCORE_CPU_H
#define _RTEMS_SCORE_CPU_H
+#ifndef ASM
#include <string.h> /* for memcpy */
+#endif
#ifdef __cplusplus
extern "C" {
@@ -96,6 +98,8 @@ extern "C" {
/* structures */
+#ifndef ASM
+
/*
* Basic integer context for the i386 family.
*/
@@ -197,6 +201,8 @@ SCORE_EXTERN Context_Control_fp _CPU_Null_fp_context;
SCORE_EXTERN void *_CPU_Interrupt_stack_low;
SCORE_EXTERN void *_CPU_Interrupt_stack_high;
+#endif /* ASM */
+
/* constants */
/*
@@ -243,13 +249,18 @@ SCORE_EXTERN void *_CPU_Interrupt_stack_high;
/*
* On i386 thread stacks require no further alignment after allocation
- * from the Workspace.
+ * from the Workspace. However, since gcc maintains 16-byte alignment
+ * we try to respect that. If you find an option to let gcc squeeze
+ * the stack more tightly then setting CPU_STACK_ALIGNMENT to 16 still
+ * doesn't waste much space since this only determines the *initial*
+ * alignment.
*/
-#define CPU_STACK_ALIGNMENT 0
+#define CPU_STACK_ALIGNMENT 16
/* macros */
+#ifndef ASM
/*
* ISR handler macros
*
@@ -277,6 +288,8 @@ SCORE_EXTERN void *_CPU_Interrupt_stack_high;
uint32_t _CPU_ISR_Get_level( void );
+#endif /* ASM */
+
/* end of ISR handler macros */
/*
@@ -292,6 +305,37 @@ uint32_t _CPU_ISR_Get_level( void );
#define CPU_EFLAGS_INTERRUPTS_ON 0x00003202
#define CPU_EFLAGS_INTERRUPTS_OFF 0x00003002
+#ifndef ASM
+
+/*
+ * Stack alignment note:
+ *
+ * We want the stack to look to the '_entry_point' routine
+ * like an ordinary stack frame as if '_entry_point' was
+ * called from C-code.
+ * Note that '_entry_point' is jumped-to by the 'ret'
+ * instruction returning from _CPU_Context_switch() or
+ * _CPU_Context_restore() thus popping the _entry_point
+ * from the stack.
+ * However, _entry_point expects a frame to look like this:
+ *
+ * args [_Thread_Handler expects no args, however]
+ * ------ (alignment boundary)
+ * SP-> return_addr return here when _entry_point returns which (never happens)
+ *
+ *
+ * Hence we must initialize the stack as follows
+ *
+ * [arg1 ]: n/a
+ * [arg0 (aligned)]: n/a
+ * [ret. addr ]: NULL
+ * SP-> [jump-target ]: _entry_point
+ *
+ * When Context_switch returns it pops the _entry_point from
+ * the stack which then finds a standard layout.
+ */
+
+
#define _CPU_Context_Initialize( _the_context, _stack_base, _size, \
_isr, _entry_point, _is_fp ) \
do { \
@@ -300,8 +344,9 @@ uint32_t _CPU_ISR_Get_level( void );
if ( (_isr) ) (_the_context)->eflags = CPU_EFLAGS_INTERRUPTS_OFF; \
else (_the_context)->eflags = CPU_EFLAGS_INTERRUPTS_ON; \
\
- _stack = ((uint32_t)(_stack_base)) + (_size) - sizeof(proc_ptr*); \
- \
+ _stack = ((uint32_t)(_stack_base)) + (_size); \
+ _stack &= ~ (CPU_STACK_ALIGNMENT - 1); \
+ _stack -= 2*sizeof(proc_ptr*); /* see above for why we need to do this */ \
*((proc_ptr *)(_stack)) = (_entry_point); \
(_the_context)->ebp = (void *) 0; \
(_the_context)->esp = (void *) _stack; \
@@ -336,6 +381,8 @@ uint32_t _CPU_ISR_Get_level( void );
); \
}
+#endif /* ASM */
+
/* end of Fatal Error manager macros */
/*
@@ -380,6 +427,7 @@ uint32_t _CPU_ISR_Get_level( void );
/* functions */
+#ifndef ASM
/*
* _CPU_Initialize
*
@@ -467,6 +515,8 @@ void _CPU_Context_restore_fp(
Context_Control_fp **fp_context_ptr
);
+#endif /* ASM */
+
#ifdef __cplusplus
}
#endif