diff --git a/ChangeLog b/ChangeLog index b752b8ec3477027191de97c145d9b9d363d185ed..2f83184f6396bd4d70d7507e92ffefe7ca8d2c4d 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 7d190a1462044be3bec37a527afc52bc85f48956..f4c699541f2cc661a5a35f5b6c5e11b34ebbff71 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. </li> <li> - <code>CONFIG_STACK_POINTER</code>: The initial stack pointer + <code>CONFIG_STACK_POINTER</code>: The initial stack pointer (may not be supported + in all architectures). + </li> + <li> + <code>CONFIG_STACK_ALIGNMENT</code>: Set if the your application has specific + stack alignment requirements (may not be supported in all architectures). </li> <li> <code>CONFIG_IDLETHREAD_STACKSIZE</code>: 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 0d78d9ce9d9f8e99a5925a9ce0c96281ebecb394..068924b4b602b217266f8919797c9f6c3f5226d3 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 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. + */ - /* 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. - */ + 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; 4 byte alignment for OABI and + * 8-byte alignment for EABI. If necessary top_of_stack must be + * rounded down to the next boundary + */ - /* The ARM stack must be aligned at word (4 byte) - * boundaries. If necessary top_of_stack must be rounded - * down to the next boundary - */ + top_of_stack = STACK_ALIGN_DOWN(top_of_stack); - top_of_stack &= ~3; - size_of_stack = top_of_stack - (uint32_t)tcb->stack_alloc_ptr + 4; + /* 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. + */ - /* Save the adjusted stack values in the _TCB */ + size_of_stack = top_of_stack - (uint32_t)tcb->stack_alloc_ptr + 4; - tcb->adj_stack_ptr = (uint32_t*)top_of_stack; - tcb->adj_stack_size = size_of_stack; + /* Save the adjusted stack values in the _TCB */ - /* If stack debug is enabled, then fill the stack with a - * recognizable value that we can use later to test for high - * water marks. - */ + 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 822f051689f819a09b3c4be9a68c0bf28a39d00d..f46be0cc9007a03e5c4eec72fb3e8582ba2e3638 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 f19fa28eea56ce4e89466ac7e82bf222fb070036..46b41d1aba72d38ce524f2f742c43de73a95daed 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