diff --git a/ChangeLog b/ChangeLog index b752b8ec347..2f83184f639 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2194,4 +2194,7 @@ support a file system (such as NXFFS). (Contributed by Hal Glenn). * include/nuttx/rgbcolors.h: More fixes to RGB color conversion macros. + * arch/arm/src/common/up_createstack.c and up_usestack.c: For ARM EABI + the stack must be aligned to 8-byte boundaries. This is necessary for + passing aligned floating point values under EABI. diff --git a/Documentation/NuttxPortingGuide.html b/Documentation/NuttxPortingGuide.html index 7d190a14620..f4c699541f2 100644 --- a/Documentation/NuttxPortingGuide.html +++ b/Documentation/NuttxPortingGuide.html @@ -5114,7 +5114,12 @@ build some functions into RAM, either for better performance or for errata workarounds.
  • - CONFIG_STACK_POINTER: The initial stack pointer + CONFIG_STACK_POINTER: The initial stack pointer (may not be supported + in all architectures). +
  • +
  • + CONFIG_STACK_ALIGNMENT: Set if the your application has specific + stack alignment requirements (may not be supported in all architectures).
  • CONFIG_IDLETHREAD_STACKSIZE: The size of the initial stack. diff --git a/arch/arm/src/common/up_createstack.c b/arch/arm/src/common/up_createstack.c index 0d78d9ce9d9..068924b4b60 100644 --- a/arch/arm/src/common/up_createstack.c +++ b/arch/arm/src/common/up_createstack.c @@ -51,6 +51,33 @@ #include "up_arch.h" #include "up_internal.h" +/**************************************************************************** + * Pre-processor Macros + ****************************************************************************/ + +/* ARM requires at least a 4-byte stack alignment. For use with EABI and + * floating point, the stack must be aligned to 8-byte addresses. + */ + +#ifndef CONFIG_STACK_ALIGNMENT + +/* The symbol __ARM_EABI__ is defined by GCC if EABI is being used. If you + * are not using GCC, make sure that CONFIG_STACK_ALIGNMENT is set correctly! + */ + +# ifdef __ARM_EABI__ +# define CONFIG_STACK_ALIGNMENT 8 +# else +# define CONFIG_STACK_ALIGNMENT 4 +# endif +#endif + +/* Stack alignment macros */ + +#define STACK_ALIGN_MASK (CONFIG_STACK_ALIGNMENT-1) +#define STACK_ALIGN_DOWN(a) ((a) & ~STACK_ALIGN_MASK) +#define STACK_ALIGN_UP(a) (((a) + STACK_ALIGN_MASK) & ~STACK_ALIGN_MASK) + /**************************************************************************** * Private Types ****************************************************************************/ @@ -110,54 +137,60 @@ int up_create_stack(_TCB *tcb, size_t stack_size) tcb->stack_alloc_ptr = NULL; } - if (!tcb->stack_alloc_ptr) - { + if (!tcb->stack_alloc_ptr) + { #ifdef CONFIG_DEBUG - tcb->stack_alloc_ptr = (uint32_t*)kzalloc(stack_size); + tcb->stack_alloc_ptr = (uint32_t*)kzalloc(stack_size); #else - tcb->stack_alloc_ptr = (uint32_t*)kmalloc(stack_size); + tcb->stack_alloc_ptr = (uint32_t*)kmalloc(stack_size); #endif - } + } - if (tcb->stack_alloc_ptr) - { - size_t top_of_stack; - size_t size_of_stack; + if (tcb->stack_alloc_ptr) + { + size_t top_of_stack; + size_t size_of_stack; - /* The ARM uses a push-down stack: the stack grows - * toward loweraddresses in memory. The stack pointer - * register, points to the lowest, valid work address - * (the "top" of the stack). Items on the stack are - * referenced as positive word offsets from sp. - */ + /* The ARM uses a push-down stack: the stack grows toward lower + * addresses in memory. The stack pointer register, points to + * the lowest, valid work address (the "top" of the stack). Items + * on the stack are referenced as positive word offsets from sp. + */ - top_of_stack = (uint32_t)tcb->stack_alloc_ptr + stack_size - 4; + top_of_stack = (uint32_t)tcb->stack_alloc_ptr + stack_size - 4; - /* The ARM stack must be aligned at word (4 byte) - * boundaries. If necessary top_of_stack must be rounded - * down to the next boundary - */ + /* The ARM stack must be aligned; 4 byte alignment for OABI and + * 8-byte alignment for EABI. If necessary top_of_stack must be + * rounded down to the next boundary + */ - top_of_stack &= ~3; - size_of_stack = top_of_stack - (uint32_t)tcb->stack_alloc_ptr + 4; + top_of_stack = STACK_ALIGN_DOWN(top_of_stack); - /* Save the adjusted stack values in the _TCB */ + /* The size of the stack in bytes is then the difference between + * the top and the bottom of the stack (+4 because if the top + * is the same as the bottom, then the size is one 32-bit element). + * The size need not be aligned. + */ - tcb->adj_stack_ptr = (uint32_t*)top_of_stack; - tcb->adj_stack_size = size_of_stack; + size_of_stack = top_of_stack - (uint32_t)tcb->stack_alloc_ptr + 4; - /* If stack debug is enabled, then fill the stack with a - * recognizable value that we can use later to test for high - * water marks. - */ + /* Save the adjusted stack values in the _TCB */ + + tcb->adj_stack_ptr = (uint32_t*)top_of_stack; + tcb->adj_stack_size = size_of_stack; + + /* If stack debug is enabled, then fill the stack with a + * recognizable value that we can use later to test for high + * water marks. + */ #if defined(CONFIG_DEBUG) && defined(CONFIG_DEBUG_STACK) - memset32(tcb->stack_alloc_ptr, 0xDEADBEEF, tcb->adj_stack_size/4); + memset32(tcb->stack_alloc_ptr, 0xDEADBEEF, tcb->adj_stack_size/4); #endif - up_ledon(LED_STACKCREATED); - return OK; - } + up_ledon(LED_STACKCREATED); + return OK; + } return ERROR; } diff --git a/arch/arm/src/common/up_usestack.c b/arch/arm/src/common/up_usestack.c index 822f051689f..f46be0cc900 100644 --- a/arch/arm/src/common/up_usestack.c +++ b/arch/arm/src/common/up_usestack.c @@ -49,6 +49,33 @@ #include "up_internal.h" +/**************************************************************************** + * Pre-processor Macros + ****************************************************************************/ + +/* ARM requires at least a 4-byte stack alignment. For use with EABI and + * floating point, the stack must be aligned to 8-byte addresses. + */ + +#ifndef CONFIG_STACK_ALIGNMENT + +/* The symbol __ARM_EABI__ is defined by GCC if EABI is being used. If you + * are not using GCC, make sure that CONFIG_STACK_ALIGNMENT is set correctly! + */ + +# ifdef __ARM_EABI__ +# define CONFIG_STACK_ALIGNMENT 8 +# else +# define CONFIG_STACK_ALIGNMENT 4 +# endif +#endif + +/* Stack alignment macros */ + +#define STACK_ALIGN_MASK (CONFIG_STACK_ALIGNMENT-1) +#define STACK_ALIGN_DOWN(a) ((a) & ~STACK_ALIGN_MASK) +#define STACK_ALIGN_UP(a) (((a) + STACK_ALIGN_MASK) & ~STACK_ALIGN_MASK) + /**************************************************************************** * Private Types ****************************************************************************/ @@ -96,21 +123,27 @@ int up_use_stack(_TCB *tcb, void *stack, size_t stack_size) tcb->stack_alloc_ptr = stack; - /* The ARM uses a push-down stack: the stack grows - * toward loweraddresses in memory. The stack pointer - * register, points to the lowest, valid work address - * (the "top" of the stack). Items on the stack are + /* The ARM uses a push-down stack: the stack grows toward lower addresses + * in memory. The stack pointer register, points to the lowest, valid + * work address (the "top" of the stack). Items on the stack are * referenced as positive word offsets from sp. */ top_of_stack = (uint32_t)tcb->stack_alloc_ptr + stack_size - 4; - /* The ARM stack must be aligned at word (4 byte) - * boundaries. If necessary top_of_stack must be rounded - * down to the next boundary + /* The ARM stack must be aligned; 4 byte alignment for OABI and 8-byte + * alignment for EABI. If necessary top_of_stack must be rounded down + * to the next boundary + */ + + top_of_stack = STACK_ALIGN_DOWN(top_of_stack); + + /* The size of the stack in bytes is then the difference between + * the top and the bottom of the stack (+4 because if the top + * is the same as the bottom, then the size is one 32-bit element). + * The size need not be aligned. */ - top_of_stack &= ~3; size_of_stack = top_of_stack - (uint32_t)tcb->stack_alloc_ptr + 4; /* Save the adjusted stack values in the _TCB */ diff --git a/configs/README.txt b/configs/README.txt index f19fa28eea5..46b41d1aba7 100644 --- a/configs/README.txt +++ b/configs/README.txt @@ -1148,7 +1148,11 @@ defconfig -- This is a configuration file similar to the Linux but copy themselves entirely into RAM for better performance. CONFIG_BOOT_RAMFUNCS - Other configurations may copy just some functions into RAM, either for better performance or for errata workarounds. - CONFIG_STACK_POINTER - The initial stack pointer + CONFIG_STACK_POINTER - The initial stack pointer (may not be supported + in all architectures). + CONFIG_STACK_ALIGNMENT - Set if the your application has specific + stack alignment requirements (may not be supported + in all architectures). CONFIG_IDLETHREAD_STACKSIZE - The size of the initial stack. This is the thread that (1) performs the inital boot of the system up to the point where user_start() is spawned, and (2) there after is the