This is an automated email from the ASF dual-hosted git repository.

xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git


The following commit(s) were added to refs/heads/master by this push:
     new eb0e05be0d arch/armv7-r: add armv7-r smp support
eb0e05be0d is described below

commit eb0e05be0db6386c806200f88e2840996edfe225
Author: zhangyuan21 <zhangyua...@xiaomi.com>
AuthorDate: Thu Mar 2 22:54:29 2023 +0800

    arch/armv7-r: add armv7-r smp support
    
    Signed-off-by: zhangyuan21 <zhangyua...@xiaomi.com>
---
 arch/arm/src/armv7-r/Make.defs                     |   6 +
 arch/arm/src/armv7-r/{arm_head.S => arm_cpuhead.S} | 451 ++++++++++-----------
 arch/arm/src/armv7-r/arm_cpuidlestack.c            | 132 ++++++
 .../arm/src/armv7-r/{barriers.h => arm_cpuindex.c} |  57 ++-
 arch/arm/src/armv7-r/arm_cpupause.c                | 326 +++++++++++++++
 arch/arm/src/armv7-r/arm_cpustart.c                | 136 +++++++
 arch/arm/src/armv7-r/arm_head.S                    |  51 ++-
 arch/arm/src/armv7-r/arm_schedulesigaction.c       | 220 ++++++++++
 arch/arm/src/armv7-r/arm_scu.c                     | 123 ++++++
 arch/arm/src/armv7-r/arm_sigdeliver.c              |  44 ++
 arch/arm/src/armv7-r/arm_vectors.S                 |  44 +-
 arch/arm/src/armv7-r/barriers.h                    |   6 +-
 arch/arm/src/armv7-r/sctlr.h                       |  32 +-
 arch/arm/src/armv7-r/scu.h                         | 252 ++++++++++++
 arch/arm/src/armv7-r/smp.h                         | 128 ++++++
 15 files changed, 1744 insertions(+), 264 deletions(-)

diff --git a/arch/arm/src/armv7-r/Make.defs b/arch/arm/src/armv7-r/Make.defs
index 7cb439f27b..c246414600 100644
--- a/arch/arm/src/armv7-r/Make.defs
+++ b/arch/arm/src/armv7-r/Make.defs
@@ -56,3 +56,9 @@ ifeq ($(CONFIG_ARCH_FPU),y)
   CMN_CSRCS += arm_fpucmp.c
   CMN_ASRCS += arm_fpuconfig.S
 endif
+
+ifeq ($(CONFIG_SMP),y)
+  CMN_ASRCS += arm_cpuhead.S
+  CMN_CSRCS += arm_cpuindex.c arm_cpustart.c arm_cpupause.c
+  CMN_CSRCS += arm_cpuidlestack.c arm_scu.c
+endif
diff --git a/arch/arm/src/armv7-r/arm_head.S 
b/arch/arm/src/armv7-r/arm_cpuhead.S
similarity index 53%
copy from arch/arm/src/armv7-r/arm_head.S
copy to arch/arm/src/armv7-r/arm_cpuhead.S
index d6433910e9..338506c68b 100644
--- a/arch/arm/src/armv7-r/arm_head.S
+++ b/arch/arm/src/armv7-r/arm_cpuhead.S
@@ -1,5 +1,5 @@
 /****************************************************************************
- * arch/arm/src/armv7-r/arm_head.S
+ * arch/arm/src/armv7-r/arm_cpuhead.S
  *
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -24,12 +24,18 @@
 
 #include <nuttx/config.h>
 
+#include <arch/irq.h>
+
 #include "arm.h"
 #include "cp15.h"
 #include "sctlr.h"
+#include "smp.h"
+#include "chip.h"
 #include "arm_internal.h"
 
-       .file   "arm_head.S"
+#ifdef CONFIG_SMP
+
+       .file   "arm_cpuhead.S"
 
 /****************************************************************************
  * Configuration
@@ -75,63 +81,130 @@
  * not require initialization (such as internal SRAM)
  */
 
-#ifndef IDLE_STACK_BASE
-#  define IDLE_STACK_BASE _ebss
-#endif
+/****************************************************************************
+ * .text
+ ****************************************************************************/
 
-#define IDLE_STACK_TOP  IDLE_STACK_BASE+CONFIG_IDLETHREAD_STACKSIZE
+       .text
+       .syntax unified
+       .arm
 
 /****************************************************************************
- * Global Symbols
+ * Name: __cpu[n]_start
+ *
+ * Description:
+ *   Boot functions for each CPU (other than CPU0).  These functions set up
+ *   the ARM operating mode, the initial stack, and configure co-processor
+ *   registers.  At the end of the boot, arm_cpu_boot() is called.
+ *
+ *   These functions are provided by the common ARMv7-R logic.
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   Do not return.
+ *
  ****************************************************************************/
 
-/* Imported symbols */
+#if CONFIG_SMP_NCPUS > 1
+       .global __cpu1_start
+       .type   __cpu1_start, #function
 
-       .global arm_boot                        /* Branch to continue 
initialization in C */
+__cpu1_start:
+       /* Make sure that we are in SYS mode with IRQs and FIQs disabled */
 
-       .global _sbss                           /* Start of .bss in RAM */
-       .global _ebss                           /* End+1 of .bss in RAM */
-#ifdef CONFIG_BOOT_RUNFROMFLASH
-       .global _eronly                         /* Where .data defaults are 
stored in FLASH */
-       .global _sdata                          /* Where .data needs to reside 
in SDRAM */
-       .global _edata
-#endif
-#ifdef CONFIG_ARCH_RAMFUNCS
-       .global _framfuncs                      /* Where RAM functions are 
stored in FLASH */
-       .global _sramfuncs                      /* Where RAM functions needs to 
reside in RAM */
-       .global _eramfuncs
-#endif
+       cpsid           if, #PSR_MODE_SYS
 
-/* Exported symbols */
+       /* Set up the stack pointer and the CPU index */
 
-       .global __start                         /* Power-up/Reset entry point */
-       .global arm_data_initialize     /* Perform C data initialization */
-       .global g_idle_topstack         /* Top of the initial/IDLE stack */
+       ldr             sp, .Lcpu1_stackpointer
+       sub             sp, sp, #XCPTCONTEXT_SIZE
+       mov             r5, #1
 
-/****************************************************************************
- * Name: __start
- ****************************************************************************/
+       /* Then branch to the common startup logic (PC-relative) */
 
-/* We assume the bootloader has already initialized most of the h/w for
- * us and that only leaves us having to do some os specific things
- * below.
- */
+       b               .Lcpu_start
 
-       .text
-       .syntax unified
-       .arm
-       .global __start
-       .type   __start, #function
+.Lcpu1_stackpointer:
+       .long   .Lcpu1_stacktop
+       .size   __cpu1_start, .-__cpu1_start
+
+#if CONFIG_SMP_NCPUS > 2
+       .global __cpu2_start
+       .type   __cpu2_start, #function
+
+__cpu2_start:
+       /* Make sure that we are in SYS mode with IRQs and FIQs disabled */
+
+       cpsid           if, #PSR_MODE_SYS
+
+       /* Set up the stack pointer and the CPU index */
+
+       ldr             sp, .Lcpu2_stackpointer
+       sub             sp, sp, #XCPTCONTEXT_SIZE
+       mov             r5, #2
+
+       /* Then branch to the common startup logic (PC-relative) */
+
+       b               .Lcpu_start
+
+.Lcpu2_stackpointer:
+       .long   .Lcpu2_stacktop
+       .size   __cpu2_start, .-__cpu2_start
+
+#if CONFIG_SMP_NCPUS > 3
+       .global __cpu3_start
+       .type   __cpu3_start, #function
 
-__start:
+__cpu3_start:
        /* Make sure that we are in SYS mode with IRQs and FIQs disabled */
 
        cpsid           if, #PSR_MODE_SYS
 
-       /* Set up the stack pointer and clear the frame pointer. */
+       /* Set up the stack pointer and the CPU index */
 
-       ldr             sp, .Lstackpointer
-       mov             fp, #0
+       ldr             sp, .Lcpu3_stackpointer
+       sub             sp, sp, #XCPTCONTEXT_SIZE
+       mov             r5, #3
+
+       /* Then branch to the common startup logic (PC-relative) */
+
+       b               .Lcpu_start
+
+.Lcpu3_stackpointer:
+       .long   .Lcpu3_stacktop
+       .size   __cpu3_start, .-__cpu3_start
+
+#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 */
+
+/****************************************************************************
+ * Name: .Lcpu_start
+ *
+ * Description:
+ *   Common CPUn startup logic (n > 0)
+ *
+ * On input:
+ *   SP = Set to top of CPU IDLE stack
+ *   R5 = CPU number
+ *
+ ****************************************************************************/
+
+       .type   .Lcpu_start, #function
+
+.Lcpu_start:
+       /* The MPU and caches should be disabled */
+
+       mrc             CP15_SCTLR(r0)
+       bic             r0, r0, #(SCTLR_M | SCTLR_C)
+       bic             r0, r0, #(SCTLR_I)
+       mcr             CP15_SCTLR(r0)
 
        /* Invalidate caches and TLBs.
         *
@@ -152,9 +225,13 @@ __start:
        mcr             CP15_DCIALLU(r0)        /* Invalidate D-cache */
        isb
 
+       /* Set lr = Resume at .Lcpu_vstart with the MMU enabled */
+
+       ldr             lr, .LCcpu_vstart               /* Abs. address */
+
        /* Configure the system control register (see sctrl.h) */
 
-       mrc             CP15_SCTLR(r0)          /* Get control register */
+       mrc             CP15_SCTLR(r0)                  /* Get control register 
*/
 
        /* Clear bits to reset values.  This is only necessary in situations 
like, for
         * example, we get here via a bootloader and the control register is in 
some
@@ -182,12 +259,17 @@ __start:
         *   SCTLR_TE       Bit 30: All exceptions handled in ARM state.
         */
 
-       /* Clear all configurable bits */
-
-       bic             r0, r0, #(SCTLR_M  | SCTLR_A  | SCTLR_C    | 
SCTLR_CCP15BEN | SCTLR_B)
-       bic             r0, r0, #(SCTLR_SW | SCTLR_I  | SCTLR_V    | SCTLR_RR)
+       bic             r0, r0, #(SCTLR_A  | SCTLR_C  | SCTLR_CCP15BEN | 
SCTLR_B)
+       bic             r0, r0, #(SCTLR_SW | SCTLR_I  | SCTLR_V        | 
SCTLR_RR)
        bic             r0, r0, #(SCTLR_BR | SCTLR_DZ | SCTLR_FI)
