diff --git a/arch/arm/src/armv7-a/arm_cpuhead.S b/arch/arm/src/armv7-a/arm_cpuhead.S index 9019f2e140..487fee0a46 100644 --- a/arch/arm/src/armv7-a/arm_cpuhead.S +++ b/arch/arm/src/armv7-a/arm_cpuhead.S @@ -45,6 +45,8 @@ #include "cp15.h" #include "sctlr.h" #include "mmu.h" +#include "smp.h" + #include "chip.h" #include "up_internal.h" @@ -114,7 +116,7 @@ __cpu1_start: b .Lcpu_start .Lcpu1_stackpointer: - .long .Lcpu1_stackbottom + .long .Lcpu1_stacktop .size __cpu1_start, .-__cpu1_start #if CONFIG_SMP_NCPUS > 2 @@ -132,7 +134,7 @@ __cpu2_start: b .Lcpu_start .Lcpu2_stackpointer: - .long .Lcpu2_stackbottom + .long .Lcpu2_stacktop .size __cpu2_start, .-__cpu2_start #if CONFIG_SMP_NCPUS > 3 @@ -150,7 +152,7 @@ __cpu3_start: b .Lcpu_start .Lcpu3_stackpointer: - .long .Lcpu3_stackbottom + .long .Lcpu3_stacktop .size __cpu3_start, .-__cpu3_start #if CONFIG_SMP_NCPUS > 4 @@ -168,7 +170,7 @@ __cpu3_start: * Common CPUn startup logic (n > 0) * * On input: - * SP = Set to bottom of CPU IDLE stack (virtual) + * SP = Set to top of CPU IDLE stack (virtual) * R5 = CPU number * ****************************************************************************/ @@ -395,7 +397,7 @@ __cpu3_start: * absolute addresses; this is not position independent. * * On input: - * SP = Set to bottom of CPU IDLE stack (virtual) + * SP = Set to top of CPU IDLE stack (virtual) * R5 = CPU number * ****************************************************************************/ @@ -438,7 +440,7 @@ __cpu3_start: #ifdef CONFIG_STACK_COLORATION .type .Lstkinit, %object .Lstkinit: - .long ((CONFIG_IDLETHREAD_STACKSIZE + 7) & ~7) >> 2) + .long SMP_STACK_WORDS .long STACK_COLOR /* Stack coloration word */ .size .Lstkinit, . -.Lstkinit #endif @@ -451,30 +453,33 @@ __cpu3_start: #if CONFIG_SMP_NCPUS > 1 .align 8 - .type .Lcpu1_idlestack, object + .globl g_cpu1_idlestack + .type g_cpu1_idlestack, object -.Lcpu1_idlestack: - .space ((CONFIG_SMP_IDLETHREAD_STACKSIZE + 7) & ~7) -.Lcpu1_stackbottom: - .size .Lcpu1_idlestack, .Lcpu1_stackbottom-.Lcpu1_idlestack +g_cpu1_idlestack: + .space SMP_STACK_SIZE +.Lcpu1_stacktop: + .size g_cpu1_idlestack, .Lcpu1_stacktop-g_cpu1_idlestack #if CONFIG_SMP_NCPUS > 2 .align 8 - .type .Lcpu2_idlestack, object + .globl g_cpu2_idlestack + .type g_cpu2_idlestack, object -.Lcpu2_idlestack: - .space ((CONFIG_SMP_IDLETHREAD_STACKSIZE + 7) & ~7) -.Lcpu2_stackbottom: - .size .Lcpu2_idlestack, .Lcpu2_stackbottom-.Lcpu2_idlestack +g_cpu2_idlestack: + .space SMP_STACK_SIZE +.Lcpu2_stacktop: + .size g_cpu2_idlestack, .Lcpu2_stacktop-g_cpu2_idlestack #if CONFIG_SMP_NCPUS > 3 .align 8 - .type .Lcpu3_idlestack, object + .globl g_cpu3_idlestack + .type g_cpu3_idlestack, object -.Lcpu3_idlestack: - .space ((CONFIG_SMP_IDLETHREAD_STACKSIZE + 7) & ~7) -.Lcpu3_stackbottom: - .size .Lcpu3_idlestack, .Lcpu3_stackbottom-.Lcpu3_idlestack +g_cpu3_idlestack: + .space SMP_STACK_SIZE +.Lcpu3_stacktop: + .size g_cpu3_idlestack, .Lcpu3_stacktop-g_cpu3_idlestack #if CONFIG_SMP_NCPUS > 4 # error This logic needs to extended for CONFIG_SMP_NCPUS > 4 diff --git a/arch/arm/src/armv7-a/arm_cpuidlestack.c b/arch/arm/src/armv7-a/arm_cpuidlestack.c new file mode 100644 index 0000000000..fe19123321 --- /dev/null +++ b/arch/arm/src/armv7-a/arm_cpuidlestack.c @@ -0,0 +1,145 @@ +/**************************************************************************** + * arch/arm/src/armv7-a/arm_cpuidlestack.c + * + * Copyright (C) 2016 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include +#include + +#include "smp.h" +#include "up_internal.h" + +#if defined(CONFIG_SMP) && CONFIG_SMP_NCPUS > 1 + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Stack alignment macros */ + +#define STACK_ISALIGNED(a) ((uintptr_t)(a) & ~SMP_STACK_MASK) + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static FAR const uint32_t *g_cpu_stackalloc[CONFIG_SMP_NCPUS] = +{ + 0 + , g_cpu1_idlestack +#if CONFIG_SMP_NCPUS > 2 + , g_cpu2_idlestack +#if CONFIG_SMP_NCPUS > 3 + , g_cpu3_idlestack +#endif /* CONFIG_SMP_NCPUS > 3 */ +#endif /* CONFIG_SMP_NCPUS > 2 */ +}; + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_cpu_idlestack + * + * Description: + * Allocate a stack for the CPU[n] IDLE task (n > 0) if appropriate and + * setup up stack-related information in the IDLE task's TCB. This + * function is always called before up_cpu_start(). This function is + * only called for the CPU's initial IDLE task; up_create_task is used for + * all normal tasks, pthreads, and kernel threads for all CPUs. + * + * The initial IDLE task is a special case because the CPUs can be started + * in different wans in different environments: + * + * 1. The CPU may already have been started and waiting in a low power + * state for up_cpu_start(). In this case, the IDLE thread's stack + * has already been allocated and is already in use. Here + * up_cpu_idlestack() only has to provide information about the + * already allocated stack. + * + * 2. The CPU may be disabled but started when up_cpu_start() is called. + * In this case, a new stack will need to be created for the IDLE + * thread and this function is then equivalent to: + * + * up_create_stack(tcb, stack_size, TCB_FLAG_TTYPE_KERNEL); + * + * The following TCB fields must be initialized by this function: + * + * - adj_stack_size: Stack size after adjustment for hardware, processor, + * etc. This value is retained only for debug purposes. + * - stack_alloc_ptr: Pointer to allocated stack + * - adj_stack_ptr: Adjusted stack_alloc_ptr for HW. The initial value of + * the stack pointer. + * + * Inputs: + * - cpu: CPU index that indicates which CPU the IDLE task is + * being created for. + * - tcb: The TCB of new CPU IDLE task + * - stack_size: The requested stack size for the IDLE task. At least + * this much must be allocated. This should be + * CONFIG_SMP_STACK_SIZE. + * + ****************************************************************************/ + +int up_cpu_idlestack(int cpu, FAR struct tcb_s *tcb, size_t stack_size) +{ + uintptr_t stack_alloc; + uintptr_t top_of_stack; + + DEBUGASSERT(cpu > 0 && cpu < CONFIG_SMP_NCPUS && tcb != NULL && + stack_size <= SMP_STACK_SIZE); + + /* Get the top of the stack */ + + + stack_alloc = (uintptr_t)g_cpu_stackalloc[cpu]; + DEBUGASSERT(stack_alloc != 0 && STACK_ISALIGNED(stack_alloc)); + top_of_stack = stack_alloc + SMP_STACK_TOP; + + tcb->adj_stack_size = SMP_STACK_SIZE; + tcb->stack_alloc_ptr = (FAR uint32_t *)stack_alloc; + tcb->adj_stack_ptr = (FAR uint32_t *)top_of_stack; + + return OK; +} + +#endif /* CONFIG_SMP && CONFIG_SMP_NCPUS > 1 */ diff --git a/arch/arm/src/armv7-a/smp.h b/arch/arm/src/armv7-a/smp.h index 42b3eda0ed..7c9d1cc72a 100644 --- a/arch/arm/src/armv7-a/smp.h +++ b/arch/arm/src/armv7-a/smp.h @@ -45,6 +45,40 @@ #ifdef CONFIG_SMP +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* 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. We will + * always use the EABI stack alignment + */ + +#define SMP_STACK_ALIGNMENT 8 +#define SMP_STACK_MASK 7 +#define SMP_STACK_SIZE ((CONFIG_SMP_IDLETHREAD_STACKSIZE + 7) & ~7) +#define SMP_STACK_WORDS (SMP_STACK_SIZE >> 2) +#define SMP_STACK_TOP (SMP_STACK_SIZE - 8) + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +#if CONFIG_SMP_NCPUS > 1 +extern uint32_t g_cpu1_idlestack[SMP_STACK_WORDS]; +#if CONFIG_SMP_NCPUS > 2 +extern uint32_t g_cpu2_idlestack[SMP_STACK_WORDS]; +#if CONFIG_SMP_NCPUS > 3 +extern uint32_t g_cpu3_idlestack[SMP_STACK_WORDS]; +#if CONFIG_SMP_NCPUS > 4 +# error This logic needs to extended for CONFIG_SMP_NCPUS > 4 +#endif /* CONFIG_SMP_NCPUS > 4 */ +#endif /* CONFIG_SMP_NCPUS > 3 */ +#endif /* CONFIG_SMP_NCPUS > 2 */ +#endif /* CONFIG_SMP_NCPUS > 1 */ + /**************************************************************************** * Public Function Prototypes ****************************************************************************/ @@ -106,5 +140,6 @@ void __cpu3_start(void); void arm_cpu_boot(int cpu); +#endif /* __ASSEMBLY__ */ #endif /* CONFIG_SMP */ #endif /* __ARCH_ARM_SRC_ARMV7_A_SMP_H */ diff --git a/arch/arm/src/imx6/Make.defs b/arch/arm/src/imx6/Make.defs index d4db520910..3f949158e3 100644 --- a/arch/arm/src/imx6/Make.defs +++ b/arch/arm/src/imx6/Make.defs @@ -80,7 +80,7 @@ CMN_CSRCS += arm_schedulesigaction.c arm_sigdeliver.c arm_syscall.c CMN_CSRCS += arm_unblocktask.c arm_undefinedinsn.c ifeq ($(CONFIG_SMP),y) -CMN_CSRCS += arm_cpuindex.c arm_cpustart.c arm_cpupause.c +CMN_CSRCS += arm_cpuindex.c arm_cpustart.c arm_cpupause.c arm_cpuidlestack.c endif ifeq ($(CONFIG_DEBUG_IRQ),y) diff --git a/arch/arm/src/imx6/imx_boot.c b/arch/arm/src/imx6/imx_boot.c index 8e5c56232f..edfd5304a1 100644 --- a/arch/arm/src/imx6/imx_boot.c +++ b/arch/arm/src/imx6/imx_boot.c @@ -309,7 +309,7 @@ static void imx_copyvectorblock(void) #ifndef CONFIG_IMX6_WDT static inline void imx_wdtdisable(void) { -# warning REVISIT WDT initialization + /* REVISIT: WDT initialization */ } #else # define imx_wdtdisable() diff --git a/arch/sim/src/Makefile b/arch/sim/src/Makefile index f4f6270660..406ac4ee93 100644 --- a/arch/sim/src/Makefile +++ b/arch/sim/src/Makefile @@ -70,7 +70,7 @@ ifeq ($(CONFIG_SPINLOCK),y) endif ifeq ($(CONFIG_SMP),y) - CSRCS += up_smpsignal.c up_smphook.c + CSRCS += up_smpsignal.c up_smphook.c up_cpuidlestack.c HOSTSRCS += up_simsmp.c endif diff --git a/arch/sim/src/up_cpuidlestack.c b/arch/sim/src/up_cpuidlestack.c new file mode 100644 index 0000000000..ee728849a9 --- /dev/null +++ b/arch/sim/src/up_cpuidlestack.c @@ -0,0 +1,108 @@ +/**************************************************************************** + * arch/sim/src/up_cpuidlestack.c + * + * Copyright (C) 2016 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include +#include + +#include "up_internal.h" + +#ifdef CONFIG_SMP + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_cpu_idlestack + * + * Description: + * Allocate a stack for the CPU[n] IDLE task (n > 0) if appropriate and + * setup up stack-related information in the IDLE task's TCB. This + * function is always called before up_cpu_start(). This function is + * only called for the CPU's initial IDLE task; up_create_task is used for + * all normal tasks, pthreads, and kernel threads for all CPUs. + * + * The initial IDLE task is a special case because the CPUs can be started + * in different wans in different environments: + * + * 1. The CPU may already have been started and waiting in a low power + * state for up_cpu_start(). In this case, the IDLE thread's stack + * has already been allocated and is already in use. Here + * up_cpu_idlestack() only has to provide information about the + * already allocated stack. + * + * 2. The CPU may be disabled but started when up_cpu_start() is called. + * In this case, a new stack will need to be created for the IDLE + * thread and this function is then equivalent to: + * + * up_create_stack(tcb, stack_size, TCB_FLAG_TTYPE_KERNEL); + * + * The following TCB fields must be initialized by this function: + * + * - adj_stack_size: Stack size after adjustment for hardware, processor, + * etc. This value is retained only for debug purposes. + * - stack_alloc_ptr: Pointer to allocated stack + * - adj_stack_ptr: Adjusted stack_alloc_ptr for HW. The initial value of + * the stack pointer. + * + * Inputs: + * - cpu: CPU index that indicates which CPU the IDLE task is + * being created for. + * - tcb: The TCB of new CPU IDLE task + * - stack_size: The requested stack size for the IDLE task. At least + * this much must be allocated. This should be + * CONFIG_SMP_IDLETHREAD_STACKSIZE. + * + ****************************************************************************/ + +int up_cpu_idlestack(int cpu, FAR struct tcb_s *tcb, size_t stack_size) +{ + /* REVISIT: I don't think anything is needed here */ + + tcb->adj_stack_size = stack_size; + tcb->stack_alloc_ptr = NULL; + tcb->adj_stack_ptr = NULL; + return OK; +} + +#endif /* CONFIG_SMP */ diff --git a/include/nuttx/arch.h b/include/nuttx/arch.h index 02fb699744..b2066b162a 100644 --- a/include/nuttx/arch.h +++ b/include/nuttx/arch.h @@ -1644,7 +1644,7 @@ int up_timer_start(FAR const struct timespec *ts); * * Description: * Return the TLS information structure for the currently executing thread. - * When TLS is enabled, up_createstack() will align allocated stacks to + * When TLS is enabled, up_create_stack() will align allocated stacks to * the TLS_STACK_ALIGN value. An instance of the following structure will * be implicitly positioned at the "lower" end of the stack. Assuming a * "push down" stack, this is at the "far" end of the stack (and can be @@ -1722,6 +1722,51 @@ int up_cpu_index(void); # define up_cpu_index() (0) #endif +/**************************************************************************** + * Name: up_cpu_idlestack + * + * Description: + * Allocate a stack for the CPU[n] IDLE task (n > 0) if appropriate and + * setup up stack-related information in the IDLE task's TCB. This + * function is always called before up_cpu_start(). This function is + * only called for the CPU's initial IDLE task; up_create_task is used for + * all normal tasks, pthreads, and kernel threads for all CPUs. + * + * The initial IDLE task is a special case because the CPUs can be started + * in different wans in different environments: + * + * 1. The CPU may already have been started and waiting in a low power + * state for up_cpu_start(). In this case, the IDLE thread's stack + * has already been allocated and is already in use. Here + * up_cpu_idlestack() only has to provide information about the + * already allocated stack. + * + * 2. The CPU may be disabled but started when up_cpu_start() is called. + * In this case, a new stack will need to be created for the IDLE + * thread and this function is then equivalent to: + * + * up_create_stack(tcb, stack_size, TCB_FLAG_TTYPE_KERNEL); + * + * The following TCB fields must be initialized by this function: + * + * - adj_stack_size: Stack size after adjustment for hardware, processor, + * etc. This value is retained only for debug purposes. + * - stack_alloc_ptr: Pointer to allocated stack + * - adj_stack_ptr: Adjusted stack_alloc_ptr for HW. The initial value of + * the stack pointer. + * + * Inputs: + * - cpu: CPU index that indicates which CPU the IDLE task is + * being created for. + * - tcb: The TCB of new CPU IDLE task + * - stack_size: The requested stack size for the IDLE task. At least + * this much must be allocated. This should be + * CONFIG_SMP_IDLETHREAD_STACKSIZE. + * + ****************************************************************************/ + +int up_cpu_idlestack(int cpu, FAR struct tcb_s *tcb, size_t stack_size); + /**************************************************************************** * Name: up_cpu_start * diff --git a/sched/init/os_smpstart.c b/sched/init/os_smpstart.c index baf91a2e37..c8be9c1cb1 100644 --- a/sched/init/os_smpstart.c +++ b/sched/init/os_smpstart.c @@ -203,8 +203,7 @@ int os_smp_start(void) FAR struct tcb_s *tcb = current_task(cpu); DEBUGASSERT(tcb != NULL); - ret = up_create_stack(tcb, CONFIG_SMP_IDLETHREAD_STACKSIZE, - TCB_FLAG_TTYPE_KERNEL); + ret = up_cpu_idlestack(cpu, tcb, CONFIG_SMP_IDLETHREAD_STACKSIZE); if (ret < 0) { sdbg("ERROR: Failed to allocate stack for CPU%d\n", cpu);