You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by ha...@apache.org on 2022/07/14 13:35:55 UTC
[incubator-nuttx] branch master updated: arch: arm64: ARMv8-A support for NuttX
This is an automated email from the ASF dual-hosted git repository.
hartmannathan pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git
The following commit(s) were added to refs/heads/master by this push:
new e77b06721b arch: arm64: ARMv8-A support for NuttX
e77b06721b is described below
commit e77b06721b18225b3b1e8414a7750d3e5038c095
Author: qinwei1 <qi...@xiaomi.com>
AuthorDate: Sat Jun 18 04:26:10 2022 -0700
arch: arm64: ARMv8-A support for NuttX
N/A
Summary:
Arm64 support for NuttX, Features supported:
1. Cortex-a53 single core and SMP support: it's can run into nsh shell at
qemu virt machine.
2. qemu-a53 board configuration support: it's only for evaluate propose
3. FPU support for armv8-a: FPU context switching at NEON/floating-point
TRAP is supported.
4. psci interface, armv8 cache operation(data cache) and smccc support.
5. fix mass code style issue, thank for @xiaoxiang781216, @hartmannathan @pkarashchenko
Please refer to boards/arm64/qemu/qemu-a53/README.txt for detail
Note:
1. GCC MACOS issue
The GCC 11.2 toolchain for MACOS may get crash while compiling
float operation function, the following link describe the issue
and give analyse at the issue:
https://bugs.linaro.org/show_bug.cgi?id=5825
it's seem GCC give a wrong instruction at certain machine which
without architecture features
the new toolchain is not available still, so just disable the MACOS
cibuild check at present
Signed-off-by: qinwei1 <qi...@xiaomi.com>
---
arch/Kconfig | 16 +
arch/arm64/Kconfig | 78 ++
arch/arm64/include/.gitignore | 2 +
arch/arm64/include/arch.h | 139 ++++
arch/arm64/include/inttypes.h | 119 +++
arch/arm64/include/irq.h | 406 ++++++++++
arch/arm64/include/limits.h | 82 ++
arch/arm64/include/qemu/chip.h | 51 ++
arch/arm64/include/qemu/irq.h | 34 +
arch/arm64/include/spinlock.h | 90 +++
arch/arm64/include/stdarg.h | 45 ++
arch/arm64/include/syscall.h | 391 +++++++++
arch/arm64/include/types.h | 110 +++
arch/arm64/src/.gitignore | 2 +
arch/arm64/src/Makefile | 205 +++++
arch/arm64/src/Toolchain.defs | 139 ++++
arch/arm64/src/common/Make.defs | 97 +++
arch/arm64/src/common/addrenv.h | 102 +++
arch/arm64/src/common/arm64_allocateheap.c | 163 ++++
arch/arm64/src/common/arm64_arch.h | 548 +++++++++++++
arch/arm64/src/common/arm64_arch_timer.c | 233 ++++++
arch/arm64/src/common/arm64_arch_timer.h | 58 ++
arch/arm64/src/common/arm64_assert.c | 583 ++++++++++++++
arch/arm64/src/common/arm64_backtrace.c | 184 +++++
arch/arm64/src/common/arm64_blocktask.c | 162 ++++
arch/arm64/src/common/arm64_boot.c | 184 +++++
arch/arm64/src/common/arm64_cache.c | 458 +++++++++++
arch/arm64/src/common/arm64_checkstack.c | 239 ++++++
arch/arm64/src/common/arm64_copystate.c | 121 +++
arch/arm64/src/common/arm64_cpu_idle.S | 70 ++
arch/arm64/src/common/arm64_cpu_psci.c | 188 +++++
arch/arm64/src/common/arm64_cpu_psci.h | 104 +++
arch/arm64/src/common/arm64_cpuidlestack.c | 112 +++
arch/arm64/src/common/arm64_cpuindex.c | 68 ++
arch/arm64/src/common/arm64_cpupause.c | 335 ++++++++
arch/arm64/src/common/arm64_cpustart.c | 266 +++++++
arch/arm64/src/common/arm64_createstack.c | 205 +++++
arch/arm64/src/common/arm64_doirq.c | 156 ++++
arch/arm64/src/common/arm64_exit.c | 158 ++++
arch/arm64/src/common/arm64_fatal.c | 365 +++++++++
arch/arm64/src/common/arm64_fatal.h | 83 ++
arch/arm64/src/common/arm64_fpu.c | 242 ++++++
arch/arm64/src/common/arm64_fpu.h | 74 ++
arch/arm64/src/common/arm64_fpu_func.S | 101 +++
arch/arm64/src/common/arm64_gic.h | 319 ++++++++
arch/arm64/src/common/arm64_gicv3.c | 613 ++++++++++++++
arch/arm64/src/common/arm64_head.S | 306 +++++++
arch/arm64/src/common/arm64_idle.c | 62 ++
arch/arm64/src/common/arm64_initialize.c | 178 +++++
arch/arm64/src/common/arm64_initialstate.c | 151 ++++
arch/arm64/src/common/arm64_internal.h | 364 +++++++++
arch/arm64/src/common/arm64_macro.inc | 82 ++
arch/arm64/src/common/arm64_mmu.c | 622 +++++++++++++++
arch/arm64/src/common/arm64_mmu.h | 254 ++++++
arch/arm64/src/common/arm64_releasepending.c | 125 +++
arch/arm64/src/common/arm64_releasestack.c | 114 +++
arch/arm64/src/common/arm64_reprioritizertr.c | 182 +++++
arch/arm64/src/common/arm64_schedulesigaction.c | 361 +++++++++
arch/arm64/src/common/arm64_sigdeliver.c | 159 ++++
arch/arm64/src/common/arm64_smccc.S | 74 ++
arch/arm64/src/common/arm64_smp.h | 83 ++
arch/arm64/src/common/arm64_stackframe.c | 100 +++
arch/arm64/src/common/arm64_syscall.c | 540 +++++++++++++
arch/arm64/src/common/arm64_task_sched.c | 119 +++
arch/arm64/src/common/arm64_testset.S | 94 +++
arch/arm64/src/common/arm64_unblocktask.c | 144 ++++
arch/arm64/src/common/arm64_usestack.c | 130 +++
arch/arm64/src/common/arm64_vector_table.S | 278 +++++++
arch/arm64/src/common/arm64_vectors.S | 438 ++++++++++
arch/arm64/src/common/arm64_vfork.c | 248 ++++++
arch/arm64/src/common/arm64_vfork.h | 89 +++
arch/arm64/src/common/arm64_vfork_func.S | 131 +++
arch/arm64/src/common/barriers.h | 67 ++
arch/arm64/src/common/crt0.c | 138 ++++
arch/arm64/src/qemu/Kconfig | 30 +
arch/arm64/src/qemu/Make.defs | 26 +
arch/arm64/src/qemu/chip.h | 42 +
arch/arm64/src/qemu/qemu_boot.c | 112 +++
arch/arm64/src/qemu/qemu_boot.h | 80 ++
arch/arm64/src/qemu/qemu_lowputc.S | 101 +++
arch/arm64/src/qemu/qemu_serial.c | 878 +++++++++++++++++++++
arch/arm64/src/qemu/qemu_serial.h | 75 ++
boards/Kconfig | 13 +
boards/arm64/qemu/qemu-a53/Kconfig | 7 +
boards/arm64/qemu/qemu-a53/README.txt | 312 ++++++++
boards/arm64/qemu/qemu-a53/configs/nsh/defconfig | 65 ++
.../arm64/qemu/qemu-a53/configs/nsh_smp/defconfig | 66 ++
.../arm64/qemu/qemu-a53/include/board_memorymap.h | 59 ++
boards/arm64/qemu/qemu-a53/scripts/Make.defs | 48 ++
boards/arm64/qemu/qemu-a53/scripts/dramboot.ld | 126 +++
boards/arm64/qemu/qemu-a53/src/Makefile | 29 +
boards/arm64/qemu/qemu-a53/src/qemu-a53.h | 59 ++
boards/arm64/qemu/qemu-a53/src/qemu_appinit.c | 76 ++
boards/arm64/qemu/qemu-a53/src/qemu_boardinit.c | 113 +++
boards/arm64/qemu/qemu-a53/src/qemu_bringup.c | 62 ++
tools/ci/testlist/macos.dat | 6 +
tools/ci/testlist/other.dat | 2 +
97 files changed, 16520 insertions(+)
diff --git a/arch/Kconfig b/arch/Kconfig
index 079776bd28..e4461c0323 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -22,6 +22,20 @@ config ARCH_ARM
---help---
The ARM architectures
+config ARCH_ARM64
+ bool "ARM64"
+ select ARCH_HAVE_BACKTRACE
+ select ARCH_HAVE_INTERRUPTSTACK
+ select ARCH_HAVE_VFORK
+ select ARCH_HAVE_STACKCHECK
+ select ARCH_HAVE_CUSTOMOPT
+ select ARCH_HAVE_STDARG_H
+ select ARCH_HAVE_SYSCALL_HOOKS
+ select ARCH_HAVE_RDWR_MEM_CPU_RUN
+ select ARCH_HAVE_THREAD_LOCAL
+ ---help---
+ The ARM64 architectures
+
config ARCH_AVR
bool "AVR"
select ARCH_NOINTC
@@ -147,6 +161,7 @@ endchoice
config ARCH
string
default "arm" if ARCH_ARM
+ default "arm64" if ARCH_ARM64
default "avr" if ARCH_AVR
default "hc" if ARCH_HC
default "mips" if ARCH_MIPS
@@ -162,6 +177,7 @@ config ARCH
default "sparc" if ARCH_SPARC
source "arch/arm/Kconfig"
+source "arch/arm64/Kconfig"
source "arch/avr/Kconfig"
source "arch/hc/Kconfig"
source "arch/mips/Kconfig"
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
new file mode 100644
index 0000000000..a693521e3c
--- /dev/null
+++ b/arch/arm64/Kconfig
@@ -0,0 +1,78 @@
+#
+# For a description of the syntax of this configuration file,
+# see the file kconfig-language.txt in the NuttX tools repository.
+#
+
+if ARCH_ARM64
+comment "ARM64 Options"
+
+choice
+ prompt "ARM64 chip selection"
+ default ARCH_CHIP_QEMU
+
+config ARCH_CHIP_QEMU
+ bool "QEMU virt platform (cortex-a53)"
+ select ARCH_CORTEX_A53
+ select ARCH_HAVE_ADDRENV
+ select ARCH_NEED_ADDRENV_MAPPING
+ ---help---
+ QEMU virt platform (cortex-a53)
+
+endchoice
+
+config ARCH_ARMV8A
+ bool
+ default n
+
+config ARCH_ARMV8R
+ bool
+ default n
+
+config ARCH_CORTEX_A53
+ bool
+ default n
+ select ARCH_ARMV8A
+ select ARM_HAVE_NEON
+ select ARCH_HAVE_TRUSTZONE
+ select ARCH_DCACHE
+ select ARCH_ICACHE
+ select ARCH_HAVE_MMU
+ select ARCH_HAVE_FPU
+ select ARCH_HAVE_TESTSET
+
+config ARCH_CORTEX_R82
+ bool
+ default n
+ select ARCH_ARMV8R
+ select ARCH_DCACHE
+ select ARCH_ICACHE
+ select ARCH_HAVE_MPU
+ select ARCH_HAVE_TESTSET
+
+config ARCH_FAMILY
+ string
+ default "armv8-a" if ARCH_ARMV8A
+ default "armv8-r" if ARCH_ARMV8R
+
+config ARCH_CHIP
+ string
+ default "qemu" if ARCH_CHIP_QEMU
+
+config ARCH_HAVE_TRUSTZONE
+ bool
+ default n
+ ---help---
+ Automatically selected to indicate that the ARM CPU supports
+ TrustZone.
+
+config ARM_HAVE_NEON
+ bool
+ default n
+ ---help---
+ Decide whether support NEON instruction
+
+if ARCH_CHIP_QEMU
+source "arch/arm64/src/qemu/Kconfig"
+endif
+
+endif # ARCH_ARM64
diff --git a/arch/arm64/include/.gitignore b/arch/arm64/include/.gitignore
new file mode 100644
index 0000000000..af8911db06
--- /dev/null
+++ b/arch/arm64/include/.gitignore
@@ -0,0 +1,2 @@
+/board
+/chip
diff --git a/arch/arm64/include/arch.h b/arch/arm64/include/arch.h
new file mode 100644
index 0000000000..d8673a12e0
--- /dev/null
+++ b/arch/arm64/include/arch.h
@@ -0,0 +1,139 @@
+/****************************************************************************
+ * arch/arm64/include/arch.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.
+ *
+ ****************************************************************************/
+
+/* This file should never be included directly but, rather,
+ * only indirectly through nuttx/arch.h
+ */
+
+#ifndef __ARCH_ARM64_INCLUDE_ARCH_H
+#define __ARCH_ARM64_INCLUDE_ARCH_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#ifndef __ASSEMBLY__
+# include <stdint.h>
+# include <nuttx/pgalloc.h>
+# include <nuttx/addrenv.h>
+#endif
+
+/****************************************************************************
+ * Pre-processor Prototypes
+ ****************************************************************************/
+
+#ifdef CONFIG_ARCH_ADDRENV
+#if CONFIG_MM_PGSIZE != 4096
+# error Only pages sizes of 4096 are currently supported (CONFIG_ARCH_ADDRENV)
+#endif
+
+#endif /* CONFIG_ARCH_ADDRENV */
+
+/****************************************************************************
+ * Inline functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+#ifdef CONFIG_ARCH_ADDRENV
+/* The task group resources are retained in a single structure, task_group_s
+ * that is defined in the header file nuttx/include/nuttx/sched.h. The type
+ * group_addrenv_t must be defined by platform specific logic in
+ * nuttx/arch/<architecture>/include/arch.h.
+ *
+ * These tables would hold the physical address of the level 2 page tables.
+ * All would be initially NULL and would not be backed up with physical
+ * memory until mappings in the level 2 page table are required.
+ */
+
+struct group_addrenv_s
+{
+ /* Level 1 page table entries for each group section */
+
+ uintptr_t *text[ARCH_TEXT_NSECTS];
+ uintptr_t *data[ARCH_DATA_NSECTS];
+#ifdef CONFIG_BUILD_KERNEL
+ uintptr_t *heap[ARCH_HEAP_NSECTS];
+#ifdef CONFIG_MM_SHM
+ uintptr_t *shm[ARCH_SHM_NSECTS];
+#endif
+
+ /* Initial heap allocation (in bytes). This exists only provide an
+ * indirect path for passing the size of the initial heap to the heap
+ * initialization logic. These operations are separated in time and
+ * architecture. REVISIT: I would like a better way to do this.
+ */
+
+ size_t heapsize;
+#endif
+};
+
+typedef struct group_addrenv_s group_addrenv_t;
+
+/* This type is used when the OS needs to temporarily instantiate a
+ * different address environment. Used in the implementation of
+ *
+ * int up_addrenv_select(group_addrenv_t addrenv, save_addrenv_t *oldenv);
+ * int up_addrenv_restore(save_addrenv_t oldenv);
+ *
+ * In this case, the saved value in the L1 page table are returned
+ */
+
+struct save_addrenv_s
+{
+ uint32_t text[ARCH_TEXT_NSECTS];
+ uint32_t data[ARCH_DATA_NSECTS];
+#ifdef CONFIG_BUILD_KERNEL
+ uint32_t heap[ARCH_HEAP_NSECTS];
+#ifdef CONFIG_MM_SHM
+ uint32_t shm[ARCH_SHM_NSECTS];
+#endif
+#endif
+};
+
+typedef struct save_addrenv_s save_addrenv_t;
+#endif
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+#ifdef __cplusplus
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+#undef EXTERN
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __ARCH_ARM64_INCLUDE_ARCH_H */
diff --git a/arch/arm64/include/inttypes.h b/arch/arm64/include/inttypes.h
new file mode 100644
index 0000000000..0acba98ef8
--- /dev/null
+++ b/arch/arm64/include/inttypes.h
@@ -0,0 +1,119 @@
+/****************************************************************************
+ * arch/arm64/include/inttypes.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_ARM64_INCLUDE_INTTYPES_H
+#define __ARCH_ARM64_INCLUDE_INTTYPES_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define PRId8 "d"
+#define PRId16 "d"
+#define PRId32 "d"
+#define PRId64 "ld"
+
+#define PRIdPTR "ld"
+
+#define PRIi8 "i"
+#define PRIi16 "i"
+#define PRIi32 "i"
+#define PRIi64 "li"
+
+#define PRIiPTR "li"
+
+#define PRIo8 "o"
+#define PRIo16 "o"
+#define PRIo32 "o"
+#define PRIo64 "lo"
+
+#define PRIoPTR "lo"
+
+#define PRIu8 "u"
+#define PRIu16 "u"
+#define PRIu32 "u"
+#define PRIu64 "lu"
+
+#define PRIuPTR "lu"
+
+#define PRIx8 "x"
+#define PRIx16 "x"
+#define PRIx32 "x"
+#define PRIx64 "lx"
+
+#define PRIxPTR "lx"
+
+#define PRIX8 "X"
+#define PRIX16 "X"
+#define PRIX32 "X"
+#define PRIX64 "lX"
+
+#define PRIXPTR "lX"
+
+#define SCNd8 "hhd"
+#define SCNd16 "hd"
+#define SCNd32 "d"
+#define SCNd64 "ld"
+
+#define SCNdPTR "ld"
+
+#define SCNi8 "hhi"
+#define SCNi16 "hi"
+#define SCNi32 "i"
+#define SCNi64 "li"
+
+#define SCNiPTR "li"
+
+#define SCNo8 "hho"
+#define SCNo16 "ho"
+#define SCNo32 "o"
+#define SCNo64 "lo"
+
+#define SCNoPTR "lo"
+
+#define SCNu8 "hhu"
+#define SCNu16 "hu"
+#define SCNu32 "u"
+#define SCNu64 "lu"
+
+#define SCNuPTR "lu"
+
+#define SCNx8 "hhx"
+#define SCNx16 "hx"
+#define SCNx32 "x"
+#define SCNx64 "lx"
+
+#define SCNxPTR "lx"
+
+#define INT8_C(x) x
+#define INT16_C(x) x
+#define INT32_C(x) x
+#define INT64_C(x) x ## l
+
+#define UINT8_C(x) x
+#define UINT16_C(x) x
+#define UINT32_C(x) x ## u
+#define UINT64_C(x) x ## ul
+
+#endif /* __ARCH_ARM64_INCLUDE_INTTYPES_H */
diff --git a/arch/arm64/include/irq.h b/arch/arm64/include/irq.h
new file mode 100644
index 0000000000..5e5fa781fb
--- /dev/null
+++ b/arch/arm64/include/irq.h
@@ -0,0 +1,406 @@
+/****************************************************************************
+ * arch/arm64/include/irq.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.
+ *
+ ****************************************************************************/
+
+/* This file should never be included directly but, rather, only indirectly
+ * through nuttx/irq.h
+ */
+
+#ifndef __ARCH_ARM64_INCLUDE_IRQ_H
+#define __ARCH_ARM64_INCLUDE_IRQ_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <sys/types.h>
+
+#ifndef __ASSEMBLY__
+# include <stdint.h>
+#endif
+
+/* Include NuttX-specific IRQ definitions */
+
+#include <nuttx/irq.h>
+
+/* Include chip-specific IRQ definitions (including IRQ numbers) */
+
+#include <arch/chip/irq.h>
+
+#ifndef __ASSEMBLY__
+# include <stdint.h>
+#endif
+
+/****************************************************************************
+ * Pre-processor Prototypes
+ ****************************************************************************/
+
+#define up_getsp() (uintptr_t)__builtin_frame_address(0)
+
+/****************************************************************************
+ * Exception stack frame format:
+ *
+ * x0 ~ x18, x30 (lr), spsr and elr
+ * Corruptible Registers and exception context
+ * reference to Armv8-A Instruction Set Architecture
+ * (ARM062-948681440-3280, Issue 1.1), chapter 11 PCS
+ * need to be saved in all exception
+ *
+ * x19 ~ x29, sp_el0, sp_elx
+ * Callee-saved Registers and SP pointer
+ * reference to Armv8-A Instruction Set Architecture
+ * (ARM062-948681440-3280, Issue 1.1), chapter 11 PCS
+ * These registers frame is allocated on stack frame
+ * when a exception is occurred and saved at task switch
+ * or crash exception
+ * check arm64_vectors.S for detail
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Registers and exception context
+ * Note:
+ * REG_EXEC_DEPTH indicate the task's exception depth
+ *
+ ****************************************************************************/
+
+#define REG_X0 (0)
+#define REG_X1 (1)
+#define REG_X2 (2)
+#define REG_X3 (3)
+#define REG_X4 (4)
+#define REG_X5 (5)
+#define REG_X6 (6)
+#define REG_X7 (7)
+#define REG_X8 (8)
+#define REG_X9 (9)
+#define REG_X10 (10)
+#define REG_X11 (11)
+#define REG_X12 (12)
+#define REG_X13 (13)
+#define REG_X14 (14)
+#define REG_X15 (15)
+#define REG_X16 (16)
+#define REG_X17 (17)
+#define REG_X18 (18)
+#define REG_X19 (19)
+#define REG_X20 (20)
+#define REG_X21 (21)
+#define REG_X22 (22)
+#define REG_X23 (23)
+#define REG_X24 (24)
+#define REG_X25 (25)
+#define REG_X26 (26)
+#define REG_X27 (27)
+#define REG_X28 (28)
+#define REG_X29 (29)
+#define REG_X30 (30)
+#define REG_SP_ELX (31)
+#define REG_ELR (32)
+#define REG_SPSR (33)
+#define REG_SP_EL0 (34)
+#define REG_EXE_DEPTH (35)
+#define REG_TPIDR_EL0 (36)
+#define REG_TPIDR_EL1 (37)
+
+/* In Armv8-A Architecture, the stack must align with 16 byte */
+
+#define XCPTCONTEXT_GP_REGS (38)
+#define XCPTCONTEXT_GP_SIZE (8 * XCPTCONTEXT_GP_REGS)
+
+#ifdef CONFIG_ARCH_FPU
+
+/****************************************************************************
+ * q0 ~ q31(128bit), fpsr, fpcr
+ * armv8 fpu registers and context
+ * With CONFIG_ARCH_FPU is enabled, armv8 fpu registers context
+ * is allocated on stack frame at exception and store/restore
+ * when switching FPU context
+ * check arm64_fpu.c for detail
+ *
+ ****************************************************************************/
+
+/* 128bit registers */
+
+#define FPU_REG_Q0 (0)
+#define FPU_REG_Q1 (1)
+#define FPU_REG_Q2 (2)
+#define FPU_REG_Q3 (3)
+#define FPU_REG_Q4 (4)
+#define FPU_REG_Q5 (5)
+#define FPU_REG_Q6 (6)
+#define FPU_REG_Q7 (7)
+#define FPU_REG_Q8 (8)
+#define FPU_REG_Q9 (9)
+#define FPU_REG_Q10 (10)
+#define FPU_REG_Q11 (11)
+#define FPU_REG_Q12 (12)
+#define FPU_REG_Q13 (13)
+#define FPU_REG_Q14 (14)
+#define FPU_REG_Q15 (15)
+#define FPU_REG_Q16 (16)
+#define FPU_REG_Q17 (17)
+#define FPU_REG_Q18 (18)
+#define FPU_REG_Q19 (19)
+#define FPU_REG_Q20 (20)
+#define FPU_REG_Q21 (21)
+#define FPU_REG_Q22 (22)
+#define FPU_REG_Q23 (23)
+#define FPU_REG_Q24 (24)
+#define FPU_REG_Q25 (25)
+#define FPU_REG_Q26 (26)
+#define FPU_REG_Q27 (27)
+#define FPU_REG_Q28 (28)
+#define FPU_REG_Q29 (29)
+#define FPU_REG_Q30 (30)
+#define FPU_REG_Q31 (31)
+
+/* 32 bit registers
+ */
+#define FPU_REG_FPSR (0)
+#define FPU_REG_FPCR (1)
+
+/* FPU registers(Q0~Q31, 128bit): 32x2 = 64
+ * FPU FPSR/SPSR(32 bit) : 1
+ * FPU TRAP: 1
+ * 64 + 1 + 1 = 66
+ */
+#define XCPTCONTEXT_FPU_REGS (66)
+#else
+#define XCPTCONTEXT_FPU_REGS (0)
+#endif
+
+#define FPUCONTEXT_SIZE (8 * XCPTCONTEXT_FPU_REGS)
+
+#define XCPTCONTEXT_REGS (XCPTCONTEXT_GP_REGS + XCPTCONTEXT_FPU_REGS)
+#define XCPTCONTEXT_SIZE (8 * XCPTCONTEXT_REGS)
+
+#ifndef __ASSEMBLY__
+
+#ifdef __cplusplus
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/* g_current_regs[] holds a references to the current interrupt level
+ * register storage structure. If is non-NULL only during interrupt
+ * processing. Access to g_current_regs[] must be through the macro
+ * CURRENT_REGS for portability.
+ */
+
+/* For the case of architectures with multiple CPUs, then there must be one
+ * such value for each processor that can receive an interrupt.
+ */
+
+EXTERN volatile uint64_t *g_current_regs[CONFIG_SMP_NCPUS];
+#define CURRENT_REGS (g_current_regs[up_cpu_index()])
+
+struct xcptcontext
+{
+ /* The following function pointer is non-zero if there are pending signals
+ * to be processed.
+ */
+
+ void *sigdeliver; /* Actual type is sig_deliver_t */
+
+#ifdef CONFIG_BUILD_KERNEL
+ /* This is the saved address to use when returning from a user-space
+ * signal handler.
+ */
+
+ uintptr_t sigreturn;
+
+#endif
+ /* task stack reg context */
+
+ uint64_t *regs;
+
+ /* task context, for signal process */
+
+ uint64_t *saved_reg;
+
+#ifdef CONFIG_ARCH_FPU
+ uint64_t *fpu_regs;
+ uint64_t *saved_fpu_regs;
+#endif
+
+ /* Extra fault address register saved for common paging logic. In the
+ * case of the pre-fetch abort, this value is the same as regs[REG_ELR];
+ * For the case of the data abort, this value is the value of the fault
+ * address register (FAR) at the time of data abort exception.
+ */
+
+#ifdef CONFIG_PAGING
+ uintptr_t far;
+#endif
+
+#ifdef CONFIG_ARCH_ADDRENV
+# ifdef CONFIG_ARCH_STACK_DYNAMIC
+ /* This array holds the physical address of the level 2 page table used
+ * to map the thread's stack memory. This array will be initially of
+ * zeroed and would be back-up up with pages during page fault exception
+ * handling to support dynamically sized stacks for each thread.
+ */
+
+ uintptr_t *ustack[ARCH_STACK_NSECTS];
+# endif
+
+# ifdef CONFIG_ARCH_KERNEL_STACK
+ /* In this configuration, all syscalls execute from an internal kernel
+ * stack. Why? Because when we instantiate and initialize the address
+ * environment of the new user process, we will temporarily lose the
+ * address environment of the old user process, including its stack
+ * contents. The kernel C logic will crash immediately with no valid
+ * stack in place.
+ */
+
+ uintptr_t *ustkptr; /* Saved user stack pointer */
+ uintptr_t *kstack; /* Allocate base of the (aligned) kernel stack */
+ uintptr_t *kstkptr; /* Saved kernel stack pointer */
+# endif
+#endif
+};
+
+/* Name: up_irq_save, up_irq_restore, and friends.
+ *
+ * NOTE: This function should never be called from application code and,
+ * as a general rule unless you really know what you are doing, this
+ * function should not be called directly from operation system code either:
+ * Typically, the wrapper functions, enter_critical_section() and
+ * leave_critical section(), are probably what you really want.
+ */
+
+/* Return the current IRQ state */
+
+static inline irqstate_t irqstate(void)
+{
+ irqstate_t flags;
+
+ __asm__ __volatile__("mrs %0, daif" : "=r" (flags):: "memory");
+
+ return flags;
+}
+
+/* Disable IRQs and return the previous IRQ state */
+
+static inline irqstate_t up_irq_save(void)
+{
+ irqstate_t flags;
+
+ __asm__ __volatile__
+ (
+ "mrs %0, daif\n"
+ "msr daifset, #2\n"
+ : "=r" (flags)
+ :
+ : "memory"
+ );
+
+ return flags;
+}
+
+/* Enable IRQs and return the previous IRQ state */
+
+static inline irqstate_t up_irq_enable(void)
+{
+ irqstate_t flags;
+
+ __asm__ __volatile__
+ (
+ "mrs %0, daif\n"
+ "msr daifclr, #2\n"
+ : "=r" (flags)
+ :
+ : "memory"
+ );
+ return flags;
+}
+
+/* Restore saved IRQ & FIQ state */
+
+static inline void up_irq_restore(irqstate_t flags)
+{
+ __asm__ __volatile__("msr daif, %0" :: "r" (flags): "memory");
+}
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * 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.
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_SMP
+int up_cpu_index(void);
+#else
+# define up_cpu_index() (0)
+#endif
+
+/****************************************************************************
+ * Name: up_interrupt_context
+ *
+ * Description: Return true is we are currently executing in
+ * the interrupt handler context.
+ *
+ ****************************************************************************/
+
+static inline bool up_interrupt_context(void)
+{
+#ifdef CONFIG_SMP
+ irqstate_t flags = up_irq_save();
+#endif
+
+ bool ret = (CURRENT_REGS != NULL);
+
+#ifdef CONFIG_SMP
+ up_irq_restore(flags);
+#endif
+
+ return ret;
+}
+
+#undef EXTERN
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* __ARCH_ARM64_INCLUDE_IRQ_H */
diff --git a/arch/arm64/include/limits.h b/arch/arm64/include/limits.h
new file mode 100644
index 0000000000..600e8f178c
--- /dev/null
+++ b/arch/arm64/include/limits.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+ * arch/arm64/include/limits.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_ARM64_INCLUDE_LIMITS_H
+#define __ARCH_ARM64_INCLUDE_LIMITS_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+/****************************************************************************
+ * Pre-processor Prototypes
+ ****************************************************************************/
+
+#define CHAR_BIT 8
+#define SCHAR_MIN (-SCHAR_MAX - 1)
+#define SCHAR_MAX 127
+#define UCHAR_MAX 255
+
+/* These could be different on machines where char is unsigned */
+
+#ifdef __CHAR_UNSIGNED__
+# define CHAR_MIN 0
+# define CHAR_MAX UCHAR_MAX
+#else
+# define CHAR_MIN SCHAR_MIN
+# define CHAR_MAX SCHAR_MAX
+#endif
+
+#define SHRT_MIN (-SHRT_MAX - 1)
+#define SHRT_MAX 32767
+#define USHRT_MAX 65535U
+
+#define INT_MIN (-INT_MAX - 1)
+#define INT_MAX 2147483647
+#define UINT_MAX 4294967295U
+
+/* For 64-bit arm64 with LP64, long is identical to long long */
+
+#define LONG_MIN LLONG_MIN
+#define LONG_MAX LLONG_MAX
+#define ULONG_MAX ULLONG_MAX
+
+#define LLONG_MIN (-LLONG_MAX - 1)
+#define LLONG_MAX 9223372036854775807LL
+#define ULLONG_MAX 18446744073709551615ULL
+
+/* A pointer is 8 bytes */
+
+#define PTR_MIN (-PTR_MAX - 1)
+#define PTR_MAX LLONG_MAX
+#define UPTR_MAX ULLONG_MAX
+
+#if !defined(__WCHAR_TYPE__)
+# define WCHAR_MIN INT_MIN
+# define WCHAR_MAX INT_MAX
+#elif defined(__WCHAR_UNSIGNED__)
+# define WCHAR_MIN 0
+# define WCHAR_MAX __WCHAR_MAX__
+#else
+# define WCHAR_MIN (-__WCHAR_MAX__ - 1)
+# define WCHAR_MAX __WCHAR_MAX__
+#endif
+
+#endif /* __ARCH_ARM64_INCLUDE_LIMITS_H */
diff --git a/arch/arm64/include/qemu/chip.h b/arch/arm64/include/qemu/chip.h
new file mode 100644
index 0000000000..e504249c3c
--- /dev/null
+++ b/arch/arm64/include/qemu/chip.h
@@ -0,0 +1,51 @@
+/****************************************************************************
+ * arch/arm64/include/qemu/chip.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_ARM64_INCLUDE_QEMU_CHIP_H
+#define __ARCH_ARM64_INCLUDE_QEMU_CHIP_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+/* Number of bytes in @p x kibibytes/mebibytes/gibibytes */
+
+#define KB(x) ((x) << 10)
+#define MB(x) (KB(x) << 10)
+#define GB(x) (MB(UINT64_C(x)) << 10)
+
+#if defined(CONFIG_ARCH_CHIP_QEMU_A53)
+
+#define CONFIG_GICD_BASE 0x8000000
+#define CONFIG_GICR_BASE 0x80a0000
+
+#define CONFIG_RAMBANK1_ADDR 0x40000000
+#define CONFIG_RAMBANK1_SIZE MB(128)
+
+#define CONFIG_DEVICEIO_BASEADDR 0x7000000
+#define CONFIG_DEVICEIO_SIZE MB(512)
+
+#define CONFIG_LOAD_BASE 0x40280000
+
+#endif
+
+#endif /* __ARCH_ARM64_INCLUDE_QEMU_CHIP_H */
diff --git a/arch/arm64/include/qemu/irq.h b/arch/arm64/include/qemu/irq.h
new file mode 100644
index 0000000000..cbff0135ce
--- /dev/null
+++ b/arch/arm64/include/qemu/irq.h
@@ -0,0 +1,34 @@
+/****************************************************************************
+ * arch/arm64/include/qemu/irq.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.
+ *
+ ****************************************************************************/
+
+/* This file should never be included directly but, rather,
+ * only indirectly through nuttx/irq.h
+ */
+
+#ifndef __ARCH_ARM64_INCLUDE_QEMU_IRQ_H
+#define __ARCH_ARM64_INCLUDE_QEMU_IRQ_H
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define NR_IRQS 220 /* Total number of interrupts */
+
+#endif /* __ARCH_ARM64_INCLUDE_QEMU_IRQ_H */
diff --git a/arch/arm64/include/spinlock.h b/arch/arm64/include/spinlock.h
new file mode 100644
index 0000000000..5eee94bb55
--- /dev/null
+++ b/arch/arm64/include/spinlock.h
@@ -0,0 +1,90 @@
+/****************************************************************************
+ * arch/arm64/include/spinlock.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_ARM64_INCLUDE_SPINLOCK_H
+#define __ARCH_ARM64_INCLUDE_SPINLOCK_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#ifndef __ASSEMBLY__
+# include <stdint.h>
+#endif /* __ASSEMBLY__ */
+
+/****************************************************************************
+ * Pre-processor Prototypes
+ ****************************************************************************/
+
+/* Spinlock states */
+
+#define SP_UNLOCKED 0 /* The Un-locked state */
+#define SP_LOCKED 1 /* The Locked state */
+
+/* Memory barriers for use with NuttX spinlock logic
+ *
+ * Data Memory Barrier (DMB) acts as a memory barrier. It ensures that all
+ * explicit memory accesses that appear in program order before the DMB
+ * instruction are observed before any explicit memory accesses that appear
+ * in program order after the DMB instruction. It does not affect the
+ * ordering of any other instructions executing on the processor
+ *
+ * dmb st - Data memory barrier. Wait for stores to complete.
+ *
+ * Data Synchronization Barrier (DSB) acts as a special kind of memory
+ * barrier. No instruction in program order after this instruction executes
+ * until this instruction completes. This instruction completes when: (1) All
+ * explicit memory accesses before this instruction complete, and (2) all
+ * Cache, Branch predictor and TLB maintenance operations before this
+ * instruction complete.
+ *
+ * dsb sy - Data synchronization barrier. Assures that the CPU waits until
+ * all memory accesses are complete
+ */
+
+#define SP_DSB(n) __asm__ __volatile__ ("dsb sy" : : : "memory")
+#define SP_DMB(n) __asm__ __volatile__ ("dmb st" : : : "memory")
+
+#define SP_WFE() __asm__ __volatile__ ("wfe" : : : "memory")
+#define SP_SEV() __asm__ __volatile__ ("sev" : : : "memory")
+
+#ifndef __ASSEMBLY__
+
+/* The Type of a spinlock.
+ * ARM official document
+ * ARM® Cortex®-A Series, Version: 1.0, Programmer’s Guide for ARMv8-A
+ * ARM DEN0024A (ID050815)
+ *
+ * chapter 14.1.4 Synchronization
+ *
+ * The A64 instruction set has instructions for implementing
+ * synchronization functions:
+ * -- Load Exclusive (LDXR): LDXR W|Xt, [Xn]
+ * -- Store Exclusive (STXR): STXR Ws, W|Xt, [Xn] where Ws
+ * indicates whether the store completed successfully.
+ * 0 = success.
+ * -- Clear Exclusive access monitor (CLREX) This is used to
+ * clear the state of the Local Exclusive Monitor.
+ */
+
+typedef uint64_t spinlock_t;
+
+#endif /* __ASSEMBLY__ */
+#endif /* __ARCH_ARM64_INCLUDE_SPINLOCK_H */
diff --git a/arch/arm64/include/stdarg.h b/arch/arm64/include/stdarg.h
new file mode 100644
index 0000000000..376568ac11
--- /dev/null
+++ b/arch/arm64/include/stdarg.h
@@ -0,0 +1,45 @@
+/****************************************************************************
+ * arch/arm64/include/stdarg.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_ARM64_INCLUDE_STDARG_H
+#define __ARCH_ARM64_INCLUDE_STDARG_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+/****************************************************************************
+ * Pre-processor Prototypes
+ ****************************************************************************/
+
+/* This should work with any modern gcc (newer than 3.4 or so) */
+
+#define va_start(v,l) __builtin_va_start(v,l)
+#define va_end(v) __builtin_va_end(v)
+#define va_arg(v,l) __builtin_va_arg(v,l)
+#define va_copy(d,s) __builtin_va_copy(d,s)
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+typedef __builtin_va_list va_list;
+
+#endif /* __ARCH_ARM64_INCLUDE_STDARG_H */
diff --git a/arch/arm64/include/syscall.h b/arch/arm64/include/syscall.h
new file mode 100644
index 0000000000..7a3e6f1822
--- /dev/null
+++ b/arch/arm64/include/syscall.h
@@ -0,0 +1,391 @@
+/****************************************************************************
+ * arch/arm64/include/syscall.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.
+ *
+ ****************************************************************************/
+
+/* This file should never be included directly but, rather, only indirectly
+ * through include/syscall.h or include/sys/sycall.h
+ */
+
+#ifndef __ARCH_ARM64_INCLUDE_SYSCALL_H
+#define __ARCH_ARM64_INCLUDE_SYSCALL_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#ifndef __ASSEMBLY__
+# include <stdint.h>
+#endif
+
+/****************************************************************************
+ * Pre-processor Prototypes
+ ****************************************************************************/
+
+#define SYS_syscall 0x00
+#define SYS_smhcall 0xf000
+
+/* Configuration ************************************************************/
+
+/* This logic uses three system calls {0,1,2} for context switching and one
+ * for the syscall return.
+ * So a minimum of four syscall values must be reserved.
+ * If CONFIG_BUILD_PROTECTED is defined, then four more syscall values must
+ * be reserved.
+ */
+
+#ifndef CONFIG_BUILD_FLAT
+# define CONFIG_SYS_RESERVED 8
+#else
+# define CONFIG_SYS_RESERVED 4
+#endif
+
+/* system calls */
+
+/* SYS call 0:
+ *
+ * int arm64_saveusercontext(void *saveregs);
+ */
+
+#define SYS_save_context (0)
+
+/* SYS call 1:
+ *
+ * void arm64_fullcontextrestore(void *restoreregs) noreturn_function;
+ */
+
+#define SYS_restore_context (1)
+
+/* SYS call 2:
+ *
+ * void arm64_switchcontext(void **saveregs, void *restoreregs);
+ */
+
+#define SYS_switch_context (2)
+
+#ifdef CONFIG_LIB_SYSCALL
+/* SYS call 3:
+ *
+ * void arm_syscall_return(void);
+ */
+
+#define SYS_syscall_return (3)
+#endif /* CONFIG_LIB_SYSCALL */
+
+#ifndef CONFIG_BUILD_FLAT
+/* SYS call 4:
+ *
+ * void up_task_start(main_t taskentry, int argc, char *argv[])
+ * noreturn_function;
+ */
+
+#define SYS_task_start (4)
+
+/* SYS call 5:
+ *
+ * void up_pthread_start((pthread_startroutine_t startup,
+ * pthread_startroutine_t entrypt, pthread_addr_t arg)
+ * noreturn_function
+ */
+
+#define SYS_pthread_start (5)
+
+/* SYS call 6:
+ *
+ * void signal_handler(_sa_sigaction_t sighand,
+ * int signo, siginfo_t *info,
+ * void *ucontext);
+ */
+
+#define SYS_signal_handler (6)
+
+/* SYS call 7:
+ *
+ * void signal_handler_return(void);
+ */
+
+#define SYS_signal_handler_return (7)
+#endif /* !CONFIG_BUILD_FLAT */
+
+#define ARM_SMCC_RES_A0 (0)
+#define ARM_SMCC_RES_A1 (1)
+#define ARM_SMCC_RES_A2 (2)
+#define ARM_SMCC_RES_A3 (3)
+#define ARM_SMCC_RES_A4 (4)
+#define ARM_SMCC_RES_A5 (5)
+#define ARM_SMCC_RES_A6 (6)
+#define ARM_SMCC_RES_A7 (7)
+
+#ifndef __ASSEMBLY__
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+/* Result from SMC/HVC call
+ * a0-a7 result values from registers 0 to 7
+ */
+
+struct arm64_smccc_res
+{
+ unsigned long a0;
+ unsigned long a1;
+ unsigned long a2;
+ unsigned long a3;
+ unsigned long a4;
+ unsigned long a5;
+ unsigned long a6;
+ unsigned long a7;
+};
+
+typedef struct arm64_smccc_res arm64_smccc_res_t;
+
+enum arm64_smccc_conduit
+{
+ SMCCC_CONDUIT_NONE,
+ SMCCC_CONDUIT_SMC,
+ SMCCC_CONDUIT_HVC,
+};
+
+/****************************************************************************
+ * Inline functions
+ ****************************************************************************/
+
+/* SVC with SYS_ call number and no parameters */
+
+static inline uintptr_t sys_call0(unsigned int nbr)
+{
+ register uint64_t reg0 __asm__("x0") = (uint64_t)(nbr);
+
+ __asm__ __volatile__
+ (
+ "svc %1"
+ : "=r"(reg0)
+ : "i"(SYS_syscall), "r"(reg0)
+ : "memory", "x30"
+ );
+
+ return reg0;
+}
+
+/* SVC with SYS_ call number and one parameter */
+
+static inline uintptr_t sys_call1(unsigned int nbr, uintptr_t parm1)
+{
+ register uint64_t reg0 __asm__("x0") = (uint64_t)(nbr);
+ register uint64_t reg1 __asm__("x1") = (uint64_t)(parm1);
+
+ __asm__ __volatile__
+ (
+ "svc %1"
+ : "=r"(reg0)
+ : "i"(SYS_syscall), "r"(reg0), "r"(reg1)
+ : "memory", "x30"
+ );
+
+ return reg0;
+}
+
+/* SVC with SYS_ call number and two parameters */
+
+static inline uintptr_t sys_call2(unsigned int nbr, uintptr_t parm1,
+ uintptr_t parm2)
+{
+ register uint64_t reg0 __asm__("x0") = (uint64_t)(nbr);
+ register uint64_t reg2 __asm__("x2") = (uint64_t)(parm2);
+ register uint64_t reg1 __asm__("x1") = (uint64_t)(parm1);
+
+ __asm__ __volatile__
+ (
+ "svc %1"
+ : "=r"(reg0)
+ : "i"(SYS_syscall), "r"(reg0), "r"(reg1), "r"(reg2)
+ : "memory", "x30"
+ );
+
+ return reg0;
+}
+
+/* SVC with SYS_ call number and three parameters */
+
+static inline uintptr_t sys_call3(unsigned int nbr, uintptr_t parm1,
+ uintptr_t parm2, uintptr_t parm3)
+{
+ register uint64_t reg0 __asm__("x0") = (uint64_t)(nbr);
+ register uint64_t reg3 __asm__("x3") = (uint64_t)(parm3);
+ register uint64_t reg2 __asm__("x2") = (uint64_t)(parm2);
+ register uint64_t reg1 __asm__("x1") = (uint64_t)(parm1);
+
+ __asm__ __volatile__
+ (
+ "svc %1"
+ : "=r"(reg0)
+ : "i"(SYS_syscall), "r"(reg0), "r"(reg1), "r"(reg2),
+ "r"(reg3)
+ : "memory", "x30"
+ );
+
+ return reg0;
+}
+
+/* SVC with SYS_ call number and four parameters */
+
+static inline uintptr_t sys_call4(unsigned int nbr, uintptr_t parm1,
+ uintptr_t parm2, uintptr_t parm3,
+ uintptr_t parm4)
+{
+ register uint64_t reg0 __asm__("x0") = (uint64_t)(nbr);
+ register uint64_t reg4 __asm__("x4") = (uint64_t)(parm4);
+ register uint64_t reg3 __asm__("x3") = (uint64_t)(parm3);
+ register uint64_t reg2 __asm__("x2") = (uint64_t)(parm2);
+ register uint64_t reg1 __asm__("x1") = (uint64_t)(parm1);
+
+ __asm__ __volatile__
+ (
+ "svc %1"
+ : "=r"(reg0)
+ : "i"(SYS_syscall), "r"(reg0), "r"(reg1), "r"(reg2),
+ "r"(reg3), "r"(reg4)
+ : "memory", "x30"
+ );
+
+ return reg0;
+}
+
+/* SVC with SYS_ call number and five parameters */
+
+static inline uintptr_t sys_call5(unsigned int nbr, uintptr_t parm1,
+ uintptr_t parm2, uintptr_t parm3,
+ uintptr_t parm4, uintptr_t parm5)
+{
+ register uint64_t reg0 __asm__("x0") = (uint64_t)(nbr);
+ register uint64_t reg5 __asm__("x5") = (uint64_t)(parm5);
+ register uint64_t reg4 __asm__("x4") = (uint64_t)(parm4);
+ register uint64_t reg3 __asm__("x3") = (uint64_t)(parm3);
+ register uint64_t reg2 __asm__("x2") = (uint64_t)(parm2);
+ register uint64_t reg1 __asm__("x1") = (uint64_t)(parm1);
+
+ __asm__ __volatile__
+ (
+ "svc %1"
+ : "=r"(reg0)
+ : "i"(SYS_syscall), "r"(reg0), "r"(reg1), "r"(reg2),
+ "r"(reg3), "r"(reg4), "r"(reg5)
+ : "memory", "x30"
+ );
+
+ return reg0;
+}
+
+/* SVC with SYS_ call number and six parameters */
+
+static inline uintptr_t sys_call6(unsigned int nbr, uintptr_t parm1,
+ uintptr_t parm2, uintptr_t parm3,
+ uintptr_t parm4, uintptr_t parm5,
+ uintptr_t parm6)
+{
+ register uint64_t reg0 __asm__("x0") = (uint64_t)(nbr);
+ register uint64_t reg6 __asm__("x6") = (uint64_t)(parm6);
+ register uint64_t reg5 __asm__("x5") = (uint64_t)(parm5);
+ register uint64_t reg4 __asm__("x4") = (uint64_t)(parm4);
+ register uint64_t reg3 __asm__("x3") = (uint64_t)(parm3);
+ register uint64_t reg2 __asm__("x2") = (uint64_t)(parm2);
+ register uint64_t reg1 __asm__("x1") = (uint64_t)(parm1);
+
+ __asm__ __volatile__
+ (
+ "svc %1"
+ : "=r"(reg0)
+ : "i"(SYS_syscall), "r"(reg0), "r"(reg1), "r"(reg2),
+ "r"(reg3), "r"(reg4), "r"(reg5), "r"(reg6)
+ : "memory", "x30"
+ );
+
+ return reg0;
+}
+
+/* semihosting(SMH) call with call number and one parameter */
+
+static inline long smh_call(unsigned int nbr, void *parm)
+{
+ register uint64_t reg0 __asm__("x0") = (uint64_t)(nbr);
+ register uint64_t reg1 __asm__("x1") = (uint64_t)(parm);
+
+ __asm__ __volatile__
+ (
+ "hlt %1"
+ : "=r"(reg0)
+ : "i"(SYS_smhcall), "r"(reg0), "r"(reg1)
+ : "memory", "x30"
+ );
+
+ return reg0;
+}
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/* Make HVC calls
+ *
+ * param a0 function identifier
+ * param a1-a7 parameters registers
+ * param res results
+ */
+
+void arm64_smccc_hvc(unsigned long a0, unsigned long a1,
+ unsigned long a2, unsigned long a3,
+ unsigned long a4, unsigned long a5,
+ unsigned long a6, unsigned long a7,
+ struct arm64_smccc_res *res);
+
+/* Make SMC calls
+ *
+ * param a0 function identifier
+ * param a1-a7 parameters registers
+ * param res results
+ */
+
+void arm64_smccc_smc(unsigned long a0, unsigned long a1,
+ unsigned long a2, unsigned long a3,
+ unsigned long a4, unsigned long a5,
+ unsigned long a6, unsigned long a7,
+ struct arm64_smccc_res *res);
+
+#ifdef __cplusplus
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+#undef EXTERN
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* __ARCH_ARM64_INCLUDE_SYSCALL_H */
diff --git a/arch/arm64/include/types.h b/arch/arm64/include/types.h
new file mode 100644
index 0000000000..5d78349673
--- /dev/null
+++ b/arch/arm64/include/types.h
@@ -0,0 +1,110 @@
+/****************************************************************************
+ * arch/arm64/include/types.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.
+ *
+ ****************************************************************************/
+
+/* This file should never be included directly but, rather, only indirectly
+ * through sys/types.h
+ */
+
+#ifndef __ARCH_ARM64_INCLUDE_TYPES_H
+#define __ARCH_ARM64_INCLUDE_TYPES_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+/****************************************************************************
+ * Pre-processor Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Type Declarations
+ ****************************************************************************/
+
+#ifndef __ASSEMBLY__
+
+/* These are the sizes of the standard integer types. NOTE that these type
+ * names have a leading underscore character. This file will be included
+ * (indirectly) by include/stdint.h and typedef'ed to the final name without
+ * the underscore character. This roundabout way of doings things allows
+ * the stdint.h to be removed from the include/ directory in the event that
+ * the user prefers to use the definitions provided by their toolchain header
+ * files
+ */
+
+typedef signed char _int8_t;
+typedef unsigned char _uint8_t;
+
+typedef signed short _int16_t;
+typedef unsigned short _uint16_t;
+
+typedef signed int _int32_t;
+typedef unsigned int _uint32_t;
+
+typedef signed long _int64_t;
+typedef unsigned long _uint64_t;
+#define __INT64_DEFINED
+
+typedef _int64_t _intmax_t;
+typedef _uint64_t _uintmax_t;
+
+#if defined(__WCHAR_TYPE__)
+typedef __WCHAR_TYPE__ _wchar_t;
+#else
+typedef int _wchar_t;
+#endif
+
+#if defined(__SIZE_TYPE__)
+/* If __SIZE_TYPE__ is defined we define ssize_t based on size_t.
+ * We simply change "unsigned" to "signed" for this single definition
+ * to make sure ssize_t and size_t only differ by their signedness.
+ */
+
+#define unsigned signed
+typedef __SIZE_TYPE__ _ssize_t;
+#undef unsigned
+typedef __SIZE_TYPE__ _size_t;
+
+#elif defined(CONFIG_ARCH_SIZET_LONG)
+
+typedef signed long _ssize_t;
+typedef unsigned long _size_t;
+
+#else
+
+typedef signed int _ssize_t;
+typedef unsigned int _size_t;
+
+#endif
+
+/* This is the size of the interrupt state save returned by
+ * up_irq_save()
+ */
+
+typedef unsigned long irqstate_t;
+
+#endif /* __ASSEMBLY__ */
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+#endif /* __ARCH_ARM64_INCLUDE_TYPES_H */
diff --git a/arch/arm64/src/.gitignore b/arch/arm64/src/.gitignore
new file mode 100644
index 0000000000..af8911db06
--- /dev/null
+++ b/arch/arm64/src/.gitignore
@@ -0,0 +1,2 @@
+/board
+/chip
diff --git a/arch/arm64/src/Makefile b/arch/arm64/src/Makefile
new file mode 100644
index 0000000000..1df237ecd0
--- /dev/null
+++ b/arch/arm64/src/Makefile
@@ -0,0 +1,205 @@
+############################################################################
+# arch/arm64/src/Makefile
+#
+# 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.
+#
+############################################################################
+
+include $(TOPDIR)/Make.defs
+include chip/Make.defs
+
+ARCH_SRCDIR = $(TOPDIR)$(DELIM)arch$(DELIM)$(CONFIG_ARCH)$(DELIM)src
+
+INCLUDES += ${shell $(INCDIR) "$(CC)" $(ARCH_SRCDIR)$(DELIM)chip}
+INCLUDES += ${shell $(INCDIR) "$(CC)" $(ARCH_SRCDIR)$(DELIM)common}
+INCLUDES += ${shell $(INCDIR) "$(CC)" $(TOPDIR)$(DELIM)sched}
+
+CPPFLAGS += $(INCLUDES)
+CFLAGS += $(INCLUDES)
+CXXFLAGS += $(INCLUDES)
+AFLAGS += $(INCLUDES)
+
+NUTTX = $(call CONVERT_PATH,$(TOPDIR)$(DELIM)nuttx$(EXEEXT))
+
+# Additional rules for system call wrapper
+
+ifeq ($(CONFIG_SCHED_INSTRUMENTATION_SYSCALL),y)
+ EXTRALINKCMDS += @$(TOPDIR)/syscall/syscall_wraps.ldcmd
+endif
+
+# The "head" object
+
+HEAD_OBJ = $(HEAD_ASRC:.S=$(OBJEXT))
+STARTUP_OBJS ?= $(HEAD_OBJ)
+
+# Flat build or kernel-mode objects
+
+ASRCS = $(CHIP_ASRCS) $(CMN_ASRCS)
+AOBJS = $(ASRCS:.S=$(OBJEXT))
+
+CSRCS = $(CHIP_CSRCS) $(CMN_CSRCS)
+COBJS = $(CSRCS:.c=$(OBJEXT))
+
+SRCS = $(ASRCS) $(CSRCS)
+OBJS = $(AOBJS) $(COBJS)
+
+# User-mode objects
+
+UASRCS = $(CHIP_UASRCS) $(CMN_UASRCS)
+UAOBJS = $(UASRCS:.S=$(OBJEXT))
+
+UCSRCS = $(CHIP_UCSRCS) $(CMN_UCSRCS)
+UCOBJS = $(UCSRCS:.c=$(OBJEXT))
+
+USRCS = $(UASRCS) $(UCSRCS)
+UOBJS = $(UAOBJS) $(UCOBJS)
+
+KBIN = libkarch$(LIBEXT)
+BIN = libarch$(LIBEXT)
+
+LDFLAGS += $(addprefix -T,$(call CONVERT_PATH,$(ARCHSCRIPT))) $(EXTRALINKCMDS)
+
+# Override in Make.defs if linker is not 'ld'
+
+ifeq ($(LD),$(CC))
+ LDSTARTGROUP ?= -Wl,--start-group
+ LDENDGROUP ?= -Wl,--end-group
+ LDFLAGS := $(addprefix -Xlinker ,$(LDFLAGS))
+ LDFLAGS += $(CFLAGS)
+else
+ LDSTARTGROUP ?= --start-group
+ LDENDGROUP ?= --end-group
+endif
+
+BOARDMAKE = $(if $(wildcard board$(DELIM)Makefile),y,)
+
+LIBPATHS += -L $(call CONVERT_PATH,$(TOPDIR)$(DELIM)staging)
+ifeq ($(BOARDMAKE),y)
+ LIBPATHS += -L $(call CONVERT_PATH,$(TOPDIR)$(DELIM)arch$(DELIM)$(CONFIG_ARCH)$(DELIM)src$(DELIM)board)
+endif
+
+LDLIBS = $(patsubst %.a,%,$(patsubst lib%,-l%,$(LINKLIBS)))
+ifeq ($(BOARDMAKE),y)
+ LDLIBS += -lboard
+endif
+
+VPATH += chip
+VPATH += common
+VPATH += $(ARCH_SUBDIR)
+
+all: $(HEAD_OBJ) $(BIN)
+
+.PHONY: board$(DELIM)libboard$(LIBEXT)
+
+$(AOBJS) $(UAOBJS) $(HEAD_OBJ): %$(OBJEXT): %.S
+ $(call ASSEMBLE, $<, $@)
+
+$(COBJS) $(UCOBJS): %$(OBJEXT): %.c
+ $(call COMPILE, $<, $@)
+
+ifeq ($(CONFIG_BUILD_FLAT),y)
+$(BIN): $(OBJS)
+ $(call ARCHIVE, $@, $(OBJS))
+else
+$(BIN): $(UOBJS)
+ $(call ARCHIVE, $@, $(UOBJS))
+endif
+
+$(KBIN): $(OBJS)
+ $(call ARCHIVE, $@, $(OBJS))
+
+board$(DELIM)libboard$(LIBEXT):
+ $(Q) $(MAKE) -C board libboard$(LIBEXT) EXTRAFLAGS="$(EXTRAFLAGS)"
+
+define LINK_ALLSYMS
+ $(Q) $(TOPDIR)/tools/mkallsyms.sh $(NUTTX) $(CROSSDEV) > allsyms.tmp
+ $(Q) $(call COMPILE, -x c allsyms.tmp, allsyms$(OBJEXT))
+ $(Q) $(LD) --entry=__start $(LDFLAGS) $(LIBPATHS) $(EXTRA_LIBPATHS) \
+ -o $(NUTTX) $(HEAD_OBJ) allsyms$(OBJEXT) $(EXTRA_OBJS) \
+ $(LDSTARTGROUP) $(LDLIBS) $(EXTRA_LIBS) $(LDENDGROUP)
+ $(Q) $(call DELFILE, allsyms.tmp allsyms$(OBJEXT))
+endef
+
+nuttx$(EXEEXT): $(HEAD_OBJ) board$(DELIM)libboard$(LIBEXT) $(ARCHSCRIPT)
+ $(Q) echo "LD: nuttx"
+ifneq ($(CONFIG_ALLSYMS),y)
+ $(Q) $(LD) --entry=__start $(LDFLAGS) $(LIBPATHS) $(EXTRA_LIBPATHS) \
+ -o $(NUTTX) $(HEAD_OBJ) $(EXTRA_OBJS) \
+ $(LDSTARTGROUP) $(LDLIBS) $(EXTRA_LIBS) $(LDENDGROUP)
+else
+ $(Q) # Link and generate default table
+ $(Q) $(if $(wildcard $(shell echo $(NUTTX))),,$(call LINK_ALLSYMS,$^))
+ $(Q) # Extract all symbols
+ $(Q) $(call LINK_ALLSYMS, $^)
+ $(Q) # Extract again since the table offset may changed
+ $(Q) $(call LINK_ALLSYMS, $^)
+endif
+ifneq ($(CONFIG_WINDOWS_NATIVE),y)
+ $(Q) $(NM) $(NUTTX) | \
+ grep -v '\(compiled\)\|\(\$(OBJEXT)$$\)\|\( [aUw] \)\|\(\.\.ng$$\)\|\(LASH[RL]DI\)' | \
+ sort > $(TOPDIR)$(DELIM)System.map
+endif
+
+# This is part of the top-level export target
+# Note that there may not be a head object if layout is handled
+# by the linker configuration.
+
+export_startup: $(STARTUP_OBJS)
+ifneq ($(STARTUP_OBJS),)
+ $(Q) if [ -d "$(EXPORT_DIR)$(DELIM)startup" ]; then \
+ cp -f $(STARTUP_OBJS) "$(EXPORT_DIR)$(DELIM)startup$(DELIM)."; \
+ else \
+ echo "$(EXPORT_DIR)$(DELIM)startup does not exist"; \
+ exit 1; \
+ fi
+endif
+
+# Dependencies
+
+makedepfile: $(CSRCS:.c=.ddc) $(ASRCS:.S=.dds) $(HEAD_ASRC:.S=.dds)
+ $(call CATFILE, Make.dep, $^)
+ $(call DELFILE, $^)
+
+.depend: Makefile chip$(DELIM)Make.defs $(SRCS) $(TOPDIR)$(DELIM).config
+ifeq ($(BOARDMAKE),y)
+ $(Q) $(MAKE) -C board depend
+endif
+ $(Q) $(MAKE) makedepfile DEPPATH="$(patsubst %,--dep-path %,$(subst :, ,$(VPATH)))"
+ $(Q) touch $@
+
+depend: .depend
+
+context::
+
+clean:
+ifeq ($(BOARDMAKE),y)
+ $(Q) $(MAKE) -C board clean
+endif
+ $(call DELFILE, $(KBIN))
+ $(call DELFILE, $(BIN))
+ifneq ($(EXTRADELFILE),)
+ $(call DELFILE, $(EXTRADELFILE))
+endif
+ $(call CLEAN)
+
+distclean:: clean
+ifeq ($(BOARDMAKE),y)
+ $(Q) $(MAKE) -C board distclean
+endif
+ $(call DELFILE, Make.dep)
+ $(call DELFILE, .depend)
+
+-include Make.dep
diff --git a/arch/arm64/src/Toolchain.defs b/arch/arm64/src/Toolchain.defs
new file mode 100644
index 0000000000..3bf0fec3cd
--- /dev/null
+++ b/arch/arm64/src/Toolchain.defs
@@ -0,0 +1,139 @@
+############################################################################
+# arch/arm64/src/Toolchain.defs
+#
+# 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.
+#
+############################################################################
+
+#
+# Supported toolchains
+#
+# Each toolchain definition should set:
+#
+# CROSSDEV The GNU toolchain triple (command prefix)
+# ARCHCPUFLAGS CPU-specific flags selecting the instruction set
+# FPU options, etc.
+# ARCHOPTIMIZATION The optimization level that results in
+# reliable code generation.
+#
+
+ifeq ($(CONFIG_ARCH_ARMV8A),y)
+ ARCHCPUFLAGS += -march=armv8-a
+endif
+
+ifeq ($(CONFIG_ARCH_CORTEX_A53),y)
+ ARCHCPUFLAGS += -mtune=cortex-a53
+endif
+
+ifeq ($(CONFIG_DEBUG_CUSTOMOPT),y)
+ ARCHOPTIMIZATION += $(CONFIG_DEBUG_OPTLEVEL)
+else ifeq ($(CONFIG_DEBUG_FULLOPT),y)
+ ARCHOPTIMIZATION += -Os
+endif
+
+ifneq ($(CONFIG_DEBUG_NOOPT),y)
+ ARCHOPTIMIZATION += -fno-strict-aliasing
+endif
+
+ifeq ($(CONFIG_FRAME_POINTER),y)
+ ARCHOPTIMIZATION += -fno-omit-frame-pointer -fno-optimize-sibling-calls
+else
+ ARCHOPTIMIZATION += -fomit-frame-pointer
+endif
+
+ifeq ($(CONFIG_STACK_CANARIES),y)
+ ARCHOPTIMIZATION += -fstack-protector-all
+endif
+
+ifeq ($(CONFIG_ARCH_COVERAGE),y)
+ ARCHOPTIMIZATION += -fprofile-generate -ftest-coverage
+endif
+
+ARCHCFLAGS += -fno-common
+ARCHCXXFLAGS += -fno-common -nostdinc++
+
+ARCHCFLAGS += -Wall -Wstrict-prototypes -Wshadow -Wundef -Werror
+ARCHCXXFLAGS += -Wall -Wshadow -Wundef
+
+ifneq ($(CONFIG_CXX_EXCEPTION),y)
+ ARCHCXXFLAGS += -fno-exceptions -fcheck-new
+endif
+
+ifneq ($(CONFIG_CXX_RTTI),y)
+ ARCHCXXFLAGS += -fno-rtti
+endif
+
+LDFLAGS += -nostdlib
+
+# Optimization of unused sections
+
+ifeq ($(CONFIG_DEBUG_OPT_UNUSED_SECTIONS),y)
+ LDFLAGS += --gc-sections
+ ARCHOPTIMIZATION += -ffunction-sections -fdata-sections
+endif
+
+# Debug link map
+
+ifeq ($(CONFIG_DEBUG_LINK_MAP),y)
+ LDFLAGS += --cref -Map=$(call CONVERT_PATH,$(TOPDIR)$(DELIM)nuttx.map)
+endif
+
+ifeq ($(CONFIG_DEBUG_SYMBOLS),y)
+ ARCHOPTIMIZATION += -g
+endif
+
+CROSSDEV ?= aarch64-none-elf-
+
+# Default toolchain
+
+CC = $(CROSSDEV)gcc
+CXX = $(CROSSDEV)g++
+CPP = $(CROSSDEV)gcc -E -P -x c
+STRIP = $(CROSSDEV)strip --strip-unneeded
+OBJCOPY = $(CROSSDEV)objcopy
+OBJDUMP = $(CROSSDEV)objdump
+LD = $(CROSSDEV)ld
+AR = $(CROSSDEV)ar rcs
+NM = $(CROSSDEV)nm
+
+# Link Time Optimization
+
+ifeq ($(CONFIG_LTO_FULL),y)
+ ARCHOPTIMIZATION += -flto
+ ifeq ($(CONFIG_ARMV7A_TOOLCHAIN),GNU_EABI)
+ LD := $(CROSSDEV)gcc
+ AR := $(CROSSDEV)gcc-ar rcs
+ NM := $(CROSSDEV)gcc-nm
+ ARCHOPTIMIZATION += -fuse-linker-plugin
+ ARCHOPTIMIZATION += -fno-builtin
+ endif
+endif
+
+# Add the builtin library
+
+EXTRA_LIBS += $(wildcard $(shell $(CC) $(ARCHCPUFLAGS) --print-libgcc-file-name))
+
+ifneq ($(CONFIG_LIBM),y)
+ EXTRA_LIBS += $(wildcard $(shell $(CC) $(ARCHCPUFLAGS) --print-file-name=libm.a))
+endif
+
+ifeq ($(CONFIG_LIBSUPCXX),y)
+ EXTRA_LIBS += $(wildcard $(shell $(CC) $(ARCHCPUFLAGS) --print-file-name=libsupc++.a))
+endif
+
+ifeq ($(CONFIG_ARCH_COVERAGE),y)
+ EXTRA_LIBS += $(wildcard $(shell $(CC) $(ARCHCPUFLAGS) --print-file-name=libgcov.a))
+endif
diff --git a/arch/arm64/src/common/Make.defs b/arch/arm64/src/common/Make.defs
new file mode 100644
index 0000000000..f9633c3bdb
--- /dev/null
+++ b/arch/arm64/src/common/Make.defs
@@ -0,0 +1,97 @@
+############################################################################
+# arch/arm64/src/common/Make.defs
+#
+# 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.
+#
+############################################################################
+
+# The vector table is the "head" object, i.e., the one that must forced into
+# the link in order to draw in all of the other components
+
+HEAD_ASRC = arm64_head.S
+
+ifeq ($(CONFIG_BUILD_KERNEL),y)
+crt0$(OBJEXT): crt0.c
+ $(CC) $(CFLAGS) -c common$(DELIM)crt0.c -o crt0$(OBJEXT)
+
+STARTUP_OBJS = crt0$(OBJEXT)
+endif
+
+# Force the start-up logic to be at the beginning of the .text to simplify
+# debug.
+
+# Common assembly language files
+CMN_ASRCS = arm64_vector_table.S arm64_vectors.S arm64_smccc.S
+CMN_ASRCS += arm64_cpu_idle.S arm64_vfork_func.S
+
+ifeq ($(CONFIG_ARCH_HAVE_TESTSET),y)
+CMN_ASRCS += arm64_testset.S
+endif
+
+# Common C source files ( OS call up_xxx)
+CMN_CSRCS = arm64_initialize.c arm64_initialstate.c arm64_boot.c
+CMN_CSRCS += arm64_idle.c arm64_copystate.c
+CMN_CSRCS += arm64_createstack.c arm64_releasestack.c arm64_stackframe.c arm64_usestack.c
+CMN_CSRCS += arm64_task_sched.c arm64_exit.c arm64_vfork.c arm64_reprioritizertr.c
+CMN_CSRCS += arm64_releasepending.c arm64_unblocktask.c arm64_blocktask.c
+CMN_CSRCS += arm64_assert.c arm64_schedulesigaction.c arm64_backtrace.c
+CMN_CSRCS += arm64_sigdeliver.c
+
+# Common C source files ( hardware BSP )
+CMN_CSRCS += arm64_mmu.c arm64_arch_timer.c arm64_cache.c
+CMN_CSRCS += arm64_doirq.c arm64_gicv3.c arm64_fatal.c
+CMN_CSRCS += arm64_syscall.c arm64_cpu_psci.c
+
+# Use common heap allocation for now (may need to be customized later)
+CMN_CSRCS += arm64_allocateheap.c
+
+ifeq ($(CONFIG_SMP),y)
+CMN_CSRCS += arm64_cpuidlestack.c arm64_cpustart.c arm64_cpuindex.c
+CMN_CSRCS += arm64_cpupause.c
+endif
+
+ifeq ($(CONFIG_BUILD_KERNEL),y)
+CMN_CSRCS += arm64_task_start.c arm64_pthread_start.c arm64_signal_dispatch.c
+endif
+
+ifeq ($(CONFIG_ARCH_ADDRENV),y)
+CMN_CSRCS += arm64_addrenv.c arm64_addrenv_utils.c arm64_pgalloc.c
+ifeq ($(CONFIG_ARCH_STACK_DYNAMIC),y)
+CMN_CSRCS += arm64_addrenv_ustack.c
+endif
+ifeq ($(CONFIG_ARCH_KERNEL_STACK),y)
+CMN_CSRCS += arm64_addrenv_kstack.c
+endif
+ifeq ($(CONFIG_MM_SHM),y)
+CMN_CSRCS += arm64_addrenv_shm.c
+endif
+endif
+
+ifeq ($(CONFIG_MM_PGALLOC),y)
+CMN_CSRCS += arm64_physpgaddr.c
+ifeq ($(CONFIG_ARCH_PGPOOL_MAPPING),y)
+CMN_CSRCS += arm64_virtpgaddr.c
+endif
+endif
+
+ifeq ($(CONFIG_ARCH_FPU),y)
+CMN_CSRCS += arm64_fpu.c
+CMN_ASRCS += arm64_fpu_func.S
+endif
+
+ifeq ($(CONFIG_STACK_COLORATION),y)
+CMN_CSRCS += arm64_checkstack.c
+endif
diff --git a/arch/arm64/src/common/addrenv.h b/arch/arm64/src/common/addrenv.h
new file mode 100644
index 0000000000..700c089596
--- /dev/null
+++ b/arch/arm64/src/common/addrenv.h
@@ -0,0 +1,102 @@
+/****************************************************************************
+ * arch/arm64/src/common/addrenv.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_ARM64_SRC_COMMON_ADDRENV_H
+#define __ARCH_ARM64_SRC_COMMON_ADDRENV_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <sys/types.h>
+#include <stdint.h>
+
+#include "arm64_internal.h"
+
+#ifdef CONFIG_ARCH_ADDRENV
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Aligned size of the kernel stack */
+
+#ifdef CONFIG_ARCH_KERNEL_STACK
+# define ARCH_KERNEL_STACKSIZE STACK_ALIGN_UP(CONFIG_ARCH_KERNEL_STACKSIZE)
+#endif
+
+/****************************************************************************
+ * Inline Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+#ifndef __ASSEMBLY__
+#ifdef __cplusplus
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: arm_addrenv_create_region
+ *
+ * Description:
+ * Create one memory region.
+ *
+ * Returned Value:
+ * On success, the number of pages allocated is returned. Otherwise, a
+ * negated errno value is returned.
+ *
+ ****************************************************************************/
+
+int arm64_addrenv_create_region(uintptr_t **list, size_t listlen,
+ uintptr_t vaddr, size_t regionsize,
+ uint32_t mmuflags);
+
+/****************************************************************************
+ * Name: arm_addrenv_destroy_region
+ *
+ * Description:
+ * Destroy one memory region.
+ *
+ ****************************************************************************/
+
+void arm64_addrenv_destroy_region(uintptr_t **list, size_t listlen,
+ uintptr_t vaddr, bool keep);
+
+#undef EXTERN
+#ifdef __cplusplus
+}
+#endif
+#endif /* __ASSEMBLY__ */
+
+#endif /* CONFIG_ARCH_ADDRENV */
+#endif /* __ARCH_ARM64_SRC_COMMON_ADDRENV_H */
diff --git a/arch/arm64/src/common/arm64_allocateheap.c b/arch/arm64/src/common/arm64_allocateheap.c
new file mode 100644
index 0000000000..cc8b7256aa
--- /dev/null
+++ b/arch/arm64/src/common/arm64_allocateheap.c
@@ -0,0 +1,163 @@
+/****************************************************************************
+ * arch/arm64/src/common/arm64_allocateheap.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 <stdint.h>
+
+#include <assert.h>
+#include <debug.h>
+#include <nuttx/arch.h>
+#include <nuttx/board.h>
+#include <nuttx/userspace.h>
+
+#include "arm64_internal.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Configuration ************************************************************/
+
+/* Terminology. In the flat build (CONFIG_BUILD_FLAT=y), there is only a
+ * single heap access with the standard allocations (malloc/free). This
+ * heap is referred to as the user heap. In the protected build
+ * (CONFIG_BUILD_PROTECTED=y) where an MPU is used to protect a region of
+ * otherwise flat memory, there will be two allocators: One that allocates
+ * protected (kernel) memory and one that allocates unprotected (user)
+ * memory. These are referred to as the kernel and user heaps,
+ * respectively.
+ *
+ * The ARMv8 has no MPU but does have an MMU. With this MMU, it can support
+ * the kernel build (CONFIG_BUILD_KERNEL=y). In this configuration, there
+ * is one kernel heap but multiple user heaps: One per task group. However,
+ * in this case, we need only be concerned about initializing the single
+ * kernel heap here.
+ */
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: up_allocate_heap/up_allocate_kheap
+ *
+ * Description:
+ * This function will be called to dynamically set aside the heap region.
+ *
+ * - For the normal "flat" build, this function returns the size of the
+ * single heap.
+ * - For the protected build (CONFIG_BUILD_PROTECTED=y) with both kernel-
+ * and user-space heaps (CONFIG_MM_KERNEL_HEAP=y), this function
+ * provides the size of the unprotected, user-space heap.
+ * - For the kernel build (CONFIG_BUILD_KERNEL=y), this function provides
+ * the size of the protected, kernel-space heap.
+ *
+ * If a protected kernel-space heap is provided, the kernel heap must be
+ * allocated by an analogous up_allocate_kheap(). A custom version of this
+ * file is needed if memory protection of the kernel heap is required.
+ *
+ * The following memory map is assumed for the flat build:
+ *
+ * .data region. Size determined at link time.
+ * .bss region Size determined at link time.
+ * IDLE thread stack. Size determined by CONFIG_IDLETHREAD_STACKSIZE.
+ * Heap. Extends to the end of SRAM.
+ *
+ * The following memory map is assumed for the kernel build:
+ *
+ * Kernel .data region. Size determined at link time.
+ * Kernel .bss region Size determined at link time.
+ * Kernel IDLE thread stack. Size determined by
+ * CONFIG_IDLETHREAD_STACKSIZE.
+ * Padding for alignment
+ * User .data region. Size determined at link time.
+ * User .bss region Size determined at link time.
+ * Kernel heap. Size determined by CONFIG_MM_KERNEL_HEAPSIZE.
+ * User heap. Extends to the end of SRAM.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_BUILD_KERNEL
+void up_allocate_kheap(void **heap_start, size_t *heap_size)
+#else
+void up_allocate_heap(void **heap_start, size_t *heap_size)
+#endif
+{
+#if defined(CONFIG_BUILD_PROTECTED) && defined(CONFIG_MM_KERNEL_HEAP)
+ /* Get the unaligned size and position of the user-space heap.
+ * This heap begins after the user-space .bss section at an offset
+ * of CONFIG_MM_KERNEL_HEAPSIZE (subject to alignment).
+ */
+
+ uintptr_t ubase = (uintptr_t)USERSPACE->us_bssend +
+ CONFIG_MM_KERNEL_HEAPSIZE;
+ size_t usize = CONFIG_RAM_END - ubase;
+
+ /* Return the user-space heap settings */
+
+ board_autoled_on(LED_HEAPALLOCATE);
+ *heap_start = (void *)ubase;
+ *heap_size = usize;
+#else
+
+ /* Return the heap settings */
+
+ *heap_start = (void *)g_idle_topstack;
+ *heap_size = CONFIG_RAM_END - (size_t)g_idle_topstack;
+ sinfo("heap_start=0x%p, heap_size=0x%"PRIx64"\n", *heap_start, *heap_size);
+#endif
+}
+
+/****************************************************************************
+ * Name: up_allocate_kheap
+ *
+ * Description:
+ * For the kernel build (CONFIG_BUILD_PROTECTED/KERNEL=y) with both kernel-
+ * and user-space heaps (CONFIG_MM_KERNEL_HEAP=y), this function allocates
+ * the kernel-space heap. A custom version of this function is needed if
+ * memory protection of the kernel heap is required.
+ *
+ ****************************************************************************/
+
+#if defined(CONFIG_BUILD_PROTECTED) && defined(CONFIG_MM_KERNEL_HEAP)
+void up_allocate_kheap(void **heap_start, size_t *heap_size)
+{
+ /* Get the unaligned size and position of the user-space heap.
+ * This heap begins after the user-space .bss section at an offset
+ * of CONFIG_MM_KERNEL_HEAPSIZE (subject to alignment).
+ */
+
+ uintptr_t ubase = (uintptr_t)USERSPACE->us_bssend +
+ CONFIG_MM_KERNEL_HEAPSIZE;
+
+ /* Return the kernel heap settings (i.e., the part of the heap region
+ * that was not dedicated to the user heap).
+ */
+
+ *heap_start = (void *)USERSPACE->us_bssend;
+ *heap_size = ubase - (uintptr_t)USERSPACE->us_bssend;
+}
+#endif
diff --git a/arch/arm64/src/common/arm64_arch.h b/arch/arm64/src/common/arm64_arch.h
new file mode 100644
index 0000000000..c481803541
--- /dev/null
+++ b/arch/arm64/src/common/arm64_arch.h
@@ -0,0 +1,548 @@
+/****************************************************************************
+ * arch/arm64/src/common/arm64_arch.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_ARM64_SRC_COMMON_ARM64_ARCH_H
+#define ___ARCH_ARM64_SRC_COMMON_ARM64_ARCH_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+/* Unsigned integer with bit position n set (signed in
+ * assembly language).
+ */
+#ifndef __ASSEMBLY__
+ #include <stdint.h>
+#endif
+
+#include "barriers.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define BIT(n) ((1UL) << (n))
+#define BIT64(n) ((1ULL) << (n))
+
+/* Bit mask with bits 0 through n-1 (inclusive) set,
+ * or 0 if n is 0.
+ */
+#define BIT_MASK(n) (BIT(n) - 1)
+#define BIT64_MASK(n) (BIT64(n) - 1ULL)
+
+#define DAIFSET_FIQ_BIT BIT(0)
+#define DAIFSET_IRQ_BIT BIT(1)
+#define DAIFSET_ABT_BIT BIT(2)
+#define DAIFSET_DBG_BIT BIT(3)
+
+#define DAIFCLR_FIQ_BIT BIT(0)
+#define DAIFCLR_IRQ_BIT BIT(1)
+#define DAIFCLR_ABT_BIT BIT(2)
+#define DAIFCLR_DBG_BIT BIT(3)
+
+#define DAIF_FIQ_BIT BIT(6)
+#define DAIF_IRQ_BIT BIT(7)
+#define DAIF_ABT_BIT BIT(8)
+#define DAIF_DBG_BIT BIT(9)
+
+#define DAIF_MASK (0xf << 6)
+
+/* Arm® Architecture Registers Armv8, for Armv8-A architecture profile
+ * ( DDI 0595, ID121321 ), defined:
+ *
+ * SCTLR_EL1: System Control Register (EL1)
+ * SCTLR_EL2: System Control Register (EL2)
+ * SCTLR_EL3: System Control Register (EL3)
+ *
+ */
+
+#define SCTLR_EL3_RES1 (BIT(29) | BIT(28) | BIT(23) | \
+ BIT(22) | BIT(18) | BIT(16) | \
+ BIT(11) | BIT(5) | BIT(4))
+
+#define SCTLR_EL2_RES1 (BIT(29) | BIT(28) | BIT(23) | \
+ BIT(22) | BIT(18) | BIT(16) | \
+ BIT(11) | BIT(5) | BIT(4))
+
+#define SCTLR_EL1_RES1 (BIT(29) | BIT(28) | BIT(23) | \
+ BIT(22) | BIT(20) | BIT(11))
+
+#define SCTLR_M_BIT BIT(0)
+#define SCTLR_A_BIT BIT(1)
+#define SCTLR_C_BIT BIT(2)
+#define SCTLR_SA_BIT BIT(3)
+#define SCTLR_I_BIT BIT(12)
+
+/* SPSR M[3:0] define
+ *
+ * Arm® Architecture Registers Armv8, for Armv8-A architecture profile
+ * ( DDI 0595, ID121321 ), defined:
+ * SPSR_EL1: Saved Program Status Register (EL1)
+ * SPSR_EL2: Saved Program Status Register (EL2)
+ * SPSR_EL3: Saved Program Status Register (EL3)
+ *
+ * reference to Programmer’s Guide for ARMv8-A
+ * (ARM DEN0024A, ID050815 ), 4.1.2 Stack pointer
+ *
+ * The T suffix, indicates use of the SP_EL0 stack pointer.
+ * The H suffix, indicates use of the SP_ELx stack pointer.
+ *
+ */
+
+#define SPSR_DAIF_SHIFT (6)
+#define SPSR_DAIF_MASK (0xf << SPSR_DAIF_SHIFT)
+
+#define SPSR_MODE_EL0T (0x0)
+#define SPSR_MODE_EL1T (0x4)
+#define SPSR_MODE_EL1H (0x5)
+#define SPSR_MODE_EL2T (0x8)
+#define SPSR_MODE_EL2H (0x9)
+#define SPSR_MODE_MASK (0xf)
+
+/* CurrentEL: Current Exception Level */
+
+#define MODE_EL_SHIFT (0x2)
+#define MODE_EL_MASK (0x3)
+
+#define MODE_EL3 (0x3)
+#define MODE_EL2 (0x2)
+#define MODE_EL1 (0x1)
+#define MODE_EL0 (0x0)
+
+/* struct arm64_boot_params member offset for assembly code
+ * struct is defined at arm64_cpustart.c
+ */
+
+#define BOOT_PARAM_MPID 0
+#define BOOT_PARAM_SP 8
+
+#ifndef __ASSEMBLY__
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define STRINGIFY(x) #x
+
+#ifndef ARRAY_SIZE
+# define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+#endif
+
+/* define MAX(a, b)/MIN(a, b)
+ * The larger/smaller value between a and b.
+ * Arguments are evaluated twice.
+ */
+#ifndef MAX
+# define MAX(a, b) (((a) > (b)) ? (a) : (b))
+#endif
+
+#ifndef MIN
+# define MIN(a, b) (((a) < (b)) ? (a) : (b))
+#endif
+
+#define GET_EL(mode) (((mode) >> MODE_EL_SHIFT) & MODE_EL_MASK)
+
+/* MPIDR_EL1, Multiprocessor Affinity Register */
+
+#define MPIDR_AFFLVL_MASK (0xff)
+
+#define MPIDR_AFF0_SHIFT (0)
+#define MPIDR_AFF1_SHIFT (8)
+#define MPIDR_AFF2_SHIFT (16)
+#define MPIDR_AFF3_SHIFT (32)
+
+#define MPIDR_AFFLVL(mpidr, aff_level) \
+ (((mpidr) >> MPIDR_AFF ## aff_level ## _SHIFT) & MPIDR_AFFLVL_MASK)
+
+#define GET_MPIDR() read_sysreg(mpidr_el1)
+#define MPIDR_TO_CORE(mpidr) MPIDR_AFFLVL((mpidr), 0)
+#define IS_PRIMARY_CORE() (!MPIDR_TO_CORE(GET_MPIDR()))
+
+/* System register interface to GICv3 */
+
+#define ICC_IGRPEN1_EL1 S3_0_C12_C12_7
+#define ICC_SGI1R S3_0_C12_C11_5
+#define ICC_SRE_EL1 S3_0_C12_C12_5
+#define ICC_SRE_EL2 S3_4_C12_C9_5
+#define ICC_SRE_EL3 S3_6_C12_C12_5
+#define ICC_CTLR_EL1 S3_0_C12_C12_4
+#define ICC_CTLR_EL3 S3_6_C12_C12_4
+#define ICC_PMR_EL1 S3_0_C4_C6_0
+#define ICC_RPR_EL1 S3_0_C12_C11_3
+#define ICC_IGRPEN1_EL3 S3_6_C12_C12_7
+#define ICC_IGRPEN0_EL1 S3_0_C12_C12_6
+#define ICC_HPPIR0_EL1 S3_0_C12_C8_2
+#define ICC_HPPIR1_EL1 S3_0_C12_C12_2
+#define ICC_IAR0_EL1 S3_0_C12_C8_0
+#define ICC_IAR1_EL1 S3_0_C12_C12_0
+#define ICC_EOIR0_EL1 S3_0_C12_C8_1
+#define ICC_EOIR1_EL1 S3_0_C12_C12_1
+#define ICC_SGI0R_EL1 S3_0_C12_C11_7
+
+/* register constants */
+#define ICC_SRE_ELX_SRE_BIT BIT(0)
+#define ICC_SRE_ELX_DFB_BIT BIT(1)
+#define ICC_SRE_ELX_DIB_BIT BIT(2)
+#define ICC_SRE_EL3_EN_BIT BIT(3)
+
+/* ICC SGI macros */
+#define SGIR_TGT_MASK (0xffff)
+#define SGIR_AFF1_SHIFT (16)
+#define SGIR_AFF2_SHIFT (32)
+#define SGIR_AFF3_SHIFT (48)
+#define SGIR_AFF_MASK (0xf)
+#define SGIR_INTID_SHIFT (24)
+#define SGIR_INTID_MASK (0xf)
+#define SGIR_IRM_SHIFT (40)
+#define SGIR_IRM_MASK (0x1)
+#define SGIR_IRM_TO_AFF (0)
+#define SGIR_IRM_TO_ALL (1)
+
+#define GICV3_SGIR_VALUE(_aff3, _aff2, _aff1, _intid, _irm, _tgt) \
+ ((((uint64_t)(_aff3) & SGIR_AFF_MASK) << SGIR_AFF3_SHIFT) | \
+ (((uint64_t)(_irm) & SGIR_IRM_MASK) << SGIR_IRM_SHIFT) | \
+ (((uint64_t)(_aff2) & SGIR_AFF_MASK) << SGIR_AFF2_SHIFT) | \
+ (((_intid) & SGIR_INTID_MASK) << SGIR_INTID_SHIFT) | \
+ (((_aff1) & SGIR_AFF_MASK) << SGIR_AFF1_SHIFT) | \
+ ((_tgt) & SGIR_TGT_MASK))
+
+/* CPTR_EL2, Architectural Feature Trap Register (EL2) */
+
+#define CPTR_EZ_BIT BIT(8)
+#define CPTR_TFP_BIT BIT(10)
+#define CPTR_TTA_BIT BIT(20)
+#define CPTR_TCPAC_BIT BIT(31)
+#define CPTR_EL2_RES1 BIT(13) | BIT(12) | BIT(9) | (0xff)
+
+/* CPACR_EL1, Architectural Feature Access Control Register */
+#define CPACR_EL1_FPEN_NOTRAP (0x3 << 20)
+
+/* SCR_EL3, Secure Configuration Register */
+#define SCR_NS_BIT BIT(0)
+#define SCR_IRQ_BIT BIT(1)
+#define SCR_FIQ_BIT BIT(2)
+#define SCR_EA_BIT BIT(3)
+#define SCR_SMD_BIT BIT(7)
+#define SCR_HCE_BIT BIT(8)
+#define SCR_RW_BIT BIT(10)
+#define SCR_ST_BIT BIT(11)
+#define SCR_RES1 (BIT(4) | BIT(5))
+
+/* HCR_EL2, Hypervisor Configuration Register */
+
+#define HCR_FMO_BIT BIT(3)
+#define HCR_IMO_BIT BIT(4)
+#define HCR_AMO_BIT BIT(5)
+#define HCR_RW_BIT BIT(31)
+
+/* CNTHCTL_EL2 bits definitions */
+
+#define CNTHCTL_EL2_EL1PCEN_EN BIT(1)
+#define CNTHCTL_EL2_EL1PCTEN_EN BIT(0)
+
+/* CNTV_CVAL, Counter-timer Virtual Timer CompareValue register
+ * CNTV_CTL, Counter-timer Virtual Timer Control register
+ */
+
+#define CNTV_CTL_ENABLE_BIT BIT(0)
+#define CNTV_CTL_IMASK_BIT BIT(1)
+
+/* Maximum numbers of translation tables
+ * This option specifies the maximum numbers of translation tables
+ * excluding the base translation table. Based on this, translation
+ * tables are allocated at compile time and used at runtime as needed.
+ * If the runtime need exceeds preallocated numbers of translation
+ * tables, it will result in assert. Number of translation tables
+ * required is decided based on how many discrete memory regions
+ * (both normal and device memory) are present on given platform and
+ * how much granularity is required while assigning attributes
+ * to these memory regions.
+ */
+
+#define CONFIG_MAX_XLAT_TABLES 7
+
+/* Virtual address space size
+ * Allows choosing one of multiple possible virtual address
+ * space sizes. The level of translation table is determined by
+ * a combination of page size and virtual address space size.
+ *
+ * The choice could be: 32, 36, 42, 48
+ */
+
+#define CONFIG_ARM64_VA_BITS 36
+
+/* Physical address space size
+ * Choose the maximum physical address range that the kernel will support.
+ *
+ * The choice could be: 32, 36, 42, 48
+ */
+
+#define CONFIG_ARM64_PA_BITS 36
+
+#define L1_CACHE_SHIFT (6)
+#define L1_CACHE_BYTES BIT(L1_CACHE_SHIFT)
+
+/****************************************************************************
+ * Type Declarations
+ ****************************************************************************/
+
+#ifdef CONFIG_ARCH_FPU
+
+/****************************************************************************
+ * armv8 fpu registers and context
+ ****************************************************************************/
+
+struct fpu_reg
+{
+ __int128 q[32];
+ uint32_t fpsr;
+ uint32_t fpcr;
+ uint64_t fpu_trap;
+};
+
+#endif
+
+/****************************************************************************
+ * Registers and exception context
+ ****************************************************************************/
+
+struct regs_context
+{
+ uint64_t regs[31]; /* x0~x30 */
+ uint64_t sp_elx;
+ uint64_t elr;
+ uint64_t spsr;
+ uint64_t sp_el0;
+ uint64_t exe_depth;
+ uint64_t tpidr_el0;
+ uint64_t tpidr_el1;
+};
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name:
+ * getreg8/16/32/64
+ * putreg8/16/32/64
+ *
+ * Description:
+ * We need to use explicit assembler instruction there, because with
+ * classic "volatile pointer" approach compiler might generate
+ * instruction with immediate value like
+ *
+ * str w4, [x1], #4
+ *
+ * Such instructions produce invalid syndrome in HSR register,
+ * so hypervisor can't emulate MMIO when it traps memory access.
+ *
+ ****************************************************************************/
+
+static inline uint8_t getreg8(unsigned long addr)
+{
+ uint8_t val;
+
+ __asm__ volatile ("ldrb %w0, [%1]" : "=r" (val) : "r" (addr));
+
+ ARM64_DMB();
+ return val;
+}
+
+static inline void putreg8(uint8_t data, unsigned long addr)
+{
+ ARM64_DMB();
+ __asm__ volatile ("strb %w0, [%1]" : : "r" (data), "r" (addr));
+}
+
+static inline uint16_t getreg16(unsigned long addr)
+{
+ uint16_t val;
+
+ __asm__ volatile ("ldrh %w0, [%1]" : "=r" (val) : "r" (addr));
+
+ ARM64_DMB();
+ return val;
+}
+
+static inline void putreg16(uint16_t data, unsigned long addr)
+{
+ ARM64_DMB();
+ __asm__ volatile ("strh %w0, [%1]" : : "r" (data), "r" (addr));
+}
+
+static inline uint32_t getreg32(unsigned long addr)
+{
+ uint32_t val;
+
+ __asm__ volatile ("ldr %w0, [%1]" : "=r" (val) : "r" (addr));
+
+ ARM64_DMB();
+ return val;
+}
+
+static inline void putreg32(uint32_t data, unsigned long addr)
+{
+ ARM64_DMB();
+ __asm__ volatile ("str %w0, [%1]" : : "r" (data), "r" (addr));
+}
+
+static inline uint64_t getreg64(unsigned long addr)
+{
+ uint64_t val;
+
+ __asm__ volatile ("ldr %x0, [%1]" : "=r" (val) : "r" (addr));
+
+ ARM64_DMB();
+ return val;
+}
+
+static inline void putreg64(uint64_t data, unsigned long addr)
+{
+ ARM64_DMB();
+ __asm__ volatile ("str %x0, [%1]" : : "r" (data), "r" (addr));
+}
+
+static inline void arch_nop(void)
+{
+ __asm__ volatile ("nop");
+}
+
+/****************************************************************************
+ * Name:
+ * read_/write_/zero_ sysreg
+ *
+ * Description:
+ *
+ * ARMv8 Architecture Registers access method
+ * All the macros need a memory clobber
+ *
+ ****************************************************************************/
+
+#define read_sysreg(reg) \
+ ({ \
+ uint64_t __val; \
+ __asm__ volatile ("mrs %0, " STRINGIFY(reg) \
+ : "=r" (__val) :: "memory"); \
+ __val; \
+ })
+
+#define read_sysreg_dump(reg) \
+ ({ \
+ uint64_t __val; \
+ __asm__ volatile ("mrs %0, " STRINGIFY(reg) \
+ : "=r" (__val) :: "memory"); \
+ sinfo("%s, regval=0x%llx\n", \
+ STRINGIFY(reg), __val); \
+ __val; \
+ })
+
+#define write_sysreg(__val, reg) \
+ ({ \
+ __asm__ volatile ("msr " STRINGIFY(reg) ", %0" \
+ : : "r" (__val) : "memory"); \
+ })
+
+#define zero_sysreg(reg) \
+ ({ \
+ __asm__ volatile ("msr " STRINGIFY(reg) ", xzr" \
+ ::: "memory"); \
+ })
+
+#define modreg8(v,m,a) putreg8((getreg8(a) & ~(m)) | ((v) & (m)), (a))
+#define modreg16(v,m,a) putreg16((getreg16(a) & ~(m)) | ((v) & (m)), (a))
+#define modreg32(v,m,a) putreg32((getreg32(a) & ~(m)) | ((v) & (m)), (a))
+
+/****************************************************************************
+ * Name:
+ * arch_get_exception_depth
+ * arch_get_current_tcb
+ *
+ * Description:
+ * tpidrro_el0 is used to record exception depth, it's used for fpu trap
+ * happened at exception context (like IRQ).
+ * tpidr_el1 is used to record TCB at present, it's used for fpu and task
+ * switch propose
+ *
+ ****************************************************************************/
+
+static inline int arch_get_exception_depth(void)
+{
+ return read_sysreg(tpidrro_el0);
+}
+
+static inline uint64_t arch_get_current_tcb(void)
+{
+ return read_sysreg(tpidr_el1);
+}
+
+void arch_cpu_idle(void);
+
+/****************************************************************************
+ * Name: arm64_cpu_disable
+ *
+ * Description:
+ * Called from CPU0 to make sure that all other CPUs are in the disabled
+ * state. This is a formality because the other CPUs are actually running
+ * then we have probably already crashed.
+ *
+ * Input Parameters:
+ * None
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_SMP
+void arm64_cpu_disable(void);
+
+#else
+# define arm64_cpu_disable()
+#endif
+
+/****************************************************************************
+ * Name: arm64_cpu_enable
+ *
+ * Description:
+ * Called from CPU0 to enable all other CPUs. The enabled CPUs will start
+ * execution at __cpuN_start and, after very low-level CPU initialization
+ * has been performed, will branch to arm_cpu_boot()
+ *
+ * Input Parameters:
+ * None
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_SMP
+void arm64_cpu_enable(void);
+
+#else
+# define arm64_cpu_enable()
+#endif
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* ___ARCH_ARM64_SRC_COMMON_ARM64_ARCH_H */
diff --git a/arch/arm64/src/common/arm64_arch_timer.c b/arch/arm64/src/common/arm64_arch_timer.c
new file mode 100644
index 0000000000..72173b1979
--- /dev/null
+++ b/arch/arm64/src/common/arm64_arch_timer.c
@@ -0,0 +1,233 @@
+/****************************************************************************
+ * arch/arm64/src/common/arm64_arch_timer.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 <debug.h>
+#include <assert.h>
+
+#include <nuttx/arch.h>
+#include <arch/irq.h>
+#include <arch/chip/chip.h>
+#include <nuttx/spinlock.h>
+
+#include "arm64_arch.h"
+#include "arm64_internal.h"
+#include "arm64_gic.h"
+#include "arm64_arch_timer.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+#define MIN_DELAY (1000)
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static uint64_t last_cycle;
+static uint64_t cycle_per_tick;
+static uint32_t arch_timer_rate;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static inline void arm64_arch_timer_set_compare(uint64_t value)
+{
+ write_sysreg(value, cntv_cval_el0);
+}
+
+static inline void arm64_arch_timer_enable(unsigned char enable)
+{
+ uint64_t value;
+
+ value = read_sysreg(cntv_ctl_el0);
+
+ if (enable)
+ {
+ value |= CNTV_CTL_ENABLE_BIT;
+ }
+ else
+ {
+ value &= ~CNTV_CTL_ENABLE_BIT;
+ }
+
+ write_sysreg(value, cntv_ctl_el0);
+}
+
+static inline void arm64_arch_timer_set_irq_mask(bool mask)
+{
+ uint64_t value;
+
+ value = read_sysreg(cntv_ctl_el0);
+
+ if (mask)
+ {
+ value |= CNTV_CTL_IMASK_BIT;
+ }
+ else
+ {
+ value &= ~CNTV_CTL_IMASK_BIT;
+ }
+
+ write_sysreg(value, cntv_ctl_el0);
+}
+
+static inline uint64_t arm64_arch_timer_count(void)
+{
+ return read_sysreg(cntvct_el0);
+}
+
+static inline uint32_t arm64_arch_timer_get_cntfrq(void)
+{
+ return read_sysreg(cntfrq_el0);
+}
+
+#ifdef CONFIG_SCHED_TICKLESS
+static int arm64_arch_timer_compare_isr(int irq, void *regs, void *arg)
+{
+ irqstate_t flags;
+ uint64_t curr_cycle;
+ uint32_t delta_ticks;
+
+ UNUSED(regs);
+ UNUSED(arg);
+
+ flags = spin_lock_irqsave(&g_arch_timer_lock);
+
+ curr_cycle = arm64_arch_timer_count();
+ delta_ticks = (uint32_t)((curr_cycle - last_cycle) / cycle_per_tick);
+
+ last_cycle += delta_ticks * cycle_per_tick;
+
+ arm_arch_timer_set_irq_mask(true);
+
+ spin_unlock_irqrestore(&g_arch_timer_lock, flags);
+
+ nxsched_process_timer();
+ return OK;
+}
+
+#else
+
+static int arm64_arch_timer_compare_isr(int irq, void *regs, void *arg)
+{
+ uint64_t curr_cycle;
+ uint32_t delta_ticks;
+ uint64_t next_cycle;
+
+ UNUSED(irq);
+ UNUSED(regs);
+ UNUSED(arg);
+
+ curr_cycle = arm64_arch_timer_count();
+ delta_ticks = (uint32_t)((curr_cycle - last_cycle) / cycle_per_tick);
+
+ last_cycle += delta_ticks * cycle_per_tick;
+
+ next_cycle = last_cycle + cycle_per_tick;
+
+ if ((uint64_t)(next_cycle - curr_cycle) < MIN_DELAY)
+ {
+ next_cycle += cycle_per_tick;
+ }
+
+ arm64_arch_timer_set_compare(next_cycle);
+ arm64_arch_timer_set_irq_mask(false);
+
+ nxsched_process_timer();
+ return OK;
+}
+
+#endif
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+#ifdef CONFIG_SMP
+/* Notes:
+ *
+ * The origin design for ARMv8-A timer is assigned private timer to
+ * every PE(CPU core), the ARM_ARCH_TIMER_IRQ is a PPI so it's
+ * should be enable at every core.
+ *
+ * But for NuttX, it's design only for primary core to handle timer
+ * interrupt and call nxsched_process_timer at timer tick mode.
+ * So we need only enable timer for primary core
+ *
+ * IMX6 use GPT which is a SPI rather than generic timer to handle
+ * timer interrupt
+ */
+
+void arm64_smp_timer_init(void)
+{
+ uint64_t curr_cycle;
+
+ /* set the initial status of timer0 of each secondary core */
+
+ curr_cycle = arm64_arch_timer_count();
+
+ arm64_arch_timer_set_compare(curr_cycle + cycle_per_tick);
+ arm64_arch_timer_enable(true);
+ up_enable_irq(ARM_ARCH_TIMER_IRQ);
+ arm64_arch_timer_set_irq_mask(false);
+}
+
+#endif
+
+uint64_t arm64_counter_read(void)
+{
+ return arm64_arch_timer_count();
+}
+
+/****************************************************************************
+ * Name: up_timer_initialize
+ *
+ * Description:
+ *
+ ****************************************************************************/
+
+void up_timer_initialize(void)
+{
+ uint64_t curr_cycle;
+
+ arch_timer_rate = arm64_arch_timer_get_cntfrq();
+ cycle_per_tick = ((uint64_t)arch_timer_rate / (uint64_t)TICK_PER_SEC);
+
+ sinfo("%s: cp15 timer(s) running at %lu.%02luMHz, cycle %ld\n", __func__,
+ (unsigned long)arch_timer_rate / 1000000,
+ (unsigned long)(arch_timer_rate / 10000) % 100, cycle_per_tick);
+
+ irq_attach(ARM_ARCH_TIMER_IRQ, arm64_arch_timer_compare_isr, 0);
+ arm64_gic_irq_set_priority(ARM_ARCH_TIMER_IRQ, ARM_ARCH_TIMER_PRIO,
+ ARM_ARCH_TIMER_FLAGS);
+
+ curr_cycle = arm64_arch_timer_count();
+ arm64_arch_timer_set_compare(curr_cycle + cycle_per_tick);
+ arm64_arch_timer_enable(true);
+
+ up_enable_irq(ARM_ARCH_TIMER_IRQ);
+ arm64_arch_timer_set_irq_mask(false);
+}
diff --git a/arch/arm64/src/common/arm64_arch_timer.h b/arch/arm64/src/common/arm64_arch_timer.h
new file mode 100644
index 0000000000..0dd0d77f58
--- /dev/null
+++ b/arch/arm64/src/common/arm64_arch_timer.h
@@ -0,0 +1,58 @@
+/****************************************************************************
+ * arch/arm64/src/common/arm64_arch_timer.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_ARM64_SRC_COMMON_ARM64_ARCH_TIMER_H
+#define __ARCH_ARM64_SRC_COMMON_ARM64_ARCH_TIMER_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <arch/irq.h>
+#include <arch/chip/chip.h>
+
+#include "arm64_gic.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define CONFIG_ARM_TIMER_SECURE_IRQ (GIC_PPI_INT_BASE + 13)
+#define CONFIG_ARM_TIMER_NON_SECURE_IRQ (GIC_PPI_INT_BASE + 14)
+#define CONFIG_ARM_TIMER_VIRTUAL_IRQ (GIC_PPI_INT_BASE + 11)
+#define CONFIG_ARM_TIMER_HYP_IRQ (GIC_PPI_INT_BASE + 10)
+
+#define ARM_ARCH_TIMER_IRQ CONFIG_ARM_TIMER_VIRTUAL_IRQ
+#define ARM_ARCH_TIMER_PRIO IRQ_DEFAULT_PRIORITY
+#define ARM_ARCH_TIMER_FLAGS IRQ_TYPE_LEVEL
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+extern uint64_t arm64_counter_read(void);
+extern void arm64_start_timer(void);
+
+#ifdef CONFIG_SMP
+void arm64_smp_timer_init(void);
+#endif
+
+#endif /* __ARCH_ARM64_SRC_COMMON_ARM64_ARCH_TIMER_H */
diff --git a/arch/arm64/src/common/arm64_assert.c b/arch/arm64/src/common/arm64_assert.c
new file mode 100644
index 0000000000..186240be20
--- /dev/null
+++ b/arch/arm64/src/common/arm64_assert.c
@@ -0,0 +1,583 @@
+/****************************************************************************
+ * arch/arm64/src/common/arm64_assert.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 <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <nuttx/irq.h>
+#include <nuttx/arch.h>
+#include <assert.h>
+#include <debug.h>
+#include <nuttx/board.h>
+#include <nuttx/syslog/syslog.h>
+#include <nuttx/usb/usbdev_trace.h>
+
+#include "sched/sched.h"
+#include "irq/irq.h"
+#include "arm64_arch.h"
+#include "arm64_internal.h"
+#include "chip.h"
+
+#ifdef CONFIG_ARCH_FPU
+#include "arm64_fpu.h"
+#endif
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* USB trace dumping */
+
+#ifndef CONFIG_USBDEV_TRACE
+# undef CONFIG_ARCH_USBDUMP
+#endif
+
+#ifndef CONFIG_BOARD_RESET_ON_ASSERT
+# define CONFIG_BOARD_RESET_ON_ASSERT 0
+#endif
+
+/****************************************************************************
+ * Name: arm_registerdump
+ ****************************************************************************/
+
+static void arm64_registerdump(struct regs_context * regs)
+{
+ _alert("stack = %p\n", regs);
+ _alert("x0: 0x%-16"PRIx64" x1: 0x%"PRIx64"\n",
+ regs->regs[REG_X0], regs->regs[REG_X1]);
+ _alert("x2: 0x%-16"PRIx64" x3: 0x%"PRIx64"\n",
+ regs->regs[REG_X2], regs->regs[REG_X3]);
+ _alert("x4: 0x%-16"PRIx64" x5: 0x%"PRIx64"\n",
+ regs->regs[REG_X4], regs->regs[REG_X5]);
+ _alert("x6: 0x%-16"PRIx64" x7: 0x%"PRIx64"\n",
+ regs->regs[REG_X6], regs->regs[REG_X7]);
+ _alert("x8: 0x%-16"PRIx64" x9: 0x%"PRIx64"\n",
+ regs->regs[REG_X8], regs->regs[REG_X9]);
+ _alert("x10: 0x%-16"PRIx64" x11: 0x%"PRIx64"\n",
+ regs->regs[REG_X10], regs->regs[REG_X11]);
+ _alert("x12: 0x%-16"PRIx64" x13: 0x%"PRIx64"\n",
+ regs->regs[REG_X12], regs->regs[REG_X13]);
+ _alert("x14: 0x%-16"PRIx64" x15: 0x%"PRIx64"\n",
+ regs->regs[REG_X14], regs->regs[REG_X15]);
+ _alert("x16: 0x%-16"PRIx64" x17: 0x%"PRIx64"\n",
+ regs->regs[REG_X16], regs->regs[REG_X17]);
+ _alert("x18: 0x%-16"PRIx64" x19: 0x%"PRIx64"\n",
+ regs->regs[REG_X18], regs->regs[REG_X19]);
+ _alert("x20: 0x%-16"PRIx64" x21: 0x%"PRIx64"\n",
+ regs->regs[REG_X20], regs->regs[REG_X21]);
+ _alert("x22: 0x%-16"PRIx64" x23: 0x%"PRIx64"\n",
+ regs->regs[REG_X22], regs->regs[REG_X23]);
+ _alert("x24: 0x%-16"PRIx64" x25: 0x%"PRIx64"\n",
+ regs->regs[REG_X24], regs->regs[REG_X25]);
+ _alert("x26: 0x%-16"PRIx64" x27: 0x%"PRIx64"\n",
+ regs->regs[REG_X26], regs->regs[REG_X27]);
+ _alert("x28: 0x%-16"PRIx64" x29: 0x%"PRIx64"\n",
+ regs->regs[REG_X28], regs->regs[REG_X29]);
+ _alert("x30: 0x%-16"PRIx64"\n", regs->regs[REG_X30]);
+
+ _alert("\n");
+ _alert("STATUS Registers:\n");
+ _alert("SPSR: 0x%-16"PRIx64"\n", regs->spsr);
+ _alert("ELR: 0x%-16"PRIx64"\n", regs->elr);
+ _alert("SP_EL0: 0x%-16"PRIx64"\n", regs->sp_el0);
+ _alert("SP_ELX: 0x%-16"PRIx64"\n", regs->sp_elx);
+ _alert("TPIDR_EL0: 0x%-16"PRIx64"\n", regs->tpidr_el0);
+ _alert("TPIDR_EL1: 0x%-16"PRIx64"\n", regs->tpidr_el1);
+ _alert("EXE_DEPTH: 0x%-16"PRIx64"\n", regs->exe_depth);
+}
+
+#ifdef CONFIG_ARCH_STACKDUMP
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: arm_stackdump
+ ****************************************************************************/
+
+static void arm64_stackdump(uint64_t sp, uint64_t stack_top)
+{
+ uint64_t stack;
+
+ /* Flush any buffered SYSLOG data to avoid overwrite */
+
+ syslog_flush();
+
+ for (stack = sp & ~0x1f; stack < (stack_top & ~0x1f); stack += 64)
+ {
+ uint64_t *ptr = (uint64_t *)stack;
+ _alert("%08" PRIx64 ": %08" PRIx64 " %08" PRIx64 " %08" PRIx64
+ " %08" PRIx64 " %08" PRIx64 " %08" PRIx64 " %08" PRIx64
+ " %08" PRIx64 "\n",
+ stack, ptr[0], ptr[1], ptr[2], ptr[3],
+ ptr[4], ptr[5], ptr[6], ptr[7]);
+ }
+}
+
+/****************************************************************************
+ * Name: arm_dump_task
+ ****************************************************************************/
+
+static void arm64_dump_task(struct tcb_s *tcb, void *arg)
+{
+ char args[64] = "";
+#ifdef CONFIG_STACK_COLORATION
+ uint64_t stack_filled = 0;
+ uint64_t stack_used;
+#endif
+#ifdef CONFIG_SCHED_CPULOAD
+ struct cpuload_s cpuload;
+ uint64_t fracpart;
+ uint64_t intpart;
+ uint64_t tmp;
+
+ clock_cpuload(tcb->pid, &cpuload);
+
+ if (cpuload.total > 0)
+ {
+ tmp = (1000 * cpuload.active) / cpuload.total;
+ intpart = tmp / 10;
+ fracpart = tmp - 10 * intpart;
+ }
+ else
+ {
+ intpart = 0;
+ fracpart = 0;
+ }
+#endif
+
+#ifdef CONFIG_STACK_COLORATION
+ stack_used = up_check_tcbstack(tcb);
+ if (tcb->adj_stack_size > 0 && stack_used > 0)
+ {
+ /* Use fixed-point math with one decimal place */
+
+ stack_filled = 10 * 100 * stack_used / tcb->adj_stack_size;
+ }
+#endif
+
+#ifndef CONFIG_DISABLE_PTHREAD
+ if ((tcb->flags & TCB_FLAG_TTYPE_MASK) == TCB_FLAG_TTYPE_PTHREAD)
+ {
+ struct pthread_tcb_s *ptcb = (struct pthread_tcb_s *)tcb;
+
+ snprintf(args, sizeof(args), "%p ", ptcb->arg);
+ }
+ else
+#endif
+ {
+ char **argv = tcb->group->tg_info->argv + 1;
+ size_t npos = 0;
+
+ while (*argv != NULL && npos < sizeof(args))
+ {
+ npos += snprintf(args + npos, sizeof(args) - npos, " %s", *argv++);
+ }
+ }
+
+ /* Dump interesting properties of this task */
+
+ _alert(" %4d %4d"
+#ifdef CONFIG_SMP
+ " %4d"
+#endif
+#ifdef CONFIG_STACK_COLORATION
+ " %7lu"
+#endif
+ " %7lu"
+#ifdef CONFIG_STACK_COLORATION
+ " %3" PRId64 ".%1" PRId64 "%%%c"
+#endif
+#ifdef CONFIG_SCHED_CPULOAD
+ " %3" PRId64 ".%01" PRId64 "%%"
+#endif
+#if CONFIG_TASK_NAME_SIZE > 0
+ " %s %s\n",
+#else
+ " %s\n",
+#endif
+ tcb->pid, tcb->sched_priority,
+#ifdef CONFIG_SMP
+ tcb->cpu,
+#endif
+#ifdef CONFIG_STACK_COLORATION
+ (unsigned long)up_check_tcbstack(tcb),
+#endif
+ (unsigned long)tcb->adj_stack_size
+#ifdef CONFIG_STACK_COLORATION
+ , stack_filled / 10, stack_filled % 10,
+ (stack_filled >= 10 * 80 ? '!' : ' ')
+#endif
+#ifdef CONFIG_SCHED_CPULOAD
+ , intpart, fracpart
+#endif
+#if CONFIG_TASK_NAME_SIZE > 0
+ , tcb->name
+#else
+ , "<noname>"
+#endif
+ , args
+ );
+}
+
+/****************************************************************************
+ * Name: arm_dump_backtrace
+ ****************************************************************************/
+
+#ifdef CONFIG_SCHED_BACKTRACE
+static void arm64_dump_backtrace(struct tcb_s *tcb, void *arg)
+{
+ /* Show back trace */
+
+ sched_dumpstack(tcb->pid);
+}
+#endif
+
+/****************************************************************************
+ * Name: arm_showtasks
+ ****************************************************************************/
+
+static void arm64_showtasks(void)
+{
+#if CONFIG_ARCH_INTERRUPTSTACK > 15
+# ifdef CONFIG_STACK_COLORATION
+ uint64_t stack_used = up_check_intstack();
+ uint64_t stack_filled = 0;
+
+ if ((CONFIG_ARCH_INTERRUPTSTACK & ~15) > 0 && stack_used > 0)
+ {
+ /* Use fixed-point math with one decimal place */
+
+ stack_filled = 10 * 100 *
+ stack_used / (CONFIG_ARCH_INTERRUPTSTACK & ~15);
+ }
+# endif
+#endif
+
+ /* Dump interesting properties of each task in the crash environment */
+
+ _alert(" PID PRI"
+#ifdef CONFIG_SMP
+ " CPU"
+#endif
+#ifdef CONFIG_STACK_COLORATION
+ " USED"
+#endif
+ " STACK"
+#ifdef CONFIG_STACK_COLORATION
+ " FILLED "
+#endif
+#ifdef CONFIG_SCHED_CPULOAD
+ " CPU"
+#endif
+ " COMMAND\n");
+
+#if CONFIG_ARCH_INTERRUPTSTACK > 7
+ _alert(" ---- ----"
+# ifdef CONFIG_SMP
+ " ----"
+# endif
+# ifdef CONFIG_STACK_COLORATION
+ " %7lu"
+# endif
+ " %7lu"
+# ifdef CONFIG_STACK_COLORATION
+ " %3" PRId64 ".%1" PRId64 "%%%c"
+# endif
+# ifdef CONFIG_SCHED_CPULOAD
+ " ----"
+# endif
+# if CONFIG_TASK_NAME_SIZE > 0
+ " irq"
+# endif
+ "\n"
+# ifdef CONFIG_STACK_COLORATION
+ , (unsigned long)stack_used
+# endif
+ , (unsigned long)(CONFIG_ARCH_INTERRUPTSTACK & ~15)
+# ifdef CONFIG_STACK_COLORATION
+ , stack_filled / 10, stack_filled % 10,
+ (stack_filled >= 10 * 80 ? '!' : ' ')
+# endif
+ );
+#endif
+
+ nxsched_foreach(arm64_dump_task, NULL);
+#ifdef CONFIG_SCHED_BACKTRACE
+ nxsched_foreach(arm64_dump_backtrace, NULL);
+#endif
+}
+
+/****************************************************************************
+ * Name: assert_tracecallback
+ ****************************************************************************/
+
+#ifdef CONFIG_ARCH_USBDUMP
+static int usbtrace_syslog(const char *fmt, ...)
+{
+ va_list ap;
+
+ /* Let vsyslog do the real work */
+
+ va_start(ap, fmt);
+ vsyslog(LOG_EMERG, fmt, ap);
+ va_end(ap);
+ return OK;
+}
+
+static int assert_tracecallback(struct usbtrace_s *trace, void *arg)
+{
+ usbtrace_trprintf(usbtrace_syslog, trace->event, trace->value);
+ return 0;
+}
+#endif
+
+/****************************************************************************
+ * Name: arm_dump_stack
+ ****************************************************************************/
+
+static void arm64_dump_stack(const char *tag, uint64_t sp,
+ uint64_t base, uint64_t size, bool force)
+{
+ uint64_t top = base + size;
+
+ _alert("%s Stack:\n", tag);
+ _alert("sp: %08" PRIx64 "\n", sp);
+ _alert(" base: %08" PRIx64 "\n", base);
+ _alert(" size: %08" PRIx64 "\n", size);
+
+ if (sp >= base && sp < top)
+ {
+ arm64_stackdump(sp, top);
+ }
+ else
+ {
+ _alert("ERROR: %s Stack pointer is not within the stack\n", tag);
+
+ if (force)
+ {
+ arm64_stackdump(base, top);
+ }
+ }
+}
+
+/****************************************************************************
+ * Name: arm64_dumpstate_assert (for assert)
+ ****************************************************************************/
+
+static void arm64_dumpstate_assert(void)
+{
+ struct tcb_s *rtcb = (struct tcb_s *)arch_get_current_tcb();
+ uint64_t sp = up_getsp();
+
+ /* Show back trace */
+
+#ifdef CONFIG_SCHED_BACKTRACE
+ sched_dumpstack(rtcb->pid);
+#endif
+
+ /* Update the xcp context */
+
+ if (CURRENT_REGS)
+ {
+ /* in interrupt */
+
+ rtcb->xcp.regs = (uint64_t *)CURRENT_REGS;
+ }
+ else
+ {
+ up_saveusercontext(rtcb->xcp.regs);
+ }
+
+ /* Dump the registers */
+
+ arm64_registerdump((struct regs_context *)rtcb->xcp.regs);
+
+ /* Dump the irq stack */
+
+#if CONFIG_ARCH_INTERRUPTSTACK > 7
+ arm64_dump_stack("IRQ", sp,
+# ifdef CONFIG_SMP
+ (uint64_t)arm64_intstack_alloc(),
+# else
+ (uint64_t)&g_interrupt_stack,
+# endif
+ (CONFIG_ARCH_INTERRUPTSTACK & ~15),
+ !!CURRENT_REGS);
+
+ if (CURRENT_REGS)
+ {
+ sp = CURRENT_REGS[REG_X13];
+ }
+#endif
+
+ /* Dump the user stack */
+
+ arm64_dump_stack("User", sp,
+ (uint64_t)rtcb->stack_base_ptr,
+ (uint64_t)rtcb->adj_stack_size,
+#ifdef CONFIG_ARCH_KERNEL_STACK
+ false
+#else
+ true
+#endif
+ );
+
+#ifdef CONFIG_ARCH_KERNEL_STACK
+ arm64_dump_stack("Kernel", sp,
+ (uint64_t)rtcb->xcp.kstack,
+ CONFIG_ARCH_KERNEL_STACKSIZE,
+ false);
+#endif
+
+ /* Dump the state of all tasks (if available) */
+
+ arm64_showtasks();
+
+#ifdef CONFIG_ARCH_USBDUMP
+ /* Dump USB trace data */
+
+ usbtrace_enumerate(assert_tracecallback, NULL);
+#endif
+}
+
+#endif /* CONFIG_ARCH_STACKDUMP */
+
+/****************************************************************************
+ * Name: arm64_dump_fatal
+ ****************************************************************************/
+
+void arm64_dump_fatal(struct regs_context * regs)
+{
+#ifdef CONFIG_SCHED_BACKTRACE
+ struct tcb_s *rtcb = (struct tcb_s *)regs->tpidr_el1;
+
+ /* Show back trace */
+
+ sched_dumpstack(rtcb->pid);
+#endif
+
+ /* Dump the registers */
+
+ arm64_registerdump(regs);
+}
+
+void up_mdelay(unsigned int milliseconds)
+{
+ volatile unsigned int i;
+ volatile unsigned int j;
+
+ for (i = 0; i < milliseconds; i++)
+ {
+ for (j = 0; j < CONFIG_BOARD_LOOPSPERMSEC; j++)
+ {
+ }
+ }
+}
+
+/****************************************************************************
+ * Name: arm64_assert
+ ****************************************************************************/
+
+static void arm64_assert(void)
+{
+ /* Flush any buffered SYSLOG data */
+
+ syslog_flush();
+
+ /* Are we in an interrupt handler or the idle task? */
+
+ if (CURRENT_REGS || (running_task())->flink == NULL)
+ {
+ /* Disable interrupts on this CPU */
+
+ up_irq_save();
+
+ for (; ; )
+ {
+#ifdef CONFIG_SMP
+ /* Try (again) to stop activity on other CPUs */
+
+ spin_trylock(&g_cpu_irqlock);
+#endif
+
+ up_mdelay(250);
+ }
+ }
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: up_assert
+ ****************************************************************************/
+
+void up_assert(const char *filename, int lineno)
+{
+#ifdef CONFIG_ARCH_FPU
+ arm64_fpu_disable();
+#endif
+
+ /* Flush any buffered SYSLOG data (prior to the assertion) */
+
+ syslog_flush();
+
+ _alert("Assertion failed "
+#ifdef CONFIG_SMP
+ "CPU%d "
+#endif
+ "at file:%s line: %d"
+#if CONFIG_TASK_NAME_SIZE > 0
+ " task: %s"
+#endif
+ "\n",
+#ifdef CONFIG_SMP
+ up_cpu_index(),
+#endif
+ filename, lineno
+#if CONFIG_TASK_NAME_SIZE > 0
+ , running_task()->name
+#endif
+ );
+
+#ifdef CONFIG_ARCH_STACKDUMP
+ arm64_dumpstate_assert();
+#endif
+
+ /* Flush any buffered SYSLOG data (from the above) */
+
+ syslog_flush();
+
+#ifdef CONFIG_BOARD_CRASHDUMP
+ board_crashdump(up_getsp(), running_task(), filename, lineno);
+#endif
+
+ arm64_assert();
+}
diff --git a/arch/arm64/src/common/arm64_backtrace.c b/arch/arm64/src/common/arm64_backtrace.c
new file mode 100644
index 0000000000..340e67f1f7
--- /dev/null
+++ b/arch/arm64/src/common/arm64_backtrace.c
@@ -0,0 +1,184 @@
+/****************************************************************************
+ * arch/arm64/src/common/arm64_backtrace.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 <nuttx/arch.h>
+
+#include "sched/sched.h"
+#include "arm64_internal.h"
+#include "arm64_arch.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#if defined(CONFIG_FRAME_POINTER)
+
+/****************************************************************************
+ * Name: backtrace
+ *
+ * Description:
+ * backtrace() parsing the return address through frame pointer
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_MM_KASAN
+__attribute__((no_sanitize_address))
+#endif
+static int backtrace(uintptr_t *base, uintptr_t *limit,
+ uintptr_t *fp, uintptr_t *pc,
+ void **buffer, int size, int *skip)
+{
+ int i = 0;
+
+ if (pc)
+ {
+ i++;
+ if (*skip-- <= 0)
+ {
+ *buffer++ = pc;
+ }
+ }
+
+ for (; i < size; fp = (uintptr_t *)*(fp - 1), i++)
+ {
+ if (fp > limit || fp < base || *fp == 0)
+ {
+ break;
+ }
+
+ if (*skip-- <= 0)
+ {
+ *buffer++ = (void *)*fp;
+ }
+ }
+
+ return i;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: up_backtrace
+ *
+ * Description:
+ * up_backtrace() returns a backtrace for the TCB, in the array
+ * pointed to by buffer. A backtrace is the series of currently active
+ * function calls for the program. Each item in the array pointed to by
+ * buffer is of type void *, and is the return address from the
+ * corresponding stack frame. The size argument specifies the maximum
+ * number of addresses that can be stored in buffer. If the backtrace is
+ * larger than size, then the addresses corresponding to the size most
+ * recent function calls are returned; to obtain the complete backtrace,
+ * make sure that buffer and size are large enough.
+ *
+ * Input Parameters:
+ * tcb - Address of the task's TCB
+ * buffer - Return address from the corresponding stack frame
+ * size - Maximum number of addresses that can be stored in buffer
+ * skip - number of addresses to be skipped
+ *
+ * Returned Value:
+ * up_backtrace() returns the number of addresses returned in buffer
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_MM_KASAN
+__attribute__((no_sanitize_address))
+#endif
+int up_backtrace(struct tcb_s *tcb,
+ void **buffer, int size, int skip)
+{
+ struct tcb_s *rtcb = (struct tcb_s *)arch_get_current_tcb();
+ struct regs_context * p_regs;
+
+#if CONFIG_ARCH_INTERRUPTSTACK > 7
+ void *istacklimit;
+#endif
+ irqstate_t flags;
+ int ret;
+
+ if (size <= 0 || !buffer)
+ {
+ return 0;
+ }
+
+ if (tcb == NULL || tcb == rtcb)
+ {
+ if (up_interrupt_context())
+ {
+#if CONFIG_ARCH_INTERRUPTSTACK > 7
+# ifdef CONFIG_SMP
+ istacklimit = (void *)arm64_intstack_top();
+# else
+ istacklimit = g_interrupt_stack + INTSTACK_SIZE;
+# endif /* CONFIG_SMP */
+ ret = backtrace(istacklimit - (CONFIG_ARCH_INTERRUPTSTACK & ~15),
+ istacklimit,
+ (void *)__builtin_frame_address(0),
+ NULL, buffer, size, &skip);
+#else
+ ret = backtrace(rtcb->stack_base_ptr,
+ rtcb->stack_base_ptr + rtcb->adj_stack_size,
+ (void *)__builtin_frame_address(0),
+ NULL, buffer, size, &skip);
+#endif /* CONFIG_ARCH_INTERRUPTSTACK > 7 */
+ if (ret < size)
+ {
+ p_regs = (struct regs_context *)CURRENT_REGS;
+ ret += backtrace(rtcb->stack_base_ptr,
+ rtcb->stack_base_ptr + rtcb->adj_stack_size,
+ (void *)p_regs->regs[REG_X29],
+ (void *)p_regs->elr,
+ &buffer[ret], size - ret, &skip);
+ }
+ }
+ else
+ {
+ ret = backtrace(rtcb->stack_base_ptr,
+ rtcb->stack_base_ptr + rtcb->adj_stack_size,
+ (void *)__builtin_frame_address(0),
+ NULL, buffer, size, &skip);
+ }
+ }
+ else
+ {
+ flags = enter_critical_section();
+ p_regs = (struct regs_context *)CURRENT_REGS;
+
+ ret = backtrace(tcb->stack_base_ptr,
+ tcb->stack_base_ptr + tcb->adj_stack_size,
+ (void *)p_regs->regs[REG_X29],
+ (void *)p_regs->elr,
+ buffer, size, &skip);
+
+ leave_critical_section(flags);
+ }
+
+ return ret;
+}
+#endif /* CONFIG_FRAME_POINTER */
diff --git a/arch/arm64/src/common/arm64_blocktask.c b/arch/arm64/src/common/arm64_blocktask.c
new file mode 100644
index 0000000000..ab38103ac4
--- /dev/null
+++ b/arch/arm64/src/common/arm64_blocktask.c
@@ -0,0 +1,162 @@
+/****************************************************************************
+ * arch/arm64/src/common/arm64_blocktask.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 <stdbool.h>
+#include <sched.h>
+#include <assert.h>
+#include <debug.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/sched.h>
+
+#include "sched/sched.h"
+#include "group/group.h"
+#include "arm64_internal.h"
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: up_block_task
+ *
+ * Description:
+ * The currently executing task at the head of the ready to run list must
+ * be stopped. Save its context and move it to the inactive list
+ * specified by task_state.
+ *
+ * Input Parameters:
+ * tcb: Refers to a task in the ready-to-run list (normally the task at
+ * the head of the list). It must be stopped, its context saved and
+ * moved into one of the waiting task lists. If it was the task at the
+ * head of the ready-to-run list, then a context switch to the new
+ * ready to run task must be performed.
+ * task_state: Specifies which waiting task list should hold the blocked
+ * task TCB.
+ *
+ ****************************************************************************/
+
+void up_block_task(struct tcb_s *tcb, tstate_t task_state)
+{
+ struct tcb_s *rtcb;
+ bool switch_needed;
+
+ rtcb = this_task();
+
+ /* Verify that the context switch can be performed */
+
+ DEBUGASSERT((tcb->task_state >= FIRST_READY_TO_RUN_STATE) &&
+ (tcb->task_state <= LAST_READY_TO_RUN_STATE));
+
+ /* Remove the tcb task from the ready-to-run list. If we are blocking the
+ * task at the head of the task list (the most likely case), then a
+ * context switch to the next ready-to-run task is needed. In this case,
+ * it should also be true that rtcb == tcb.
+ */
+
+ switch_needed = nxsched_remove_readytorun(tcb);
+
+ /* Add the task to the specified blocked task list */
+
+ nxsched_add_blocked(tcb, (tstate_t)task_state);
+
+ /* If there are any pending tasks, then add them to the ready-to-run
+ * task list now
+ */
+
+ if (g_pendingtasks.head)
+ {
+ switch_needed |= nxsched_merge_pending();
+ }
+
+ /* Now, perform the context switch if one is needed */
+
+ if (switch_needed)
+ {
+ /* Update scheduler parameters */
+
+ nxsched_suspend_scheduler(rtcb);
+
+ /* Are we in an interrupt handler? */
+
+ if (CURRENT_REGS)
+ {
+ /* Yes, then we have to do things differently.
+ * Just copy the CURRENT_REGS into the OLD rtcb.
+ */
+
+ arm64_savestate(rtcb->xcp.regs);
+
+ /* Restore the exception context of the rtcb at the (new) head
+ * of the ready-to-run task list.
+ */
+
+ rtcb = this_task();
+
+ /* Reset scheduler parameters */
+
+ nxsched_resume_scheduler(rtcb);
+
+ /* Then switch contexts. Any necessary address environment
+ * changes will be made when the interrupt returns.
+ */
+
+ arm64_restorestate(rtcb->xcp.regs);
+ }
+
+ /* No, then we will need to perform the user context switch */
+
+ else
+ {
+ struct tcb_s *nexttcb = this_task();
+
+#ifdef CONFIG_ARCH_ADDRENV
+ /* Make sure that the address environment for the previously
+ * running task is closed down gracefully (data caches dump,
+ * MMU flushed) and set up the address environment for the new
+ * thread at the head of the ready-to-run list.
+ */
+
+ group_addrenv(nexttcb);
+#endif
+ /* Reset scheduler parameters */
+
+ nxsched_resume_scheduler(nexttcb);
+
+ /* Switch context to the context of the task at the head of the
+ * ready to run list.
+ */
+
+ arm64_switchcontext(&rtcb->xcp.regs, nexttcb->xcp.regs);
+
+ /* arm_switchcontext forces a context switch to the task at the
+ * head of the ready-to-run list. It does not 'return' in the
+ * normal sense. When it does return, it is because the blocked
+ * task is again ready to run and has execution priority.
+ */
+ }
+ }
+}
diff --git a/arch/arm64/src/common/arm64_boot.c b/arch/arm64/src/common/arm64_boot.c
new file mode 100644
index 0000000000..4b1492c01e
--- /dev/null
+++ b/arch/arm64/src/common/arm64_boot.c
@@ -0,0 +1,184 @@
+/****************************************************************************
+ * arch/arm64/src/common/arm64_boot.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 <nuttx/arch.h>
+#include <nuttx/init.h>
+
+#include "arm64_internal.h"
+#include "arm64_arch.h"
+
+extern void *_vector_table[];
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+void arm64_boot_el3_init(void)
+{
+ uint64_t reg;
+
+ /* Setup vector table */
+
+ write_sysreg((uint64_t)_vector_table, vbar_el3);
+ ARM64_ISB();
+
+ reg = 0U; /* Mostly RES0 */
+ reg &= ~(CPTR_TTA_BIT | /* Do not trap sysreg accesses */
+ CPTR_TFP_BIT | /* Do not trap SVE, SIMD and FP */
+ CPTR_TCPAC_BIT); /* Do not trap CPTR_EL2 CPACR_EL1 accesses */
+
+ /* CPTR_EL3, Architectural Feature Trap Register (EL3) */
+
+ write_sysreg(reg, cptr_el3);
+
+ reg = 0U; /* Reset */
+ reg |= SCR_NS_BIT; /* EL2 / EL3 non-secure */
+ reg |= (SCR_RES1 | /* RES1 */
+ SCR_RW_BIT | /* EL2 execution state is AArch64 */
+ SCR_ST_BIT | /* Do not trap EL1 accesses to timer */
+ SCR_HCE_BIT | /* Do not trap HVC */
+ SCR_SMD_BIT); /* Do not trap SMC */
+ write_sysreg(reg, scr_el3);
+
+ reg = read_sysreg(ICC_SRE_EL3);
+ reg |= (ICC_SRE_ELX_DFB_BIT | /* Disable FIQ bypass */
+ ICC_SRE_ELX_DIB_BIT | /* Disable IRQ bypass */
+ ICC_SRE_ELX_SRE_BIT | /* System register interface is used */
+ ICC_SRE_EL3_EN_BIT); /* Enables lower Exception level access to
+ * ICC_SRE_EL1 */
+ write_sysreg(reg, ICC_SRE_EL3);
+
+ ARM64_ISB();
+}
+
+void arm64_boot_el3_get_next_el(uint64_t switch_addr)
+{
+ uint64_t spsr;
+
+ write_sysreg(switch_addr, elr_el3);
+
+ /* Mask the DAIF */
+
+ spsr = SPSR_DAIF_MASK;
+ spsr |= SPSR_MODE_EL2T;
+
+ write_sysreg(spsr, spsr_el3);
+}
+
+void arm64_boot_el2_init(void)
+{
+ uint64_t reg;
+
+ reg = read_sysreg(sctlr_el2);
+ reg |= (SCTLR_EL2_RES1 | /* RES1 */
+ SCTLR_I_BIT | /* Enable i-cache */
+ SCTLR_SA_BIT); /* Enable SP alignment check */
+ write_sysreg(reg, sctlr_el2);
+
+ reg = read_sysreg(hcr_el2);
+ reg |= HCR_RW_BIT; /* EL1 Execution state is AArch64 */
+ write_sysreg(reg, hcr_el2);
+
+ reg = 0U; /* RES0 */
+ reg |= CPTR_EL2_RES1; /* RES1 */
+ reg &= ~(CPTR_TFP_BIT | /* Do not trap SVE, SIMD and FP */
+ CPTR_TCPAC_BIT); /* Do not trap CPACR_EL1 accesses */
+ write_sysreg(reg, cptr_el2);
+
+ /* Enable EL1 access to timers */
+
+ reg = read_sysreg(cnthctl_el2);
+ reg |= (CNTHCTL_EL2_EL1PCEN_EN | CNTHCTL_EL2_EL1PCTEN_EN);
+ write_sysreg(reg, cnthctl_el2);
+
+ zero_sysreg(cntvoff_el2); /* Set 64-bit virtual timer offset to 0 */
+
+#ifdef CONFIG_ARCH_ARMV8R
+ zero_sysreg(cnthps_ctl_el2);
+#else
+ zero_sysreg(cnthp_ctl_el2);
+#endif
+
+ /* Enable this if/when we use the hypervisor timer.
+ * write_cnthp_cval_el2(~(uint64_t)0);
+ */
+
+ ARM64_ISB();
+}
+
+void arm64_boot_el1_init(void)
+{
+ uint64_t reg;
+
+ /* Setup vector table */
+
+ write_sysreg((uint64_t)_vector_table, vbar_el1);
+ ARM64_ISB();
+
+ reg = 0U; /* RES0 */
+ reg |= CPACR_EL1_FPEN_NOTRAP; /* Do not trap NEON/SIMD/FP initially */
+
+ /* TODO: CONFIG_FLOAT_*_FORBIDDEN */
+
+ write_sysreg(reg, cpacr_el1);
+
+ reg = read_sysreg(sctlr_el1);
+ reg |= (SCTLR_EL1_RES1 | /* RES1 */
+ SCTLR_I_BIT | /* Enable i-cache */
+ SCTLR_SA_BIT); /* Enable SP alignment check */
+ write_sysreg(reg, sctlr_el1);
+
+ write_sysreg((~(uint64_t)0), cntv_cval_el0);
+
+ /* Enable these if/when we use the corresponding timers.
+ * write_cntp_cval_el0(~(uint64_t)0);
+ * write_cntps_cval_el1(~(uint64_t)0);
+ */
+
+ ARM64_ISB();
+}
+
+/* These simple memset alternatives are necessary
+ * as the function at libc is depend on the MMU
+ * to be active.
+ */
+
+static void boot_early_memset(void *dst, int c, size_t n)
+{
+ uint8_t *d = dst;
+
+ while (n--)
+ {
+ *d++ = c;
+ }
+}
+
+void arm64_boot_primary_c_routine(void)
+{
+ boot_early_memset(_START_BSS, 0, _END_BSS - _START_BSS);
+ arm64_chip_boot();
+ nx_start();
+}
diff --git a/arch/arm64/src/common/arm64_cache.c b/arch/arm64/src/common/arm64_cache.c
new file mode 100644
index 0000000000..5e69d4c010
--- /dev/null
+++ b/arch/arm64/src/common/arm64_cache.c
@@ -0,0 +1,458 @@
+/****************************************************************************
+ * arch/arm64/src/common/arm64_cache.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 <nuttx/cache.h>
+#include <nuttx/irq.h>
+
+#include <nuttx/arch.h>
+#include <arch/irq.h>
+#include <arch/chip/chip.h>
+#include <nuttx/spinlock.h>
+
+#include "arm64_arch.h"
+#include "arm64_internal.h"
+#include "arm64_mmu.h"
+
+/****************************************************************************
+ * Pre-processor Macros
+ ****************************************************************************/
+
+/* Common operations for the caches
+ *
+ * WB means write-back and intends to transfer dirty cache lines to memory in
+ * a copy-back cache policy. May be a no-op in write-back cache policy.
+ *
+ * INVD means invalidate and will mark cache lines as not valid. A future
+ * access to the associated address is guaranteed to generate a memory fetch.
+ *
+ * armv8 data cache instruction:
+ *
+ * DC CIVAC (WB+INVD):
+ * Data or unified Cache line Clean and Invalidate by VA to PoC
+ * Clean and Invalidate data cache by address to Point of Coherency.
+ *
+ * DC CVAC (WB):
+ * Data or unified Cache line Clean by VA to PoC
+ * Clean data cache by address to Point of Coherency.
+ *
+ * DC IVAC (INVD):
+ * Data or unified Cache line Invalidate by VA to PoC
+ * Invalidate data cache by address to Point of Coherency
+ */
+
+#define CACHE_OP_WB BIT(0)
+#define CACHE_OP_INVD BIT(1)
+#define CACHE_OP_WB_INVD (CACHE_OP_WB | CACHE_OP_INVD)
+
+#define LINE_MASK(line) ((line) - 1)
+#define LINE_ALIGN_DOWN(a, line) ((a) & ~LINE_MASK(line))
+#define LINE_ALIGN_UP(a, line) \
+ (((a) + LINE_MASK(line)) & ~LINE_MASK(line))
+
+#define dc_ops(op, val) \
+ ({ \
+ __asm__ volatile ("dc " op ", %0" : : "r" (val) : "memory"); \
+ })
+
+/* IC IALLUIS, Instruction Cache Invalidate All to PoU, Inner Shareable
+ * Purpose
+ * Invalidate all instruction caches in the Inner Shareable domain of
+ * the PE executing the instruction to the Point of Unification.
+ */
+
+static inline void __ic_iallu(void)
+{
+ __asm__ volatile ("ic iallu" : : : "memory");
+}
+
+/* IC IALLU, Instruction Cache Invalidate All to PoU
+ * Purpose
+ * Invalidate all instruction caches of the PE executing
+ * the instruction to the Point of Unification.
+ */
+
+static inline void __ic_ialluis(void)
+{
+ __asm__ volatile ("ic ialluis" : : : "memory");
+}
+
+size_t dcache_line_size;
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* operation for data cache by virtual address to PoC */
+
+static inline int arm64_dcache_range(uintptr_t start_addr,
+ uintptr_t end_addr, int op)
+{
+ /* Align address to line size */
+
+ start_addr = LINE_ALIGN_DOWN(start_addr, dcache_line_size);
+
+ while (start_addr < end_addr)
+ {
+ switch (op)
+ {
+ case CACHE_OP_WB:
+ {
+ dc_ops("cvac", start_addr);
+ break;
+ }
+
+ case CACHE_OP_INVD:
+ {
+ dc_ops("ivac", start_addr);
+ break;
+ }
+
+ case CACHE_OP_WB_INVD:
+ {
+ dc_ops("civac", start_addr);
+ break;
+ }
+
+ default:
+ {
+ DEBUGASSERT(0);
+ }
+ }
+ start_addr += dcache_line_size;
+ }
+
+ ARM64_DSB();
+
+ return 0;
+}
+
+/* operation for all data cache */
+
+static inline int arm64_dcache_all(int op)
+{
+ uint32_t clidr_el1;
+ uint32_t csselr_el1;
+ uint32_t ccsidr_el1;
+ uint8_t loc;
+ uint8_t ctype;
+ uint8_t cache_level;
+ uint8_t line_size;
+ uint8_t way_pos;
+ uint32_t max_ways;
+ uint32_t max_sets;
+ uint32_t dc_val;
+ uint32_t set;
+ uint32_t way;
+
+ /* Data barrier before start */
+
+ ARM64_DSB();
+
+ clidr_el1 = read_sysreg(clidr_el1);
+
+ loc = (clidr_el1 >> CLIDR_EL1_LOC_SHIFT) & CLIDR_EL1_LOC_MASK;
+ if (!loc)
+ {
+ return 0;
+ }
+
+ for (cache_level = 0; cache_level < loc; cache_level++)
+ {
+ ctype =
+ (clidr_el1 >>
+ CLIDR_EL1_CTYPE_SHIFT(cache_level)) & CLIDR_EL1_CTYPE_MASK;
+
+ /* No data cache, continue */
+
+ if (ctype < 2)
+ {
+ continue;
+ }
+
+ /* select cache level */
+
+ csselr_el1 = cache_level << 1;
+ write_sysreg(csselr_el1, csselr_el1);
+ ARM64_ISB();
+
+ ccsidr_el1 = read_sysreg(ccsidr_el1);
+ line_size =
+ (ccsidr_el1 >> CCSIDR_EL1_LN_SZ_SHIFT & CCSIDR_EL1_LN_SZ_MASK) + 4;
+ max_ways =
+ (ccsidr_el1 >> CCSIDR_EL1_WAYS_SHIFT) & CCSIDR_EL1_WAYS_MASK;
+ max_sets =
+ (ccsidr_el1 >> CCSIDR_EL1_SETS_SHIFT) & CCSIDR_EL1_SETS_MASK;
+
+ /* 32-log2(ways), bit position of way in DC operand */
+
+ way_pos = __builtin_clz(max_ways);
+
+ for (set = 0; set <= max_sets; set++)
+ {
+ for (way = 0; way <= max_ways; way++)
+ {
+ /* way number, aligned to pos in DC operand */
+
+ dc_val = way << way_pos;
+
+ /* cache level, aligned to pos in DC operand */
+
+ dc_val |= csselr_el1;
+
+ /* set number, aligned to pos in DC operand */
+
+ dc_val |= set << line_size;
+ switch (op)
+ {
+ case CACHE_OP_WB:
+ {
+ dc_ops("csw", dc_val);
+ break;
+ }
+
+ case CACHE_OP_INVD:
+ {
+ dc_ops("isw", dc_val);
+ break;
+ }
+
+ case CACHE_OP_WB_INVD:
+ {
+ dc_ops("cisw", dc_val);
+ break;
+ }
+ default:
+ {
+ DEBUGASSERT(0);
+ }
+ }
+ }
+ }
+ }
+
+ /* Restore csselr_el1 to level 0 */
+
+ write_sysreg(0, csselr_el1);
+ __ic_iallu();
+ ARM64_DSB();
+ ARM64_ISB();
+
+ return 0;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: up_invalidate_dcache
+ *
+ * Description:
+ * Invalidate the data cache within the specified region; we will be
+ * performing a DMA operation in this region and we want to purge old data
+ * in the cache.
+ *
+ * Input Parameters:
+ * start - virtual start address of region
+ * end - virtual end address of region + 1
+ *
+ * Returned Value:
+ * None
+ *
+ * Assumptions:
+ * This operation is not atomic. This function assumes that the caller
+ * has exclusive access to the address range so that no harm is done if
+ * the operation is pre-empted.
+ *
+ ****************************************************************************/
+
+void up_invalidate_dcache(uintptr_t start, uintptr_t end)
+{
+ arm64_dcache_range(start, end, CACHE_OP_INVD);
+}
+
+/****************************************************************************
+ * Name: up_invalidate_dcache_all
+ *
+ * Description:
+ * Invalidate the entire contents of D cache.
+ *
+ * NOTE: This function forces L1 and L2 cache operations to be atomic
+ * by disabling interrupts.
+ *
+ * Input Parameters:
+ * None
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+void up_invalidate_dcache_all(void)
+{
+ arm64_dcache_all(CACHE_OP_INVD);
+}
+
+/****************************************************************************
+ * Name: up_invalidate_icache_all
+ *
+ * Description:
+ * Invalidate all instruction caches to PoU, also flushes branch target
+ * cache
+ *
+ * Input Parameters:
+ * None
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+void up_invalidate_icache_all(void)
+{
+ __ic_ialluis();
+}
+
+/****************************************************************************
+ * Name: up_clean_dcache
+ *
+ * Description:
+ * Clean the data cache within the specified region by flushing the
+ * contents of the data cache to memory.
+ *
+ * Input Parameters:
+ * start - virtual start address of region
+ * end - virtual end address of region + 1
+ *
+ * Returned Value:
+ * None
+ *
+ * Assumptions:
+ * This operation is not atomic. This function assumes that the caller
+ * has exclusive access to the address range so that no harm is done if
+ * the operation is pre-empted.
+ *
+ ****************************************************************************/
+
+void up_clean_dcache(uintptr_t start, uintptr_t end)
+{
+ if (dcache_line_size < (end - start))
+ {
+ arm64_dcache_range(start, end, CACHE_OP_WB);
+ }
+ else
+ {
+ arm64_dcache_all(CACHE_OP_WB);
+ }
+}
+
+/****************************************************************************
+ * Name: up_clean_dcache_all
+ *
+ * Description:
+ * Clean the entire data cache within the specified region by flushing the
+ * contents of the data cache to memory.
+ *
+ * NOTE: This operation is un-necessary if the DCACHE is configured in
+ * write-through mode.
+ *
+ * Input Parameters:
+ * None
+ *
+ * Returned Value:
+ * None
+ *
+ * Assumptions:
+ * This operation is not atomic. This function assumes that the caller
+ * has exclusive access to the address range so that no harm is done if
+ * the operation is pre-empted.
+ *
+ ****************************************************************************/
+
+void up_clean_dcache_all(void)
+{
+ arm64_dcache_all(CACHE_OP_WB);
+}
+
+/****************************************************************************
+ * Name: up_flush_dcache
+ *
+ * Description:
+ * Flush the data cache within the specified region by cleaning and
+ * invalidating the D cache.
+ *
+ * Input Parameters:
+ * start - virtual start address of region
+ * end - virtual end address of region + 1
+ *
+ * Returned Value:
+ * None
+ *
+ * Assumptions:
+ * This operation is not atomic. This function assumes that the caller
+ * has exclusive access to the address range so that no harm is done if
+ * the operation is pre-empted.
+ *
+ ****************************************************************************/
+
+void up_flush_dcache(uintptr_t start, uintptr_t end)
+{
+ if (dcache_line_size < (end - start))
+ {
+ arm64_dcache_range(start, end, CACHE_OP_WB_INVD);
+ }
+ else
+ {
+ arm64_dcache_all(CACHE_OP_WB_INVD);
+ }
+}
+
+/****************************************************************************
+ * Name: up_flush_dcache_all
+ *
+ * Description:
+ * Flush the entire data cache by cleaning and invalidating the D cache.
+ *
+ * NOTE: If DCACHE write-through is configured, then this operation is the
+ * same as up_invalidate_cache_all().
+ *
+ * Input Parameters:
+ * None
+ *
+ * Returned Value:
+ * None
+ *
+ * Assumptions:
+ * This operation is not atomic. This function assumes that the caller
+ * has exclusive access to the address range so that no harm is done if
+ * the operation is pre-empted.
+ *
+ ****************************************************************************/
+
+void up_flush_dcache_all(void)
+{
+ arm64_dcache_all(CACHE_OP_WB_INVD);
+}
+
diff --git a/arch/arm64/src/common/arm64_checkstack.c b/arch/arm64/src/common/arm64_checkstack.c
new file mode 100644
index 0000000000..588da146b6
--- /dev/null
+++ b/arch/arm64/src/common/arm64_checkstack.c
@@ -0,0 +1,239 @@
+/****************************************************************************
+ * arch/arm64/src/common/arm64_checkstack.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 <stdint.h>
+#include <sched.h>
+#include <assert.h>
+#include <debug.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/board.h>
+
+#include "sched/sched.h"
+#include "arm64_internal.h"
+
+#ifdef CONFIG_STACK_COLORATION
+
+/****************************************************************************
+ * Pre-processor Macros
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static size_t do_stackcheck(void *stackbase, size_t nbytes);
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: do_stackcheck
+ *
+ * Description:
+ * Determine (approximately) how much stack has been used by searching the
+ * stack memory for a high water mark. That is, the deepest level of the
+ * stack that clobbered some recognizable marker in the stack memory.
+ *
+ * Input Parameters:
+ * alloc - Allocation base address of the stack
+ * size - The size of the stack in bytes
+ *
+ * Returned Value:
+ * The estimated amount of stack space used.
+ *
+ ****************************************************************************/
+
+static size_t do_stackcheck(void *stackbase, size_t nbytes)
+{
+ uintptr_t start;
+ uintptr_t end;
+ uint64_t *ptr;
+ size_t mark;
+
+ if (nbytes == 0)
+ {
+ return 0;
+ }
+
+ /* Take extra care that we do not check outside the stack boundaries */
+
+ start = STACK_ALIGN_UP((uintptr_t)stackbase);
+ end = STACK_ALIGN_DOWN((uintptr_t)stackbase + nbytes);
+
+ /* Get the adjusted size based on the top and bottom of the stack */
+
+ nbytes = end - start;
+
+ /* The ARM uses a push-down stack: the stack grows toward lower addresses
+ * in memory. We need to start at the lowest address in the stack memory
+ * allocation and search to higher addresses. The first word we encounter
+ * that does not have the magic value is the high water mark.
+ */
+
+ for (ptr = (uint64_t *)start, mark = (nbytes >> 2);
+ *ptr == STACK_COLOR && mark > 0;
+ ptr++, mark--);
+
+ /* If the stack is completely used, then this might mean that the stack
+ * overflowed from above (meaning that the stack is too small), or may
+ * have been overwritten from below meaning that some other stack or data
+ * structure overflowed.
+ *
+ * If you see returned values saying that the entire stack is being used
+ * then enable the following logic to see it there are unused areas in the
+ * middle of the stack.
+ */
+
+#if 0
+ if (mark + 16 > nwords)
+ {
+ int i;
+ int j;
+
+ ptr = (uint32_t *)start;
+ for (i = 0; i < nbytes; i += 4 * 64)
+ {
+ for (j = 0; j < 64; j++)
+ {
+ int ch;
+ if (*ptr++ == STACK_COLOR)
+ {
+ ch = '.';
+ }
+ else
+ {
+ ch = 'X';
+ }
+
+ up_putc(ch);
+ }
+
+ up_putc('\n');
+ }
+ }
+#endif
+
+ /* Return our guess about how much stack space was used */
+
+ return mark << 2;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: arm64_stack_color
+ *
+ * Description:
+ * Write a well know value into the stack
+ *
+ ****************************************************************************/
+
+void arm64_stack_color(void *stackbase, size_t nbytes)
+{
+ uintptr_t start;
+ uintptr_t end;
+ size_t nwords;
+ uint32_t *ptr;
+
+ /* Take extra care that we do not write outside the stack boundaries */
+
+ start = STACK_ALIGN_UP((uintptr_t)stackbase);
+ end = nbytes ? STACK_ALIGN_DOWN((uintptr_t)stackbase + nbytes) :
+ up_getsp(); /* 0: colorize the running stack */
+
+ /* Get the adjusted size based on the top and bottom of the stack */
+
+ nwords = (end - start) >> 2;
+ ptr = (uint32_t *)start;
+
+ /* Set the entire stack to the coloration value */
+
+ while (nwords-- > 0)
+ {
+ *ptr++ = STACK_COLOR;
+ }
+}
+
+/****************************************************************************
+ * Name: up_check_stack and friends
+ *
+ * Description:
+ * Determine (approximately) how much stack has been used by searching the
+ * stack memory for a high water mark. That is, the deepest level of the
+ * stack that clobbered some recognizable marker in the stack memory.
+ *
+ * Input Parameters:
+ * None
+ *
+ * Returned Value:
+ * The estimated amount of stack space used.
+ *
+ ****************************************************************************/
+
+size_t up_check_tcbstack(struct tcb_s *tcb)
+{
+ return do_stackcheck(tcb->stack_base_ptr, tcb->adj_stack_size);
+}
+
+ssize_t up_check_tcbstack_remain(struct tcb_s *tcb)
+{
+ return tcb->adj_stack_size - up_check_tcbstack(tcb);
+}
+
+size_t up_check_stack(void)
+{
+ return up_check_tcbstack(this_task());
+}
+
+ssize_t up_check_stack_remain(void)
+{
+ return up_check_tcbstack_remain(this_task());
+}
+
+#if CONFIG_ARCH_INTERRUPTSTACK > 7
+size_t up_check_intstack(void)
+{
+#ifdef CONFIG_SMP
+ return do_stackcheck((void *)arm64_intstack_alloc(),
+ STACK_ALIGN_DOWN(CONFIG_ARCH_INTERRUPTSTACK));
+#else
+ return do_stackcheck((void *)&g_interrupt_stack,
+ STACK_ALIGN_DOWN(CONFIG_ARCH_INTERRUPTSTACK));
+#endif
+}
+
+size_t up_check_intstack_remain(void)
+{
+ return STACK_ALIGN_DOWN(CONFIG_ARCH_INTERRUPTSTACK) - up_check_intstack();
+}
+#endif
+
+#endif /* CONFIG_STACK_COLORATION */
diff --git a/arch/arm64/src/common/arm64_copystate.c b/arch/arm64/src/common/arm64_copystate.c
new file mode 100644
index 0000000000..47ddd39568
--- /dev/null
+++ b/arch/arm64/src/common/arm64_copystate.c
@@ -0,0 +1,121 @@
+/****************************************************************************
+ * arch/arm64/src/common/arm64_copystate.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 <stdbool.h>
+#include <sched.h>
+#include <debug.h>
+#include <assert.h>
+#include <nuttx/arch.h>
+#include <nuttx/sched.h>
+#include <arch/syscall.h>
+#include <arch/irq.h>
+
+#include "arm64_internal.h"
+
+#ifdef CONFIG_ARCH_FPU
+#include "arm64_fpu.h"
+#endif
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+#ifdef CONFIG_ARCH_FPU
+int arch_save_fpucontext(void *saveregs)
+{
+ irqstate_t flags;
+ uint64_t *p_save;
+
+ /* Take a snapshot of the thread context right now */
+
+ flags = enter_critical_section();
+
+ p_save = saveregs + XCPTCONTEXT_GP_SIZE;
+ arm64_fpu_save((struct fpu_reg *)p_save);
+ ARM64_DSB();
+
+ leave_critical_section(flags);
+ return 0;
+}
+#endif
+
+int arm64_syscall_save_context(uint64_t * regs)
+{
+ struct regs_context *f_regs;
+ uint64_t *p_save;
+ int i;
+
+#ifdef CONFIG_ARCH_FPU
+ uint64_t *p_fpu;
+ struct tcb_s *rtcb;
+ struct tcb_s *rtcb_cur =
+ (struct tcb_s *)arch_get_current_tcb();
+#endif
+
+ DEBUGASSERT(regs);
+
+ f_regs = (struct regs_context *)regs;
+ DEBUGASSERT(f_regs->regs[REG_X1] != 0 && f_regs->regs[REG_X2] != 0);
+
+ p_save = (uint64_t *)f_regs->regs[REG_X2];
+
+ for (i = 0; i < XCPTCONTEXT_GP_REGS; i++)
+ {
+ p_save[i] = regs[i];
+ }
+
+#ifdef CONFIG_ARCH_FPU
+ rtcb = (struct tcb_s *)f_regs->regs[REG_X1];
+ p_save += XCPTCONTEXT_GP_SIZE;
+ if (rtcb_cur == rtcb)
+ {
+ arch_save_fpucontext(p_save);
+ }
+ else
+ {
+ p_fpu = (uint64_t *)rtcb->xcp.fpu_regs;
+ for (i = 0; i < XCPTCONTEXT_FPU_REGS; i++)
+ {
+ p_save[i] = p_fpu[i];
+ }
+ }
+#endif
+
+ return OK;
+}
diff --git a/arch/arm64/src/common/arm64_cpu_idle.S b/arch/arm64/src/common/arm64_cpu_idle.S
new file mode 100644
index 0000000000..6252168dcd
--- /dev/null
+++ b/arch/arm64/src/common/arm64_cpu_idle.S
@@ -0,0 +1,70 @@
+/****************************************************************************
+ * arch/arm64/src/common/arm64_cpu_idle.S
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include "arm64_arch.h"
+#include "arm64_macro.inc"
+
+/****************************************************************************
+ * Public Symbols
+ ****************************************************************************/
+
+ .file "arm64_cpu_idle.S"
+
+/****************************************************************************
+ * Assembly Macros
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+GTEXT(arch_cpu_idle)
+SECTION_FUNC(text, arch_cpu_idle)
+#ifdef CONFIG_TRACING_IDLE
+ stp xzr, x30, [sp, #-16]!
+ bl sys_trace_idle
+ ldp xzr, x30, [sp], #16
+#endif
+ dsb sy
+ wfi
+ msr daifclr, #(DAIFCLR_IRQ_BIT)
+ ret
+
+GTEXT(arch_cpu_atomic_idle)
+SECTION_FUNC(text, arch_cpu_atomic_idle)
+#ifdef CONFIG_TRACING_IDLE
+ stp xzr, x30, [sp, #-16]!
+ bl sys_trace_idle
+ ldp xzr, x30, [sp], #16
+#endif
+ msr daifset, #(DAIFSET_IRQ_BIT)
+ isb
+ wfe
+ tst x0, #(DAIF_IRQ_BIT)
+ beq _irq_disabled
+ msr daifclr, #(DAIFCLR_IRQ_BIT)
+_irq_disabled:
+ ret
diff --git a/arch/arm64/src/common/arm64_cpu_psci.c b/arch/arm64/src/common/arm64_cpu_psci.c
new file mode 100644
index 0000000000..cc384a98cc
--- /dev/null
+++ b/arch/arm64/src/common/arm64_cpu_psci.c
@@ -0,0 +1,188 @@
+/****************************************************************************
+ * arch/arm64/src/common/arm64_cpu_psci.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 <debug.h>
+#include <assert.h>
+#include <nuttx/arch.h>
+#include <arch/irq.h>
+#include <arch/chip/chip.h>
+#include <nuttx/spinlock.h>
+
+#include "arch/syscall.h"
+#include "arm64_arch.h"
+#include "arm64_internal.h"
+
+#include "arm64_cpu_psci.h"
+
+static struct psci_interface psci_data;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static int psci_to_dev_err(int ret)
+{
+ switch (ret)
+ {
+ case PSCI_RET_SUCCESS:
+ {
+ return 0;
+ }
+
+ case PSCI_RET_NOT_SUPPORTED:
+ {
+ return -ENOTSUP;
+ }
+
+ case PSCI_RET_INVALID_PARAMS:
+ case PSCI_RET_INVALID_ADDRESS:
+ {
+ return -EINVAL;
+ }
+
+ case PSCI_RET_DENIED:
+ {
+ return -EPERM;
+ }
+ }
+
+ return -EINVAL;
+}
+
+static unsigned long __invoke_psci_fn_hvc(unsigned long function_id,
+ unsigned long arg0,
+ unsigned long arg1,
+ unsigned long arg2)
+{
+ struct arm64_smccc_res res;
+
+ arm64_smccc_hvc(function_id, arg0, arg1, arg2, 0, 0, 0, 0, &res);
+ return res.a0;
+}
+
+static unsigned long __invoke_psci_fn_smc(unsigned long function_id,
+ unsigned long arg0,
+ unsigned long arg1,
+ unsigned long arg2)
+{
+ struct arm64_smccc_res res;
+
+ arm64_smccc_smc(function_id, arg0, arg1, arg2, 0, 0, 0, 0, &res);
+ return res.a0;
+}
+
+static uint32_t psci_get_version(void)
+{
+ return psci_data.invoke_psci_fn(PSCI_0_2_FN_PSCI_VERSION, 0, 0, 0);
+}
+
+static int set_conduit_method(const char *method)
+{
+ if (!strcmp("hvc", method))
+ {
+ psci_data.conduit = SMCCC_CONDUIT_HVC;
+ psci_data.invoke_psci_fn = __invoke_psci_fn_hvc;
+ }
+ else if (!strcmp("smc", method))
+ {
+ psci_data.conduit = SMCCC_CONDUIT_SMC;
+ psci_data.invoke_psci_fn = __invoke_psci_fn_smc;
+ }
+ else
+ {
+ serr("Invalid conduit method");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int psci_detect(void)
+{
+ uint32_t ver = psci_get_version();
+
+ sinfo("Detected PSCI v%d.%d\n",
+ PSCI_VERSION_MAJOR(ver), PSCI_VERSION_MINOR(ver));
+
+ if (PSCI_VERSION_MAJOR(ver) == 0 && PSCI_VERSION_MINOR(ver) < 2)
+ {
+ serr("PSCI unsupported version");
+ return -ENOTSUP;
+ }
+
+ psci_data.version = ver;
+
+ return 0;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+uint32_t psci_version(void)
+{
+ return psci_data.version;
+}
+
+int pcsi_cpu_off(void)
+{
+ int ret;
+
+ if (psci_data.conduit == SMCCC_CONDUIT_NONE)
+ {
+ return -EINVAL;
+ }
+
+ ret = psci_data.invoke_psci_fn(PSCI_0_2_FN_CPU_OFF, 0, 0, 0);
+
+ return psci_to_dev_err(ret);
+}
+
+int pcsi_cpu_on(unsigned long cpuid, uintptr_t entry_point)
+{
+ int ret;
+
+ if (psci_data.conduit == SMCCC_CONDUIT_NONE)
+ {
+ return -EINVAL;
+ }
+
+ ret = psci_data.invoke_psci_fn(PSCI_FN_NATIVE(0_2, CPU_ON),
+ cpuid, (unsigned long)entry_point, 0);
+
+ return psci_to_dev_err(ret);
+}
+
+int arm64_psci_init(const char * method)
+{
+ psci_data.conduit = SMCCC_CONDUIT_NONE;
+
+ if (set_conduit_method(method))
+ {
+ return -ENOTSUP;
+ }
+
+ return psci_detect();
+}
diff --git a/arch/arm64/src/common/arm64_cpu_psci.h b/arch/arm64/src/common/arm64_cpu_psci.h
new file mode 100644
index 0000000000..d078360ca8
--- /dev/null
+++ b/arch/arm64/src/common/arm64_cpu_psci.h
@@ -0,0 +1,104 @@
+/****************************************************************************
+ * arch/arm64/src/common/arm64_cpu_psci.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_ARM64_SRC_COMMON_ARM64_CPU_PSCI_H
+#define __ARCH_ARM64_SRC_COMMON_ARM64_CPU_PSCI_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+#include <nuttx/config.h>
+#include <arch/irq.h>
+#include <arch/chip/chip.h>
+#include <arch/syscall.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define PSCI_FN_NATIVE(version, name) PSCI_##version##_FN64_##name
+
+/* PSCI v0.2 interface */
+#define PSCI_0_2_FN_BASE 0x84000000
+#define PSCI_0_2_FN(n) (PSCI_0_2_FN_BASE + (n))
+#define PSCI_0_2_64BIT 0x40000000
+#define PSCI_0_2_FN64_BASE \
+ (PSCI_0_2_FN_BASE + PSCI_0_2_64BIT)
+#define PSCI_0_2_FN64(n) (PSCI_0_2_FN64_BASE + (n))
+
+#define PSCI_0_2_FN_PSCI_VERSION PSCI_0_2_FN(0)
+#define PSCI_0_2_FN_CPU_SUSPEND PSCI_0_2_FN(1)
+#define PSCI_0_2_FN_CPU_OFF PSCI_0_2_FN(2)
+#define PSCI_0_2_FN_CPU_ON PSCI_0_2_FN(3)
+#define PSCI_0_2_FN_AFFINITY_INFO PSCI_0_2_FN(4)
+#define PSCI_0_2_FN_MIGRATE PSCI_0_2_FN(5)
+#define PSCI_0_2_FN_MIGRATE_INFO_TYPE PSCI_0_2_FN(6)
+#define PSCI_0_2_FN_MIGRATE_INFO_UP_CPU PSCI_0_2_FN(7)
+#define PSCI_0_2_FN_SYSTEM_OFF PSCI_0_2_FN(8)
+#define PSCI_0_2_FN_SYSTEM_RESET PSCI_0_2_FN(9)
+
+#define PSCI_0_2_FN64_CPU_SUSPEND PSCI_0_2_FN64(1)
+#define PSCI_0_2_FN64_CPU_ON PSCI_0_2_FN64(3)
+#define PSCI_0_2_FN64_AFFINITY_INFO PSCI_0_2_FN64(4)
+#define PSCI_0_2_FN64_MIGRATE PSCI_0_2_FN64(5)
+#define PSCI_0_2_FN64_MIGRATE_INFO_UP_CPU PSCI_0_2_FN64(7)
+
+/* PSCI return values (inclusive of all PSCI versions) */
+#define PSCI_RET_SUCCESS 0
+#define PSCI_RET_NOT_SUPPORTED -1
+#define PSCI_RET_INVALID_PARAMS -2
+#define PSCI_RET_DENIED -3
+#define PSCI_RET_ALREADY_ON -4
+#define PSCI_RET_ON_PENDING -5
+#define PSCI_RET_INTERNAL_FAILURE -6
+#define PSCI_RET_NOT_PRESENT -7
+#define PSCI_RET_DISABLED -8
+#define PSCI_RET_INVALID_ADDRESS -9
+
+/* PSCI version decoding (independent of PSCI version) */
+#define PSCI_VERSION_MAJOR_SHIFT 16
+#define PSCI_VERSION_MINOR_MASK \
+ ((1U << PSCI_VERSION_MAJOR_SHIFT) - 1)
+#define PSCI_VERSION_MAJOR_MASK ~PSCI_VERSION_MINOR_MASK
+
+#define PSCI_VERSION_MAJOR(ver) \
+ (((ver) & PSCI_VERSION_MAJOR_MASK) >> PSCI_VERSION_MAJOR_SHIFT)
+#define PSCI_VERSION_MINOR(ver) \
+ ((ver) & PSCI_VERSION_MINOR_MASK)
+
+typedef unsigned long (*psci_fn)(unsigned long, unsigned long, unsigned long,
+ unsigned long);
+
+struct psci_interface
+{
+ enum arm64_smccc_conduit conduit;
+ psci_fn invoke_psci_fn;
+ uint32_t version;
+};
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+uint32_t psci_version(void);
+int pcsi_cpu_off(void);
+int pcsi_cpu_on(unsigned long cpuid, uintptr_t entry_point);
+
+#endif /* __ARCH_ARM64_SRC_COMMON_ARM64_CPU_PSCI_H */
diff --git a/arch/arm64/src/common/arm64_cpuidlestack.c b/arch/arm64/src/common/arm64_cpuidlestack.c
new file mode 100644
index 0000000000..d92dc5419e
--- /dev/null
+++ b/arch/arm64/src/common/arm64_cpuidlestack.c
@@ -0,0 +1,112 @@
+/****************************************************************************
+ * arch/arm64/src/common/arm64_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 "arm64_smp.h"
+#include "arm64_internal.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Stack alignment macros */
+
+#define STACK_ISALIGNED(a) ((uintptr_t)(a) & ~STACK_ALIGN_MASK)
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * 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 ways 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_idlestackalloc[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;
+}
diff --git a/arch/arm64/src/common/arm64_cpuindex.c b/arch/arm64/src/common/arm64_cpuindex.c
new file mode 100644
index 0000000000..a0249d8273
--- /dev/null
+++ b/arch/arm64/src/common/arm64_cpuindex.c
@@ -0,0 +1,68 @@
+/****************************************************************************
+ * arch/arm64/src/common/arm64_cpuindex.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 <nuttx/arch.h>
+
+#include "arm64_arch.h"
+
+#ifdef CONFIG_SMP
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * 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)
+ * And return the CPU ID field
+ */
+
+ return MPIDR_TO_CORE(GET_MPIDR());
+}
+
+#endif /* CONFIG_SMP */
diff --git a/arch/arm64/src/common/arm64_cpupause.c b/arch/arm64/src/common/arm64_cpupause.c
new file mode 100644
index 0000000000..37f118b84a
--- /dev/null
+++ b/arch/arm64/src/common/arm64_cpupause.c
@@ -0,0 +1,335 @@
+/****************************************************************************
+ * arch/arm64/src/common/arm64_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 <debug.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/sched.h>
+#include <nuttx/spinlock.h>
+#include <nuttx/sched_note.h>
+
+#include "arm64_internal.h"
+#include "arm64_gic.h"
+#include "sched/sched.h"
+
+/****************************************************************************
+ * 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.
+ */
+
+ arm64_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.
+ */
+
+ arm64_restorestate(tcb->xcp.regs);
+ spin_unlock(&g_cpu_wait[cpu]);
+
+ return OK;
+}
+
+/****************************************************************************
+ * Name: arm64_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 arm64_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)
+{
+ int ret;
+ uint64_t mpidr = GET_MPIDR();
+
+ 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 */
+
+ ret = arm64_gic_raise_sgi(SGI_CPU_PAUSE, mpidr, (1 << cpu));
+ if (ret < 0)
+ {
+ /* What happened? Unlock the g_cpu_wait spinlock */
+
+ spin_unlock(&g_cpu_wait[cpu]);
+ }
+ else
+ {
+ /* 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 ret;
+}
+
+/****************************************************************************
+ * 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;
+}
diff --git a/arch/arm64/src/common/arm64_cpustart.c b/arch/arm64/src/common/arm64_cpustart.c
new file mode 100644
index 0000000000..12b2b73492
--- /dev/null
+++ b/arch/arm64/src/common/arm64_cpustart.c
@@ -0,0 +1,266 @@
+/****************************************************************************
+ * arch/arm64/src/common/arm64_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 <sched/sched.h>
+#include <nuttx/cache.h>
+#include <arch/spinlock.h>
+#include <nuttx/init.h>
+
+#include "init/init.h"
+#include "arm64_arch.h"
+#include "arm64_internal.h"
+#include "arm64_gic.h"
+#include "arm64_arch_timer.h"
+#include "arm64_smp.h"
+#include "arm64_cpu_psci.h"
+#include "arm64_mmu.h"
+
+/****************************************************************************
+ * Public data
+ ****************************************************************************/
+
+typedef void (*arm64_cpustart_t)(void *data);
+
+struct arm64_boot_params
+{
+ uint64_t mpid;
+ char *boot_sp;
+ arm64_cpustart_t func;
+ void *arg;
+ int cpu_num;
+};
+
+volatile struct arm64_boot_params aligned_data(L1_CACHE_BYTES)
+cpu_boot_params =
+{
+ .mpid = -1,
+ .boot_sp = (char *)g_cpu_idlestackalloc[0],
+};
+
+volatile uint64_t *g_cpu_int_stacktop[CONFIG_SMP_NCPUS] =
+{
+ (uint64_t *)(g_interrupt_stacks[0] + INTSTACK_SIZE),
+};
+
+/****************************************************************************
+ * Private data
+ ****************************************************************************/
+
+static volatile long cpu_ready_flag;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static inline void local_delay(void)
+{
+ for (volatile int i = 0; i < 1000; i++)
+ {
+ }
+}
+
+static void arm64_smp_init_top(void *arg)
+{
+ struct tcb_s *tcb = this_task();
+
+ cpu_ready_flag = 1;
+
+#ifndef CONFIG_SUPPRESS_INTERRUPTS
+ /* And finally, enable interrupts */
+
+ up_irq_enable();
+#endif
+
+#ifdef CONFIG_SCHED_INSTRUMENTATION
+
+ /* Notify that this CPU has started */
+
+ sched_note_cpu_started(tcb);
+#endif
+
+ /* Reset scheduler parameters */
+
+ nxsched_resume_scheduler(tcb);
+
+ /* core n, idle n */
+
+ write_sysreg(0, tpidrro_el0);
+ write_sysreg(tcb, tpidr_el1);
+ write_sysreg(tcb, tpidr_el0);
+
+ nx_idle_trampoline();
+}
+
+static void arm64_start_cpu(int cpu_num, char *stack, int stack_sz,
+ arm64_cpustart_t fn)
+{
+ uint64_t cpu_mpid = cpu_num;
+
+ uintptr_t flush_start;
+ uintptr_t flush_end;
+
+#ifdef CONFIG_SCHED_INSTRUMENTATION
+
+ /* Notify of the start event */
+
+ sched_note_cpu_start(this_task(), cpu);
+#endif
+
+ cpu_boot_params.boot_sp = stack;
+ cpu_boot_params.func = fn;
+ cpu_boot_params.arg = 0;
+ cpu_boot_params.cpu_num = cpu_num;
+ g_cpu_int_stacktop[cpu_num] =
+ (uint64_t *)(g_interrupt_stacks[cpu_num] + INTSTACK_SIZE);
+
+ ARM64_DSB();
+
+ /* store mpid last as this is our synchronization point */
+
+ cpu_boot_params.mpid = cpu_num;
+
+ flush_start = (uintptr_t)&cpu_boot_params;
+ flush_end = flush_start + sizeof(cpu_boot_params);
+ up_flush_dcache(flush_start, flush_end);
+
+ if (pcsi_cpu_on(cpu_mpid, (uint64_t)&__start))
+ {
+ sinfo("Failed to boot secondary CPU core %d (MPID:%#llx)\n", cpu_num,
+ cpu_mpid);
+ return;
+ }
+
+ /* Wait secondary cores up, see z_arm64_secondary_start */
+
+ while (cpu_boot_params.func)
+ {
+ SP_WFE();
+ }
+
+ sinfo("Secondary CPU core %d (MPID:%#llx) is up\n", cpu_num, cpu_mpid);
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * 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)
+{
+ 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
+
+ cpu_ready_flag = 0;
+ arm64_start_cpu(cpu, (char *)g_cpu_idlestackalloc[cpu], SMP_STACK_SIZE,
+ arm64_smp_init_top);
+
+ /* Waiting for this CPU to be boot complete */
+
+ while (!cpu_ready_flag)
+ {
+ local_delay();
+ }
+
+ return 0;
+}
+
+/* the C entry of secondary cores */
+
+void arm64_boot_secondary_c_routine(void)
+{
+ arm64_cpustart_t func;
+ void *arg;
+
+ arm64_mmu_init(false);
+
+ arm64_gic_secondary_init();
+
+ up_enable_irq(SGI_CPU_PAUSE);
+
+ func = cpu_boot_params.func;
+ arg = cpu_boot_params.arg;
+ ARM64_DSB();
+
+ /* Secondary core clears .func to announce its presence.
+ * Primary core is polling for this. We no longer own
+ * arm64_cpu_boot_params afterwards.
+ */
+
+ cpu_boot_params.func = NULL;
+
+ ARM64_DSB();
+ SP_SEV();
+
+ func(arg);
+}
+
+int arm64_smp_sgi_init(void)
+{
+ irq_attach(SGI_CPU_PAUSE, arm64_pause_handler, 0);
+ arm64_gic_irq_set_priority(SGI_CPU_PAUSE, IRQ_DEFAULT_PRIORITY, 0);
+ up_enable_irq(SGI_CPU_PAUSE);
+
+ return 0;
+}
diff --git a/arch/arm64/src/common/arm64_createstack.c b/arch/arm64/src/common/arm64_createstack.c
new file mode 100644
index 0000000000..d25754566e
--- /dev/null
+++ b/arch/arm64/src/common/arm64_createstack.c
@@ -0,0 +1,205 @@
+/****************************************************************************
+ * arch/arm64/src/common/arm64_createstack.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 <stdint.h>
+#include <sched.h>
+#include <debug.h>
+#include <nuttx/arch.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/tls.h>
+#include <nuttx/board.h>
+#include <arch/irq.h>
+#include "arm64_internal.h"
+#include "arm64_fatal.h"
+
+/****************************************************************************
+ * Pre-processor Macros
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: up_create_stack
+ *
+ * Description:
+ * Allocate a stack for a new thread and setup up stack-related information
+ * in the TCB.
+ *
+ * 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:
+ * - tcb: The TCB of new task
+ * - stack_size: The requested stack size. At least this much
+ * must be allocated.
+ * - ttype: The thread type. This may be one of following (defined in
+ * include/nuttx/sched.h):
+ *
+ * TCB_FLAG_TTYPE_TASK Normal user task
+ * TCB_FLAG_TTYPE_PTHREAD User pthread
+ * TCB_FLAG_TTYPE_KERNEL Kernel thread
+ *
+ * This thread type is normally available in the flags field of the TCB,
+ * however, there are certain contexts where the TCB may not be fully
+ * initialized when up_create_stack is called.
+ *
+ * If either CONFIG_BUILD_PROTECTED or CONFIG_BUILD_KERNEL are defined,
+ * then this thread type may affect how the stack is allocated. For
+ * example, kernel thread stacks should be allocated from protected
+ * kernel memory. Stacks for user tasks and threads must come from
+ * memory that is accessible to user code.
+ *
+ ****************************************************************************/
+
+int up_create_stack(struct tcb_s *tcb, size_t stack_size, uint8_t ttype)
+{
+ stack_size = STACK_ALIGN_UP(stack_size);
+
+#ifdef CONFIG_TLS_ALIGNED
+ /* The allocated stack size must not exceed the maximum possible for the
+ * TLS feature.
+ */
+
+ DEBUGASSERT(stack_size <= TLS_MAXSTACK);
+ if (stack_size > TLS_MAXSTACK)
+ {
+ stack_size = TLS_MAXSTACK;
+ }
+#endif
+
+ /* Is there already a stack allocated of a different size? */
+
+ if (tcb->stack_alloc_ptr && tcb->adj_stack_size != stack_size)
+ {
+ /* Yes.. Release the old stack */
+
+ up_release_stack(tcb, ttype);
+ }
+
+ /* Do we need to allocate a new stack? */
+
+ if (!tcb->stack_alloc_ptr)
+ {
+ /* Allocate the stack. If DEBUG is enabled (but not stack debug),
+ * then create a zeroed stack to make stack dumps easier to trace.
+ * If TLS is enabled, then we must allocate aligned stacks.
+ */
+
+#ifdef CONFIG_TLS_ALIGNED
+#ifdef CONFIG_MM_KERNEL_HEAP
+ /* Use the kernel allocator if this is a kernel thread */
+
+ if (ttype == TCB_FLAG_TTYPE_KERNEL)
+ {
+ tcb->stack_alloc_ptr = kmm_memalign(TLS_STACK_ALIGN, stack_size);
+ }
+ else
+#endif
+ {
+ /* Use the user-space allocator if this is a task or pthread */
+
+ tcb->stack_alloc_ptr = kumm_memalign(TLS_STACK_ALIGN, stack_size);
+ }
+
+#else /* CONFIG_TLS_ALIGNED */
+#ifdef CONFIG_MM_KERNEL_HEAP
+ /* Use the kernel allocator if this is a kernel thread */
+
+ if (ttype == TCB_FLAG_TTYPE_KERNEL)
+ {
+ tcb->stack_alloc_ptr =
+ kmm_memalign(STACK_ALIGNMENT, stack_size);
+ }
+ else
+#endif
+ {
+ /* Use the user-space allocator if this is a task or pthread */
+
+ tcb->stack_alloc_ptr =
+ kumm_memalign(STACK_ALIGNMENT, stack_size);
+ }
+#endif /* CONFIG_TLS_ALIGNED */
+
+#ifdef CONFIG_DEBUG_FEATURES
+ /* Was the allocation successful? */
+
+ if (!tcb->stack_alloc_ptr)
+ {
+ serr("ERROR: Failed to allocate stack, size %ld\n", stack_size);
+ }
+#endif
+ }
+
+ /* Did we successfully allocate a stack? */
+
+ if (tcb->stack_alloc_ptr)
+ {
+ /* The ARM uses a "full descending" stack:
+ * the stack grows toward lower addresses in memory.
+ * The stack pointer register points to the last pushed item in
+ * the stack.
+ * Items on the stack are referenced as positive word offsets from sp.
+ */
+
+ /* Since both stack_alloc_ptr and stack_size are in
+ * CONFIG_STACK_ALIGNMENT, and the stack ptr is decremented before
+ * the first write, we can directly save our variables to struct
+ * tcb_s.
+ */
+
+ tcb->adj_stack_size = stack_size;
+ tcb->stack_base_ptr = tcb->stack_alloc_ptr;
+
+#ifdef CONFIG_STACK_COLORATION
+ /* If stack debug is enabled, then fill the stack with a
+ * recognizable value that we can use later to test for high
+ * water marks.
+ */
+
+ arm64_stack_color(tcb->stack_base_ptr, tcb->adj_stack_size);
+#endif /* CONFIG_STACK_COLORATION */
+ tcb->flags |= TCB_FLAG_FREE_STACK;
+
+ return OK;
+ }
+
+ return ERROR;
+}
diff --git a/arch/arm64/src/common/arm64_doirq.c b/arch/arm64/src/common/arm64_doirq.c
new file mode 100644
index 0000000000..15bc7fd84d
--- /dev/null
+++ b/arch/arm64/src/common/arm64_doirq.c
@@ -0,0 +1,156 @@
+/****************************************************************************
+ * arch/arm64/src/common/arm64_doirq.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 <sched.h>
+#include <debug.h>
+#include <nuttx/irq.h>
+#include <nuttx/arch.h>
+#include <nuttx/board.h>
+
+#include "task/task.h"
+#include "sched/sched.h"
+#include "group/group.h"
+#include "irq/irq.h"
+#include "arm64_arch.h"
+#include "arm64_internal.h"
+#include "arm64_gic.h"
+#include "arm64_fatal.h"
+
+/****************************************************************************
+ * Public data
+ ****************************************************************************/
+
+/* g_current_regs[] holds a references to the current interrupt level
+ * register storage structure. If is non-NULL only during interrupt
+ * processing. Access to g_current_regs[] must be through the macro
+ * CURRENT_REGS for portability.
+ */
+
+/* For the case of configurations with multiple CPUs, then there must be one
+ * such value for each processor that can receive an interrupt.
+ */
+
+volatile uint64_t *g_current_regs[CONFIG_SMP_NCPUS];
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: arm64_doirq
+ *
+ * Description:
+ * Receives the decoded GIC interrupt information and dispatches control
+ * to the attached interrupt handler.
+ *
+ ****************************************************************************/
+
+uint64_t *arm64_doirq(int irq, uint64_t * regs)
+{
+ /* Nested interrupts are not supported */
+
+ DEBUGASSERT(CURRENT_REGS == NULL);
+
+ /* Current regs non-zero indicates that we are processing an interrupt;
+ * CURRENT_REGS is also used to manage interrupt level context switches.
+ */
+
+ CURRENT_REGS = regs;
+
+ /* Deliver the IRQ */
+
+ irq_dispatch(irq, regs);
+
+ /* Check for a context switch. If a context switch occurred, then
+ * CURRENT_REGS will have a different value than it did on entry. If an
+ * interrupt level context switch has occurred, then restore the floating
+ * point state and the establish the correct address environment before
+ * returning from the interrupt.
+ */
+
+ if (regs != CURRENT_REGS)
+ {
+ /* need to do a context switch */
+
+#ifdef CONFIG_ARCH_ADDRENV
+ /* Make sure that the address environment for the previously
+ * running task is closed down gracefully (data caches dump,
+ * MMU flushed) and set up the address environment for the new
+ * thread at the head of the ready-to-run list.
+ */
+
+ group_addrenv(NULL);
+#endif
+ }
+
+ /* Set CURRENT_REGS to NULL to indicate that we are no longer in an
+ * interrupt handler.
+ */
+
+ regs = (uint64_t *)CURRENT_REGS;
+ CURRENT_REGS = NULL;
+
+ return regs;
+}
+
+/****************************************************************************
+ * Name: up_irqinitialize
+ *
+ * Description:
+ * This function is called by up_initialize() during the bring-up of the
+ * system. It is the responsibility of this function to but the interrupt
+ * subsystem into the working and ready state.
+ *
+ ****************************************************************************/
+
+void up_irqinitialize(void)
+{
+ /* The following operations need to be atomic, but since this function is
+ * called early in the initialization sequence, we expect to have exclusive
+ * access to the GIC.
+ */
+
+ /* Initialize the Generic Interrupt Controller (GIC) for CPU0 */
+
+ arm64_gic_initialize(); /* Initialization common to all CPUs */
+
+ /* currents_regs is non-NULL only while processing an interrupt */
+
+ CURRENT_REGS = NULL;
+
+#ifdef CONFIG_SMP
+ arm64_smp_sgi_init();
+#endif
+
+#ifndef CONFIG_SUPPRESS_INTERRUPTS
+
+ /* And finally, enable interrupts */
+
+ up_irq_enable();
+#endif
+}
diff --git a/arch/arm64/src/common/arm64_exit.c b/arch/arm64/src/common/arm64_exit.c
new file mode 100644
index 0000000000..ea16db416c
--- /dev/null
+++ b/arch/arm64/src/common/arm64_exit.c
@@ -0,0 +1,158 @@
+/****************************************************************************
+ * arch/arm64/src/common/arm64_exit.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 <sched.h>
+#include <debug.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/irq.h>
+#ifdef CONFIG_DUMP_ON_EXIT
+# include <nuttx/fs/fs.h>
+#endif
+
+#include "task/task.h"
+#include "sched/sched.h"
+#include "group/group.h"
+#include "irq/irq.h"
+#include "arm64_internal.h"
+
+#ifdef CONFIG_ARCH_FPU
+#include "arm64_fpu.h"
+#endif
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#ifndef CONFIG_DEBUG_SCHED_INFO
+# undef CONFIG_DUMP_ON_EXIT
+#endif
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: _up_dumponexit
+ *
+ * Description:
+ * Dump the state of all tasks whenever on task exits. This is debug
+ * instrumentation that was added to check file-related reference counting
+ * but could be useful again sometime in the future.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_DUMP_ON_EXIT
+static void _up_dumponexit(struct tcb_s *tcb, void *arg)
+{
+ struct filelist *filelist;
+ int i;
+ int j;
+
+ sinfo(" TCB=%p name=%s pid=%d\n", tcb, tcb->name, tcb->pid);
+ sinfo(" priority=%d state=%d\n", tcb->sched_priority, tcb->task_state);
+
+ filelist = tcb->group->tg_filelist;
+ for (i = 0; i < filelist->fl_rows; i++)
+ {
+ for (j = 0; j < CONFIG_NFILE_DESCRIPTORS_PER_BLOCK; j++)
+ {
+ struct inode *inode = filelist->fl_files[i][j].f_inode;
+ if (inode)
+ {
+ sinfo(" fd=%d refcount=%d\n",
+ i * CONFIG_NFILE_DESCRIPTORS_PER_BLOCK + j,
+ inode->i_crefs);
+ }
+ }
+ }
+}
+#endif
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: up_exit
+ *
+ * Description:
+ * This function causes the currently executing task to cease
+ * to exist. This is a special case of task_delete() where the task to
+ * be deleted is the currently executing task. It is more complex because
+ * a context switch must be perform to the next ready to run task.
+ *
+ ****************************************************************************/
+
+void up_exit(int status)
+{
+ struct tcb_s *tcb = this_task();
+ UNUSED(status);
+
+ /* Make sure that we are in a critical section with local interrupts.
+ * The IRQ state will be restored when the next task is started.
+ */
+
+ enter_critical_section();
+
+#ifdef CONFIG_DUMP_ON_EXIT
+ sinfo("Other tasks:\n");
+ nxsched_foreach(_up_dumponexit, NULL);
+#endif
+
+ /* Destroy the task at the head of the ready to run list. */
+#ifdef CONFIG_ARCH_FPU
+ arm64_destory_fpu(tcb);
+#endif
+
+ nxtask_exit();
+
+ /* Now, perform the context switch to the new ready-to-run task at the
+ * head of the list.
+ */
+
+ tcb = this_task();
+
+ /* Adjusts time slice for SCHED_RR & SCHED_SPORADIC cases
+ * NOTE: the API also adjusts the global IRQ control for SMP
+ */
+
+ nxsched_resume_scheduler(tcb);
+
+#ifdef CONFIG_ARCH_ADDRENV
+ /* Make sure that the address environment for the previously running
+ * task is closed down gracefully (data caches dump, MMU flushed) and
+ * set up the address environment for the new thread at the head of
+ * the ready-to-run list.
+ */
+
+ group_addrenv(tcb);
+#endif
+
+ /* Then switch contexts */
+
+ arm64_fullcontextrestore(tcb->xcp.regs);
+}
diff --git a/arch/arm64/src/common/arm64_fatal.c b/arch/arm64/src/common/arm64_fatal.c
new file mode 100644
index 0000000000..fac6db9082
--- /dev/null
+++ b/arch/arm64/src/common/arm64_fatal.c
@@ -0,0 +1,365 @@
+/****************************************************************************
+ * arch/arm64/src/common/arm64_fatal.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 <stdint.h>
+
+#include <arch/irq.h>
+#include <debug.h>
+#include <assert.h>
+#include <sched.h>
+#include <nuttx/arch.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/tls.h>
+#include <nuttx/board.h>
+#include <arch/chip/chip.h>
+#include <nuttx/syslog/syslog.h>
+#include "sched/sched.h"
+#include "irq/irq.h"
+#include "arm64_arch.h"
+#include "arm64_internal.h"
+#include "arm64_fatal.h"
+#include "arm64_mmu.h"
+#include "arm64_fatal.h"
+#include "arm64_arch_timer.h"
+
+#ifdef CONFIG_ARCH_FPU
+#include "arm64_fpu.h"
+#endif
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: print_ec_cause
+ ****************************************************************************/
+
+static void print_ec_cause(uint64_t esr)
+{
+ uint32_t ec = (uint32_t)esr >> 26;
+
+ switch (ec)
+ {
+ case 0b000000:
+ {
+ sinfo("Unknown reason\n");
+ break;
+ }
+
+ case 0b000001:
+ {
+ sinfo("Trapped WFI or WFE instruction execution\n");
+ break;
+ }
+
+ case 0b000011:
+ {
+ sinfo(
+ "Trapped MCR or MRC access with (coproc==0b1111) that "
+ "is not reported using EC 0b000000\n");
+ break;
+ }
+
+ case 0b000100:
+ {
+ sinfo(
+ "Trapped MCRR or MRRC access with (coproc==0b1111) "
+ "that is not reported using EC 0b000000\n");
+ break;
+ }
+
+ case 0b000101:
+ {
+ sinfo("Trapped MCR or MRC access with (coproc==0b1110)\n");
+ break;
+ }
+
+ case 0b000110:
+ {
+ sinfo("Trapped LDC or STC access\n");
+ break;
+ }
+
+ case 0b000111:
+ {
+ sinfo(
+ "Trapped access to SVE, Advanced SIMD, or "
+ "floating-point functionality\n");
+ break;
+ }
+
+ case 0b001100:
+ {
+ sinfo("Trapped MRRC access with (coproc==0b1110)\n");
+ break;
+ }
+
+ case 0b001101:
+ {
+ sinfo("Branch Target Exception\n");
+ break;
+ }
+
+ case 0b001110:
+ {
+ sinfo("Illegal Execution state\n");
+ break;
+ }
+
+ case 0b010001:
+ {
+ sinfo("SVC instruction execution in AArch32 state\n");
+ break;
+ }
+
+ case 0b011000:
+ {
+ sinfo(
+ "Trapped MSR, MRS or System instruction execution in "
+ "AArch64 state, that is not reported using EC "
+ "0b000000, 0b000001 or 0b000111\n");
+ break;
+ }
+
+ case 0b011001:
+ {
+ sinfo("Trapped access to SVE functionality\n");
+ break;
+ }
+
+ case 0b100000:
+ {
+ sinfo(
+ "Instruction Abort from a lower Exception level, that "
+ "might be using AArch32 or AArch64\n");
+ break;
+ }
+
+ case 0b100001:
+ {
+ sinfo(
+ "Instruction Abort taken without a change "
+ "in Exception level.\n");
+ break;
+ }
+
+ case 0b100010:
+ {
+ sinfo("PC alignment fault exception.\n");
+ break;
+ }
+
+ case 0b100100:
+ {
+ sinfo(
+ "Data Abort from a lower Exception level, that might "
+ "be using AArch32 or AArch64\n");
+ break;
+ }
+
+ case 0b100101:
+ {
+ sinfo("Data Abort taken without a change in Exception level\n");
+ break;
+ }
+
+ case 0b100110:
+ {
+ sinfo("SP alignment fault exception\n");
+ break;
+ }
+
+ case 0b101000:
+ {
+ sinfo(
+ "Trapped floating-point exception "
+ "taken from AArch32 state\n");
+ break;
+ }
+
+ case 0b101100:
+ {
+ sinfo(
+ "Trapped floating-point exception "
+ "taken from AArch64 state.\n");
+ break;
+ }
+
+ case 0b101111:
+ {
+ sinfo("SError interrupt\n");
+ break;
+ }
+
+ case 0b110000:
+ {
+ sinfo(
+ "Breakpoint exception from a lower Exception level, "
+ "that might be using AArch32 or AArch64\n");
+ break;
+ }
+
+ case 0b110001:
+ {
+ sinfo(
+ "Breakpoint exception taken without a change in "
+ "Exception level\n");
+ break;
+ }
+
+ case 0b110010:
+ {
+ sinfo(
+ "Software Step exception from a lower Exception level, "
+ "that might be using AArch32 or AArch64\n");
+ break;
+ }
+
+ case 0b110011:
+ {
+ sinfo(
+ "Software Step exception taken without a change in "
+ "Exception level\n");
+ break;
+ }
+
+ case 0b110100:
+ {
+ sinfo(
+ "Watchpoint exception from a lower Exception level, "
+ "that might be using AArch32 or AArch64\n");
+ break;
+ }
+
+ case 0b110101:
+ {
+ sinfo(
+ "Watchpoint exception taken without a change in "
+ "Exception level.\n");
+ break;
+ }
+
+ case 0b111000:
+ {
+ sinfo("BKPT instruction execution in AArch32 state\n");
+ break;
+ }
+
+ case 0b111100:
+ {
+ sinfo("BRK instruction execution in AArch64 state.\n");
+ break;
+ }
+
+ default:
+ break;
+ }
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: arm64_fatal_error
+ *
+ * Description:
+ *
+ ****************************************************************************/
+
+void arm64_fatal_error(unsigned int reason, struct regs_context * reg)
+{
+ uint64_t el, esr, elr, far;
+ int cpu = up_cpu_index();
+
+ sinfo("reason = %d\n", reason);
+ sinfo("arm64_fatal_error: CPU%d task: %s\n", cpu, running_task()->name);
+
+ if (reason != K_ERR_SPURIOUS_IRQ)
+ {
+ __asm__ volatile ("mrs %0, CurrentEL" : "=r" (el));
+
+ switch (GET_EL(el))
+ {
+ case MODE_EL1:
+ {
+ sinfo("CurrentEL: MODE_EL1\n");
+ __asm__ volatile ("mrs %0, esr_el1" : "=r" (esr));
+ __asm__ volatile ("mrs %0, far_el1" : "=r" (far));
+ __asm__ volatile ("mrs %0, elr_el1" : "=r" (elr));
+ break;
+ }
+
+ case MODE_EL2:
+ {
+ sinfo("CurrentEL: MODE_EL2\n");
+ __asm__ volatile ("mrs %0, esr_el2" : "=r" (esr));
+ __asm__ volatile ("mrs %0, far_el2" : "=r" (far));
+ __asm__ volatile ("mrs %0, elr_el2" : "=r" (elr));
+ break;
+ }
+
+ case MODE_EL3:
+ {
+ sinfo("CurrentEL: MODE_EL3\n");
+ __asm__ volatile ("mrs %0, esr_el3" : "=r" (esr));
+ __asm__ volatile ("mrs %0, far_el3" : "=r" (far));
+ __asm__ volatile ("mrs %0, elr_el3" : "=r" (elr));
+ break;
+ }
+
+ default:
+ {
+ sinfo("CurrentEL: unknown\n");
+
+ /* Just to keep the compiler happy */
+
+ esr = elr = far = 0;
+ break;
+ }
+ }
+
+ if (GET_EL(el) != MODE_EL0)
+ {
+ sinfo("ESR_ELn: 0x%"PRIx64"\n", esr);
+ sinfo("FAR_ELn: 0x%"PRIx64"\n", far);
+ sinfo("ELR_ELn: 0x%"PRIx64"\n", elr);
+
+ print_ec_cause(esr);
+ }
+ }
+
+ if (reg != NULL)
+ {
+ arm64_dump_fatal(reg);
+ }
+
+ for (; ; )
+ {
+ up_mdelay(1000);
+ }
+}
diff --git a/arch/arm64/src/common/arm64_fatal.h b/arch/arm64/src/common/arm64_fatal.h
new file mode 100644
index 0000000000..e1d88bc97d
--- /dev/null
+++ b/arch/arm64/src/common/arm64_fatal.h
@@ -0,0 +1,83 @@
+/****************************************************************************
+ * arch/arm64/src/common/arm64_fatal.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_ARM64_SRC_COMMON_ARM64_FATAL_H
+#define __ARCH_ARM64_SRC_COMMON_ARM64_FATAL_H
+
+/**
+ * @defgroup fatal_apis Fatal error APIs
+ * @ingroup kernel_apis
+ * @{
+ */
+
+#define K_ERR_CPU_EXCEPTION (0)
+#define K_ERR_CPU_MODE32 (1)
+#define K_ERR_SPURIOUS_IRQ (2)
+
+#ifndef __ASSEMBLY__
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <debug.h>
+#include <assert.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define __builtin_unreachable() \
+ do \
+ { \
+ sinfo("Unreachable code\n"); \
+ PANIC(); \
+ } while (true)
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: arm64_fatal_error
+ *
+ * Description:
+ * fatal error handle for arm64
+ * Input Parameters:
+ * reason: error reason
+ * reg: exception stack reg context
+ *
+ * Returned Value:
+ *
+ ****************************************************************************/
+
+void arm64_fatal_error(unsigned int reason, struct regs_context * reg);
+void arm64_dump_fatal(struct regs_context * reg);
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* __ARCH_ARM64_SRC_COMMON_ARM64_FATAL_H */
diff --git a/arch/arm64/src/common/arm64_fpu.c b/arch/arm64/src/common/arm64_fpu.c
new file mode 100644
index 0000000000..1516268359
--- /dev/null
+++ b/arch/arm64/src/common/arm64_fpu.c
@@ -0,0 +1,242 @@
+/***************************************************************************
+ * arch/arm64/src/common/arm64_fpu.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 <inttypes.h>
+#include <stdint.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+#include <debug.h>
+#include <nuttx/sched.h>
+#include <nuttx/arch.h>
+#include <arch/irq.h>
+
+#include "sched/sched.h"
+#include "arm64_arch.h"
+#include "arm64_vfork.h"
+#include "arm64_internal.h"
+#include "arm64_fatal.h"
+#include "arm64_fpu.h"
+
+/***************************************************************************
+ * Private Data
+ ***************************************************************************/
+
+static struct fpu_reg g_idle_thread_fpu[CONFIG_SMP_NCPUS];
+static struct arm64_cpu_fpu_context g_cpu_fpu_ctx[CONFIG_SMP_NCPUS];
+
+/***************************************************************************
+ * Private Functions
+ ***************************************************************************/
+
+/* enable FPU access trap */
+
+static void arm64_fpu_access_trap_enable(void)
+{
+ uint64_t cpacr;
+
+ cpacr = read_sysreg(cpacr_el1);
+ cpacr &= ~CPACR_EL1_FPEN_NOTRAP;
+ write_sysreg(cpacr, cpacr_el1);
+
+ ARM64_ISB();
+}
+
+/* disable FPU access trap */
+
+static void arm64_fpu_access_trap_disable(void)
+{
+ uint64_t cpacr;
+
+ cpacr = read_sysreg(cpacr_el1);
+ cpacr |= CPACR_EL1_FPEN_NOTRAP;
+ write_sysreg(cpacr, cpacr_el1);
+
+ ARM64_ISB();
+}
+
+/***************************************************************************
+ * Public Functions
+ ***************************************************************************/
+
+void arm64_init_fpu(struct tcb_s *tcb)
+{
+ struct fpu_reg *fpu_reg;
+
+ if (tcb->pid < CONFIG_SMP_NCPUS)
+ {
+ memset(&g_cpu_fpu_ctx[this_cpu()], 0,
+ sizeof(struct arm64_cpu_fpu_context));
+ g_cpu_fpu_ctx[this_cpu()].idle_thread = tcb;
+
+ tcb->xcp.fpu_regs = (uint64_t *)&g_idle_thread_fpu[this_cpu()];
+ }
+
+ memset(tcb->xcp.fpu_regs, 0, sizeof(struct fpu_reg));
+ fpu_reg = (struct fpu_reg *)tcb->xcp.fpu_regs;
+ fpu_reg->fpu_trap = 0;
+}
+
+void arm64_destory_fpu(struct tcb_s * tcb)
+{
+ struct tcb_s * owner;
+
+ /* save current fpu owner's context */
+
+ owner = g_cpu_fpu_ctx[this_cpu()].fpu_owner;
+
+ if (owner == tcb)
+ {
+ g_cpu_fpu_ctx[this_cpu()].fpu_owner = NULL;
+ }
+}
+
+/***************************************************************************
+ * Name: arm64_fpu_enter_exception
+ *
+ * Description:
+ * called at every time get into a exception
+ *
+ ***************************************************************************/
+
+void arm64_fpu_enter_exception(void)
+{
+}
+
+void arm64_fpu_exit_exception(void)
+{
+}
+
+void arm64_fpu_trap(struct regs_context * regs)
+{
+ struct tcb_s * owner;
+ struct fpu_reg *fpu_reg;
+
+ UNUSED(regs);
+
+ /* disable fpu trap access */
+
+ arm64_fpu_access_trap_disable();
+
+ /* save current fpu owner's context */
+
+ owner = g_cpu_fpu_ctx[this_cpu()].fpu_owner;
+
+ if (owner != NULL)
+ {
+ arm64_fpu_save((struct fpu_reg *)owner->xcp.fpu_regs);
+ ARM64_DSB();
+ g_cpu_fpu_ctx[this_cpu()].save_count++;
+ g_cpu_fpu_ctx[this_cpu()].fpu_owner = NULL;
+ }
+
+ if (arch_get_exception_depth() > 1)
+ {
+ /* if get_exception_depth > 1
+ * it means FPU access exception occurred in exception context
+ * switch FPU owner to idle thread
+ */
+
+ owner = g_cpu_fpu_ctx[this_cpu()].idle_thread;
+ }
+ else
+ {
+ owner = (struct tcb_s *)arch_get_current_tcb();
+ }
+
+ /* restore our context */
+
+ arm64_fpu_restore((struct fpu_reg *)owner->xcp.fpu_regs);
+ g_cpu_fpu_ctx[this_cpu()].restore_count++;
+
+ /* become new owner */
+
+ g_cpu_fpu_ctx[this_cpu()].fpu_owner = owner;
+ fpu_reg = (struct fpu_reg *)owner->xcp.fpu_regs;
+ fpu_reg->fpu_trap = 0;
+}
+
+void arm64_fpu_context_restore(void)
+{
+ struct tcb_s *new_tcb = (struct tcb_s *)arch_get_current_tcb();
+ struct fpu_reg *fpu_reg = (struct fpu_reg *)new_tcb->xcp.fpu_regs;
+
+ arm64_fpu_access_trap_enable();
+
+ if (fpu_reg->fpu_trap == 0)
+ {
+ /* FPU trap hasn't happened at this task */
+
+ arm64_fpu_access_trap_enable();
+ }
+ else
+ {
+ /* FPU trap has happened at this task */
+
+ if (new_tcb == g_cpu_fpu_ctx[this_cpu()].fpu_owner)
+ {
+ arm64_fpu_access_trap_disable();
+ }
+ else
+ {
+ arm64_fpu_access_trap_enable();
+ }
+ }
+
+ g_cpu_fpu_ctx[this_cpu()].switch_count++;
+}
+
+void arm64_fpu_enable(void)
+{
+ irqstate_t flags = up_irq_save();
+
+ arm64_fpu_access_trap_enable();
+ up_irq_restore(flags);
+}
+
+void arm64_fpu_disable(void)
+{
+ irqstate_t flags = up_irq_save();
+
+ arm64_fpu_access_trap_disable();
+ up_irq_restore(flags);
+}
+
+/***************************************************************************
+ * Name: up_fpucmp
+ *
+ * Description:
+ * compare FPU areas from thread context
+ *
+ ***************************************************************************/
+
+bool up_fpucmp(const void *saveregs1, const void *saveregs2)
+{
+ const uint64_t *regs1 = saveregs1 + XCPTCONTEXT_GP_SIZE;
+ const uint64_t *regs2 = saveregs2 + XCPTCONTEXT_GP_SIZE;
+
+ return memcmp(regs1, regs2, 8 * XCPTCONTEXT_FPU_REGS) == 0;
+}
diff --git a/arch/arm64/src/common/arm64_fpu.h b/arch/arm64/src/common/arm64_fpu.h
new file mode 100644
index 0000000000..ba2ec64d85
--- /dev/null
+++ b/arch/arm64/src/common/arm64_fpu.h
@@ -0,0 +1,74 @@
+/****************************************************************************
+ * arch/arm64/src/common/arm64_fpu.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_ARM64_SRC_COMMON_ARM64_FPU_H
+#define __ARCH_ARM64_SRC_COMMON_ARM64_FPU_H
+
+#ifndef __ASSEMBLY__
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <stdint.h>
+#include <debug.h>
+#include <assert.h>
+
+/****************************************************************************
+ * Type Declarations
+ ****************************************************************************/
+
+struct arm64_cpu_fpu_context
+{
+ /* owner of current CPU's FPU */
+
+ struct tcb_s *fpu_owner;
+
+ struct tcb_s *idle_thread;
+
+ /* for statistic propose */
+
+ int save_count;
+ int restore_count;
+ int switch_count;
+ int exe_depth_count;
+};
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+void arm64_init_fpu(struct tcb_s *tcb);
+void arm64_destory_fpu(struct tcb_s *tcb);
+
+void arm64_fpu_disable(void);
+void arm64_fpu_enable(void);
+
+void arm64_fpu_save(struct fpu_reg *saved_fp_context);
+void arm64_fpu_restore(struct fpu_reg *saved_fp_context);
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* __ARCH_ARM64_SRC_COMMON_ARM64_FPU_H */
diff --git a/arch/arm64/src/common/arm64_fpu_func.S b/arch/arm64/src/common/arm64_fpu_func.S
new file mode 100644
index 0000000000..da68a0c94c
--- /dev/null
+++ b/arch/arm64/src/common/arm64_fpu_func.S
@@ -0,0 +1,101 @@
+/****************************************************************************
+ * arch/arm64/src/common/arm64_fpu_func.S
+ *
+ * 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 "arm64_macro.inc"
+#include "arch/irq.h"
+#include "arm64_fatal.h"
+
+/****************************************************************************
+ * Public Symbols
+ ****************************************************************************/
+
+ .file "arm64_fpu_func.S"
+
+/****************************************************************************
+ * Assembly Macros
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+GTEXT(arm64_fpu_save)
+SECTION_FUNC(text, arm64_fpu_save)
+
+ stp q0, q1, [x0, #(16 * FPU_REG_Q0)]
+ stp q2, q3, [x0, #(16 * FPU_REG_Q2)]
+ stp q4, q5, [x0, #(16 * FPU_REG_Q4)]
+ stp q6, q7, [x0, #(16 * FPU_REG_Q6)]
+ stp q8, q9, [x0, #(16 * FPU_REG_Q8)]
+ stp q10, q11, [x0, #(16 * FPU_REG_Q10)]
+ stp q12, q13, [x0, #(16 * FPU_REG_Q12)]
+ stp q14, q15, [x0, #(16 * FPU_REG_Q14)]
+ stp q16, q17, [x0, #(16 * FPU_REG_Q16)]
+ stp q18, q19, [x0, #(16 * FPU_REG_Q18)]
+ stp q20, q21, [x0, #(16 * FPU_REG_Q20)]
+ stp q22, q23, [x0, #(16 * FPU_REG_Q22)]
+ stp q24, q25, [x0, #(16 * FPU_REG_Q24)]
+ stp q26, q27, [x0, #(16 * FPU_REG_Q26)]
+ stp q28, q29, [x0, #(16 * FPU_REG_Q28)]
+ stp q30, q31, [x0, #(16 * FPU_REG_Q30)]
+
+ mrs x1, fpsr
+ mrs x2, fpcr
+ str w1, [x0, #(16 * 32 + 0)]
+ str w2, [x0, #(16 * 32 + 4)]
+
+ ret
+
+GTEXT(arm64_fpu_restore)
+SECTION_FUNC(text, arm64_fpu_restore)
+
+ ldp q0, q1, [x0, #(16 * FPU_REG_Q0)]
+ ldp q2, q3, [x0, #(16 * FPU_REG_Q2)]
+ ldp q4, q5, [x0, #(16 * FPU_REG_Q4)]
+ ldp q6, q7, [x0, #(16 * FPU_REG_Q6)]
+ ldp q8, q9, [x0, #(16 * FPU_REG_Q8)]
+ ldp q10, q11, [x0, #(16 * FPU_REG_Q10)]
+ ldp q12, q13, [x0, #(16 * FPU_REG_Q12)]
+ ldp q14, q15, [x0, #(16 * FPU_REG_Q14)]
+ ldp q16, q17, [x0, #(16 * FPU_REG_Q16)]
+ ldp q18, q19, [x0, #(16 * FPU_REG_Q18)]
+ ldp q20, q21, [x0, #(16 * FPU_REG_Q20)]
+ ldp q22, q23, [x0, #(16 * FPU_REG_Q22)]
+ ldp q24, q25, [x0, #(16 * FPU_REG_Q24)]
+ ldp q26, q27, [x0, #(16 * FPU_REG_Q26)]
+ ldp q28, q29, [x0, #(16 * FPU_REG_Q28)]
+ ldp q30, q31, [x0, #(16 * FPU_REG_Q30)]
+
+ ldr w1, [x0, #(16 * 32 + 0)]
+ ldr w2, [x0, #(16 * 32 + 4)]
+ msr fpsr, x1
+ msr fpcr, x2
+
+ ret
diff --git a/arch/arm64/src/common/arm64_gic.h b/arch/arm64/src/common/arm64_gic.h
new file mode 100644
index 0000000000..496fa944a6
--- /dev/null
+++ b/arch/arm64/src/common/arm64_gic.h
@@ -0,0 +1,319 @@
+/****************************************************************************
+ * arch/arm64/src/common/arm64_gic.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_ARM64_SRC_COMMON_ARM64_GIC_H
+#define __ARCH_ARM64_SRC_COMMON_ARM64_GIC_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <arch/irq.h>
+#include <arch/chip/chip.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* GIC Distributor register Interface Base Addresses
+ * Arm® Generic Interrupt Controller Architecture Specification
+ * GIC architecture version 3 and version 4
+ */
+
+#define GIC_DIST_BASE CONFIG_GICD_BASE
+#define GICD_CTLR (GIC_DIST_BASE + 0x0)
+#define GICD_TYPER (GIC_DIST_BASE + 0x4)
+#define GICD_IIDR (GIC_DIST_BASE + 0x8)
+#define GICD_STATUSR (GIC_DIST_BASE + 0x10)
+#define GICD_SETSPI_NSR (GIC_DIST_BASE + 0x40)
+#define GICD_CLRSPI_NSR (GIC_DIST_BASE + 0x48)
+#define GICD_SETSPI_SR (GIC_DIST_BASE + 0x50)
+#define GICD_CLRSPI_SR (GIC_DIST_BASE + 0x58)
+#define GICD_IGROUPRn (GIC_DIST_BASE + 0x80)
+#define GICD_ISENABLERn (GIC_DIST_BASE + 0x100)
+#define GICD_ICENABLERn (GIC_DIST_BASE + 0x180)
+#define GICD_ISPENDRn (GIC_DIST_BASE + 0x200)
+#define GICD_ICPENDRn (GIC_DIST_BASE + 0x280)
+#define GICD_ISACTIVERn (GIC_DIST_BASE + 0x300)
+#define GICD_ICACTIVERn (GIC_DIST_BASE + 0x380)
+#define GICD_IPRIORITYRn (GIC_DIST_BASE + 0x400)
+#define GICD_ITARGETSRn (GIC_DIST_BASE + 0x800)
+#define GICD_ICFGRn (GIC_DIST_BASE + 0xc00)
+#define GICD_SGIR (GIC_DIST_BASE + 0xf00)
+#define GICD_IDREGS (GIC_DIST_BASE + 0xFFD0)
+#define GICD_PIDR2 (GIC_DIST_BASE + 0xFFE8)
+
+/* Offsets from GICD base or GICR(n) SGI_base */
+
+#define GIC_DIST_IGROUPR 0x0080
+#define GIC_DIST_ISENABLER 0x0100
+#define GIC_DIST_ICENABLER 0x0180
+#define GIC_DIST_ISPENDR 0x0200
+#define GIC_DIST_ICPENDR 0x0280
+#define GIC_DIST_ISACTIVER 0x0300
+#define GIC_DIST_ICACTIVER 0x0380
+#define GIC_DIST_IPRIORITYR 0x0400
+#define GIC_DIST_ITARGETSR 0x0800
+#define GIC_DIST_ICFGR 0x0c00
+#define GIC_DIST_IGROUPMODR 0x0d00
+#define GIC_DIST_SGIR 0x0f00
+
+/* GICD GICR common access macros */
+
+#define IGROUPR(base, n) (base + GIC_DIST_IGROUPR + (n) * 4)
+#define ISENABLER(base, n) (base + GIC_DIST_ISENABLER + (n) * 4)
+#define ICENABLER(base, n) (base + GIC_DIST_ICENABLER + (n) * 4)
+#define ISPENDR(base, n) (base + GIC_DIST_ISPENDR + (n) * 4)
+#define ICPENDR(base, n) (base + GIC_DIST_ICPENDR + (n) * 4)
+#define IPRIORITYR(base, n) (base + GIC_DIST_IPRIORITYR + n)
+#define ITARGETSR(base, n) (base + GIC_DIST_ITARGETSR + (n) * 4)
+#define ICFGR(base, n) (base + GIC_DIST_ICFGR + (n) * 4)
+#define IGROUPMODR(base, n) (base + GIC_DIST_IGROUPMODR + (n) * 4)
+
+/* GICD_PIDR2 : Peripheral ID2 Register
+ * bit assignments
+ * [31:8] - IMPLEMENTATION DEFINED
+ * [7:4] ArchRev 0x1. GICv1.
+ * 0x2. GICv2.
+ * 0x3. GICv3.
+ * 0x4. GICv4.
+ * [3:0] - IMPLEMENTATION DEFINED.
+ */
+#define GICD_PIDR2_ARCH_MASK 0xf0
+#define GICD_PIDR2_ARCH_GICV3 0x30
+#define GICD_PIDR2_ARCH_GICV4 0x40
+
+/* GICD_TYPER : Interrupt Controller Type Register
+ * Arm® Generic Interrupt Controller Architecture Specification
+ * GIC architecture version 3 and version 4
+ */
+#define GICD_TYPER_RSS BIT(26)
+#define GICD_TYPER_LPIS BIT(17)
+#define GICD_TYPER_MBIS BIT(16)
+#define GICD_TYPER_ESPI BIT(8)
+#define GICD_TYPER_ID_BITS(typer) ((((typer) >> 19) & 0x1f) + 1)
+#define GICD_TYPER_NUM_LPIS(typer) ((((typer) >> 11) & 0x1f) + 1)
+#define GICD_TYPER_SPIS(typer) ((((typer) & 0x1f) + 1) * 32)
+#define GICD_TYPER_ESPIS(typer) \
+ (((typer) & GICD_TYPER_ESPI) ? GICD_TYPER_SPIS((typer) >> 27) : 0)
+
+/* Common Helper Constants */
+#define GIC_SGI_INT_BASE 0
+#define GIC_PPI_INT_BASE 16
+#define GIC_IS_SGI(intid) (((intid) >= GIC_SGI_INT_BASE) && \
+ ((intid) < GIC_PPI_INT_BASE))
+
+#define GIC_SPI_INT_BASE 32
+#define GIC_NUM_INTR_PER_REG 32
+#define GIC_NUM_CFG_PER_REG 16
+#define GIC_NUM_PRI_PER_REG 4
+
+/* GIC idle priority : value '0xff' will allow all interrupts */
+
+#define GIC_IDLE_PRIO 0xff
+
+/* Priority levels 0:255 */
+
+#define GIC_PRI_MASK 0xff
+
+/* '0xa0'is used to initialize each interrtupt default priority.
+ * This is an arbitrary value in current context.
+ * Any value '0x80' to '0xff' will work for both NS and S state.
+ * The values of individual interrupt and default has to be chosen
+ * carefully if PMR and BPR based nesting and preemption has to be done.
+ */
+
+#define GIC_INT_DEF_PRI_X4 0xa0a0a0a0
+
+/* Register bit definitions */
+
+/* GICD_CTLR Interrupt group definitions */
+#define GICD_CTLR_ENABLE_G0 0
+#define GICD_CTLR_ENABLE_G1NS 1
+#define GICD_CTLR_ENABLE_G1S 2
+#define GICD_CTRL_ARE_S 4
+#define GICD_CTRL_ARE_NS 5
+#define GICD_CTRL_NS 6
+#define GICD_CGRL_E1NWF 7
+
+/* GICD_CTLR Register write progress bit */
+#define GICD_CTLR_RWP 31
+
+/* GICR_CTLR */
+#define GICR_CTLR_ENABLE_LPIS BIT(0)
+#define GICR_CTLR_RWP 3
+
+/* GICD_TYPER.ITLinesNumber 0:4 */
+#define GICD_TYPER_ITLINESNUM_MASK 0x1f
+
+/* GICR: Re-Distributor registers, offsets from RD_base(n) */
+#define GICR_CTLR 0x0000
+#define GICR_IIDR 0x0004
+#define GICR_TYPER 0x0008
+#define GICR_STATUSR 0x0010
+#define GICR_WAKER 0x0014
+#define GICR_SETLPIR 0x0040
+#define GICR_CLRLPIR 0x0048
+#define GICR_PROPBASER 0x0070
+#define GICR_PENDBASER 0x0078
+#define GICR_INVLPIR 0x00A0
+#define GICR_INVALLR 0x00B0
+#define GICR_SYNCR 0x00C0
+#define GICR_MOVLPIR 0x0100
+#define GICR_MOVALLR 0x0110
+#define GICR_IDREGS 0xFFD0
+#define GICR_PIDR2 0xFFE8
+
+/* GICR_PIDR2 : Peripheral ID2 Register
+ * bit assignments are the same as those for GICD_PIDR2)
+ * [31:8] - IMPLEMENTATION DEFINED
+ * [7:4] ArchRev 0x1. GICv1.
+ * 0x2. GICv2.
+ * 0x3. GICv3.
+ * 0x4. GICv4.
+ * [3:0] - IMPLEMENTATION DEFINED.
+ */
+
+#define GICR_PIDR2_ARCH_MASK 0xf0
+#define GICR_PIDR2_ARCH_GICV3 0x30
+#define GICR_PIDR2_ARCH_GICV4 0x40
+
+/* GICR_TYPER : Redistributor Type Register
+ * Arm® Generic Interrupt Controller Architecture Specification
+ * GIC architecture version 3 and version 4
+ * chapter 9.11.35 for detail descriptions
+ */
+
+#define GICR_TYPER_PLPIS BIT(0)
+#define GICR_TYPER_VLPIS BIT(1)
+#define GICR_TYPER_DIRECTLPIS BIT(3)
+#define GICR_TYPER_LAST BIT(4)
+
+/* GICR_WAKER */
+#define GICR_WAKER_PS 1
+#define GICR_WAKER_CA 2
+
+/* SGI base is at 64K offset from Redistributor */
+#define GICR_SGI_BASE_OFF 0x10000
+
+/* GICD_ICFGR */
+#define GICD_ICFGR_MASK BIT_MASK(2)
+#define GICD_ICFGR_TYPE BIT(1)
+
+/* BIT(0) reserved for IRQ_ZERO_LATENCY */
+#define IRQ_TYPE_LEVEL BIT(1)
+#define IRQ_TYPE_EDGE BIT(2)
+
+#define GIC_SPI_INT_BASE 32
+#define GIC_SPI_MAX_INTID 1019
+#define GIC_IS_SPI(intid) (((intid) >= GIC_SPI_INT_BASE) && \
+ ((intid) <= GIC_SPI_MAX_INTID))
+
+/* GITCD_IROUTER */
+#define GIC_DIST_IROUTER 0x6000
+#define IROUTER(base, n) (base + GIC_DIST_IROUTER + (n) * 8)
+
+/* BIT(0) reserved for IRQ_ZERO_LATENCY */
+#define IRQ_TYPE_LEVEL BIT(1)
+#define IRQ_TYPE_EDGE BIT(2)
+
+#define IRQ_DEFAULT_PRIORITY 0xa0
+
+#define GIC_IRQ_SGI0 0
+#define GIC_IRQ_SGI1 1
+#define GIC_IRQ_SGI2 2
+#define GIC_IRQ_SGI3 3
+#define GIC_IRQ_SGI4 4
+#define GIC_IRQ_SGI5 5
+#define GIC_IRQ_SGI6 6
+#define GIC_IRQ_SGI7 7
+#define GIC_IRQ_SGI8 8
+#define GIC_IRQ_SGI9 9
+#define GIC_IRQ_SGI10 10
+#define GIC_IRQ_SGI11 11
+#define GIC_IRQ_SGI12 12
+#define GIC_IRQ_SGI13 13
+#define GIC_IRQ_SGI14 14
+#define GIC_IRQ_SGI15 15
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+bool arm64_gic_irq_is_enabled(unsigned int intid);
+int arm64_gic_initialize(void);
+void arm64_gic_irq_set_priority(unsigned int intid, unsigned int prio,
+ uint32_t flags);
+
+/****************************************************************************
+ * Name: arm64_decodeirq
+ *
+ * Description:
+ * This function is called from the IRQ vector handler in arm_vectors.S.
+ * At this point, the interrupt has been taken and the registers have
+ * been saved on the stack. This function simply needs to determine the
+ * the irq number of the interrupt and then to call arm_doirq to dispatch
+ * the interrupt.
+ *
+ * Input Parameters:
+ * regs - A pointer to the register save area on the stack.
+ *
+ ****************************************************************************/
+
+uint64_t * arm64_decodeirq(uint64_t *regs);
+
+int arm64_gic_raise_sgi(unsigned int sgi_id, uint64_t target_aff,
+ uint16_t target_list);
+
+#ifdef CONFIG_SMP
+
+#define SGI_CPU_PAUSE GIC_IRQ_SGI0
+
+/****************************************************************************
+ * Name: arm64_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 arm64_pause_handler(int irq, void *context, void *arg);
+
+void arm64_gic_secondary_init(void);
+
+int arm64_smp_sgi_init(void);
+
+#endif
+
+#endif /* __ARCH_ARM64_SRC_COMMON_ARM64_GIC_H */
diff --git a/arch/arm64/src/common/arm64_gicv3.c b/arch/arm64/src/common/arm64_gicv3.c
new file mode 100644
index 0000000000..8416476359
--- /dev/null
+++ b/arch/arm64/src/common/arm64_gicv3.c
@@ -0,0 +1,613 @@
+/***************************************************************************
+ * arch/arm64/src/common/arm64_gicv3.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 <debug.h>
+#include <assert.h>
+
+#include <nuttx/arch.h>
+#include <arch/irq.h>
+#include <arch/chip/chip.h>
+#include <sched/sched.h>
+
+#include "arm64_arch.h"
+#include "arm64_internal.h"
+#include "arm64_gic.h"
+#include "arm64_fatal.h"
+
+/***************************************************************************
+ * Pre-processor Definitions
+ ***************************************************************************/
+
+#define GICR_TYPER_NR_PPIS(r) \
+ ({ \
+ unsigned int __ppinum = ((r) >> 27) & 0x1f; \
+ unsigned int __nr_ppis = 16; \
+ if (__ppinum == 1 || __ppinum == 2) \
+ { __nr_ppis += __ppinum * 32; } \
+ __nr_ppis; \
+ })
+
+/* selects redistributor SGI_base for current core for PPI and SGI
+ * selects distributor base for SPI
+ * The macro translates to distributor base for GICv2 and GICv1
+ */
+#define GET_DIST_BASE(intid) ((intid < GIC_SPI_INT_BASE) ? \
+ (gic_get_rdist() + GICR_SGI_BASE_OFF) \
+ : GIC_DIST_BASE)
+
+#define IGROUPR_VAL 0xFFFFFFFFU
+
+/* Redistributor base addresses for each core */
+
+unsigned long gic_rdists[CONFIG_SMP_NCPUS];
+
+/***************************************************************************
+ * Private Functions
+ ***************************************************************************/
+
+static inline unsigned long gic_get_rdist(void)
+{
+ return gic_rdists[this_cpu()];
+}
+
+static inline uint32_t read_gicd_wait_rwp(void)
+{
+ uint32_t value;
+
+ value = getreg32(GICD_CTLR);
+
+ while (value & BIT(GICD_CTLR_RWP))
+ {
+ value = getreg32(GICD_CTLR);
+ }
+
+ return value;
+}
+
+/* Wait for register write pending
+ * TODO: add timed wait
+ */
+
+static int gic_wait_rwp(uint32_t intid)
+{
+ uint32_t rwp_mask;
+ unsigned long base;
+
+ if (intid < GIC_SPI_INT_BASE)
+ {
+ base = (gic_get_rdist() + GICR_CTLR);
+ rwp_mask = BIT(GICR_CTLR_RWP);
+ }
+ else
+ {
+ base = GICD_CTLR;
+ rwp_mask = BIT(GICD_CTLR_RWP);
+ }
+
+ while (getreg32(base) & rwp_mask)
+ {
+ }
+
+ return 0;
+}
+
+void arm64_gic_irq_set_priority(unsigned int intid, unsigned int prio,
+ uint32_t flags)
+{
+ uint32_t mask = BIT(intid & (GIC_NUM_INTR_PER_REG - 1));
+ uint32_t idx = intid / GIC_NUM_INTR_PER_REG;
+ uint32_t shift;
+ uint32_t val;
+ unsigned long base = GET_DIST_BASE(intid);
+
+ /* Disable the interrupt */
+
+ putreg32(mask, ICENABLER(base, idx));
+ gic_wait_rwp(intid);
+
+ /* PRIORITYR registers provide byte access */
+
+ putreg8(prio & GIC_PRI_MASK, IPRIORITYR(base, intid));
+
+ /* Interrupt type config */
+
+ if (!GIC_IS_SGI(intid))
+ {
+ idx = intid / GIC_NUM_CFG_PER_REG;
+ shift = (intid & (GIC_NUM_CFG_PER_REG - 1)) * 2;
+
+ val = getreg32(ICFGR(base, idx));
+ val &= ~(GICD_ICFGR_MASK << shift);
+ if (flags & IRQ_TYPE_EDGE)
+ {
+ val |= (GICD_ICFGR_TYPE << shift);
+ }
+
+ putreg32(val, ICFGR(base, idx));
+ }
+}
+
+void arm64_gic_irq_enable(unsigned int intid)
+{
+ uint32_t mask = BIT(intid & (GIC_NUM_INTR_PER_REG - 1));
+ uint32_t idx = intid / GIC_NUM_INTR_PER_REG;
+
+ putreg32(mask, ISENABLER(GET_DIST_BASE(intid), idx));
+
+ /* Affinity routing is enabled for Non-secure state (GICD_CTLR.ARE_NS
+ * is set to '1' when GIC distributor is initialized) ,so need to set
+ * SPI's affinity, now set it to be the PE on which it is enabled.
+ */
+
+ if (GIC_IS_SPI(intid))
+ {
+ putreg64(MPIDR_TO_CORE(GET_MPIDR()),
+ IROUTER(GET_DIST_BASE(intid), intid));
+ }
+}
+
+void arm64_gic_irq_disable(unsigned int intid)
+{
+ uint32_t mask = BIT(intid & (GIC_NUM_INTR_PER_REG - 1));
+ uint32_t idx = intid / GIC_NUM_INTR_PER_REG;
+
+ putreg32(mask, ICENABLER(GET_DIST_BASE(intid), idx));
+
+ /* poll to ensure write is complete */
+
+ gic_wait_rwp(intid);
+}
+
+bool arm64_gic_irq_is_enabled(unsigned int intid)
+{
+ uint32_t mask = BIT(intid & (GIC_NUM_INTR_PER_REG - 1));
+ uint32_t idx = intid / GIC_NUM_INTR_PER_REG;
+ uint32_t val;
+
+ val = getreg32(ISENABLER(GET_DIST_BASE(intid), idx));
+
+ return (val & mask) != 0;
+}
+
+unsigned int arm64_gic_get_active(void)
+{
+ int intid;
+
+ /* (Pending -> Active / AP) or (AP -> AP) */
+
+ intid = read_sysreg(ICC_IAR1_EL1);
+
+ return intid;
+}
+
+void arm64_gic_eoi(unsigned int intid)
+{
+ /* Interrupt request deassertion from peripheral to GIC happens
+ * by clearing interrupt condition by a write to the peripheral
+ * register. It is desired that the write transfer is complete
+ * before the core tries to change GIC state from 'AP/Active' to
+ * a new state on seeing 'EOI write'.
+ * Since ICC interface writes are not ordered against Device
+ * memory writes, a barrier is required to ensure the ordering.
+ * The dsb will also ensure *completion* of previous writes with
+ * DEVICE nGnRnE attribute.
+ */
+
+ ARM64_DSB();
+
+ /* (AP -> Pending) Or (Active -> Inactive) or (AP to AP) nested case */
+
+ write_sysreg(intid, ICC_EOIR1_EL1);
+}
+
+int arm64_gic_raise_sgi(unsigned int sgi_id, uint64_t target_aff,
+ uint16_t target_list)
+{
+ uint32_t aff3;
+ uint32_t aff2;
+ uint32_t aff1;
+ uint64_t sgi_val;
+
+ assert(GIC_IS_SGI(sgi_id));
+
+ /* Extract affinity fields from target */
+
+ aff1 = MPIDR_AFFLVL(target_aff, 1);
+ aff2 = MPIDR_AFFLVL(target_aff, 2);
+ aff3 = MPIDR_AFFLVL(target_aff, 3);
+
+ sgi_val = GICV3_SGIR_VALUE(aff3, aff2, aff1, sgi_id, SGIR_IRM_TO_AFF,
+ target_list);
+
+ ARM64_DSB();
+ write_sysreg(sgi_val, ICC_SGI1R);
+ ARM64_ISB();
+
+ return 0;
+}
+
+/* Wake up GIC redistributor.
+ * clear ProcessorSleep and wait till ChildAsleep is cleared.
+ * ProcessSleep to be cleared only when ChildAsleep is set
+ * Check if redistributor is not powered already.
+ */
+
+static void gicv3_rdist_enable(unsigned long rdist)
+{
+ uint32_t temp;
+
+ if (!(getreg32(rdist + GICR_WAKER) & BIT(GICR_WAKER_CA)))
+ {
+ return;
+ }
+
+ temp = getreg32(rdist + GICR_WAKER);
+ temp = temp & ~(BIT(GICR_WAKER_PS));
+ putreg32(temp, rdist + GICR_WAKER);
+
+ while (getreg32(rdist + GICR_WAKER) & BIT(GICR_WAKER_CA))
+ {
+ }
+}
+
+/* Initialize the cpu interface. This should be called by each core. */
+
+static void gicv3_cpuif_init(void)
+{
+ uint32_t icc_sre;
+ uint32_t intid;
+
+ unsigned long base = gic_get_rdist() + GICR_SGI_BASE_OFF;
+
+ /* Disable all sgi ppi */
+
+ putreg32(BIT64_MASK(GIC_NUM_INTR_PER_REG), ICENABLER(base, 0));
+
+ /* Any sgi/ppi intid ie. 0-31 will select GICR_CTRL */
+
+ gic_wait_rwp(0);
+
+ /* Clear pending */
+
+ putreg32(BIT64_MASK(GIC_NUM_INTR_PER_REG), ICPENDR(base, 0));
+
+ /* Configure all SGIs/PPIs as G1S or G1NS depending on Zephyr
+ * is run in EL1S or EL1NS respectively.
+ * All interrupts will be delivered as irq
+ */
+
+ putreg32(IGROUPR_VAL, IGROUPR(base, 0));
+ putreg32(BIT64_MASK(GIC_NUM_INTR_PER_REG), IGROUPMODR(base, 0));
+
+ /* Configure default priorities for SGI 0:15 and PPI 0:15. */
+
+ for (intid = 0; intid < GIC_SPI_INT_BASE;
+ intid += GIC_NUM_PRI_PER_REG)
+ {
+ putreg32(GIC_INT_DEF_PRI_X4, IPRIORITYR(base, intid));
+ }
+
+ /* Configure PPIs as level triggered */
+
+ putreg32(0, ICFGR(base, 1));
+
+ /* Check if system interface can be enabled.
+ * 'icc_sre_el3' needs to be configured at 'EL3'
+ * to allow access to 'icc_sre_el1' at 'EL1'
+ * eg: z_arch_el3_plat_init can be used by platform.
+ */
+
+ icc_sre = read_sysreg(ICC_SRE_EL1);
+
+ if (!(icc_sre & ICC_SRE_ELX_SRE_BIT))
+ {
+ icc_sre =
+ (icc_sre | ICC_SRE_ELX_SRE_BIT | ICC_SRE_ELX_DIB_BIT |
+ ICC_SRE_ELX_DFB_BIT);
+ write_sysreg(icc_sre, ICC_SRE_EL1);
+ icc_sre = read_sysreg(ICC_SRE_EL1);
+
+ assert(icc_sre & ICC_SRE_ELX_SRE_BIT);
+ }
+
+ write_sysreg(GIC_IDLE_PRIO, ICC_PMR_EL1);
+
+ /* Allow group1 interrupts */
+
+ write_sysreg(1, ICC_IGRPEN1_EL1);
+}
+
+static void gicv3_dist_init(void)
+{
+ unsigned int num_ints;
+ unsigned int intid;
+ unsigned int idx;
+ unsigned long base = GIC_DIST_BASE;
+
+ num_ints = getreg32(GICD_TYPER);
+ num_ints &= GICD_TYPER_ITLINESNUM_MASK;
+ num_ints = (num_ints + 1) << 5;
+
+ /* Disable the distributor */
+
+ putreg32(0, GICD_CTLR);
+ gic_wait_rwp(GIC_SPI_INT_BASE);
+
+#if 0
+
+ /* Before configuration, we need to check whether
+ * the GIC single security state mode is supported.
+ * Make sure GICD_CTRL_NS is 1.
+ */
+
+ sys_set_bit(GICD_CTLR, GICD_CTRL_NS);
+ __ASSERT(sys_test_bit(GICD_CTLR,
+ GICD_CTRL_NS),
+ "Current GIC does not support single security state");
+#endif
+
+ /* Default configuration of all SPIs */
+
+ for (intid = GIC_SPI_INT_BASE; intid < num_ints;
+ intid += GIC_NUM_INTR_PER_REG)
+ {
+ idx = intid / GIC_NUM_INTR_PER_REG;
+
+ /* Disable interrupt */
+
+ putreg32(BIT64_MASK(GIC_NUM_INTR_PER_REG),
+ ICENABLER(base, idx));
+
+ /* Clear pending */
+
+ putreg32(BIT64_MASK(GIC_NUM_INTR_PER_REG),
+ ICPENDR(base, idx));
+ putreg32(IGROUPR_VAL, IGROUPR(base, idx));
+ putreg32(BIT64_MASK(GIC_NUM_INTR_PER_REG),
+ IGROUPMODR(base, idx));
+ }
+
+ /* wait for rwp on GICD */
+
+ gic_wait_rwp(GIC_SPI_INT_BASE);
+
+ /* Configure default priorities for all SPIs. */
+
+ for (intid = GIC_SPI_INT_BASE; intid < num_ints;
+ intid += GIC_NUM_PRI_PER_REG)
+ {
+ putreg32(GIC_INT_DEF_PRI_X4, IPRIORITYR(base, intid));
+ }
+
+ /* Configure all SPIs as active low, level triggered by default */
+
+ for (intid = GIC_SPI_INT_BASE; intid < num_ints;
+ intid += GIC_NUM_CFG_PER_REG)
+ {
+ idx = intid / GIC_NUM_CFG_PER_REG;
+ putreg32(0, ICFGR(base, idx));
+ }
+
+ /* Enable distributor with ARE */
+
+ putreg32(BIT(GICD_CTRL_ARE_NS) | BIT(GICD_CTLR_ENABLE_G1NS),
+ GICD_CTLR);
+#if 0
+
+ /* TODO: ARMv8-R support
+ *
+ * For GIC single security state(ARMv8-R), the config means
+ * the GIC is under single security state which has
+ * only two groups:
+ * group 0 and group 1.
+ * Then set GICD_CTLR_ARE and GICD_CTLR_ENABLE_G1 to enable Group 1
+ * interrupt.
+ * Since the GICD_CTLR_ARE and GICD_CTRL_ARE_S share BIT(4), and
+ * similarly the GICD_CTLR_ENABLE_G1 and GICD_CTLR_ENABLE_G1NS share
+ * BIT(1), we can reuse them.
+ */
+
+ putreg32(BIT(GICD_CTRL_ARE_S) | BIT(GICD_CTLR_ENABLE_G1NS),
+ GICD_CTLR);
+#endif
+}
+
+void up_enable_irq(int irq)
+{
+ arm64_gic_irq_enable(irq);
+}
+
+void up_disable_irq(int irq)
+{
+ arm64_gic_irq_disable(irq);
+}
+
+/***************************************************************************
+ * Name: arm64_decodeirq
+ *
+ * Description:
+ * This function is called from the IRQ vector handler in arm64_vectors.S.
+ * At this point, the interrupt has been taken and the registers have
+ * been saved on the stack. This function simply needs to determine the
+ * the irq number of the interrupt and then to call arm_doirq to dispatch
+ * the interrupt.
+ *
+ * Input Parameters:
+ * regs - A pointer to the register save area on the stack.
+ ***************************************************************************/
+
+uint64_t * arm64_decodeirq(uint64_t * regs)
+{
+ int irq;
+
+ /* Read the interrupt acknowledge register and get the interrupt ID */
+
+ irq = arm64_gic_get_active();
+
+ /* Ignore spurions IRQs. ICCIAR will report 1023 if there is no pending
+ * interrupt.
+ */
+
+ DEBUGASSERT(irq < NR_IRQS || irq == 1023);
+ if (irq < NR_IRQS)
+ {
+ /* Dispatch the interrupt */
+
+ regs = arm64_doirq(irq, regs);
+ }
+
+ /* Write to the end-of-interrupt register */
+
+ arm64_gic_eoi(irq);
+
+ return regs;
+}
+
+static int gic_validate_dist_version(void)
+{
+ uint32_t typer;
+ bool has_rss;
+ uint32_t reg = getreg32(GICD_PIDR2) & GICD_PIDR2_ARCH_MASK;
+ int spis;
+ int espis;
+
+ if (reg == GICD_PIDR2_ARCH_GICV3)
+ {
+ sinfo("GICv3 version detect\n");
+ }
+ else if (reg == GICD_PIDR2_ARCH_GICV4)
+ {
+ sinfo("GICv4 version detect\n");
+ }
+ else
+ {
+ sinfo("No GIC version detect\n");
+ return -ENODEV;
+ }
+
+ /* Find out how many interrupts are supported. */
+
+ typer = getreg32(GICD_TYPER);
+ spis = MIN(GICD_TYPER_SPIS(typer), 1020U) - 32;
+ espis = GICD_TYPER_ESPIS(typer);
+
+ sinfo("GICD_TYPER = 0x%x\n", typer);
+ sinfo("%d SPIs implemented\n", spis);
+ sinfo("%d Extended SPIs implemented\n", espis);
+
+ has_rss = !!(typer & GICD_TYPER_RSS);
+ sinfo("Distributor has %sRange Selector support\n", has_rss ? "" : "no ");
+
+ if (typer & GICD_TYPER_MBIS)
+ {
+ sinfo("MBIs is present, But No support\n");
+ }
+
+ return 0;
+}
+
+static int gic_validate_redist_version(void)
+{
+ uint64_t typer;
+ unsigned int ppi_nr;
+ bool has_vlpis = true;
+ bool has_direct_lpi = true;
+ uint32_t reg;
+ unsigned long redist_base = gic_get_rdist();
+
+ ppi_nr = (~0U);
+ reg = getreg32(redist_base +
+ GICR_PIDR2) & GICR_PIDR2_ARCH_MASK;
+ if (reg != GICR_PIDR2_ARCH_GICV3 &&
+ reg != GICR_PIDR2_ARCH_GICV4)
+ {
+ sinfo("No redistributor present 0x%lx\n", redist_base);
+ return -ENODEV;
+ }
+
+ typer = getreg64(redist_base + GICR_TYPER);
+ has_vlpis &= !!(typer & GICR_TYPER_VLPIS);
+ has_direct_lpi &= !!(typer & GICR_TYPER_DIRECTLPIS);
+ ppi_nr = MIN(GICR_TYPER_NR_PPIS(typer), ppi_nr);
+
+ if (ppi_nr == (~0U))
+ {
+ ppi_nr = 0;
+ }
+
+ sinfo("GICD_TYPER = 0x%"PRIx64"\n", typer);
+ sinfo("%d PPIs implemented\n", ppi_nr);
+ sinfo("%sVLPI support, %sdirect LPI support\n", !has_vlpis ? "no " : "",
+ !has_direct_lpi ? "no " : "");
+
+ return 0;
+}
+
+static void arm64_gic_init(void)
+{
+ uint8_t cpu;
+ int err;
+
+ cpu = this_cpu();
+ gic_rdists[cpu] = CONFIG_GICR_BASE +
+ MPIDR_TO_CORE(GET_MPIDR()) * 0x20000;
+
+ err = gic_validate_redist_version();
+ if (err)
+ {
+ sinfo("no redistributor detected, giving up ret=%d\n", err);
+ return;
+ }
+
+ gicv3_rdist_enable(gic_get_rdist());
+
+ gicv3_cpuif_init();
+}
+
+int arm64_gic_initialize(void)
+{
+ int err;
+
+ err = gic_validate_dist_version();
+ if (err)
+ {
+ sinfo("no distributor detected, giving up ret=%d\n", err);
+ return err;
+ }
+
+ gicv3_dist_init();
+
+ arm64_gic_init();
+
+ return 0;
+}
+
+#ifdef CONFIG_SMP
+void arm64_gic_secondary_init(void)
+{
+ arm64_gic_init();
+}
+
+#endif
diff --git a/arch/arm64/src/common/arm64_head.S b/arch/arm64/src/common/arm64_head.S
new file mode 100644
index 0000000000..ec6cc41f40
--- /dev/null
+++ b/arch/arm64/src/common/arm64_head.S
@@ -0,0 +1,306 @@
+/****************************************************************************
+ * arch/arm64/src/common/arm64_head.S
+ *
+ * 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.
+ *
+ * DESCRIPTION
+ * Bring-up code for ARMv8.
+ * Based on head.S(arm64 porting) at Xen Hypervisor Project
+ * Based on reset.S(aarch64 porting) at Zephyr RTOS Project
+ *
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include "arm64_arch.h"
+#include "arm64_macro.inc"
+
+/****************************************************************************
+ * Public Symbols
+ ****************************************************************************/
+
+ .file "arm64_head.S"
+
+/****************************************************************************
+ * Assembly Macros
+ ****************************************************************************/
+
+/* macro define from xen head, for efi head define */
+#define PAGE_SHIFT 12
+#define __HEAD_FLAG_PAGE_SIZE ((PAGE_SHIFT - 10) / 2)
+
+#define __HEAD_FLAG_PHYS_BASE 1
+
+
+#define __HEAD_FLAGS ((__HEAD_FLAG_PAGE_SIZE << 1) | \
+ (__HEAD_FLAG_PHYS_BASE << 3))
+
+#ifdef CONFIG_DEBUG_FEATURES
+
+#define RODATA_STR(label, msg) \
+.pushsection .rodata.str, "aMS", %progbits, 1 ; \
+label: .asciz msg; \
+.popsection
+
+/* Macro to print a string to the UART, if there is one.
+ * Clobbers x0 - x3, x30 is lr for return
+ */
+#define PRINT(sym, _s) \
+ mov x3, x30 ; \
+ ldr x1, =boot_string_##sym ; \
+ bl boot_stage_puts; \
+ mov x30, x3 ; \
+ RODATA_STR(boot_string_##sym, _s)
+#else
+#define PRINT(sym, s)
+#endif /* CONFIG_DEBUG_FEATURES */
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+ /* Kernel startup entry point.
+ * ---------------------------
+ *
+ * The requirements are:
+ * MMU = off, D-cache = off, I-cache = on or off,
+ * x0 = physical address to the FDT blob.
+ * it will be used when NuttX support device tree in the future
+ *
+ * This must be the very first address in the loaded image.
+ * It should be loaded at any 4K-aligned address.
+ */
+ .globl __start;
+__start:
+
+ /* DO NOT MODIFY. Image header expected by Linux boot-loaders.
+ *
+ * This add instruction has no meaningful effect except that
+ * its opcode forms the magic "MZ" signature of a PE/COFF file
+ * that is required for UEFI applications.
+ *
+ * Some bootloader (such imx8 uboot) checking the magic "MZ" to see
+ * if the image is a valid Linux image. but modifying the bootLoader is
+ * unnecessary unless we need to do a customize secure boot.
+ * so just put the ''MZ" in the header to make bootloader happiness
+ */
+
+ add x13, x18, #0x16 /* the magic "MZ" signature */
+ b real_start /* branch to kernel start */
+ .quad 0x480000 /* Image load offset from start of RAM */
+ .quad _e_initstack - __start /* Effective size of kernel image, little-endian */
+ .quad __HEAD_FLAGS /* Informative flags, little-endian */
+ .quad 0 /* reserved */
+ .quad 0 /* reserved */
+ .quad 0 /* reserved */
+ .ascii "ARM\x64" /* Magic number, "ARM\x64" */
+ .long 0 /* reserved */
+
+real_start:
+ /* Disable all exceptions and interrupts */
+
+ msr DAIFSet, 0xf
+#ifdef CONFIG_SMP
+
+ ldr x0, =cpu_boot_params
+ get_cpu_id x1
+
+ /* If the cores start up at the same time, we should atomically load and
+ * store the mpid into arm64_cpu_boot_params.
+ */
+
+ ldaxr x2, [x0, #BOOT_PARAM_MPID]
+ cmp x2, #-1
+ bne 1f
+
+ /* try to store x1 (mpid) */
+
+ stlxr w3, x1, [x0]
+
+ /* If succeed, go to primary_core */
+
+ cbz w3, primary_core
+
+ /* loop until our turn comes */
+
+1: dmb ld
+ ldr x2, [x0, #BOOT_PARAM_MPID]
+ cmp x1, x2
+ bne 1b
+
+ /* we can now load our stack pointer value and move on */
+ ldr x24, [x0, #BOOT_PARAM_SP]
+ add x24, x24, #(CONFIG_IDLETHREAD_STACKSIZE)
+ ldr x25, =arm64_boot_secondary_c_routine
+ bl __reset_prep_c
+ b cpu_boot
+
+primary_core:
+ ldr x24, [x0, #BOOT_PARAM_SP]
+ add x24, x24, #(CONFIG_IDLETHREAD_STACKSIZE)
+#else
+ /* load stack and entry point */
+ ldr x24, =(g_idle_stack + CONFIG_IDLETHREAD_STACKSIZE)
+#endif
+
+ ldr x25, =arm64_boot_primary_c_routine
+
+ /* Prepare for calling C code */
+
+ bl __reset_prep_c
+
+#ifdef CONFIG_DEBUG_FEATURES
+ /* Initialize the UART for early print.
+ * Should only be called on the boot CPU
+ */
+
+ bl up_earlyserialinit
+#endif
+
+cpu_boot:
+ PRINT(cpu_boot, "- Ready to Boot CPU\r\n")
+
+switch_el:
+ switch_el x0, 3f, 2f, 1f
+3:
+ PRINT(switch_el3, "- Boot from EL3\r\n")
+
+ /* EL3 init */
+
+ bl arm64_boot_el3_init
+
+ /* Get next EL */
+
+ adr x0, switch_el
+ bl arm64_boot_el3_get_next_el
+ eret
+
+2:
+ PRINT(switch_el2, "- Boot from EL2\r\n")
+
+ /* EL2 init */
+
+ bl arm64_boot_el2_init
+
+ /* Move to EL1 with all exceptions masked */
+
+ mov_imm x0, (SPSR_DAIF_MASK | SPSR_MODE_EL1T)
+ msr spsr_el2, x0
+
+ adr x0, 1f
+ msr elr_el2, x0
+ eret
+
+1:
+ PRINT(switch_el1, "- Boot from EL1\r\n")
+
+ /* EL1 init */
+
+ bl arm64_boot_el1_init
+
+ /* set SP_ELx and Enable SError interrupts */
+
+ msr SPSel, #1
+ msr DAIFClr, #(DAIFCLR_ABT_BIT)
+ isb
+
+jump_to_c_entry:
+ PRINT(jump_to_c_entry, "- Boot to C runtime for OS Initialize\r\n")
+ ret x25
+
+/* Fail-stop */
+
+fail:
+ PRINT(fail, "- Boot failed -\r\n")
+1: wfe
+ b 1b
+
+/* Set the minimum necessary to safely call C code */
+
+__reset_prep_c:
+
+ /* return address: x23 */
+
+ mov x23, lr
+
+ switch_el x0, 3f, 2f, 1f
+3:
+ /* Reinitialize SCTLR from scratch in EL3 */
+
+ ldr w0, =(SCTLR_EL3_RES1 | SCTLR_I_BIT | SCTLR_SA_BIT)
+ msr sctlr_el3, x0
+
+ /* Set SP_EL1 */
+
+ msr sp_el1, x24
+ b out
+2:
+ /* Disable alignment fault checking */
+
+ mrs x0, sctlr_el2
+ bic x0, x0, SCTLR_A_BIT
+ msr sctlr_el2, x0
+
+ /* Set SP_EL1 */
+
+ msr sp_el1, x24
+ b out
+1:
+ /* Disable alignment fault checking */
+
+ mrs x0, sctlr_el1
+ bic x0, x0, SCTLR_A_BIT
+ msr sctlr_el1, x0
+
+ /* Set SP_EL1. We cannot use sp_el1 at EL1 */
+
+ msr SPSel, #1
+ mov sp, x24
+out:
+ isb
+
+ /* Select SP_EL0 and Initialize stack */
+
+ msr SPSel, #0
+ mov sp, x24
+
+ ret x23
+
+#ifdef CONFIG_DEBUG_FEATURES
+
+/* Print early debug messages.
+ * x0: Nul-terminated string to print.
+ * Clobbers x0-x1
+ */
+
+boot_stage_puts:
+ ldrb w0, [x1], #1 /* Load next char */
+ cmp w0, 0
+ beq 1f /* Exit on nul */
+ stp xzr, x30, [sp, #-16]!
+ bl up_lowputc
+ ldp xzr, x30, [sp], #16
+ b boot_stage_puts
+1:
+ ret
+
+.type boot_low_puts, %function;
+
+#endif /* !CONFIG_DEBUG_FEATURES */
diff --git a/arch/arm64/src/common/arm64_idle.c b/arch/arm64/src/common/arm64_idle.c
new file mode 100644
index 0000000000..88db506f78
--- /dev/null
+++ b/arch/arm64/src/common/arm64_idle.c
@@ -0,0 +1,62 @@
+/****************************************************************************
+ * arch/arm64/src/common/arm64_idle.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 <nuttx/arch.h>
+#include "arm64_internal.h"
+#include "arm64_arch.h"
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: up_idle
+ *
+ * Description:
+ * up_idle() is the logic that will be executed when there is no other
+ * ready-to-run task. This is processor idle time and will continue until
+ * some interrupt occurs to cause a context switch from the idle task.
+ *
+ * Processing in this state may be processor-specific. e.g., this is where
+ * power management operations might be performed.
+ *
+ ****************************************************************************/
+
+void up_idle(void)
+{
+#if defined(CONFIG_SUPPRESS_INTERRUPTS) || defined(CONFIG_SUPPRESS_TIMER_INTS)
+ /* If the system is idle and there are no timer interrupts, then process
+ * "fake" timer interrupts. Hopefully, something will wake up.
+ */
+
+ nxsched_process_timer();
+#else
+
+ /* Sleep until an interrupt occurs to save power */
+
+ arch_cpu_idle();
+#endif
+}
diff --git a/arch/arm64/src/common/arm64_initialize.c b/arch/arm64/src/common/arm64_initialize.c
new file mode 100644
index 0000000000..d16bbe3158
--- /dev/null
+++ b/arch/arm64/src/common/arm64_initialize.c
@@ -0,0 +1,178 @@
+/****************************************************************************
+ * arch/arm64/src/common/arm64_initialize.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 <debug.h>
+#include <arch/limits.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/board.h>
+#include <nuttx/drivers/drivers.h>
+#include <nuttx/fs/loop.h>
+#include <nuttx/net/loopback.h>
+#include <nuttx/net/tun.h>
+#include <nuttx/net/telnet.h>
+#include <nuttx/power/pm.h>
+#include <arch/chip/chip.h>
+
+#include "arm64_arch.h"
+#include "arm64_internal.h"
+#include "chip.h"
+
+/****************************************************************************
+ * Public data
+ ****************************************************************************/
+
+#ifdef CONFIG_SMP
+INIT_STACK_ARRAY_DEFINE(g_cpu_idlestackalloc, CONFIG_SMP_NCPUS,
+ SMP_STACK_SIZE);
+INIT_STACK_ARRAY_DEFINE(g_interrupt_stacks, CONFIG_SMP_NCPUS,
+ INTSTACK_SIZE);
+#else
+/* idle thread stack for primary core */
+
+INIT_STACK_DEFINE(g_idle_stack, CONFIG_IDLETHREAD_STACKSIZE);
+INIT_STACK_DEFINE(g_interrupt_stack, INTSTACK_SIZE);
+#endif
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: arm64_intstack_alloc
+ *
+ * Description:
+ * Return a pointer to the "alloc" the correct interrupt stack allocation
+ * for the current CPU.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_SMP
+uintptr_t arm64_intstack_alloc(void)
+{
+ return (uintptr_t)(g_interrupt_stacks[up_cpu_index()]);
+}
+
+/****************************************************************************
+ * Name: arm64_intstack_top
+ *
+ * Description:
+ * Return a pointer to the top the correct interrupt stack allocation
+ * for the current CPU.
+ *
+ ****************************************************************************/
+
+uintptr_t arm64_intstack_top(void)
+{
+ return (uintptr_t)(g_interrupt_stacks[up_cpu_index()] + INTSTACK_SIZE);
+}
+
+#endif
+
+/****************************************************************************
+ * Name: up_color_intstack
+ *
+ * Description:
+ * Set the interrupt stack to a value so that later we can determine how
+ * much stack space was used by interrupt handling logic
+ *
+ ****************************************************************************/
+
+#if defined(CONFIG_STACK_COLORATION) && CONFIG_ARCH_INTERRUPTSTACK > 3
+static void up_color_intstack(void)
+{
+#ifdef CONFIG_SMP
+ void *ptr = (void *)g_interrupt_stacks[up_cpu_index()];
+#else
+ void *ptr = (void *)g_interrupt_stack;
+#endif
+ arm64_stack_color(ptr, INTSTACK_SIZE);
+}
+#else
+# define up_color_intstack()
+#endif
+
+/****************************************************************************
+ * Name: up_initialize
+ *
+ * Description:
+ * up_initialize will be called once during OS initialization after the
+ * basic OS services have been initialized. The architecture specific
+ * details of initializing the OS will be handled here. Such things as
+ * setting up interrupt service routines, starting the clock, and
+ * registering device drivers are some of the things that are different
+ * for each processor and hardware platform.
+ *
+ * up_initialize is called after the OS initialized but before the user
+ * initialization logic has been started and before the libraries have
+ * been initialized. OS services and driver services are available.
+ *
+ ****************************************************************************/
+
+void up_initialize(void)
+{
+ /* Initialize global variables */
+
+ up_color_intstack();
+
+ /* Add any extra memory fragments to the memory manager */
+
+ arm64_addregion();
+
+#ifdef CONFIG_PM
+ /* Initialize the power management subsystem. This MCU-specific function
+ * must be called *very* early in the initialization sequence *before* any
+ * other device drivers are initialized (since they may attempt to register
+ * with the power management subsystem).
+ */
+
+ arm64_pminitialize();
+#endif
+
+#ifdef CONFIG_ARCH_DMA
+
+ arm64_dma_initialize();
+
+#endif
+
+ /* Initialize the serial device driver */
+
+#ifdef USE_SERIALDRIVER
+ arm64_serialinit();
+#endif
+
+#ifndef CONFIG_NETDEV_LATEINIT
+ /* Initialize the network */
+
+ arm64_netinitialize();
+#endif
+
+#if defined(CONFIG_USBDEV) || defined(CONFIG_USBHOST)
+ /* Initialize USB -- device and/or host */
+
+ arm64_usbinitialize();
+#endif
+}
diff --git a/arch/arm64/src/common/arm64_initialstate.c b/arch/arm64/src/common/arm64_initialstate.c
new file mode 100644
index 0000000000..7212ff3b85
--- /dev/null
+++ b/arch/arm64/src/common/arm64_initialstate.c
@@ -0,0 +1,151 @@
+/****************************************************************************
+ * arch/arm64/src/common/arm64_initialstate.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 <debug.h>
+#include <arch/limits.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/board.h>
+#include <nuttx/drivers/drivers.h>
+#include <nuttx/fs/loop.h>
+#include <nuttx/net/loopback.h>
+#include <nuttx/net/tun.h>
+#include <nuttx/net/telnet.h>
+#include <nuttx/note/note_driver.h>
+#include <nuttx/syslog/syslog_console.h>
+#include <nuttx/serial/pty.h>
+#include <nuttx/crypto/crypto.h>
+#include <nuttx/power/pm.h>
+#include <arch/chip/chip.h>
+
+#include "arm64_arch.h"
+#include "arm64_internal.h"
+#include "chip.h"
+#include "arm64_fatal.h"
+
+#ifdef CONFIG_ARCH_FPU
+#include "arm64_fpu.h"
+#endif
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+void arm64_new_task(struct tcb_s * tcb)
+{
+ char *stack_ptr = tcb->stack_base_ptr + tcb->adj_stack_size;
+ struct regs_context * pinitctx;
+
+#ifdef CONFIG_ARCH_FPU
+ struct fpu_reg * pfpuctx;
+ pfpuctx = STACK_PTR_TO_FRAME(struct fpu_reg, stack_ptr);
+ tcb->xcp.fpu_regs = (uint64_t *)pfpuctx;
+
+ /* set fpu context */
+
+ arm64_init_fpu(tcb);
+ stack_ptr = (char *)pfpuctx;
+#endif
+
+ pinitctx = STACK_PTR_TO_FRAME(struct regs_context, stack_ptr);
+ memset(pinitctx, 0, sizeof(struct regs_context));
+ pinitctx->elr = (uint64_t)tcb->start;
+
+ /* Keep using SP_EL1 */
+
+ pinitctx->spsr = SPSR_MODE_EL1H;
+
+#ifdef CONFIG_SUPPRESS_INTERRUPTS
+ pinitctx->spsr |= (DAIF_IRQ_BIT | DAIF_FIQ_BIT);
+#endif /* CONFIG_SUPPRESS_INTERRUPTS */
+
+ pinitctx->sp_elx = (uint64_t)pinitctx;
+ pinitctx->sp_el0 = (uint64_t)pinitctx;
+ pinitctx->exe_depth = 0;
+ pinitctx->tpidr_el0 = (uint64_t)tcb;
+ pinitctx->tpidr_el1 = (uint64_t)tcb;
+
+ tcb->xcp.regs = (uint64_t *)pinitctx;
+}
+
+/****************************************************************************
+ * Name: up_initial_state
+ *
+ * Description:
+ * A new thread is being started and a new TCB has been created. This
+ * function is called to initialize the processor specific portions of
+ * the new TCB.
+ *
+ * This function must setup the initial architecture registers and/or
+ * stack so that execution will begin at tcb->start on the next context
+ * switch.
+ *
+ ****************************************************************************/
+
+void up_initial_state(struct tcb_s *tcb)
+{
+ struct xcptcontext *xcp = &tcb->xcp;
+
+ memset(xcp, 0, sizeof(struct xcptcontext));
+
+ if (tcb->pid == IDLE_PROCESS_ID)
+ {
+ /* Initialize the idle thread stack */
+#ifdef CONFIG_SMP
+ tcb->stack_alloc_ptr = (void *)(g_cpu_idlestackalloc[0]);
+#else
+ tcb->stack_alloc_ptr = (void *)(g_idle_stack);
+#endif
+ tcb->stack_base_ptr = tcb->stack_alloc_ptr;
+ tcb->adj_stack_size = CONFIG_IDLETHREAD_STACKSIZE;
+
+#ifdef CONFIG_ARCH_FPU
+ /* set fpu context */
+
+ arm64_init_fpu(tcb);
+#endif
+ /* set initialize idle thread tcb and exception depth
+ * core 0, idle0
+ */
+
+ write_sysreg(0, tpidrro_el0);
+ write_sysreg(tcb, tpidr_el1);
+ write_sysreg(tcb, tpidr_el0);
+
+#ifdef CONFIG_STACK_COLORATION
+
+ /* If stack debug is enabled, then fill the stack with a
+ * recognizable value that we can use later to test for high
+ * water marks.
+ */
+
+ arm64_stack_color(tcb->stack_alloc_ptr, 0);
+#endif /* CONFIG_STACK_COLORATION */
+ return;
+ }
+
+ arm64_new_task(tcb);
+}
diff --git a/arch/arm64/src/common/arm64_internal.h b/arch/arm64/src/common/arm64_internal.h
new file mode 100644
index 0000000000..d92523b821
--- /dev/null
+++ b/arch/arm64/src/common/arm64_internal.h
@@ -0,0 +1,364 @@
+/****************************************************************************
+ * arch/arm64/src/common/arm64_internal.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_ARM64_SRC_COMMON_ARM64_INTERNAL_H
+#define __ARCH_ARM64_SRC_COMMON_ARM64_INTERNAL_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#ifndef __ASSEMBLY__
+# include <nuttx/compiler.h>
+# include <nuttx/arch.h>
+# include <sys/types.h>
+# include <stdint.h>
+#endif
+
+#include "arm64_arch.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Determine which (if any) console driver to use. If a console is enabled
+ * and no other console device is specified, then a serial console is
+ * assumed.
+ */
+
+#ifndef CONFIG_DEV_CONSOLE
+# undef USE_SERIALDRIVER
+# undef USE_EARLYSERIALINIT
+#else
+# if defined(CONFIG_LWL_CONSOLE)
+# undef USE_SERIALDRIVER
+# undef USE_EARLYSERIALINIT
+# elif defined(CONFIG_CONSOLE_SYSLOG)
+# undef USE_SERIALDRIVER
+# undef USE_EARLYSERIALINIT
+# else
+# define USE_SERIALDRIVER 1
+# define USE_EARLYSERIALINIT 1
+# endif
+#endif
+
+/* If some other device is used as the console, then the serial driver may
+ * still be needed. Let's assume that if the upper half serial driver is
+ * built, then the lower half will also be needed. There is no need for
+ * the early serial initialization in this case.
+ */
+
+#if !defined(USE_SERIALDRIVER) && defined(CONFIG_STANDARD_SERIAL)
+# define USE_SERIALDRIVER 1
+#endif
+
+/* Check if an interrupt stack size is configured */
+
+#ifndef CONFIG_ARCH_INTERRUPTSTACK
+# define CONFIG_ARCH_INTERRUPTSTACK 0
+#endif
+
+/* If the floating point unit is present and enabled, then save the
+ * floating point registers as well as normal ARM registers.
+ */
+
+#define arm64_savestate(regs) (regs = (uint64_t *)CURRENT_REGS)
+#define arm64_restorestate(regs) (CURRENT_REGS = regs)
+
+/* This is the value used to mark the stack for subsequent stack monitoring
+ * logic.
+ */
+
+#define STACK_COLOR 0xdeaddead
+#define HEAP_COLOR 'h'
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+#ifndef __ASSEMBLY__
+typedef void (*up_vector_t)(void);
+#endif
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+#ifndef __ASSEMBLY__
+#ifdef __cplusplus
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+/* AArch64 the stack-pointer must be 128-bit aligned */
+
+#define STACK_ALIGNMENT 16
+
+/* Stack alignment macros */
+
+#define STACK_ALIGN_MASK (STACK_ALIGNMENT - 1)
+#define STACK_ALIGN_DOWN(a) ((a) & ~STACK_ALIGN_MASK)
+#define STACK_ALIGN_UP(a) (((a) + STACK_ALIGN_MASK) & ~STACK_ALIGN_MASK)
+
+#define INIT_STACK_DEFINE(sym, size) \
+ char locate_data(".initstack") \
+ aligned_data(STACK_ALIGNMENT) sym[size]
+
+#define INIT_STACK_ARRAY_DEFINE(sym, n, size) \
+ char locate_data(".initstack") \
+ aligned_data(STACK_ALIGNMENT) sym[n][size]
+
+#define INIT_STACK_DEFINE_EXTERN(sym, size) \
+ EXTERN char sym[size]
+
+#define INIT_STACK_ARRAY_DEFINE_EXTERN(sym, n, size) \
+ EXTERN char sym[n][size]
+
+#define STACK_PTR_TO_FRAME(type, ptr) \
+ (type *)((uintptr_t)(ptr) - sizeof(type))
+
+#define INTSTACK_SIZE (CONFIG_ARCH_INTERRUPTSTACK & ~STACK_ALIGN_MASK)
+
+#ifdef CONFIG_SMP
+
+/* The size of interrupt and idle stack. This is the configured
+ * value aligned the 8-bytes as required by the ARM EABI.
+ */
+
+#define SMP_STACK_SIZE STACK_ALIGN_UP(CONFIG_IDLETHREAD_STACKSIZE)
+
+INIT_STACK_ARRAY_DEFINE_EXTERN(g_cpu_idlestackalloc, CONFIG_SMP_NCPUS,
+ SMP_STACK_SIZE);
+INIT_STACK_ARRAY_DEFINE_EXTERN(g_interrupt_stacks, CONFIG_SMP_NCPUS,
+ INTSTACK_SIZE);
+uintptr_t arm64_intstack_alloc(void);
+uintptr_t arm64_intstack_top(void);
+#else
+/* idle thread stack for primary core */
+
+INIT_STACK_DEFINE_EXTERN(g_idle_stack, CONFIG_IDLETHREAD_STACKSIZE);
+INIT_STACK_DEFINE_EXTERN(g_interrupt_stack, INTSTACK_SIZE);
+#endif
+
+/* This is the beginning of heap as provided from arm64_head.S.
+ * This is the first address in DRAM after the loaded
+ * program + bss + idle stack. The end of the heap is
+ * CONFIG_RAM_END
+ */
+
+/* Address of the saved user stack pointer */
+
+#if CONFIG_ARCH_INTERRUPTSTACK > 3
+EXTERN uint64_t g_intstackalloc; /* Allocated stack base */
+EXTERN uint64_t g_intstacktop; /* Initial top of interrupt stack */
+#else
+# error CONFIG_ARCH_INTERRUPTSTACK must be defined (4096 at least) at arm64
+#endif
+
+/* These 'addresses' of these values are setup by the linker script. They
+ * are not actual uint64_t storage locations! They are only used
+ * meaningfully in the following way:
+ *
+ * - The linker script defines, for example, the symbol_sdata.
+ * - The declaration extern uint64_t _sdata; makes C happy. C will believe
+ * that the value _sdata is the address of a uint64_t variable _data
+ * (it is not!).
+ * - We can recover the linker value then by simply taking the address of
+ * of _data. like: uint64_t *pdata = &_sdata;
+ *
+ * Memory layout for Nuttx at arm64 for FLAT Build
+ *
+ * +-------------------------+ <- RAM BASE
+ * | |
+ * |<<<<<<<<<<<<<<<<<<<<<<<<<| <- LOAD_BASE
+ * | text(code) section |
+ * | vector table |
+ * +-------------------------+-- page align(4096)
+ * | rodata section |
+ * +-------------------------+-- page align(4096)
+ * | data/bss section |
+ * +-------------------------+-- page align(4096)
+ * | initstack section |
+ * +-------------------------+-- page align(4096)
+ * | heap alloc area |
+ * | |
+ * | |
+ * | |
+ * +-------------------------+
+ *
+ * Note:
+ * 1. initstack is for idle_thread and interrupt stack,
+ * it has dedicated stack for IRQ handler in arm64
+ * 2. Every section with different memory attribute,
+ * please check mmu_nxrt_regions at arm64_mmu.c
+ *
+ * please check dramboot.ld at specified platform for more detail
+ */
+
+EXTERN char _stext[]; /* Start of .text */
+EXTERN char _etext[]; /* End of .text */
+EXTERN char _sztext[]; /* Size of .text */
+EXTERN char _srodata[]; /* Start of .rodata */
+EXTERN char _erodata[]; /* End+1 of .rodata */
+EXTERN char _szrodata[]; /* Size of .rodata */
+EXTERN const char _eronly[]; /* End+1 of read only section (.text + .rodata) */
+EXTERN char _sdata[]; /* Start of .data */
+EXTERN char _edata[]; /* End+1 of .data */
+EXTERN char _sbss[]; /* Start of .bss */
+EXTERN char _ebss[]; /* End+1 of .bss */
+EXTERN char _szdata[]; /* Size of data(.data + .bss) */
+EXTERN char _e_initstack[]; /* End+1 of .initstack */
+EXTERN char g_idle_topstack[]; /* End+1 of heap */
+
+# define _START_TEXT _stext
+# define _END_TEXT _etext
+# define _START_BSS _sbss
+# define _END_BSS _ebss
+# define _DATA_INIT _eronly
+# define _START_DATA _sdata
+# define _END_DATA _edata
+
+/****************************************************************************
+ * Inline Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+void arm64_new_task(struct tcb_s *tak_new);
+
+/* Low level initialization provided by chip logic */
+
+void arm64_chip_boot(void);
+
+int arm64_psci_init(const char *method);
+
+void __start(void);
+void arm64_secondary_start(void);
+
+/* Context switching */
+
+void arm64_fullcontextrestore(uint64_t *restoreregs) noreturn_function;
+void arm64_switchcontext(uint64_t **saveregs, uint64_t *restoreregs);
+void arm64_context_snapshot(void *savereg);
+
+/* Signal handling **********************************************************/
+
+void arm64_sigdeliver(void);
+
+/* Power management *********************************************************/
+
+#ifdef CONFIG_PM
+void arm64_pminitialize(void);
+#else
+# define arm64_pminitialize()
+#endif
+
+/* Interrupt handling */
+
+/* Exception handling logic unique to the Cortex-A and Cortex-R families
+ * (but should be back-ported to the ARM7 and ARM9 families).
+ */
+
+/* Interrupt acknowledge and dispatch */
+
+uint64_t *arm64_doirq(int irq, uint64_t *regs);
+
+/* Paging support */
+
+#ifdef CONFIG_PAGING
+void arm64_pginitialize(void);
+#else /* CONFIG_PAGING */
+# define arm64_pginitialize()
+#endif /* CONFIG_PAGING */
+
+uint64_t * arm64_syscall_switch(uint64_t *regs);
+int arm64_syscall(uint64_t *regs);
+
+#ifdef USE_SERIALDRIVER
+void arm64_serialinit(void);
+#endif
+
+#ifdef USE_EARLYSERIALINIT
+void arm64_earlyserialinit(void);
+#endif
+
+/* DMA */
+
+#ifdef CONFIG_ARCH_DMA
+void weak_function arm64_dma_initialize(void);
+#endif
+
+/* Memory management */
+
+#if CONFIG_MM_REGIONS > 1
+void arm64_addregion(void);
+#else
+# define arm64_addregion()
+#endif
+
+/* Networking */
+
+/* Defined in board/xyz_network.c for board-specific Ethernet
+ * implementations, or chip/xyx_ethernet.c for chip-specific Ethernet
+ * implementations, or common/arm_etherstub.c for a corner case where the
+ * network is enabled yet there is no Ethernet driver to be initialized.
+ *
+ * Use of common/arm_etherstub.c is deprecated. The preferred mechanism is
+ * to use CONFIG_NETDEV_LATEINIT=y to suppress the call to
+ * arm_netinitialize() in up_initialize(). Then this stub would not be
+ * needed.
... 7289 lines suppressed ...