-       bic             r0, r0, #(SCTLR_VE | SCTLR_EE | SCTLR_NMFI | SCTLR_TE)
+       bic             r0, r0, #(SCTLR_VE | SCTLR_EE | SCTLR_NMFI     | 
SCTLR_TE)
+
+       /* Set bits to enable the MPU
+        *
+        *   SCTLR_M     Bit 0:  Enable the MPU
+        */
+
+       orr             r0, r0, #(SCTLR_M)
 
        /* Set configured bits */
 
@@ -200,15 +282,6 @@ __start:
        orr             r0, r0, #(SCTLR_A)
 #endif
 
-#ifndef CONFIG_ARMV7R_DCACHE_DISABLE
-       /* Dcache enable
-        *
-        *   SCTLR_C    Bit 2:  DCache enable
-        */
-
-       orr             r0, r0, #(SCTLR_C)
-#endif
-
 #ifdef CONFIG_ARMV7R_SCTLR_CCP15BEN
        /* Enable memory barriers
         *
@@ -218,15 +291,6 @@ __start:
        orr             r0, r0, #(SCTLR_CCP15BEN)
 #endif
 
-#ifndef CONFIG_ARMV7R_ICACHE_DISABLE
-       /* Icache enable
-        *
-        *   SCTLR_I    Bit 12: ICache enable
-        */
-
-       orr             r0, r0, #(SCTLR_I)
-#endif
-
 #ifndef CONFIG_ARCH_LOWVECTORS
        /* Position vectors to 0xffff0000 if so configured.
         *
@@ -307,193 +371,124 @@ __start:
        nop
        .endr
 
-#if 0
-       /* Cortex-R/RF Errata Work-Around
-        *
-        * Errata 754269: Register corruption during a load-multiple instruction
-        *                at an exception vector.
-        * Workaround:    To workaround this erratum, set bit [7] of the
-        *                Auxiliary Control Register to disable out-of-order
-        *                completion for divide instructions. Code performance
-        *                may be reduced depending on how often divide
-        *                operations are used.
-        * NOTE:          The ARMv7-A/R Architecture reference many lists the 
bits
-        *                bits of the ACTLR as "implementation defined"
-        *
-        * REVISIT: I do not think this is needed because the NuttX vectors do 
not
-        * begin with an LDM instruction.
-        */
+       /* And "jump" to .Lcpu_vstart in the newly mapped virtual address space 
*/
 
-       mrc             CP15_ACTLR(r0)                  /* Read Auxiliary 
Control register */
-       orr             r0, r0, #(1 << 7)               /* Disable out-of-order 
completion */
-       mcr             CP15_ACTLR(r0)                  /* Write Auxiliary 
Control register */
-#endif
-
-#ifndef CONFIG_ARMV7R_MEMINIT
-       /* Initialize .bss and .data ONLY if .bss and .data lie in RAM that is
-        * ready to use.  Other memory, such as SDRAM, must be initialized 
before
-        * it can be used.  arm_boot() will perform that memory initialization 
and
-        * .bss and .data can be initialized by arm_boot() by calling this
-        * arm_data_initialize() later.
-        */
+       mov             pc, lr
 
-       bl              arm_data_initialize
-#endif
-
-       /* Perform early C-level, platform-specific initialization.  Logic
-        * within arm_boot() must configure SDRAM and call arm_data_initialize()
-        * if CONFIG_ARMV7R_MEMINIT=y.
-        *
-        * This function does not return.  It must give control to nx_start()
-        * at the completion of its initialization.
-        *
-        * Why not just call arm_boot() and branch to nx_start() when it 
returns?
-        * If the stack pointer initialized above lies in SDRAM, then that may
-        * not be possible.  Also, in the special case of the TMS570, it may
-        * perform a destructive test, losing the pushed content of the stack.
-        */
-
-       b               arm_boot
-
-       /* .text Data */
-
-.Lstackpointer:
-       .long   IDLE_STACK_TOP
-       .size   __start, .-__start
+/****************************************************************************
+ * PC_Relative Data
+ ****************************************************************************/
 
-/***************************************************************************
- * Name: arm_data_initialize
- ***************************************************************************/
+       /* The start address of the second phase boot logic */
 
-       .global arm_data_initialize
-       .type   arm_data_initialize, #function
+       .type   .LCcpu_vstart, %object
+.LCcpu_vstart:
+       .long   .Lcpu_vstart
+       .size   .LCcpu_vstart, . -.LCcpu_vstart
 
-arm_data_initialize:
+       .size   .Lcpu_start, .-.Lcpu_start
 
-       /* Zero BSS */
+/****************************************************************************
+ * Name: .Lcpu_vstart
+ *
+ * Description:
+ *   Continue initialization after the MPU has been enabled.
+ *
+ *   The following is executed after the MPU has been enabled. This uses
+ *   absolute addresses; this is not position independent.
+ *
+ * On input:
+ *   SP = Set to top of CPU IDLE stack
+ *   R5 = CPU number
+ *
+ ****************************************************************************/
 
-       adr             r0, .Linitparms
-       ldmia           r0, {r0, r1}
+       .align  8
+       .globl  arm_cpu_boot
+       .type   .Lcpu_vstart, %function
 
-       mov             r2, #0
-1:
-       cmp             r0, r1                          /* Clear up to 
_bss_end_ */
-       strcc           r2, [r0], #4
-       bcc             1b
+.Lcpu_vstart:
 
-#ifdef CONFIG_BOOT_RUNFROMFLASH
-       /* If the .data section is in a separate, uninitialized address space,
-        * then we will also need to copy the initial values of the .data
-        * section from the .text region into that .data region.  This would
-        * be the case if we are executing from FLASH and the .data section
-        * lies in a different physical address region OR if we are support
-        * on-demand paging and the .data section lies in a different virtual
-        * address region.
+#ifdef CONFIG_STACK_COLORATION
+       /* Write a known value to the IDLE thread stack to support stack
+        * monitoring logic
         */
 
-       adr             r3, .Ldatainit
-       ldmia           r3, {r0, r1, r2}
+       adr             r3, .Lstkinit
+       mov             r0, sp          /* R0 = end of IDLE stack */
+       ldmia           r3, {r1, r2}    /* R1 = Size of stack; R2 = coloration 
*/
 
-2:
-       ldr             r3, [r0], #4
-       str             r3, [r1], #4
-       cmp             r1, r2
-       blt             2b
+1:                                                     /* Top of the loop */
+       sub             r1, r1, #1                      /* R1 = Number of words 
remaining */
+       cmp             r1, #0                          /* Check (nwords == 0) 
*/
+       str             r2, [r0, #-4]!                  /* Save stack color 
word, increment stack address */
+       bne             1b                              /* Bottom of the loop */
 #endif
 
-#ifdef CONFIG_ARCH_RAMFUNCS
-       /* Copy any necessary code sections from FLASH to RAM.  The correct
-        * destination in SRAM is given by _sramfuncs and _eramfuncs.  The
-        * temporary location is in flash after the data initialization code
-        * at _framfuncs
-        */
-
-       adr             r3, .Lfuncinit
-       ldmia           r3, {r0, r1, r2}
-
-3:
-       ldr             r3, [r0], #4
-       str             r3, [r1], #4
-       cmp             r1, r2
-       blt             3b
-
-#ifndef CONFIG_ARMV7R_DCACHE_DISABLE
-       /* Flush the copied RAM functions into physical RAM so that will
-        * be available when fetched into the I-Cache.
-        *
-        * Note that this is a branch, not a call and so will return
-        * directly to the caller without returning here.
-        */
+       /* Branch to continue C level CPU initialization */
 
-       adr             r3, ..Lramfunc
-       ldmia           r3, {r0, r1}
-       ldr             r3, =up_clean_dcache
-       b               r3
-#else
-       /* Otherwise return to the caller */
-
-       bx              lr
-#endif
-#else
-       /* Return to the caller */
-
-       bx              lr
-#endif
+       mov             fp, #0                          /* Clear framepointer */
+       mov             lr, #0                          /* LR = return address 
(none) */
+       mov             r0, r5                          /* Input parameter = 
CPU index */
+       b               arm_cpu_boot                    /* Branch to C level 
CPU initialization */
+       .size   .Lcpu_vstart, .-.Lcpu_vstart
 
 /***************************************************************************
  * Text-section constants
  ***************************************************************************/
 
-       /* Text-section constants:
-        *
-        *   _sbss is the start of the BSS region (see linker script)
-        *   _ebss is the end of the BSS region (see linker script)
-        *
-        * Typical Configuration:
-        * The idle task stack usually starts at the end of BSS and is of size
-        * CONFIG_IDLETHREAD_STACKSIZE.  The heap continues from there until the
-        * end of memory.  See g_idle_topstack below.
-        */
+       /* Text-section constants: */
 
-       .type   .Linitparms, %object
-.Linitparms:
-       .long   _sbss
-       .long   _ebss
-
-#ifdef CONFIG_BOOT_RUNFROMFLASH
-       .type   .Ldatainit, %object
-.Ldatainit:
-       .long   _eronly                                 /* Where .data defaults 
are stored in FLASH */
-       .long   _sdata                                  /* Where .data needs to 
reside in SDRAM */
-       .long   _edata
+#ifdef CONFIG_STACK_COLORATION
+       .type   .Lstkinit, %object
+.Lstkinit:
+       .long   SMP_STACK_WORDS - (XCPTCONTEXT_SIZE / 4)
+       .long   STACK_COLOR                             /* Stack coloration 
word */
+       .size   .Lstkinit, . -.Lstkinit
 #endif
 
-#ifdef CONFIG_ARCH_RAMFUNCS
-       .type   .Lfuncinit, %object
-.Lfuncinit:
-       .long   _framfuncs                              /* Where RAM functions 
are stored in FLASH */
-.Lramfuncs:
-       .long   _sramfuncs                              /* Where RAM functions 
needs to reside in RAM */
-       .long   _eramfuncs
-#endif
-       .size   arm_data_initialize, . - arm_data_initialize
-
 /***************************************************************************
- * Data section variables
+ * .noinit section data
  ***************************************************************************/
 
-       /* This global variable is unsigned long g_idle_topstack and is
-        * exported from here only because of its coupling to .Lstackpointer
-        * above.
-        */
-
-       .section        .rodata, "a"
-       .align  4
-       .globl  g_idle_topstack
-       .type   g_idle_topstack, object
-
-g_idle_topstack:
-
-       .long   IDLE_STACK_TOP
-       .size   g_idle_topstack, .-g_idle_topstack
+       .section        .noinit, "aw"
+
+#if CONFIG_SMP_NCPUS > 1
+       .align  8
+       .globl  g_cpu1_idlestack
+       .type   g_cpu1_idlestack, object
+
+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
+       .globl  g_cpu2_idlestack
+       .type   g_cpu2_idlestack, object
+
+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
+       .globl  g_cpu3_idlestack
+       .type   g_cpu3_idlestack, object
+
+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
+
+#endif /* CONFIG_SMP_NCPUS > 4 */
+#endif /* CONFIG_SMP_NCPUS > 3 */
+#endif /* CONFIG_SMP_NCPUS > 2 */
+#endif /* CONFIG_SMP_NCPUS > 1 */
+#endif /* CONFIG_SMP */
        .end
diff --git a/arch/arm/src/armv7-r/arm_cpuidlestack.c 
b/arch/arm/src/armv7-r/arm_cpuidlestack.c
new file mode 100644
index 0000000000..00b0bebe98
--- /dev/null
+++ b/arch/arm/src/armv7-r/arm_cpuidlestack.c
@@ -0,0 +1,132 @@
+/****************************************************************************
+ * arch/arm/src/armv7-r/arm_cpuidlestack.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <sys/types.h>
+#include <assert.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/sched.h>
+
+#include "smp.h"
+#include "arm_internal.h"
+
+#ifdef CONFIG_SMP
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Stack alignment macros */
+
+#define STACK_ISALIGNED(a) ((uintptr_t)(a) & ~SMP_STACK_MASK)
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+#if CONFIG_SMP_NCPUS > 1
+static 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 */
+};
+#endif
+
+/****************************************************************************
+ * 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:
+ *
+ *      return 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
+ *   - stack_base_ptr: Adjusted stack base pointer after the TLS Data and
+ *     Arguments has been removed from the stack allocation.
+ *
+ * Input Parameters:
+ *   - 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, struct tcb_s *tcb, size_t stack_size)
+{
+#if CONFIG_SMP_NCPUS > 1
+  uintptr_t stack_alloc;
+
+  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));
+
+  tcb->adj_stack_size  = SMP_STACK_SIZE;
+  tcb->stack_alloc_ptr = (void *)stack_alloc;
+  tcb->stack_base_ptr  = tcb->stack_alloc_ptr;
+#endif
+
+  return OK;
+}
+
+#endif /* CONFIG_SMP */
diff --git a/arch/arm/src/armv7-r/barriers.h 
b/arch/arm/src/armv7-r/arm_cpuindex.c
similarity index 53%
copy from arch/arm/src/armv7-r/barriers.h
copy to arch/arm/src/armv7-r/arm_cpuindex.c
index 030b5f4a50..c36cd0d2f8 100644
--- a/arch/arm/src/armv7-r/barriers.h
+++ b/arch/arm/src/armv7-r/arm_cpuindex.c
@@ -1,5 +1,5 @@
 /****************************************************************************
- * arch/arm/src/armv7-r/barriers.h
+ * arch/arm/src/armv7-r/arm_cpuindex.c
  *
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -18,27 +18,54 @@
  *
  ****************************************************************************/
 
