diff --git a/arch/arm/src/common/arm_createstack.c b/arch/arm/src/common/arm_createstack.c index 94a5855154..51cc7bde35 100644 --- a/arch/arm/src/common/arm_createstack.c +++ b/arch/arm/src/common/arm_createstack.c @@ -102,26 +102,26 @@ int up_create_stack(FAR struct tcb_s *tcb, size_t stack_size, uint8_t ttype) { - /* Add the size of the TLS information structure */ + size_t alloc_size; - stack_size += sizeof(struct tls_info_s); + /* Add the size of the TLS information structure and align */ + + alloc_size = STACK_ALIGN_UP(stack_size + sizeof(struct tls_info_s)); #ifdef CONFIG_TLS_ALIGNED /* The allocated stack size must not exceed the maximum possible for the * TLS feature. */ - DEBUGASSERT(stack_size <= TLS_MAXSTACK); - if (stack_size >= TLS_MAXSTACK) + DEBUGASSERT(alloc_size <= TLS_MAXSTACK); + if (alloc_size > TLS_MAXSTACK) { - stack_size = TLS_MAXSTACK; + alloc_size = TLS_MAXSTACK; + stack_size = alloc_size - sizeof(struct tls_info_s); } #endif - /* Is there already a stack allocated of a different size? Because of - * alignment issues, stack_size might erroneously appear to be of a - * different size. Fortunately, this is not a critical operation. - */ + /* Is there already a stack allocated of a different size? */ if (tcb->stack_alloc_ptr && tcb->adj_stack_size != stack_size) { @@ -146,7 +146,7 @@ int up_create_stack(FAR struct tcb_s *tcb, size_t stack_size, uint8_t ttype) if (ttype == TCB_FLAG_TTYPE_KERNEL) { tcb->stack_alloc_ptr = - (uint32_t *)kmm_memalign(TLS_STACK_ALIGN, stack_size); + (uint32_t *)kmm_memalign(TLS_STACK_ALIGN, alloc_size); } else #endif @@ -154,7 +154,7 @@ int up_create_stack(FAR struct tcb_s *tcb, size_t stack_size, uint8_t ttype) /* Use the user-space allocator if this is a task or pthread */ tcb->stack_alloc_ptr = - (uint32_t *)kumm_memalign(TLS_STACK_ALIGN, stack_size); + (uint32_t *)kumm_memalign(TLS_STACK_ALIGN, alloc_size); } #else /* CONFIG_TLS_ALIGNED */ @@ -163,14 +163,16 @@ int up_create_stack(FAR struct tcb_s *tcb, size_t stack_size, uint8_t ttype) if (ttype == TCB_FLAG_TTYPE_KERNEL) { - tcb->stack_alloc_ptr = (uint32_t *)kmm_malloc(stack_size); + tcb->stack_alloc_ptr = + (uint32_t *)kmm_memalign(CONFIG_STACK_ALIGNMENT, alloc_size); } else #endif { /* Use the user-space allocator if this is a task or pthread */ - tcb->stack_alloc_ptr = (uint32_t *)kumm_malloc(stack_size); + tcb->stack_alloc_ptr = + (uint32_t *)kumm_memalign(CONFIG_STACK_ALIGNMENT, alloc_size); } #endif /* CONFIG_TLS_ALIGNED */ @@ -188,39 +190,21 @@ int up_create_stack(FAR struct tcb_s *tcb, size_t stack_size, uint8_t ttype) if (tcb->stack_alloc_ptr) { -#if defined(CONFIG_STACK_COLORATION) - uintptr_t stack_base; -#endif - 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. */ - top_of_stack = (uint32_t)tcb->stack_alloc_ptr + stack_size - 4; - - /* The ARM stack must be aligned to 8-byte alignment for EABI. - * If necessary top_of_stack must be rounded down to the next - * boundary + /* Since both stack_alloc_ptr and alloc_size are in + * CONFIG_STACK_ALIGNMENT, and the stack ptr is decremented before + * the first write, we can directly save our variables to struct + * tcb_s. */ - 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. - */ - - size_of_stack = top_of_stack - (uint32_t)tcb->stack_alloc_ptr + 4; - - /* Save the adjusted stack values in the struct tcb_s */ - - tcb->adj_stack_ptr = (uint32_t *)top_of_stack; - tcb->adj_stack_size = size_of_stack; + tcb->adj_stack_size = stack_size; + tcb->adj_stack_ptr = (FAR void *)((uintptr_t)tcb->stack_alloc_ptr + + alloc_size); /* Initialize the TLS data structure */ @@ -232,11 +216,8 @@ int up_create_stack(FAR struct tcb_s *tcb, size_t stack_size, uint8_t ttype) * water marks. */ - stack_base = (uintptr_t)tcb->stack_alloc_ptr + - sizeof(struct tls_info_s); - stack_size = tcb->adj_stack_size - - sizeof(struct tls_info_s); - arm_stack_color((FAR void *)stack_base, stack_size); + arm_stack_color((FAR void *)((uintptr_t)tcb->adj_stack_ptr - + tcb->adj_stack_size), tcb->adj_stack_size); #endif /* CONFIG_STACK_COLORATION */ diff --git a/arch/arm/src/common/arm_usestack.c b/arch/arm/src/common/arm_usestack.c index 593cacfe64..9975578268 100644 --- a/arch/arm/src/common/arm_usestack.c +++ b/arch/arm/src/common/arm_usestack.c @@ -87,9 +87,6 @@ int up_use_stack(struct tcb_s *tcb, void *stack, size_t stack_size) { - size_t top_of_stack; - size_t size_of_stack; - #ifdef CONFIG_TLS_ALIGNED /* Make certain that the user provided stack is properly aligned */ @@ -105,51 +102,54 @@ int up_use_stack(struct tcb_s *tcb, void *stack, size_t stack_size) up_release_stack(tcb, tcb->flags & TCB_FLAG_TTYPE_MASK); } + /* 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. + */ + + /* We align all sizes and pointer to CONFIG_STACK_ALIGNMENT. + * Since the stack ptr is decremented before + * the first write, we can directly save our variables to struct + * tcb_s. + */ + /* Save the new stack allocation */ tcb->stack_alloc_ptr = 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. - */ + /* Align stack top */ - top_of_stack = (uint32_t)tcb->stack_alloc_ptr + stack_size - 4; + tcb->adj_stack_ptr = + (FAR void *)STACK_ALIGN_DOWN((uintptr_t)stack + stack_size); - /* The ARM stack must be aligned to 8-byte alignment for EABI. - * If necessary top_of_stack must be rounded down to the next - * boundary - */ + /* Offset by tls_size */ - top_of_stack = STACK_ALIGN_DOWN(top_of_stack); + stack = (FAR void *)((uintptr_t)stack + sizeof(struct tls_info_s)); - /* 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. - */ + /* Is there enough room for at least TLS ? */ - size_of_stack = top_of_stack - (uint32_t)tcb->stack_alloc_ptr + 4; + if ((uintptr_t)stack <= (uintptr_t)tcb->adj_stack_ptr) + { + tcb->adj_stack_size = (uintptr_t)tcb->adj_stack_ptr - (uintptr_t)stack; - /* Save the adjusted stack values in the struct tcb_s */ + /* Initialize the TLS data structure */ - tcb->adj_stack_ptr = (uint32_t *)top_of_stack; - tcb->adj_stack_size = size_of_stack; + memset(tcb->stack_alloc_ptr, 0, sizeof(struct tls_info_s)); - /* Initialize the TLS data structure */ + #ifdef CONFIG_STACK_COLORATION + /* If stack debug is enabled, then fill the stack with a + * recognizable value that we can use later to test for high + * water marks. + */ - memset(tcb->stack_alloc_ptr, 0, sizeof(struct tls_info_s)); + arm_stack_color((FAR void *)((uintptr_t)tcb->adj_stack_ptr - + tcb->adj_stack_size), tcb->adj_stack_size); -#ifdef CONFIG_STACK_COLORATION - /* If stack debug is enabled, then fill the stack with a recognizable - * value that we can use later to test for high water marks. - */ + #endif /* CONFIG_STACK_COLORATION */ - arm_stack_color((FAR void *)((uintptr_t)tcb->stack_alloc_ptr + - sizeof(struct tls_info_s)), - tcb->adj_stack_size - sizeof(struct tls_info_s)); -#endif + return OK; + } - return OK; + return ERROR; } diff --git a/arch/arm/src/common/arm_vfork.c b/arch/arm/src/common/arm_vfork.c index 61791889a5..7d33d918ab 100644 --- a/arch/arm/src/common/arm_vfork.c +++ b/arch/arm/src/common/arm_vfork.c @@ -126,12 +126,9 @@ pid_t up_vfork(const struct vfork_s *context) sinfo("TCBs: Parent=%p Child=%p\n", parent, child); - /* Get the size of the parent task's stack. Due to alignment operations, - * the adjusted stack size may be smaller than the stack size originally - * requested. - */ + /* Get the size of the parent task's stack. */ - stacksize = parent->adj_stack_size + CONFIG_STACK_ALIGNMENT - 1; + stacksize = parent->adj_stack_size; /* Allocate the stack for the TCB */