From a6d48e3941123189084882866361ff009de1ee04 Mon Sep 17 00:00:00 2001 From: Till Straumann Date: Thu, 29 Oct 2009 03:15:03 +0000 Subject: 2009-10-28 Till Straumann * 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. --- cpukit/score/cpu/i386/cpu_asm.S | 21 ++++++++---- cpukit/score/cpu/i386/rtems/score/cpu.h | 58 ++++++++++++++++++++++++++++++--- 2 files changed, 69 insertions(+), 10 deletions(-) (limited to 'cpukit/score/cpu/i386') 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 +#include + +#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 /* 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 -- cgit v1.2.3