-#ifndef __ARCH_ARM_SRC_ARMV7_R_BARRIERS_H
-#define __ARCH_ARM_SRC_ARMV7_R_BARRIERS_H
-
 /****************************************************************************
  * Included Files
  ****************************************************************************/
 
+#include <nuttx/config.h>
+
+#include <stdint.h>
+
+#include <nuttx/arch.h>
+
+#include "cp15.h"
+#include "sctlr.h"
+
+#ifdef CONFIG_SMP
+
 /****************************************************************************
- * Pre-processor Definitions
+ * Public Functions
  ****************************************************************************/
 
-/* ARMv7-R memory barriers */
+/****************************************************************************
+ * Name: up_cpu_index
+ *
+ * Description:
+ *   Return an index in the range of 0 through (CONFIG_SMP_NCPUS-1) that
+ *   corresponds to the currently executing CPU.
+ *
+ *   If TLS is enabled, then the RTOS can get this information from the TLS
+ *   info structure.  Otherwise, the MCU-specific logic must provide some
+ *   mechanism to provide the CPU index.
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   An integer index in the range of 0 through (CONFIG_SMP_NCPUS-1) that
+ *   corresponds to the currently executing CPU.
+ *
+ ****************************************************************************/
+
+int up_cpu_index(void)
+{
+  /* Read the Multiprocessor Affinity Register (MPIDR) */
+
+  uint32_t mpidr = cp15_rdmpidr();
 
-#define arm_isb(n) __asm__ __volatile__ ("isb " #n : : : "memory")
-#define arm_dsb(n) __asm__ __volatile__ ("dsb " #n : : : "memory")
-#define arm_dmb(n) __asm__ __volatile__ ("dmb " #n : : : "memory")
-#define arm_nop(n) __asm__ __volatile__ ("nop\n")
+  /* And return the CPU ID field */
 
-#define ARM_DSB()  arm_dsb(15)
-#define ARM_ISB()  arm_isb(15)
-#define ARM_DMB()  arm_dmb(15)
-#define ARM_NOP()  arm_nop(15)
+  return (mpidr & MPIDR_CPUID_MASK) >> MPIDR_CPUID_SHIFT;
+}
 
