diff --git a/arch/Kconfig b/arch/Kconfig index d093a7d6986..43c7915d7f3 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -10,6 +10,7 @@ choice config ARCH_ARM bool "ARM" select ARCH_HAVE_INTERRUPTSTACK + select ARCH_HAVE_TLS select ARCH_HAVE_VFORK select ARCH_HAVE_STACKCHECK select ARCH_HAVE_CUSTOMOPT diff --git a/arch/arm/src/common/up_checkstack.c b/arch/arm/src/common/up_checkstack.c index 10127057693..55f89388e3e 100644 --- a/arch/arm/src/common/up_checkstack.c +++ b/arch/arm/src/common/up_checkstack.c @@ -1,7 +1,7 @@ /**************************************************************************** * arch/arm/src/common/up_checkstack.c * - * Copyright (C) 2011, 2013, 2015 Gregory Nutt. All rights reserved. + * Copyright (C) 2011, 2013, 2015-2016 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -42,9 +42,11 @@ #include #include #include +#include #include #include +#include #include #include "sched/sched.h" @@ -82,11 +84,20 @@ static size_t do_stackcheck(uintptr_t alloc, size_t size) FAR uint32_t *ptr; size_t mark; - /* Get aligned addresses and adjusted sizes */ + /* Get aligned addresses of the top and bottom of the stack */ +#ifdef CONFIG_TLS + /* Skip over the TLS data structure at the bottom of the stack */ - start = alloc & ~3; - end = (alloc + size + 3) & ~3; - size = end - start; + DEBUGASSERT((alloc & TLS_STACK_MASK) == 0); + start = alloc + sizeof(struct tls_info_s); +#else + start = alloc & ~3; +#endif + end = (alloc + size + 3) & ~3; + + /* Get the adjusted size based on the top and bottom of the stack */ + + size = end - start; /* The ARM uses a push-down stack: the stack grows toward lower addresses * in memory. We need to start at the lowest address in the stack memory diff --git a/arch/arm/src/common/up_createstack.c b/arch/arm/src/common/up_createstack.c index 5d03ee4556e..90a3d3c4f87 100644 --- a/arch/arm/src/common/up_createstack.c +++ b/arch/arm/src/common/up_createstack.c @@ -1,7 +1,7 @@ /**************************************************************************** * arch/arm/src/common/up_createstack.c * - * Copyright (C) 2007-2014 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2014, 2016 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -41,11 +41,14 @@ #include #include +#include #include +#include #include #include #include +#include #include #include @@ -86,14 +89,6 @@ #define STACK_ALIGN_DOWN(a) ((a) & ~STACK_ALIGN_MASK) #define STACK_ALIGN_UP(a) (((a) + STACK_ALIGN_MASK) & ~STACK_ALIGN_MASK) -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - /**************************************************************************** * Public Functions ****************************************************************************/ @@ -138,6 +133,22 @@ int up_create_stack(FAR struct tcb_s *tcb, size_t stack_size, uint8_t ttype) { +#ifdef CONFIG_TLS + /* Add the size of the TLS information structure */ + + stack_size += sizeof(struct tls_info_s); + + /* The allocated stack size must not exceed the maximum possible for the + * TLS feature. + */ + + DEBUGASSERT(stack_size <= TLS_MAXSTACK); + if (stack_size >= TLS_MAXSTACK) + { + stack_size = TLS_MAXSTACK; + } +#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. @@ -156,8 +167,28 @@ int up_create_stack(FAR struct tcb_s *tcb, size_t stack_size, uint8_t ttype) { /* Allocate the stack. If DEBUG is enabled (but not stack debug), * then create a zeroed stack to make stack dumps easier to trace. + * If TLS is enabled, then we must allocate aligned stacks. */ +#ifdef CONFIG_TLS +#ifdef HAVE_KERNEL_HEAP + /* Use the kernel allocator if this is a kernel thread */ + + if (ttype == TCB_FLAG_TTYPE_KERNEL) + { + tcb->stack_alloc_ptr = + (uint32_t *)kmm_memalign(TLS_STACK_ALIGN, stack_size); + } + else +#endif + { + /* 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); + } + +#else /* CONFIG_TLS */ #ifdef HAVE_KERNEL_HEAP /* Use the kernel allocator if this is a kernel thread */ @@ -172,6 +203,7 @@ int up_create_stack(FAR struct tcb_s *tcb, size_t stack_size, uint8_t ttype) tcb->stack_alloc_ptr = (uint32_t *)kumm_malloc(stack_size); } +#endif /* CONFIG_TLS */ #ifdef CONFIG_DEBUG /* Was the allocation successful? */ @@ -187,6 +219,12 @@ int up_create_stack(FAR struct tcb_s *tcb, size_t stack_size, uint8_t ttype) if (tcb->stack_alloc_ptr) { +#ifdef CONFIG_TLS + FAR struct tls_info_s *info; +#ifdef CONFIG_STACK_COLORATION + uinptr_t stack_base; +#endif +#endif size_t top_of_stack; size_t size_of_stack; @@ -218,14 +256,35 @@ int up_create_stack(FAR struct tcb_s *tcb, size_t stack_size, uint8_t ttype) tcb->adj_stack_ptr = (uint32_t *)top_of_stack; tcb->adj_stack_size = size_of_stack; +#ifdef CONFIG_TLS + /* Initialize the TLS data structure */ + + info = (FAR struct tls_info_s *)tcb->stack_alloc_ptr; + memset(info, 0, sizeof(struct tls_info_s)); + info->tl_tcb = tcb; + +#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. */ + stackbase = (uintptr_t)info + sizeof(struct tls_info_s); + stack_size = tcb->adj_stack_size - sizeof(struct tls_info_s); + up_stack_color((FAR void *)stack_base, stack_size); + +#endif /* CONFIG_STACK_COLORATION */ +#else /* CONFIG_TLS */ #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. + */ + up_stack_color(tcb->stack_alloc_ptr, tcb->adj_stack_size); -#endif + +#endif /* CONFIG_STACK_COLORATION */ +#endif /* CONFIG_TLS */ board_autoled_on(LED_STACKCREATED); return OK; diff --git a/arch/arm/src/common/up_usestack.c b/arch/arm/src/common/up_usestack.c index 74bfecca354..cb6dd6adbff 100644 --- a/arch/arm/src/common/up_usestack.c +++ b/arch/arm/src/common/up_usestack.c @@ -1,7 +1,7 @@ /**************************************************************************** * arch/arm/src/common/up_usestack.c * - * Copyright (C) 2007-2009, 2013 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2009, 2013, 2016 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -41,11 +41,14 @@ #include #include +#include #include +#include #include #include #include +#include #include "up_internal.h" @@ -76,14 +79,6 @@ #define STACK_ALIGN_DOWN(a) ((a) & ~STACK_ALIGN_MASK) #define STACK_ALIGN_UP(a) (((a) + STACK_ALIGN_MASK) & ~STACK_ALIGN_MASK) -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - /**************************************************************************** * Public Functions ****************************************************************************/ @@ -118,9 +113,18 @@ int up_use_stack(struct tcb_s *tcb, void *stack, size_t stack_size) { +#ifdef CONFIG_TLS + FAR struct tls_info_s *info; +#endif size_t top_of_stack; size_t size_of_stack; +#ifdef CONFIG_TLS + /* Make certain that the user provided stack is properly aligned */ + + DEBUGASSERT(((uintptr_t)stack & TLS_STACK_MASK) == 0); +#endif + /* Is there already a stack allocated? */ if (tcb->stack_alloc_ptr) @@ -162,5 +166,21 @@ int up_use_stack(struct tcb_s *tcb, void *stack, size_t stack_size) tcb->adj_stack_ptr = (uint32_t *)top_of_stack; tcb->adj_stack_size = size_of_stack; +#ifdef CONFIG_TLS + /* Initialize the TLS data structure */ + + info = (FAR struct tls_info_s *)tcb->stack_alloc_ptr; + memset(info, 0, sizeof(struct tls_info_s)); + info->tl_tcb = tcb; +#endif + +#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. + */ + +# warning Missing logic +#endif + return OK; }