-#endif /* __ARCH_ARM_SRC_ARMV7_R_BARRIERS_H */
+#endif /* CONFIG_SMP */
diff --git a/arch/arm/src/armv7-r/arm_cpupause.c 
b/arch/arm/src/armv7-r/arm_cpupause.c
new file mode 100644
index 0000000000..ccd865809e
--- /dev/null
+++ b/arch/arm/src/armv7-r/arm_cpupause.c
@@ -0,0 +1,326 @@
+/****************************************************************************
+ * arch/arm/src/armv7-r/arm_cpupause.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdint.h>
+#include <assert.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/sched.h>
+#include <nuttx/spinlock.h>
+#include <nuttx/sched_note.h>
+
+#include "arm_internal.h"
+#include "gic.h"
+#include "sched/sched.h"
+
+#ifdef CONFIG_SMP
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* These spinlocks are used in the SMP configuration in order to implement
+ * up_cpu_pause().  The protocol for CPUn to pause CPUm is as follows
+ *
+ * 1. The up_cpu_pause() implementation on CPUn locks both g_cpu_wait[m]
+ *    and g_cpu_paused[m].  CPUn then waits spinning on g_cpu_paused[m].
+ * 2. CPUm receives the interrupt it (1) unlocks g_cpu_paused[m] and
+ *    (2) locks g_cpu_wait[m].  The first unblocks CPUn and the second
+ *    blocks CPUm in the interrupt handler.
+ *
+ * When CPUm resumes, CPUn unlocks g_cpu_wait[m] and the interrupt handler
+ * on CPUm continues.  CPUm must, of course, also then unlock g_cpu_wait[m]
+ * so that it will be ready for the next pause operation.
+ */
+
+static volatile spinlock_t g_cpu_wait[CONFIG_SMP_NCPUS];
+static volatile spinlock_t g_cpu_paused[CONFIG_SMP_NCPUS];
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: up_cpu_pausereq
+ *
+ * Description:
+ *   Return true if a pause request is pending for this CPU.
+ *
+ * Input Parameters:
+ *   cpu - The index of the CPU to be queried
+ *
+ * Returned Value:
+ *   true   = a pause request is pending.
+ *   false = no pasue request is pending.
+ *
+ ****************************************************************************/
+
+bool up_cpu_pausereq(int cpu)
+{
+  return spin_islocked(&g_cpu_paused[cpu]);
+}
+
+/****************************************************************************
+ * Name: up_cpu_paused
+ *
+ * Description:
+ *   Handle a pause request from another CPU.  Normally, this logic is
+ *   executed from interrupt handling logic within the architecture-specific
+ *   However, it is sometimes necessary necessary to perform the pending
+ *   pause operation in other contexts where the interrupt cannot be taken
+ *   in order to avoid deadlocks.
+ *
+ *   This function performs the following operations:
+ *
+ *   1. It saves the current task state at the head of the current assigned
+ *      task list.
+ *   2. It waits on a spinlock, then
+ *   3. Returns from interrupt, restoring the state of the new task at the
+ *      head of the ready to run list.
+ *
+ * Input Parameters:
+ *   cpu - The index of the CPU to be paused
+ *
+ * Returned Value:
+ *   On success, OK is returned.  Otherwise, a negated errno value indicating
+ *   the nature of the failure is returned.
+ *
+ ****************************************************************************/
+
+int up_cpu_paused(int cpu)
+{
+  struct tcb_s *tcb = this_task();
+
+  /* Update scheduler parameters */
+
+  nxsched_suspend_scheduler(tcb);
+
+#ifdef CONFIG_SCHED_INSTRUMENTATION
+  /* Notify that we are paused */
+
+  sched_note_cpu_paused(tcb);
+#endif
+
+  /* Save the current context at CURRENT_REGS into the TCB at the head
+   * of the assigned task list for this CPU.
+   */
+
+  arm_savestate(tcb->xcp.regs);
+
+  /* Release the g_cpu_paused spinlock to synchronize with the
+   * requesting CPU.
+   */
+
+  spin_unlock(&g_cpu_paused[cpu]);
+
+  /* Wait for the spinlock to be released.  The requesting CPU will release
+   * the spinlock when the CPU is resumed.
+   */
+
+  spin_lock(&g_cpu_wait[cpu]);
+
+  /* This CPU has been resumed. Restore the exception context of the TCB at
+   * the (new) head of the assigned task list.
+   */
+
+  tcb = this_task();
+
+#ifdef CONFIG_SCHED_INSTRUMENTATION
+  /* Notify that we have resumed */
+
+  sched_note_cpu_resumed(tcb);
+#endif
+
+  /* Reset scheduler parameters */
+
+  nxsched_resume_scheduler(tcb);
+
+  /* Then switch contexts.  Any necessary address environment changes
+   * will be made when the interrupt returns.
+   */
+
+  arm_restorestate(tcb->xcp.regs);
+  spin_unlock(&g_cpu_wait[cpu]);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: arm_pause_handler
+ *
+ * Description:
+ *   This is the handler for SGI2.  It performs the following operations:
+ *
+ *   1. It saves the current task state at the head of the current assigned
+ *      task list.
+ *   2. It waits on a spinlock, then
+ *   3. Returns from interrupt, restoring the state of the new task at the
+ *      head of the ready to run list.
+ *
+ * Input Parameters:
+ *   Standard interrupt handling
+ *
+ * Returned Value:
+ *   Zero on success; a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+int arm_pause_handler(int irq, void *context, void *arg)
+{
+  int cpu = this_cpu();
+
+  /* Check for false alarms.  Such false could occur as a consequence of
+   * some deadlock breaking logic that might have already serviced the SG2
+   * interrupt by calling up_cpu_paused().  If the pause event has already
+   * been processed then g_cpu_paused[cpu] will not be locked.
+   */
+
+  if (up_cpu_pausereq(cpu))
+    {
+      /* NOTE: The following enter_critical_section() will call
+       * up_cpu_paused() to process a pause request to break a deadlock
+       * because the caller held a critical section. Once up_cpu_paused()
+       * finished, the caller will proceed and release the g_cpu_irqlock.
+       * Then this CPU will acquire g_cpu_irqlock in the function.
+       */
+
+      irqstate_t flags = enter_critical_section();
+
+      /* NOTE: the pause request should not exist here */
+
+      DEBUGVERIFY(!up_cpu_pausereq(cpu));
+
+      leave_critical_section(flags);
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: up_cpu_pause
+ *
+ * Description:
+ *   Save the state of the current task at the head of the
+ *   g_assignedtasks[cpu] task list and then pause task execution on the
+ *   CPU.
+ *
+ *   This function is called by the OS when the logic executing on one CPU
+ *   needs to modify the state of the g_assignedtasks[cpu] list for another
+ *   CPU.
+ *
+ * Input Parameters:
+ *   cpu - The index of the CPU to be stopped
+ *
+ * Returned Value:
+ *   Zero on success; a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+int up_cpu_pause(int cpu)
+{
+  DEBUGASSERT(cpu >= 0 && cpu < CONFIG_SMP_NCPUS && cpu != this_cpu());
+
+#ifdef CONFIG_SCHED_INSTRUMENTATION
+  /* Notify of the pause event */
+
+  sched_note_cpu_pause(this_task(), cpu);
+#endif
+
+  /* Take the both spinlocks.  The g_cpu_wait spinlock will prevent the SGI2
+   * handler from returning until up_cpu_resume() is called; g_cpu_paused
+   * is a handshake that will prefent this function from returning until
+   * the CPU is actually paused.
+   * Note that we might spin before getting g_cpu_wait, this just means that
+   * the other CPU still hasn't finished responding to the previous resume
+   * request.
+   */
+
+  DEBUGASSERT(!spin_islocked(&g_cpu_paused[cpu]));
+
+  spin_lock(&g_cpu_wait[cpu]);
+  spin_lock(&g_cpu_paused[cpu]);
+
+  /* Execute SGI2 */
+
+  arm_cpu_sgi(GIC_IRQ_SGI2, (1 << cpu));
+
+  /* Wait for the other CPU to unlock g_cpu_paused meaning that
+   * it is fully paused and ready for up_cpu_resume();
+   */
+
+  spin_lock(&g_cpu_paused[cpu]);
+  spin_unlock(&g_cpu_paused[cpu]);
+
+  /* On successful return g_cpu_wait will be locked, the other CPU will be
+   * spinning on g_cpu_wait and will not continue until g_cpu_resume() is
+   * called.  g_cpu_paused will be unlocked in any case.
+   */
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: up_cpu_resume
+ *
+ * Description:
+ *   Restart the cpu after it was paused via up_cpu_pause(), restoring the
+ *   state of the task at the head of the g_assignedtasks[cpu] list, and
+ *   resume normal tasking.
+ *
+ *   This function is called after up_cpu_pause in order resume operation of
+ *   the CPU after modifying its g_assignedtasks[cpu] list.
+ *
+ * Input Parameters:
+ *   cpu - The index of the CPU being re-started.
+ *
+ * Returned Value:
+ *   Zero on success; a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+int up_cpu_resume(int cpu)
+{
+  DEBUGASSERT(cpu >= 0 && cpu < CONFIG_SMP_NCPUS && cpu != this_cpu());
+
+#ifdef CONFIG_SCHED_INSTRUMENTATION
+  /* Notify of the resume event */
+
+  sched_note_cpu_resume(this_task(), cpu);
+#endif
+
+  /* Release the spinlock.  Releasing the spinlock will cause the SGI2
+   * handler on 'cpu' to continue and return from interrupt to the newly
+   * established thread.
+   */
+
+  DEBUGASSERT(spin_islocked(&g_cpu_wait[cpu]) &&
+              !spin_islocked(&g_cpu_paused[cpu]));
+
+  spin_unlock(&g_cpu_wait[cpu]);
+  return OK;
+}
+
+#endif /* CONFIG_SMP */
diff --git a/arch/arm/src/armv7-r/arm_cpustart.c 
b/arch/arm/src/armv7-r/arm_cpustart.c
new file mode 100644
index 0000000000..51e24476a7
--- /dev/null
+++ b/arch/arm/src/armv7-r/arm_cpustart.c
@@ -0,0 +1,136 @@
+/****************************************************************************
+ * arch/arm/src/armv7-r/arm_cpustart.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdint.h>
+#include <assert.h>
+#include <debug.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/sched.h>
+#include <nuttx/sched_note.h>
+
+#include "arm_internal.h"
+#include "cp15_cacheops.h"
+#include "gic.h"
+#include "sched/sched.h"
+
+#ifdef CONFIG_SMP
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: arm_start_handler
+ *
+ * Description:
+ *   This is the handler for SGI1.  This handler simply returns from the
+ *   interrupt, restoring the state of the new task at the head of the ready
+ *   to run list.
+ *
+ * Input Parameters:
+ *   Standard interrupt handling
+ *
+ * Returned Value:
+ *   Zero on success; a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+int arm_start_handler(int irq, void *context, void *arg)
+{
+  struct tcb_s *tcb = this_task();
+
+  sinfo("CPU%d Started\n", this_cpu());
+
+#ifdef CONFIG_SCHED_INSTRUMENTATION
+  /* Notify that this CPU has started */
+
+  sched_note_cpu_started(tcb);
+#endif
+
+  /* Reset scheduler parameters */
+
+  nxsched_resume_scheduler(tcb);
+
+  /* Then switch contexts. This instantiates the exception context of the
+   * tcb at the head of the assigned task list.  In this case, this should
+   * be the CPUs NULL task.
+   */
+
+  arm_restorestate(tcb->xcp.regs);
+  return OK;
+}
+
+/****************************************************************************
+ * Name: up_cpu_start
+ *
+ * Description:
+ *   In an SMP configuration, only one CPU is initially active (CPU 0).
+ *   System initialization occurs on that single thread. At the completion of
+ *   the initialization of the OS, just before beginning normal multitasking,
+ *   the additional CPUs would be started by calling this function.
+ *
+ *   Each CPU is provided the entry point to its IDLE task when started.  A
+ *   TCB for each CPU's IDLE task has been initialized and placed in the
+ *   CPU's g_assignedtasks[cpu] list.  No stack has been allocated or
+ *   initialized.
+ *
+ *   The OS initialization logic calls this function repeatedly until each
+ *   CPU has been started, 1 through (CONFIG_SMP_NCPUS-1).
+ *
+ * Input Parameters:
+ *   cpu - The index of the CPU being started.  This will be a numeric
+ *         value in the range of one to (CONFIG_SMP_NCPUS-1).
+ *         (CPU 0 is already active)
+ *
+ * Returned Value:
+ *   Zero on success; a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+int up_cpu_start(int cpu)
+{
+  sinfo("Starting CPU%d\n", cpu);
+
+  DEBUGASSERT(cpu >= 0 && cpu < CONFIG_SMP_NCPUS && cpu != this_cpu());
+
+#ifdef CONFIG_SCHED_INSTRUMENTATION
+  /* Notify of the start event */
+
+  sched_note_cpu_start(this_task(), cpu);
+#endif
+
+  /* Execute SGI1 */
+
+  arm_cpu_sgi(GIC_IRQ_SGI1, (1 << cpu));
+  return OK;
+}
+
+#endif /* CONFIG_SMP */
diff --git a/arch/arm/src/armv7-r/arm_head.S b/arch/arm/src/armv7-r/arm_head.S
index d6433910e9..428b0b2d3d 100644
--- a/arch/arm/src/armv7-r/arm_head.S
+++ b/arch/arm/src/armv7-r/arm_head.S
@@ -76,7 +76,11 @@
  */
 
 #ifndef IDLE_STACK_BASE
-#  define IDLE_STACK_BASE _ebss
+#  ifdef CONFIG_SMP
+#    define IDLE_STACK_BASE _enoinit
+#  else
+#    define IDLE_STACK_BASE _ebss
+#  endif
 #endif
 
 #define IDLE_STACK_TOP  IDLE_STACK_BASE+CONFIG_IDLETHREAD_STACKSIZE
@@ -124,6 +128,32 @@
        .type   __start, #function
 
 __start:
+#if defined(CONFIG_SMP) && CONFIG_SMP_NCPUS > 1
+       /* Get cpuindex, cpu0 continue boot, others wait event from cpu0 */
+
+       mrc             CP15_MPIDR(r0)
+       and             r0, r0, #0x3
+       cmp             r0, #0
+       beq             __cpu0_start
+       wfe
+       cmp             r0, #1
+       beq             __cpu1_start
+#  if CONFIG_SMP_NCPUS > 2
+       cmp             r0, #2
+       beq             __cpu2_start
+#  endif
+#  if CONFIG_SMP_NCPUS > 3
+       cmp             r0, #3
+       beq             __cpu3_start
+#  endif
+#  if CONFIG_SMP_NCPUS > 4
+       cmp             r0, #4
+       beq             __cpu4_start
+#  endif
+
+__cpu0_start:
+#endif
+
        /* Make sure that we are in SYS mode with IRQs and FIQs disabled */
 
        cpsid           if, #PSR_MODE_SYS
@@ -184,10 +214,19 @@ __start:
 
        /* Clear all configurable bits */
 
-       bic             r0, r0, #(SCTLR_M  | SCTLR_A  | SCTLR_C    | 
SCTLR_CCP15BEN | SCTLR_B)
-       bic             r0, r0, #(SCTLR_SW | SCTLR_I  | SCTLR_V    | SCTLR_RR)
+       bic             r0, r0, #(SCTLR_A  | SCTLR_C  | SCTLR_CCP15BEN | 
SCTLR_B)
+       bic             r0, r0, #(SCTLR_SW | SCTLR_I  | SCTLR_V        | 
SCTLR_RR)
        bic             r0, r0, #(SCTLR_BR | SCTLR_DZ | SCTLR_FI)
-       bic             r0, r0, #(SCTLR_VE | SCTLR_EE | SCTLR_NMFI | SCTLR_TE)
+       bic             r0, r0, #(SCTLR_VE | SCTLR_EE | SCTLR_NMFI     | 
SCTLR_TE)
+
+#ifndef CONFIG_SMP
+       /* Set bits to enable the MPU
+        *
+        *   SCTLR_M     Bit 0:  Enable the MPU
+        */
+
+       orr             r0, r0, #(SCTLR_M)
+#endif
 
        /* Set configured bits */
 
@@ -200,7 +239,7 @@ __start:
        orr             r0, r0, #(SCTLR_A)
 #endif
 
-#ifndef CONFIG_ARMV7R_DCACHE_DISABLE
+#if !defined(CONFIG_ARMV7R_DCACHE_DISABLE) && !defined(CONFIG_SMP)
        /* Dcache enable
         *
         *   SCTLR_C    Bit 2:  DCache enable
@@ -218,7 +257,7 @@ __start:
        orr             r0, r0, #(SCTLR_CCP15BEN)
 #endif
 
-#ifndef CONFIG_ARMV7R_ICACHE_DISABLE
+#if !defined(CONFIG_ARMV7R_ICACHE_DISABLE) && !defined(CONFIG_SMP)
        /* Icache enable
         *
         *   SCTLR_I    Bit 12: ICache enable
diff --git a/arch/arm/src/armv7-r/arm_schedulesigaction.c 
b/arch/arm/src/armv7-r/arm_schedulesigaction.c
index 472699930b..bf44b93de5 100644
--- a/arch/arm/src/armv7-r/arm_schedulesigaction.c
+++ b/arch/arm/src/armv7-r/arm_schedulesigaction.c
@@ -75,6 +75,7 @@
  *
  ****************************************************************************/
 
+#ifndef CONFIG_SMP
 void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
 {
   sinfo("tcb=%p sigdeliver=%p\n", tcb, sigdeliver);
@@ -208,3 +209,222 @@ void up_schedule_sigaction(struct tcb_s *tcb, 
sig_deliver_t sigdeliver)
         }
     }
 }
+#else
+void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
+{
+  int cpu;
+  int me;
+
+  sinfo("tcb=%p sigdeliver=%p\n", tcb, sigdeliver);
+
+  /* Refuse to handle nested signal actions */
+
+  if (!tcb->xcp.sigdeliver)
+    {
+      /* First, handle some special cases when the signal is being delivered
+       * to task that is currently executing on any CPU.
+       */
+
+      sinfo("rtcb=%p CURRENT_REGS=%p\n", this_task(), CURRENT_REGS);
+
+      if (tcb->task_state == TSTATE_TASK_RUNNING)
+        {
+          me  = this_cpu();
+          cpu = tcb->cpu;
+
+          /* CASE 1:  We are not in an interrupt handler and a task is
+           * signaling itself for some reason.
+           */
+
+          if (cpu == me && !CURRENT_REGS)
+            {
+              /* In this case just deliver the signal now.
+               * REVISIT:  Signal handler will run in a critical section!
+               */
+
+              sigdeliver(tcb);
+            }
+
+          /* CASE 2:  The task that needs to receive the signal is running.
+           * This could happen if the task is running on another CPU OR if
+           * we are in an interrupt handler and the task is running on this
+           * CPU.  In the former case, we will have to PAUSE the other CPU
+           * first.  But in either case, we will have to modify the return
+           * state as well as the state in the TCB.
+           */
+
+          else
+            {
+              /* If we signaling a task running on the other CPU, we have
+               * to PAUSE the other CPU.
+               */
+
+              if (cpu != me)
+                {
+                  /* Pause the CPU */
+
+                  up_cpu_pause(cpu);
+
+                  /* Wait while the pause request is pending */
+
+                  while (up_cpu_pausereq(cpu))
+                    {
+                    }
+
+                  /* Now tcb on the other CPU can be accessed safely */
+
+                  /* Copy tcb->xcp.regs to tcp.xcp.saved. These will be
+                   * restored by the signal trampoline after the signal has
+                   * been delivered.
+                   */
+
+                  tcb->xcp.sigdeliver      = sigdeliver;
+
+                  /* Save the current register context location */
+
+                  tcb->xcp.saved_regs      = tcb->xcp.regs;
+
+                  /* Duplicate the register context.  These will be
+                   * restored by the signal trampoline after the signal has
+                   * been delivered.
+                   */
+
+                  tcb->xcp.regs            = (void *)
+                                             ((uint32_t)tcb->xcp.regs -
+                                              (uint32_t)XCPTCONTEXT_SIZE);
+                  memcpy(tcb->xcp.regs, tcb->xcp.saved_regs,
+                         XCPTCONTEXT_SIZE);
+
+                  tcb->xcp.regs[REG_SP]    = (uint32_t)tcb->xcp.regs +
+                                             (uint32_t)XCPTCONTEXT_SIZE;
+
+                  /* Then set up to vector to the trampoline with interrupts
+                   * disabled
+                   */
+
+                  tcb->xcp.regs[REG_PC]    = (uint32_t)arm_sigdeliver;
+                  tcb->xcp.regs[REG_CPSR]  = (PSR_MODE_SYS | PSR_I_BIT |
+                                              PSR_F_BIT);
+#ifdef CONFIG_ARM_THUMB
+                  tcb->xcp.regs[REG_CPSR] |= PSR_T_BIT;
+#endif
+                }
+              else
+                {
+                  /* tcb is running on the same CPU */
+
+                  /* Save the return PC, CPSR and either the BASEPRI or
+                   * PRIMASK registers (and perhaps also the LR).  These will
+                   * be restored by the signal trampoline after the signal
+                   * has been delivered.
+                   */
+
+                  tcb->xcp.sigdeliver     = (void *)sigdeliver;
+
+                  /* And make sure that the saved context in the TCB is the
+                   * same as the interrupt return context.
+                   */
+
+                  arm_savestate(tcb->xcp.saved_regs);
+
+                  /* Duplicate the register context.  These will be
+                   * restored by the signal trampoline after the signal has
+                   * been delivered.
+                   */
+
+                  CURRENT_REGS            = (void *)
+                                            ((uint32_t)CURRENT_REGS -
+                                             (uint32_t)XCPTCONTEXT_SIZE);
+                  memcpy((uint32_t *)CURRENT_REGS, tcb->xcp.saved_regs,
+                         XCPTCONTEXT_SIZE);
+
+                  CURRENT_REGS[REG_SP]    = (uint32_t)CURRENT_REGS +
+                                            (uint32_t)XCPTCONTEXT_SIZE;
+
+                  /* Then set up vector to the trampoline with interrupts
+                   * disabled.  The kernel-space trampoline must run in
+                   * privileged thread mode.
+                   */
+
+                  CURRENT_REGS[REG_PC]    = (uint32_t)arm_sigdeliver;
+                  CURRENT_REGS[REG_CPSR]  = (PSR_MODE_SYS | PSR_I_BIT |
+                                             PSR_F_BIT);
+#ifdef CONFIG_ARM_THUMB
+                  CURRENT_REGS[REG_CPSR] |= PSR_T_BIT;
+#endif
+                }
+
+              /* Increment the IRQ lock count so that when the task is
+               * restarted, it will hold the IRQ spinlock.
+               */
+
+              DEBUGASSERT(tcb->irqcount < INT16_MAX);
+              tcb->irqcount++;
+
+              /* NOTE: If the task runs on another CPU(cpu), adjusting
+               * global IRQ controls will be done in the pause handler
+               * on the CPU(cpu) by taking a critical section.
+               * If the task is scheduled on this CPU(me), do nothing
+               * because this CPU already took a critical section
+               */
+
+              /* RESUME the other CPU if it was PAUSED */
+
+              if (cpu != me)
+                {
+                  up_cpu_resume(cpu);
+                }
+            }
+        }
+
+      /* Otherwise, we are (1) signaling a task is not running from an
+       * interrupt handler or (2) we are not in an interrupt handler and the
+       * running task is signaling some other non-running task.
+       */
+
+      else
+        {
+          /* Save the return lr and cpsr and one scratch register.  These
+           * will be restored by the signal trampoline after the signals
+           * have been delivered.
+           */
+
+          tcb->xcp.sigdeliver      = sigdeliver;
+
+          /* Save the current register context location */
+
+          tcb->xcp.saved_regs      = tcb->xcp.regs;
+
+          /* Duplicate the register context.  These will be
+           * restored by the signal trampoline after the signal has been
+           * delivered.
+           */
+
+          tcb->xcp.regs            = (void *)
+                                     ((uint32_t)tcb->xcp.regs -
+                                      (uint32_t)XCPTCONTEXT_SIZE);
+          memcpy(tcb->xcp.regs, tcb->xcp.saved_regs, XCPTCONTEXT_SIZE);
+
+          tcb->xcp.regs[REG_SP]    = (uint32_t)tcb->xcp.regs +
+                                     (uint32_t)XCPTCONTEXT_SIZE;
+
+          /* Increment the IRQ lock count so that when the task is restarted,
+           * it will hold the IRQ spinlock.
+           */
+
+          DEBUGASSERT(tcb->irqcount < INT16_MAX);
+          tcb->irqcount++;
+
+          /* Then set up to vector to the trampoline with interrupts
+           * disabled
+           */
+
+          tcb->xcp.regs[REG_PC]    = (uint32_t)arm_sigdeliver;
+          tcb->xcp.regs[REG_CPSR]  = (PSR_MODE_SYS | PSR_I_BIT | PSR_F_BIT);
+#ifdef CONFIG_ARM_THUMB
+          tcb->xcp.regs[REG_CPSR] |= PSR_T_BIT;
+#endif
+        }
+    }
+}
+#endif
diff --git a/arch/arm/src/armv7-r/arm_scu.c b/arch/arm/src/armv7-r/arm_scu.c
new file mode 100644
index 0000000000..9e2d04f7dc
--- /dev/null
+++ b/arch/arm/src/armv7-r/arm_scu.c
@@ -0,0 +1,123 @@
+/****************************************************************************
+ * arch/arm/src/armv7-r/arm_scu.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdint.h>
+
+#include "arm_internal.h"
+#include "cp15_cacheops.h"
+#include "barriers.h"
+#include "sctlr.h"
+#include "scu.h"
+#include "cp15.h"
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: arm_enable_smp
+ *
+ * Description:
+ *   Enable the SCU and make certain that current CPU is participating in
+ *   the SMP cache coherency.
+ *
+ * Assumption:
+ *   Called early in the CPU start-up.  No special critical sections are
+ *   needed if only CPU-private registers are modified.
+ *
+ ****************************************************************************/
+
+void arm_enable_smp(int cpu)
+{
+  uint32_t regval;
+
+  /* Handle actions unique to CPU0 which comes up first */
+
+  if (cpu == 0)
+    {
+      /* Invalidate the SCU duplicate tags for all processors */
+
+      putreg32((SCU_INVALIDATE_ALL_WAYS << SCU_INVALIDATE_CPU0_SHIFT)
+               | (SCU_INVALIDATE_ALL_WAYS << SCU_INVALIDATE_CPU1_SHIFT)
+#if CONFIG_SMP_NCPUS > 2
+               | (SCU_INVALIDATE_ALL_WAYS << SCU_INVALIDATE_CPU2_SHIFT)
+               | (SCU_INVALIDATE_ALL_WAYS << SCU_INVALIDATE_CPU3_SHIFT)
+#endif
+               , SCU_INVALIDATE);
+
+      /* Invalidate CPUn L1 data cache so that is will we be reloaded from
+       * coherent L2.
+       */
+
+      cp15_invalidate_dcache_all();
+      ARM_DSB();
+
+      /* Invalidate the L2C-310 -- Missing logic. */
+
+      /* Enable the SCU */
+
+      regval  = getreg32(SCU_CTRL);
+      regval |= SCU_CTRL_ENABLE;
+      putreg32(regval, SCU_CTRL);
+
+      /* Initialize done, kick other cpus which waiting on __start */
+
+      ARM_SEV();
+    }
+
+  /* Actions for other CPUs */
+
+  else
+    {
+      /* Invalidate CPUn L1 data cache so that is will we be reloaded from
+       * coherent L2.
+       */
+
+      cp15_dcache_op_level(0, CP15_CACHE_INVALIDATE);
+      ARM_DSB();
+
+      /* Wait for the SCU to be enabled by the primary processor -- should
+       * not be necessary.
+       */
+    }
+
+  /* Enable the data cache, set the SMP mode with ACTLR.SMP=1.
+   *
+   *   SMP - Sgnals if the processor is taking part in coherency
+   *         or not.
+   *
+   *   FW  - Cache and TLB maintenance broadcast.
+   */
+
+  regval  = CP15_GET(ACTLR);
+  regval |= ACTLR_SMP;
+  regval |= ACTLR_FW;
+  CP15_SET(ACTLR, regval);
+
+  regval  = CP15_GET(SCTLR);
+  regval |= SCTLR_C | SCTLR_I | SCTLR_M;
+  CP15_SET(SCTLR, regval);
+}
diff --git a/arch/arm/src/armv7-r/arm_sigdeliver.c 
b/arch/arm/src/armv7-r/arm_sigdeliver.c
index 6699aaa777..be1553b0f6 100644
--- a/arch/arm/src/armv7-r/arm_sigdeliver.c
+++ b/arch/arm/src/armv7-r/arm_sigdeliver.c
@@ -56,12 +56,41 @@ void arm_sigdeliver(void)
   struct tcb_s  *rtcb = this_task();
   uint32_t *regs = rtcb->xcp.saved_regs;
 
+#ifdef CONFIG_SMP
+  /* In the SMP case, we must terminate the critical section while the signal
+   * handler executes, but we also need to restore the irqcount when the
+   * we resume the main thread of the task.
+   */
+
+  int16_t saved_irqcount;
+#endif
+
   board_autoled_on(LED_SIGNAL);
 
   sinfo("rtcb=%p sigdeliver=%p sigpendactionq.head=%p\n",
         rtcb, rtcb->xcp.sigdeliver, rtcb->sigpendactionq.head);
   DEBUGASSERT(rtcb->xcp.sigdeliver != NULL);
 
+#ifdef CONFIG_SMP
+  /* In the SMP case, up_schedule_sigaction(0) will have incremented
+   * 'irqcount' in order to force us into a critical section.  Save the
+   * pre-incremented irqcount.
+   */
+
+  saved_irqcount = rtcb->irqcount - 1;
+  DEBUGASSERT(saved_irqcount >= 0);
+
+  /* Now we need call leave_critical_section() repeatedly to get the irqcount
+   * to zero, freeing all global spinlocks that enforce the critical section.
+   */
+
+  do
+    {
+      leave_critical_section(regs[REG_CPSR]);
+    }
+  while (rtcb->irqcount > 0);
+#endif /* CONFIG_SMP */
+
 #ifndef CONFIG_SUPPRESS_INTERRUPTS
   /* Then make sure that interrupts are enabled.  Signal handlers must always
    * run with interrupts enabled.
@@ -80,7 +109,22 @@ void arm_sigdeliver(void)
    */
 
   sinfo("Resuming\n");
+
+#ifdef CONFIG_SMP
+  /* Restore the saved 'irqcount' and recover the critical section
+   * spinlocks.
+   */
+
+  DEBUGASSERT(rtcb->irqcount == 0);
+  while (rtcb->irqcount < saved_irqcount)
+    {
+      enter_critical_section();
+    }
+#endif
+
+#ifndef CONFIG_SUPPRESS_INTERRUPTS
   up_irq_save();
+#endif
 
   /* Modify the saved return state with the actual saved values in the
    * TCB.  This depends on the fact that nested signal handling is
diff --git a/arch/arm/src/armv7-r/arm_vectors.S 
b/arch/arm/src/armv7-r/arm_vectors.S
index 659ac8d249..0f8e2224b9 100644
--- a/arch/arm/src/armv7-r/arm_vectors.S
+++ b/arch/arm/src/armv7-r/arm_vectors.S
@@ -42,6 +42,36 @@
  * Assembly Macros
  ****************************************************************************/
 
+/****************************************************************************
+ * Name: setirqstack
+ *
+ * Description:
+ *   Set the current stack pointer to the "top" of the IRQ interrupt stack.  
Single
+ *   CPU case.  Must be provided by MCU-specific logic in chip.h for the SMP 
case.
+ *
+ ****************************************************************************/
+
+#if !defined(CONFIG_SMP) && CONFIG_ARCH_INTERRUPTSTACK > 7
+       .macro  setirqstack, tmp1, tmp2
+       ldr             sp, .Lirqstacktop               /* SP = IRQ stack top */
+       .endm
+#endif
+
+/****************************************************************************
+ * Name: setfiqstack
+ *
+ * Description:
+ *   Set the current stack pointer to the "top" of the FIQ interrupt stack.  
Single
+ *   CPU case.  Must be provided by MCU-specific logic in chip.h for the SMP 
case.
+ *
+ ****************************************************************************/
+
+#if !defined(CONFIG_SMP) && CONFIG_ARCH_INTERRUPTSTACK > 7
+       .macro  setfiqstack, tmp1, tmp2
+       ldr             sp, .Lfiqstacktop               /* SP = FIQ stack top */
+       .endm
+#endif
+
 /****************************************************************************
  * Name: savefpu
  *
@@ -169,7 +199,7 @@ arm_vectorirq:
 #if CONFIG_ARCH_INTERRUPTSTACK > 7
        /* Call arm_decodeirq() on the interrupt stack */
 
-       ldr             sp, .Lirqstacktop               /* SP = interrupt stack 
top */
+       setirqstack     r1, r3                          /* SP = interrupt stack 
top */
 #else
        /* Call arm_decodeirq() on the user stack */
 
@@ -216,7 +246,7 @@ arm_vectorirq:
 
        rfeia           r14
 
-#if CONFIG_ARCH_INTERRUPTSTACK > 7
+#if !defined(CONFIG_SMP) && CONFIG_ARCH_INTERRUPTSTACK > 7
 .Lirqstacktop:
        .word   g_intstacktop
 #endif
@@ -281,7 +311,7 @@ arm_vectorsvc:
 #if CONFIG_ARCH_INTERRUPTSTACK > 7
        /* Call arm_syscall() on the interrupt stack */
 
-       ldr             sp, .Lirqstacktop               /* SP = interrupt stack 
top */
+       setirqstack     r1, r3                          /* SP = interrupt stack 
top */
 #else
        /* Call arm_syscall() on the user stack */
 
@@ -641,7 +671,7 @@ arm_vectorfiq:
 #if CONFIG_ARCH_INTERRUPTSTACK > 7
        /* Call arm_decodefiq() on the interrupt stack */
 
-       ldr             sp, .Lfiqstacktop               /* SP = interrupt stack 
top */
+       setfiqstack     r1, r3                          /* SP = interrupt stack 
top */
 #endif
 
        bic             sp, sp, #7                      /* Force 8-byte 
alignment */
@@ -676,7 +706,7 @@ arm_vectorfiq:
 
        rfeia           r14
 
-#if CONFIG_ARCH_INTERRUPTSTACK > 7
+#if !defined(CONFIG_SMP) && CONFIG_ARCH_INTERRUPTSTACK > 7
 .Lfiqstacktop:
        .word   g_fiqstacktop
 #endif
@@ -690,7 +720,7 @@ arm_vectorfiq:
  *  Name: g_intstackalloc/g_intstacktop
  ****************************************************************************/
 
-#if CONFIG_ARCH_INTERRUPTSTACK > 7
+#if !defined(CONFIG_SMP) && CONFIG_ARCH_INTERRUPTSTACK > 7
        .bss
        .balign 8
 
@@ -722,5 +752,5 @@ g_fiqstacktop:
        .size   g_fiqstackalloc, (CONFIG_ARCH_INTERRUPTSTACK & ~7)
 #endif
 
-#endif /* CONFIG_ARCH_INTERRUPTSTACK > 7 */
+#endif /* !CONFIG_SMP && CONFIG_ARCH_INTERRUPTSTACK > 7 */
        .end
diff --git a/arch/arm/src/armv7-r/barriers.h b/arch/arm/src/armv7-r/barriers.h
index 030b5f4a50..fe17d57db3 100644
--- a/arch/arm/src/armv7-r/barriers.h
+++ b/arch/arm/src/armv7-r/barriers.h
@@ -34,11 +34,13 @@
 #define arm_isb(n) __asm__ __volatile__ ("isb " #n : : : "memory")
 #define arm_dsb(n) __asm__ __volatile__ ("dsb " #n : : : "memory")
 #define arm_dmb(n) __asm__ __volatile__ ("dmb " #n : : : "memory")
-#define arm_nop(n) __asm__ __volatile__ ("nop\n")
+#define arm_nop()  __asm__ __volatile__ ("nop\n")
+#define arm_sev()  __asm__ __volatile__ ("sev\n")
 
 #define ARM_DSB()  arm_dsb(15)
 #define ARM_ISB()  arm_isb(15)
 #define ARM_DMB()  arm_dmb(15)
-#define ARM_NOP()  arm_nop(15)
+#define ARM_NOP()  arm_nop()
+#define ARM_SEV()  arm_sev()
 
 #endif /* __ARCH_ARM_SRC_ARMV7_R_BARRIERS_H */
diff --git a/arch/arm/src/armv7-r/sctlr.h b/arch/arm/src/armv7-r/sctlr.h
index 532cc3617c..5da84ed8f2 100644
--- a/arch/arm/src/armv7-r/sctlr.h
+++ b/arch/arm/src/armv7-r/sctlr.h
@@ -61,9 +61,19 @@
  * TODO: To be provided
  */
 
-/* Multiprocessor Affinity Register (MPIDR): CRn=c0, opc1=0, CRm=c0, opc2=5
- * TODO: To be provided
- */
+/* Multiprocessor Affinity Register (MPIDR): CRn=c0, opc1=0, CRm=c0, opc2=5 */
+
+#define MPIDR_CPUID_SHIFT        (0)       /* Bits 0-1: CPU ID */
+#define MPIDR_CPUID_MASK         (3 << MPIDR_CPUID_SHIFT)
+#  define MPIDR_CPUID_CPU0       (0 << MPIDR_CPUID_SHIFT)
+#  define MPIDR_CPUID_CPU1       (1 << MPIDR_CPUID_SHIFT)
+#  define MPIDR_CPUID_CPU2       (2 << MPIDR_CPUID_SHIFT)
+#  define MPIDR_CPUID_CPU3       (3 << MPIDR_CPUID_SHIFT)
+                                           /* Bits 2-7: Reserved */
+#define MPIDR_CLUSTID_SHIFT      (8)       /* Bits 8-11: Cluster ID value */
+#define MPIDR_CLUSTID_MASK       (15 << MPIDR_CLUSTID_SHIFT)
+                                           /* Bits 12-29: Reserved */
+#define MPIDR_U                  (1 << 30) /* Bit 30: Multiprocessing 
Extensions. */
 
 /* Revision ID Register (REVIDR): CRn=c0, opc1=0, CRm=c0, opc2=6
  * TODO: To be provided
@@ -160,9 +170,19 @@
                                      /* Bits 28-29: Reserved */
 #define SCTLR_TE           (1 << 30) /* Bit 30: Thumb exception enable */
 
-/* Auxiliary Control Register (ACTLR): CRn=c1, opc1=0, CRm=c0, opc2=1
- * Implementation defined
- */
+/* Auxiliary Control Register (ACTLR): CRn=c1, opc1=0, CRm=c0, opc2=1 */
+
+#define ACTLR_FW                 (1 << 0)  /* Bit 0: Enable Cache/TLB 
maintenance broadcast */
+                                           /* Bits 1-2: Reserved */
+#define ACTLR_MRP                (1 << 3)  /* Bit 3: Enable MRP */
+                                           /* Bits 4-5: Reserved */
+#define ACTLR_SMP                (1 << 6)  /* Bit 6: Cortex-A9 taking part in 
coherency */
+                                           /* Bits 7: Reserved */
+#define ACTLR_ALLOC_1WAY         (1 << 8)  /* Bit 8: Allocation in 1-way cache 
only */
+#define ACTLR_DTCM_ECC           (1 << 9)  /* Bit 9: ECC on caches and DTCM */
+#define ACTLR_ITCM_ECC           (1 << 10) /* Bit 10: ECC on caches and ITCM */
+#define ACTLR_ITCM_QOS           (1 << 11) /* Bit 11: Enable QoS*/
+                                           /* Bits 12-31: Reserved */
 
 /* Coprocessor Access Control Register (CPACR):
  * CRn=c1, opc1=0, CRm=c0, opc2=2
diff --git a/arch/arm/src/armv7-r/scu.h b/arch/arm/src/armv7-r/scu.h
new file mode 100644
index 0000000000..df732d9ca7
--- /dev/null
+++ b/arch/arm/src/armv7-r/scu.h
@@ -0,0 +1,252 @@
+/****************************************************************************
+ * arch/arm/src/armv7-r/scu.h
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/* Reference:
+ *   Cortex™-R8 MPCore, Revision: r0p3, Technical Reference Manual.
+ */
+
+#ifndef __ARCH_ARM_SRC_ARMV7_R_SCU_H
+#define __ARCH_ARM_SRC_ARMV7_R_SCU_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include "mpcore.h"                         /* For MPCORE_SCU_VBASE */
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Register offsets *********************************************************/
+
+#define SCU_CTRL_OFFSET              0x0000           /* SCU Control Register 
(Implementation defined) */
+#define SCU_CONFIG_OFFSET            0x0004           /* SCU Configuration 
Register (Implementation defined) */
+#define SCU_PWRSTATUS_OFFSET         0x0008           /* SCU CPU Power Status 
Register */
+#define SCU_INVALIDATE_OFFSET        0x000c           /* SCU Invalidate All 
Registers in Secure State */
+#define SCU_FILTERSTART_OFFSET       0x0040           /* Filtering Start 
Address Register Defined by FILTERSTART input */
+#define SCU_FILTEREND_OFFSET         0x0044           /* Filtering End Address 
Register Defined by FILTEREND input */
+#define SCU_PFILTERSTART_OFFSET      0x0048           /* Peripherals Filtering 
Start Address Register */
+#define SCU_PFILTEREND_OFFSET        0x004c           /* Peripherals Filtering 
End Address Register */
+#define SCU_SAC_OFFSET               0x0050           /* SCU Access Control 
(SAC) Register */
+#define SCU_ERRBANKFST_OFFSET        0x0060           /* SCU Error Bank First 
Entry Register */
+#define SCU_ERRBANKSND_OFFSET        0x0064           /* SCU Error Bank Second 
Entry Register */
+#define SCU_DEBUGRAM_OFFSET          0x0070           /* SCU Debug Tag RAM 
Operation Register */
+#define SCU_DEBUGRAMDATA_OFFSET      0x0074           /* SCU Debug Tag RAM 
Data Value Register */
+#define SCU_DEBUGRAMECC_OFFSET       0x0078           /* SCU Debug Tag RAM ECC 
Chunk Register */
+#define SCU_ECCERR_OFFSET            0x007c           /* ECC Fatal Error 
Registe */
+#define SCU_FPPFILTERSTART_OFFSET(n) (0x0080 + (n)*8) /* FPP Filtering Start 
Address Register for core n */
+#define SCU_FPPFILTEREND_OFFSET(n)   (0x0084 + (n)*8) /* FPP Filtering End 
Address Register for core n */
+
+/* Register addresses *******************************************************/
+
+#define SCU_CTRL                     (MPCORE_SCU_VBASE+SCU_CTRL_OFFSET)
+#define SCU_CONFIG                   (MPCORE_SCU_VBASE+SCU_CONFIG_OFFSET)
+#define SCU_PWRSTATUS                (MPCORE_SCU_VBASE+SCU_PWRSTATUS_OFFSET)
+#define SCU_INVALIDATE               (MPCORE_SCU_VBASE+SCU_INVALIDATE_OFFSET)
+#define SCU_FILTERSTART              (MPCORE_SCU_VBASE+SCU_FILTERSTART_OFFSET)
+#define SCU_FILTEREND                (MPCORE_SCU_VBASE+SCU_FILTEREND_OFFSET)
+#define SCU_PFILTERSTART             (MPCORE_SCU_VBASE+SCU_PFILTERSTART_OFFSET)
+#define SCU_PFILTEREND               (MPCORE_SCU_VBASE+SCU_PFILTEREND_OFFSET)
+#define SCU_SAC                      (MPCORE_SCU_VBASE+SCU_SAC_OFFSET)
+#define SCU_ERRBANKFST               (MPCORE_SCU_VBASE+SCU_ERRBANKFST_OFFSET)
+#define SCU_ERRBANKSND               (MPCORE_SCU_VBASE+SCU_ERRBANKSND_OFFSET)
+#define SCU_DEBUGRAM                 (MPCORE_SCU_VBASE+SCU_DEBUGRAM_OFFSET)
+#define SCU_DEBUGRAMDATA             (MPCORE_SCU_VBASE+SCU_DEBUGRAMDATA_OFFSET)
+#define SCU_DEBUGRAMECC              (MPCORE_SCU_VBASE+SCU_DEBUGRAMECC_OFFSET)
+#define SCU_ECCERR                   (MPCORE_SCU_VBASE+SCU_ECCERR_OFFSET)
+#define SCU_FPPFILTERSTART(n)        
(MPCORE_SCU_VBASE+SCU_FPPFILTERSTART0_OFFSET(n))
+#define SCU_FPPFILTEREND(n)          
(MPCORE_SCU_VBASE+SCU_FPPFILTEREND0_OFFSET(n))
+
+/* Register bit-field definitions *******************************************/
+
+/* SCU Control Register (Implementation defined) */
+
+#define SCU_CTRL_ENABLE              (1 << 0)         /* SCU enable */
+#define SCU_CTRL_ADDRFILTER          (1 << 1)         /* Address filtering 
enable */
+#define SCU_CTRL_RAMPARITY           (1 << 2)         /* SCU RAMs ECC enable */
+#define SCU_CTRL_LINFILL             (1 << 3)         /* SCU speculative 
linefill enable */
+#define SCU_CTRL_STANDBY             (1 << 5)         /* SCU standby enable */
+#define SCU_CTRL_ICSTANDBY           (1 << 6)         /* IC standby enable */
+#define SCU_CTRL_ECCCHKEN_M0         (1 << 12)        /* ECC check enable on 
M0 */
+#define SCU_CTRL_ECCCHKEN_M1         (1 << 13)        /* ECC check enable on 
M1 */
+#define SCU_CTRL_ECCCHKEN_MP         (1 << 14)        /* ECC check enable on 
MP */
+#define SCU_CTRL_ECCCHKEN_ACP        (1 << 15)        /* ECC check enable on 
ACP */
+#define SCU_CTRL_ECCCHKEN_FPP(n)     (1 << ((n)+16))  /* ECC check enable on 
FPP for core n */
+#define SCU_CTRL_ECCCHKEN_TCM        (1 << 20)        /* ECC check enable on 
AXI TCM */
+
+/* SCU Configuration Register (Implementation defined) */
+
+#define SCU_CONFIG_NCPUS_SHIFT       0         /* CPU number Number of CPUs 
present */
+#define SCU_CONFIG_NCPUS_MASK        (3 << SCU_CONFIG_NCPUS_SHIFT)
+#  define SCU_CONFIG_NCPUS(r)        ((((uint32_t)(r) &  
SCU_CONFIG_NCPUS_MASK) >> SCU_CONFIG_NCPUS_SHIFT) + 1)
+#define SCU_CONFIG_SMPCPUS_SHIFT     4         /* Processors that are in SMP 
or AMP mode */
+#define SCU_CONFIG_SMPCPUS_MASK      (15 << SCU_CONFIG_SMPCPUS_SHIFT)
+#  define SCU_CONFIG_CPU_SMP(n)      (1 << ((n)+4))
+#  define SCU_CONFIG_CPU0_SMP        (1 << 4)
+#  define SCU_CONFIG_CPU1_SMP        (1 << 5)
+#  define SCU_CONFIG_CPU2_SMP        (1 << 6)
+#  define SCU_CONFIG_CPU3_SMP        (1 << 7)
+
+#define SCU_CONFIG_CACHE_0KB         0
+#define SCU_CONFIG_CACHE_4KB         1
+#define SCU_CONFIG_CACHE_8KB         2
+#define SCU_CONFIG_CACHE_16KB        3
+#define SCU_CONFIG_CACHE_32KB        4
+#define SCU_CONFIG_CACHE_64KB        5
+
+#define SCU_CONFIG_CPU0_CACHE_SHIFT  8         /* CPU 0 cache size */
+#define SCU_CONFIG_CPU0_CACHE_MASK   (4 << SCU_CONFIG_CPU0_CACHE_SHIFT)
+#define SCU_CONFIG_CPU1_CACHE_SHIFT  12        /* CPU 1 cache size */
+#define SCU_CONFIG_CPU1_CACHE_MASK   (4 << SCU_CONFIG_CPU1_CACHE_SHIFT)
+#define SCU_CONFIG_CPU2_CACHE_SHIFT  16        /* CPU 2 cache size */
+#define SCU_CONFIG_CPU2_CACHE_MASK   (4 << SCU_CONFIG_CPU2_CACHE_SHIFT)
+#define SCU_CONFIG_CPU3_CACHE_SHIFT  20        /* CPU 3 cache size */
+#define SCU_CONFIG_CPU3_CACHE_MASK   (4 << SCU_CONFIG_CPU3_CACHE_SHIFT)
+
+#define SCU_CONFIG_AXI_PORT1_SHIFT   31
+
+/* SCU CPU Power Status Register */
+
+#define SCU_PWRSTATUS_NORMAL         0
+#define SCU_PWRSTATUS_DORMANT        2
+#define SCU_PWRSTATUS_PWROFF         3
+
+#define SCU_PWRSTATUS_CPU0_SHIFT     0         /* CPU0 status Power status */
+#define SCU_PWRSTATUS_CPU0_MASK      (3 << SCU_PWRSTATUS_CPU0_SHIFT)
+#define SCU_PWRSTATUS_CPU1_SHIFT     8         /* CPU1 status Power status */
+#define SCU_PWRSTATUS_CPU1_MASK      (3 << SCU_PWRSTATUS_CPU1_SHIFT)
+#define SCU_PWRSTATUS_CPU2_SHIFT     16        /* CPU2 status Power status */
+#define SCU_PWRSTATUS_CPU2_MASK      (3 << SCU_PWRSTATUS_CPU2_SHIFT)
+#define SCU_PWRSTATUS_CPU3_SHIFT     24        /* CPU3 status Power status */
+#define SCU_PWRSTATUS_CPU3_MASK      (3 << SCU_PWRSTATUS_CPU3_SHIFT)
+
+/* SCU Invalidate All Registers in Secure State */
+
+#define SCU_INVALIDATE_ALL_WAYS      15
+#define SCU_INVALIDATE_CPU0_SHIFT    0         /* Ways that must be 
invalidated for CPU0 */
+#define SCU_INVALIDATE_CPU0_MASK     (15 << SCU_INVALIDATE_CPU0_SHIFT)
+#define SCU_INVALIDATE_CPU1_SHIFT    4         /* Ways that must be 
invalidated for CPU1 */
+#define SCU_INVALIDATE_CPU1_MASK     (15 << SCU_INVALIDATE_CPU1_SHIFT)
+#define SCU_INVALIDATE_CPU2_SHIFT    8         /* Ways that must be 
invalidated for CPU2 */
+#define SCU_INVALIDATE_CPU2_MASK     (15 << SCU_INVALIDATE_CPU2_SHIFT)
+#define SCU_INVALIDATE_CPU3_SHIFT    12        /* Ways that must be 
invalidated for CPU3 */
+#define SCU_INVALIDATE_CPU3_MASK     (15 << SCU_INVALIDATE_CPU3_SHIFT)
+
+/* Filtering Start Address Register Defined by FILTERSTART input */
+
+#define SCU_FILTERSTART_SHIFT        20        /* Filtering start address */
+#define SCU_FILTERSTART_MASK         (0xfff << SCU_FILTERSTART_SHIFT)
+
+/* Filtering End Address Register Defined by FILTEREND input */
+
+#define SCU_FILTEREND_SHIFT          20        /* Filtering start address */
+#define SCU_FILTEREND_MASK           (0xfff << SCU_FILTEREND_SHIFT)
+
+/* LLP Filtering Start Address Register */
+
+#define SCU_LLPFILTERSTART_SHIFT     20
+#define SCU_LLPFILTERSTART_MASK      (0xfff << SCU_LLPFILTERSTART_SHIFT)
+
+/* LLP Filtering End Address Register */
+
+#define SCU_LLPFILTEREND_SHIFT       20
+#define SCU_LLPFILTEREND_MASK        (0xfff << SCU_LLPFILTEREND_SHIFT)
+
+/* SCU Access Control (SAC) Register */
+
+#define SCU_SAC_CPU(n)               (1 << (n)) /* CPUn may access components 
*/
+
+/* SCU Error Bank First Entry Register */
+
+#define SCU_ERRBANKFST_STATUS_SHIFT  0
+#define SCU_ERRBANKFST_STATUS_MASK   (3 << SCU_ERRBANKFST_STATUS_SHIFT)
+
+#define SCU_ERRBANKFST_WAYS_SHIFT(n) (16 + (n)*4)
+#define SCU_ERRBANKFST_WAYS_MASK(n)  (0xf << SCU_ERRBANKFST_WAYS_SHIFT(n))
+
+/* SCU Error Bank Second Entry Register */
+
+#define SCU_ERRBANKSND_STATUS_SHIFT  0
+#define SCU_ERRBANKSND_STATUS_MASK   (3 << SCU_ERRBANKSND_STATUS_SHIFT)
+
+#define SCU_ERRBANKSND_INDEX_SHIFT   5
+#define SCU_ERRBANKSND_INDEX_MASK    (0x1ff << SCU_ERRBANKSND_INDEX_SHIFT)
+
+#define SCU_ERRBANKSND_WAYS_SHIFT    16
+#define SCU_ERRBANKSND_WAYS_MASK     (0xffff << SCU_ERRBANKSND_WAYS_SHIFT)
+
+/* SCU Debug Tag RAM Operation Register */
+
+#define SCU_DEBUGRAM_READ            0
+#define SCU_DEBUGRAM_WRITE           1
+
+#define SCU_DEBUGRAM_INDEX_SHIFT     5
+#define SCU_DEBUGRAM_INDEX_MASK      (0x1ff << SCU_DEBUGRAM_INDEX_SHIFT)
+
+#define SCU_DEBUGRAM_CORE_SHIFT      24
+#define SCU_DEBUGRAM_CORE_MASK       (3 << SCU_DEBUGRAM_CORE_SHIFT)
+
+#define SCU_DEBUGRAM_WAY_SHIFT       30
+#define SCU_DEBUGRAM_WAY_MASK        (3 << SCU_DEBUGRAM_WAY_SHIFT)
+
+/* SCU Debug Tag RAM Data Value Register */
+
+#define SCU_DEBUGRAMDATA_VALUE_SHIFT 17
+#define SCU_DEBUGRAMDATA_VALUE_MASK  (0x1f << SCU_DEBUGRAMDATA_VALUE_SHIFT)
+
+#define SCU_DEBUGRAMDATA_VALID       (1 << 22)
+
+/* SCU Debug Tag RAM ECC Chunk Register */
+
+#define SCU_DEBUGRAMECC_CHUNK_SHIFT  0
+#define SCU_DEBUGRAMECC_CHUNK_MASK   (0x3f << SCU_DEBUGRAMECC_CHUNK_SHIFT)
+
+/* ECC Fatal Error Register */
+
+#define SCU_ECCERR_CORE_DETECTED(n)  (n)
+#define SCU_ECCERR_DETECTED          (1 << 8)
+
+/* FPP Filtering Start Address Registers 0-3 */
+
+#define SCU_FPPFILTERSTART_SHIFT     20
+#define SCU_FPPFILTERSTART_MASK      (0xfff << SCU_FPPFILTERSTART_SHIFT)
+
+/* FPP Filtering End Address Registers 0-3 */
+
+#define SCU_FPPFILTEREND_SHIFT       20
+#define SCU_FPPFILTEREND_MASK        (0xfff << SCU_FPPFILTEREND_SHIFT)
+
+/****************************************************************************
+ * Public Functions Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: arm_enable_smp
+ *
+ * Description:
+ *   Enable the SCU and make certain that current CPU is participating in
+ *   the SMP cache coherency.
+ *
+ ****************************************************************************/
+
+void arm_enable_smp(int cpu);
+
+#endif /* __ARCH_ARM_SRC_ARMV7_R_SCU_H */
diff --git a/arch/arm/src/armv7-r/smp.h b/arch/arm/src/armv7-r/smp.h
new file mode 100644
index 0000000000..b0d37fbff4
--- /dev/null
+++ b/arch/arm/src/armv7-r/smp.h
@@ -0,0 +1,128 @@
+/****************************************************************************
+ * arch/arm/src/armv7-r/smp.h
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+#ifndef __ARCH_ARM_SRC_ARMV7_R_SMP_H
+#define __ARCH_ARM_SRC_ARMV7_R_SMP_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#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_IDLETHREAD_STACKSIZE + 7) & ~7)
+#define SMP_STACK_WORDS      (SMP_STACK_SIZE >> 2)
+
+/****************************************************************************
+ * 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
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: __cpu[n]_start
+ *
+ * Description:
+ *   Boot functions for each CPU (other than CPU0).  These functions set up
+ *   the ARM operating mode, the initial stack, and configure co-processor
+ *   registers.  At the end of the boot, arm_cpu_boot() is called.
+ *
+ *   These functions are provided by the common ARMv7-R logic.
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   Do not return.
+ *
+ ****************************************************************************/
+
+#if CONFIG_SMP_NCPUS > 1
+void __cpu1_start(void);
+#endif
+
+#if CONFIG_SMP_NCPUS > 2
+void __cpu2_start(void);
+#endif
+
+#if CONFIG_SMP_NCPUS > 3
+void __cpu3_start(void);
+#endif
+
+#if CONFIG_SMP_NCPUS > 4
+#  error This logic needs to extended for CONFIG_SMP_NCPUS > 4
+#endif
+
+/****************************************************************************
+ * Name: arm_cpu_boot
+ *
+ * Description:
+ *   Continues the C-level initialization started by the assembly language
+ *   __cpu[n]_start function.  At a minimum, this function needs to
+ *   initialize interrupt handling and, perhaps, wait on WFI for
+ *   arm_cpu_start() to issue an SGI.
+ *
+ *   This function must be provided by the each ARMv7-R MCU and implement
+ *   MCU-specific initialization logic.
+ *
+ * Input Parameters:
+ *   cpu - The CPU index.  This is the same value that would be obtained by
+ *      calling up_cpu_index();
+ *
+ * Returned Value:
+ *   Does not return.
+ *
+ ****************************************************************************/
+
+void arm_cpu_boot(int cpu);
+
+#endif /* __ASSEMBLY__ */
+#endif /* CONFIG_SMP */
+#endif /* __ARCH_ARM_SRC_ARMV7_R_SMP_H */

Reply via email to