You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by xi...@apache.org on 2023/03/01 05:23:58 UTC

[nuttx] 03/07: arm64: ARMv8-r(Cortex-R82) support

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

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

commit 0841f4dbaa700ef61b7c476f31cda8ef31bd0a95
Author: qinwei1 <qi...@xiaomi.com>
AuthorDate: Tue Feb 28 17:01:24 2023 +0800

    arm64: ARMv8-r(Cortex-R82) support
    
    Summary:
    
      Adding armv8-r(Cortex-R82) support and modify some common code to
    fit the change, the change including:
    
    1. ARM Single Security State Support, ARMv8-R support only single
       security state, and some GIC configure need to change and fit
    2. For ARMv8-R, only have EL0 ~ EL2, the code at EL3 is not necessary
       and system register for EL3 is not accessible(gcc will failed when
       access these registers)
    3. add base MPU configure for the platform.
    
    Signed-off-by: qinwei1 <qi...@xiaomi.com>
---
 arch/arm64/Kconfig                       |  20 ++
 arch/arm64/src/Toolchain.defs            |   6 +
 arch/arm64/src/a64/a64_boot.c            |  18 ++
 arch/arm64/src/common/Make.defs          |  20 +-
 arch/arm64/src/common/arm64_arch_timer.c |   2 -
 arch/arm64/src/common/arm64_boot.c       |   8 +
 arch/arm64/src/common/arm64_cpustart.c   |  51 ++++--
 arch/arm64/src/common/arm64_fatal.c      |   2 +
 arch/arm64/src/common/arm64_gic.h        |  29 ++-
 arch/arm64/src/common/arm64_gicv3.c      |  70 +++++--
 arch/arm64/src/common/arm64_head.S       |   8 +-
 arch/arm64/src/common/arm64_mpu.c        | 241 +++++++++++++++++++++++++
 arch/arm64/src/common/arm64_mpu.h        | 301 +++++++++++++++++++++++++++++++
 arch/arm64/src/qemu/qemu_boot.c          |  20 ++
 arch/arm64/src/qemu/qemu_boot.h          |   6 +
 arch/arm64/src/qemu/qemu_serial.c        |   1 -
 16 files changed, 761 insertions(+), 42 deletions(-)

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index cb9c7fcc58..e0b187f002 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -49,10 +49,12 @@ endchoice
 config ARCH_ARMV8A
 	bool
 	default n
+	select ARCH_HAVE_EL3
 
 config ARCH_ARMV8R
 	bool
 	default n
+	select ARCH_SINGLE_SECURITY_STATE
 
 config ARCH_HAVE_PSCI
 	bool "ARM PCSI (Power State Coordination Interface) Support"
@@ -64,6 +66,24 @@ config ARCH_HAVE_PSCI
 		maybe not applicable for arm core without PCSI firmware
 		interface implement
 
+config ARCH_SINGLE_SECURITY_STATE
+	bool "ARM Single Security State Support"
+	default n
+	---help---
+		Some ARM aarch64 Cortex-family processors only supports single
+		security state(eg. Cortex-R82). For these Processors,
+		GIC or other ARM architecture feature will with different
+		configure
+
+config ARCH_HAVE_EL3
+	bool
+	default n
+	---help---
+		Some ARM aarch64 Cortex-family processors only supports
+		EL0~El2(eg. Cortex-R82). For these Processors, the code
+		runing at EL3 is not necessary and system register for EL3
+		is not accessible
+
 config ARCH_EARLY_PRINT
 	bool "arch early print support"
 	default n
diff --git a/arch/arm64/src/Toolchain.defs b/arch/arm64/src/Toolchain.defs
index 7b2c9cb0d0..a62d87c14e 100644
--- a/arch/arm64/src/Toolchain.defs
+++ b/arch/arm64/src/Toolchain.defs
@@ -34,12 +34,18 @@ ifeq ($(CONFIG_ARCH_ARMV8A),y)
   ARCHCPUFLAGS += -march=armv8-a
 endif
 
+ifeq ($(CONFIG_ARCH_ARMV8R),y)
+  ARCHCPUFLAGS += -march=armv8-r
+endif
+
 ifeq ($(CONFIG_ARCH_CORTEX_A53),y)
   ARCHCPUFLAGS += -mtune=cortex-a53
 else ifeq ($(CONFIG_ARCH_CORTEX_A57),y)
   ARCHCPUFLAGS += -mtune=cortex-a57
 else ifeq ($(CONFIG_ARCH_CORTEX_A72),y)
   ARCHCPUFLAGS += -mtune=cortex-a72
+else ifeq ($(CONFIG_ARCH_CORTEX_R82),y)
+  ARCHCPUFLAGS += -mtune=cortex-r82
 endif
 
 ifeq ($(CONFIG_DEBUG_CUSTOMOPT),y)
diff --git a/arch/arm64/src/a64/a64_boot.c b/arch/arm64/src/a64/a64_boot.c
index 02777e120e..65a5c8ce99 100644
--- a/arch/arm64/src/a64/a64_boot.c
+++ b/arch/arm64/src/a64/a64_boot.c
@@ -70,6 +70,24 @@ const struct arm_mmu_config mmu_config =
  * Public Functions
  ****************************************************************************/
 
+/****************************************************************************
+ * Name: arm64_el_init
+ *
+ * Description:
+ *   The function called from arm64_head.S at very early stage for these
+ * platform, it's use to:
+ *   - Handling special hardware initialize routine which is need to
+ *     run at high ELs
+ *   - Initialize system software such as hypervisor or security firmware
+ *     which is need to run at high ELs
+ *
+ ****************************************************************************/
+
+void arm64_el_init(void)
+{
+  /* TODO: A64 set init sys clock */
+}
+
 /****************************************************************************
  * Name: arm64_chip_boot
  *
diff --git a/arch/arm64/src/common/Make.defs b/arch/arm64/src/common/Make.defs
index cc4aecdfc6..eea3c1d3de 100644
--- a/arch/arm64/src/common/Make.defs
+++ b/arch/arm64/src/common/Make.defs
@@ -50,13 +50,29 @@ CMN_CSRCS += arm64_schedulesigaction.c arm64_sigdeliver.c
 CMN_CSRCS += arm64_backtrace.c arm64_getintstack.c arm64_registerdump.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_gicv2.c arm64_gicv3.c arm64_fatal.c
+CMN_CSRCS += arm64_arch_timer.c arm64_cache.c
+CMN_CSRCS += arm64_doirq.c arm64_fatal.c
 CMN_CSRCS += arm64_syscall.c
 
 # Use common heap allocation for now (may need to be customized later)
 CMN_CSRCS += arm64_allocateheap.c
 
+ifeq ($(CONFIG_ARM_GIC_VERSION),3)
+CMN_CSRCS += arm64_gicv3.c
+endif
+
+ifeq ($(CONFIG_ARM_GIC_VERSION),2)
+CMN_CSRCS += arm64_gicv2.c
+endif
+
+ifeq ($(CONFIG_ARCH_HAVE_MMU),y)
+CMN_CSRCS += arm64_mmu.c
+endif
+
+ifeq ($(CONFIG_ARCH_HAVE_MPU),y)
+CMN_CSRCS += arm64_mpu.c
+endif
+
 ifeq ($(CONFIG_ARCH_HAVE_PSCI),y)
 CMN_CSRCS += arm64_cpu_psci.c arm64_systemreset.c
 endif
diff --git a/arch/arm64/src/common/arm64_arch_timer.c b/arch/arm64/src/common/arm64_arch_timer.c
index 4500a1fad5..51518a2fee 100644
--- a/arch/arm64/src/common/arm64_arch_timer.c
+++ b/arch/arm64/src/common/arm64_arch_timer.c
@@ -221,8 +221,6 @@ void up_timer_initialize(void)
         (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);
diff --git a/arch/arm64/src/common/arm64_boot.c b/arch/arm64/src/common/arm64_boot.c
index 4b1492c01e..1d4013733a 100644
--- a/arch/arm64/src/common/arm64_boot.c
+++ b/arch/arm64/src/common/arm64_boot.c
@@ -36,6 +36,13 @@ extern void *_vector_table[];
  * Public Functions
  ****************************************************************************/
 
+#ifdef CONFIG_ARCH_HAVE_EL3
+
+/* Some ARM aarch64 Cortex-family processors have not EL3
+ * these two function should never called
+ * defined to available compile error when with gcc option
+ */
+
 void arm64_boot_el3_init(void)
 {
   uint64_t reg;
@@ -87,6 +94,7 @@ void arm64_boot_el3_get_next_el(uint64_t switch_addr)
 
   write_sysreg(spsr, spsr_el3);
 }
+#endif
 
 void arm64_boot_el2_init(void)
 {
diff --git a/arch/arm64/src/common/arm64_cpustart.c b/arch/arm64/src/common/arm64_cpustart.c
index 53262c7b39..1eac831cf0 100644
--- a/arch/arm64/src/common/arm64_cpustart.c
+++ b/arch/arm64/src/common/arm64_cpustart.c
@@ -43,7 +43,12 @@
 #include "arm64_arch_timer.h"
 #include "arm64_smp.h"
 #include "arm64_cpu_psci.h"
+
+#ifdef CONFIG_ARCH_HAVE_MPU
+#include "arm64_mpu.h"
+#else
 #include "arm64_mmu.h"
+#endif
 
 /****************************************************************************
  * Public data
@@ -58,6 +63,7 @@ struct arm64_boot_params
   arm64_cpustart_t func;
   void *arg;
   int cpu_num;
+  volatile long cpu_ready_flag;
 };
 
 volatile struct arm64_boot_params aligned_data(L1_CACHE_BYTES)
@@ -76,8 +82,6 @@ volatile uint64_t *g_cpu_int_stacktop[CONFIG_SMP_NCPUS] =
  * Private data
  ****************************************************************************/
 
-static volatile long cpu_ready_flag;
-
 /****************************************************************************
  * Private Functions
  ****************************************************************************/
@@ -89,12 +93,28 @@ static inline void local_delay(void)
     }
 }
 
+#ifdef CONFIG_ARCH_HAVE_MMU
+static void flush_boot_params(void)
+{
+  uintptr_t flush_start;
+  uintptr_t flush_end;
+
+  flush_start   = (uintptr_t)&cpu_boot_params;
+  flush_end     = flush_start + sizeof(cpu_boot_params);
+
+  up_flush_dcache(flush_start, flush_end);
+}
+#else
+static void flush_boot_params(void)
+{
+  /* TODO: Flush at MPU platform */
+}
+#endif
+
 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 */
 
@@ -118,6 +138,9 @@ static void arm64_smp_init_top(void *arg)
   write_sysreg(tcb, tpidr_el1);
   write_sysreg(tcb, tpidr_el0);
 
+  cpu_boot_params.cpu_ready_flag = 1;
+  SP_SEV();
+
   nx_idle_trampoline();
 }
 
@@ -126,8 +149,6 @@ static void arm64_start_cpu(int cpu_num, char *stack, int stack_sz,
 {
   uint64_t cpu_mpid = cpu_num;
 
-  uintptr_t flush_start;
-  uintptr_t flush_end;
 
 #ifdef CONFIG_SCHED_INSTRUMENTATION
 
@@ -149,9 +170,7 @@ static void arm64_start_cpu(int cpu_num, char *stack, int stack_sz,
 
   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);
+  flush_boot_params();
 
 #ifdef CONFIG_ARCH_HAVE_PSCI
   if (psci_cpu_on(cpu_mpid, (uint64_t)__start))
@@ -216,15 +235,16 @@ int up_cpu_start(int cpu)
   arm64_stack_color(g_cpu_idlestackalloc[cpu], SMP_STACK_SIZE);
 #endif
 
-  cpu_ready_flag = 0;
+  cpu_boot_params.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)
+  while (!cpu_boot_params.cpu_ready_flag)
     {
-      local_delay();
+      SP_WFE();
+      flush_boot_params();
     }
 
   return 0;
@@ -237,7 +257,13 @@ void arm64_boot_secondary_c_routine(void)
   arm64_cpustart_t  func;
   void              *arg;
 
+#ifdef CONFIG_ARCH_HAVE_MPU
+  arm64_mpu_init(false);
+#endif
+
+#ifdef CONFIG_ARCH_HAVE_MMU
   arm64_mmu_init(false);
+#endif
 
   arm64_gic_secondary_init();
 
@@ -263,7 +289,6 @@ void arm64_boot_secondary_c_routine(void)
 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_fatal.c b/arch/arm64/src/common/arm64_fatal.c
index 36321ec828..0bb4b3b552 100644
--- a/arch/arm64/src/common/arm64_fatal.c
+++ b/arch/arm64/src/common/arm64_fatal.c
@@ -359,6 +359,7 @@ void arm64_fatal_error(unsigned int reason, struct regs_context * reg)
               break;
             }
 
+#ifdef CONFIG_ARCH_HAVE_EL3
           case MODE_EL3:
             {
               sinfo("CurrentEL: MODE_EL3\n");
@@ -367,6 +368,7 @@ void arm64_fatal_error(unsigned int reason, struct regs_context * reg)
               __asm__ volatile ("mrs %0, elr_el3" : "=r" (elr));
               break;
             }
+#endif
 
           default:
             {
diff --git a/arch/arm64/src/common/arm64_gic.h b/arch/arm64/src/common/arm64_gic.h
index 4cc1b01e2f..aa5ca27031 100644
--- a/arch/arm64/src/common/arm64_gic.h
+++ b/arch/arm64/src/common/arm64_gic.h
@@ -145,15 +145,38 @@
 
 #define GIC_INT_DEF_PRI_X4          0xa0a0a0a0
 
-/* Register bit definitions */
+/* GICD_CTLR : Distributor Control Register
+ *
+ * [31](RO)  RWP Register Write Pending:
+ *            -- 0 No register write in progress
+ *            -- 1 Register write in progress
+ * [30:8]    - Reserved -
+ * [7](RW)   E1NWF Enable 1 of N Wakeup Functionality  0
+ * [6](RO)   DS Disable Security status:
+ *            -- 0 The gicd_ctlr_ds signal was LOW when the GIC
+ *                 exited reset. Therefore, the Distributor supports
+ *                 two Security states and Non-secure accesses cannot
+ *                 access and modify registers that control Group 0
+ *                 interrupts.
+ *            -- 1 The gicd_ctlr_ds signal was HIGH when the GIC
+ *                 exited reset. Therefore, the Distributor only supports
+ *                 a single Security state and Non-secure accesses
+ *                 can access and modify registers that control
+ *                 Group 0 interrupts.
+ * [5](RO)   ARE_NS Affinity Routing Enable, Non-secure state
+ * [4](RO)   ARE_S Affinity Routing Enable, Secure state
+ * [3]       - Reserved -
+ * [2](RW)   EnableGrp1S Enable Secure Group 1 interrupts
+ * [1](RW)   EnableGrp1NS Enable Non-secure Group 1 interrupts
+ * [0](RW)   EnableGrp0 Enable Group 0 interrupts
+ */
 
-/* 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_CTRL_DS                6
 #define GICD_CGRL_E1NWF             7
 
 /* GICD_CTLR Register write progress bit */
diff --git a/arch/arm64/src/common/arm64_gicv3.c b/arch/arm64/src/common/arm64_gicv3.c
index 5df8b9c9cc..3c23d0aa53 100644
--- a/arch/arm64/src/common/arm64_gicv3.c
+++ b/arch/arm64/src/common/arm64_gicv3.c
@@ -73,6 +73,32 @@ static unsigned long gic_rdists[CONFIG_SMP_NCPUS];
  * Private Functions
  ***************************************************************************/
 
+static inline void sys_set_bit(unsigned long addr, unsigned int bit)
+{
+  uint32_t temp;
+
+  temp = getreg32(addr);
+  temp = temp | (BIT(bit));
+  putreg32(temp, addr);
+}
+
+static inline void sys_clear_bit(unsigned long addr, unsigned int bit)
+{
+  uint32_t temp;
+
+  temp = getreg32(addr);
+  temp = temp & ~(BIT(bit));
+  putreg32(temp, addr);
+}
+
+static inline int sys_test_bit(unsigned long addr, unsigned int bit)
+{
+  uint32_t temp;
+
+  temp = getreg32(addr);
+  return (temp & BIT(bit));
+}
+
 static inline unsigned long gic_get_rdist(void)
 {
   return gic_rdists[this_cpu()];
@@ -170,7 +196,7 @@ void arm64_gic_irq_enable(unsigned int intid)
   if (GIC_IS_SPI(intid))
     {
       putreg64(MPIDR_TO_CORE(GET_MPIDR()),
-               IROUTER(GET_DIST_BASE(intid), intid));
+              IROUTER(GET_DIST_BASE(intid), intid));
     }
 }
 
@@ -262,16 +288,12 @@ int arm64_gic_raise_sgi(unsigned int sgi_id, uint64_t target_aff,
 
 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);
+  sys_clear_bit(rdist + GICR_WAKER, GICR_WAKER_PS);
 
   while (getreg32(rdist + GICR_WAKER) & BIT(GICR_WAKER_CA))
     {
@@ -361,17 +383,19 @@ static void gicv3_dist_init(void)
   putreg32(0, GICD_CTLR);
   gic_wait_rwp(GIC_SPI_INT_BASE);
 
-#if 0
+#ifdef CONFIG_ARCH_SINGLE_SECURITY_STATE
 
   /* 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");
+  sys_set_bit(GICD_CTLR, GICD_CTRL_DS);
+  if (!sys_test_bit(GICD_CTLR, GICD_CTRL_DS))
+    {
+      sinfo("Current GIC does not support single security state\n");
+      PANIC();
+    }
 #endif
 
   /* Default configuration of all SPIs */
@@ -416,15 +440,12 @@ static void gicv3_dist_init(void)
       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: Some arrch64 Cortex-A core maybe without security state
+   * it has different GIC configure with standard arrch64 A or R core
+   */
 
-  /* TODO: ARMv8-R support
-   *
-   * For GIC single security state(ARMv8-R), the config means
+#ifdef CONFIG_ARCH_SINGLE_SECURITY_STATE
+  /* 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.
@@ -437,11 +458,20 @@ static void gicv3_dist_init(void)
 
   putreg32(BIT(GICD_CTRL_ARE_S) | BIT(GICD_CTLR_ENABLE_G1NS),
                  GICD_CTLR);
+
+#else
+  /* Enable distributor with ARE */
+
+  putreg32(BIT(GICD_CTRL_ARE_NS) | BIT(GICD_CTLR_ENABLE_G1NS),
+           GICD_CTLR);
 #endif
 }
 
 void up_enable_irq(int irq)
 {
+  /* TODO: add common interface to set IRQ type for NuttX */
+
+  arm64_gic_irq_set_priority(irq, IRQ_DEFAULT_PRIORITY, IRQ_TYPE_LEVEL);
   arm64_gic_irq_enable(irq);
 }
 
@@ -563,7 +593,7 @@ static int gic_validate_redist_version(void)
       ppi_nr = 0;
     }
 
-  sinfo("GICD_TYPER = 0x%"PRIx64"\n", typer);
+  sinfo("GICR_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 " : "");
diff --git a/arch/arm64/src/common/arm64_head.S b/arch/arm64/src/common/arm64_head.S
index 82104b7d57..40ded82937 100644
--- a/arch/arm64/src/common/arm64_head.S
+++ b/arch/arm64/src/common/arm64_head.S
@@ -176,10 +176,14 @@ primary_core:
 
 cpu_boot:
     PRINT(cpu_boot, "- Ready to Boot CPU\r\n")
+    /* Platform hook for highest EL */
+
+    bl  arm64_el_init
 
 switch_el:
     switch_el x0, 3f, 2f, 1f
 3:
+#ifdef CONFIG_ARCH_HAVE_EL3
     PRINT(switch_el3, "- Boot from EL3\r\n")
 
     /* EL3 init */
@@ -191,7 +195,7 @@ switch_el:
     adr   x0, switch_el
     bl    arm64_boot_el3_get_next_el
     eret
-
+#endif
 2:
     PRINT(switch_el2, "- Boot from EL2\r\n")
 
@@ -243,10 +247,12 @@ __reset_prep_c:
 
     switch_el x0, 3f, 2f, 1f
 3:
+#ifdef CONFIG_ARCH_HAVE_EL3
     /* Reinitialize SCTLR from scratch in EL3 */
 
     ldr   w0, =(SCTLR_EL3_RES1 | SCTLR_I_BIT | SCTLR_SA_BIT)
     msr   sctlr_el3, x0
+#endif
 
     /* Set SP_EL1 */
 
diff --git a/arch/arm64/src/common/arm64_mpu.c b/arch/arm64/src/common/arm64_mpu.c
new file mode 100644
index 0000000000..3344d5f544
--- /dev/null
+++ b/arch/arm64/src/common/arm64_mpu.c
@@ -0,0 +1,241 @@
+/***************************************************************************
+ * arch/arm64/src/common/arm64_mpu.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 <debug.h>
+#include <assert.h>
+
+#include <nuttx/arch.h>
+#include <arch/irq.h>
+#include <arch/chip/chip.h>
+
+#include "arm64_arch.h"
+#include "arm64_internal.h"
+#include "arm64_fatal.h"
+#include "arm64_mpu.h"
+
+/***************************************************************************
+ * Pre-processor Definitions
+ ***************************************************************************/
+
+#define __MPU_ASSERT(__cond, fmt, ...) \
+  do                                   \
+    {                                  \
+      if (!(__cond))                   \
+        {                              \
+          sinfo(fmt, ## __VA_ARGS__);  \
+          PANIC();                     \
+        }                              \
+    }                                  \
+  while (false)
+
+/* AArch64 Memory Model Feature Register 0
+ * Provides information about the implemented memory model and memory
+ * management support in AArch64 state.
+ * See Arm Architecture Reference Manual Supplement
+ *  Armv8, for Armv8-R AArch64 architecture profile, G1.3.7
+ *
+ * ID_AA64MMFR0_MSA_FRAC, bits[55:52]
+ * ID_AA64MMFR0_MSA, bits [51:48]
+ */
+
+#define ID_AA64MMFR0_MSA_MSK        (0xFFUL << 48U)
+#define ID_AA64MMFR0_PMSA_EN        (0x1FUL << 48U)
+#define ID_AA64MMFR0_PMSA_VMSA_EN   (0x2FUL << 48U)
+
+/* Global status variable holding the number of HW MPU region indices, which
+ * have been reserved by the MPU driver to program the static (fixed) memory
+ * regions.
+ */
+
+static uint8_t static_regions_num;
+
+/***************************************************************************
+ * Private Functions
+ ***************************************************************************/
+
+/* Get the number of supported MPU regions. */
+
+static inline uint8_t get_num_regions(void)
+{
+  uint64_t type;
+
+  type  = read_sysreg(mpuir_el1);
+  type  = type & MPU_IR_REGION_MSK;
+
+  return (uint8_t)type;
+}
+
+/* ARM Core MPU Driver API Implementation for ARM MPU */
+
+/**
+ * @brief enable the MPU
+ */
+
+void arm64_core_mpu_enable(void)
+{
+  uint64_t val;
+
+  val   = read_sysreg(sctlr_el1);
+  val   |= SCTLR_M_BIT;
+  write_sysreg(val, sctlr_el1);
+  ARM64_DSB();
+  ARM64_ISB();
+}
+
+/**
+ * @brief disable the MPU
+ */
+
+void arm64_core_mpu_disable(void)
+{
+  uint64_t val;
+
+  /* Force any outstanding transfers to complete before disabling MPU */
+
+  ARM64_DMB();
+
+  val   = read_sysreg(sctlr_el1);
+  val   &= ~SCTLR_M_BIT;
+  write_sysreg(val, sctlr_el1);
+  ARM64_DSB();
+  ARM64_ISB();
+}
+
+/* ARM MPU Driver Initial Setup
+ *
+ * Configure the cache-ability attributes for all the
+ * different types of memory regions.
+ */
+
+static void mpu_init(void)
+{
+  /* Device region(s): Attribute-0
+   * Flash region(s): Attribute-1
+   * SRAM region(s): Attribute-2
+   * SRAM no cache-able regions(s): Attribute-3
+   */
+
+  uint64_t mair = MPU_MAIR_ATTRS;
+
+  write_sysreg(mair, mair_el1);
+  ARM64_DSB();
+  ARM64_ISB();
+}
+
+static inline void mpu_set_region(uint32_t rnr, uint64_t rbar,
+                                  uint64_t rlar)
+{
+  write_sysreg(rnr, prselr_el1);
+  ARM64_DSB();
+  write_sysreg(rbar, prbar_el1);
+  write_sysreg(rlar, prlar_el1);
+  ARM64_DSB();
+  ARM64_ISB();
+}
+
+/* This internal functions performs MPU region initialization. */
+
+static void region_init(const uint32_t index,
+                        const struct arm64_mpu_region *region_conf)
+{
+  uint64_t  rbar    = region_conf->base & MPU_RBAR_BASE_MSK;
+  uint64_t  rlar    = (region_conf->limit - 1) & MPU_RLAR_LIMIT_MSK;
+
+  rbar |= region_conf->attr.rbar &
+          (MPU_RBAR_XN_MSK | MPU_RBAR_AP_MSK | MPU_RBAR_SH_MSK);
+  rlar |=
+    (region_conf->attr.mair_idx <<
+      MPU_RLAR_ATTRINDX_POS) & MPU_RLAR_ATTRINDX_MSK;
+  rlar |= MPU_RLAR_EN_MSK;
+
+  mpu_set_region(index, rbar, rlar);
+}
+
+/***************************************************************************
+ * Public Functions
+ ***************************************************************************/
+
+/* @brief MPU default configuration
+ *
+ * This function here provides the default configuration mechanism
+ * for the Memory Protection Unit (MPU).
+ */
+
+void arm64_mpu_init(bool is_primary_core)
+{
+  uint64_t  val;
+  uint32_t  r_index;
+
+  /* Current MPU code supports only EL1 */
+
+  __asm__ volatile ("mrs %0, CurrentEL" : "=r" (val));
+
+  __MPU_ASSERT(GET_EL(
+                 val) == MODE_EL1,
+               "Exception level not EL1, MPU not enabled!\n");
+
+  /* Check whether the processor supports MPU */
+
+  val = read_sysreg(id_aa64mmfr0_el1) & ID_AA64MMFR0_MSA_MSK;
+  if ((val != ID_AA64MMFR0_PMSA_EN) && (val != ID_AA64MMFR0_PMSA_VMSA_EN))
+    {
+      __MPU_ASSERT(0, "MPU not supported!\n");
+      return;
+    }
+
+  if (mpu_config.num_regions > get_num_regions())
+    {
+      /* Attempt to configure more MPU regions than
+       * what is supported by hardware. As this operation
+       * is executed during system (pre-kernel) initialization,
+       * we want to ensure we can detect an attempt to
+       * perform invalid configuration.
+       */
+
+      __MPU_ASSERT(0, "Request to configure: %u regions (supported: %u)\n",
+                   mpu_config.num_regions, get_num_regions());
+      return;
+    }
+
+  arm64_core_mpu_disable();
+
+  /* Architecture-specific configuration */
+
+  mpu_init();
+
+  /* Program fixed regions configured at SOC definition. */
+
+  for (r_index = 0U; r_index < mpu_config.num_regions; r_index++)
+    {
+      region_init(r_index, &mpu_config.mpu_regions[r_index]);
+    }
+
+  /* Update the number of programmed MPU regions. */
+
+  static_regions_num = mpu_config.num_regions;
+
+  arm64_core_mpu_enable();
+}
diff --git a/arch/arm64/src/common/arm64_mpu.h b/arch/arm64/src/common/arm64_mpu.h
new file mode 100644
index 0000000000..fe19fdaf43
--- /dev/null
+++ b/arch/arm64/src/common/arm64_mpu.h
@@ -0,0 +1,301 @@
+/****************************************************************************
+ * arch/arm64/src/common/arm64_mpu.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_MPU_H
+#define __ARCH_ARM64_SRC_COMMON_ARM64_MPU_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include "arm64_arch.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Convenience macros to represent the ARMv8-R64-specific configuration
+ * for memory access permission and cache-ability attribution.
+ */
+
+/* MPU MPUIR Register Definitions */
+
+#define MPU_IR_REGION_MSK      (0xFFU)
+
+/* MPU RBAR Register attribute msk Definitions */
+
+#define MPU_RBAR_BASE_POS   6U
+#define MPU_RBAR_BASE_MSK   (0x3FFFFFFFFFFFFFFUL << MPU_RBAR_BASE_POS)
+#define MPU_RBAR_SH_POS     4U
+#define MPU_RBAR_SH_MSK     (0x3UL << MPU_RBAR_SH_POS)
+#define MPU_RBAR_AP_POS     2U
+#define MPU_RBAR_AP_MSK     (0x3UL << MPU_RBAR_AP_POS)
+
+/* RBAR_EL1 XN */
+
+#define MPU_RBAR_XN_POS     1U
+#define MPU_RBAR_XN_MSK     (0x1UL << MPU_RBAR_XN_POS)
+
+/* MPU PLBAR_ELx Register Definitions */
+
+#define MPU_RLAR_LIMIT_POS     6U
+#define MPU_RLAR_LIMIT_MSK     (0x3FFFFFFFFFFFFFFUL << MPU_RLAR_LIMIT_POS)
+#define MPU_RLAR_ATTRINDX_POS  1U
+#define MPU_RLAR_ATTRINDX_MSK  (0x7UL << MPU_RLAR_ATTRINDX_POS)
+#define MPU_RLAR_EN_MSK        (0x1UL)
+
+/* PRBAR_ELx: Attribute flag for not-allowing
+ * execution (eXecute Never)
+ */
+
+#define NOT_EXEC      MPU_RBAR_XN_MSK /* PRBAR_EL1 */
+
+/* PRBAR_ELx: Attribute flag for access permissions
+ * Privileged Read Write, Unprivileged No Access
+ */
+
+#define P_RW_U_NA      0x0U
+#define P_RW_U_NA_MSK  ((P_RW_U_NA << \
+  MPU_RBAR_AP_POS) & MPU_RBAR_AP_MSK)
+
+/* Privileged Read Write, Unprivileged Read Write */
+
+#define P_RW_U_RW                       0x1U
+#define P_RW_U_RW_MSK                   ((P_RW_U_RW << \
+  MPU_RBAR_AP_POS) & MPU_RBAR_AP_MSK)
+
+/* Privileged Read Only, Unprivileged No Access */
+
+#define P_RO_U_NA                       0x2U
+#define P_RO_U_NA_MSK                   ((P_RO_U_NA << \
+  MPU_RBAR_AP_POS) & MPU_RBAR_AP_MSK)
+
+/* Privileged Read Only, Unprivileged Read Only */
+
+#define P_RO_U_RO                       0x3U
+#define P_RO_U_RO_MSK                   ((P_RO_U_RO << \
+  MPU_RBAR_AP_POS) & MPU_RBAR_AP_MSK)
+
+/* PRBAR_ELx: Attribute flags for share-ability */
+
+#define NON_SHAREABLE                   0x0U
+#define NON_SHAREABLE_MSK \
+  ((NON_SHAREABLE << MPU_RBAR_SH_POS) & MPU_RBAR_SH_MSK)
+#define OUTER_SHAREABLE                 0x2U
+#define OUTER_SHAREABLE_MSK \
+  ((OUTER_SHAREABLE << MPU_RBAR_SH_POS) & MPU_RBAR_SH_MSK)
+#define INNER_SHAREABLE                 0x3U
+#define INNER_SHAREABLE_MSK \
+  ((INNER_SHAREABLE << MPU_RBAR_SH_POS) & MPU_RBAR_SH_MSK)
+
+/* MPIR_ELx Attribute flags for cache-ability */
+
+/* Memory Attributes for Device Memory
+ * 1.Gathering (G/nG)
+ *   Determines whether multiple accesses can be merged into a single
+ *   bus transaction.
+ *   nG: Number/size of accesses on the bus = number/size of accesses
+ *   in code.
+ *
+ * 2.Reordering (R/nR)
+ *   Determines whether accesses to the same device can be reordered.
+ *   nR: Accesses to the same IMPLEMENTATION DEFINED block size will
+ *   appear on the bus in program order.
+ *
+ * 3 Early Write Acknowledgment (E/nE)
+ *   Indicates to the memory system whether a buffer can send
+ *   acknowledgements.
+ *   nE: The response should come from the end slave, not buffering in
+ *   the interconnect.
+ */
+
+#define DEVICE_nGnRnE       0x0U
+#define DEVICE_nGnRE        0x4U
+#define DEVICE_nGRE         0x8U
+#define DEVICE_GRE          0xCU
+
+/* Read/Write Allocation Configurations for Cacheable Memory
+ * R_NON_W_NON:      Do not allocate Read/Write
+ * R_NON_W_ALLOC:    Do not allocate Read, Allocate Write
+ * R_ALLOC_W_NON:    Allocate Read, Do not allocate Write
+ * R_ALLOC_W_ALLOC:  Allocate Read/Write
+ */
+
+#define R_NON_W_NON                     0x0U
+#define R_NON_W_ALLOC                   0x1U
+#define R_ALLOC_W_NON                   0x2U
+#define R_ALLOC_W_ALLOC                 0x3U
+
+/* Memory Attributes for Normal Memory
+ * NORMAL_O_WT_NT: Normal, Outer Write-through on-transient
+ * NORMAL_O_WB_NT: Normal, Outer Write-back non-transient
+ * NORMAL_O_NON_C: Normal, Outer Non-Cacheable
+ * NORMAL_I_WT_NT: Normal, Inner Write-through non-transient
+ * NORMAL_I_WB_NT: Normal, Inner Write-back non-transient
+ * NORMAL_I_NON_C: Normal, Inner Non-Cacheable
+ */
+#define NORMAL_O_WT_NT          0x80U
+#define NORMAL_O_WB_NT          0xC0U
+#define NORMAL_O_NON_C          0x40U
+#define NORMAL_I_WT_NT          0x08U
+#define NORMAL_I_WB_NT          0x0CU
+#define NORMAL_I_NON_C          0x04U
+
+/* Global MAIR configurations */
+
+#define MPU_MAIR_INDEX_DEVICE           0U
+#define MPU_MAIR_ATTR_DEVICE            (DEVICE_nGnRnE)
+
+#define MPU_MAIR_INDEX_FLASH            1U
+#define MPU_MAIR_ATTR_FLASH                  \
+  ((NORMAL_O_WT_NT | (R_ALLOC_W_NON << 4)) | \
+   (NORMAL_I_WT_NT | R_ALLOC_W_NON))
+
+#define MPU_MAIR_INDEX_SRAM             2U
+#define MPU_MAIR_ATTR_SRAM                     \
+  ((NORMAL_O_WB_NT | (R_ALLOC_W_ALLOC << 4)) | \
+   (NORMAL_I_WB_NT | R_ALLOC_W_ALLOC))
+
+#define MPU_MAIR_INDEX_SRAM_NOCACHE     3U
+#define MPU_MAIR_ATTR_SRAM_NOCACHE         \
+  ((NORMAL_O_NON_C | (R_NON_W_NON << 4)) | \
+   (NORMAL_I_NON_C | R_NON_W_NON))
+
+#define MPU_MAIR_ATTRS                                     \
+  ((MPU_MAIR_ATTR_DEVICE << (MPU_MAIR_INDEX_DEVICE * 8)) | \
+   (MPU_MAIR_ATTR_FLASH << (MPU_MAIR_INDEX_FLASH * 8)) |   \
+   (MPU_MAIR_ATTR_SRAM << (MPU_MAIR_INDEX_SRAM * 8)) |     \
+   (MPU_MAIR_ATTR_SRAM_NOCACHE << (MPU_MAIR_INDEX_SRAM_NOCACHE * 8)))
+
+/* Some helper defines for common regions.
+ *
+ * Note that the ARMv8-R MPU architecture requires that the
+ * enabled MPU regions are non-overlapping. Therefore, it is
+ * recommended to use these helper defines only for configuring
+ * fixed MPU regions at build-time.
+ */
+
+#define REGION_DEVICE_ATTR                                \
+  {                                                       \
+    /* AP, XN, SH */                                      \
+    .rbar = NOT_EXEC | P_RW_U_NA_MSK | NON_SHAREABLE_MSK, \
+    /* Cache-ability */                                   \
+    .mair_idx = MPU_MAIR_INDEX_DEVICE,                    \
+  }
+
+#define REGION_RAM_ATTR                                   \
+  {                                                       \
+    /* AP, XN, SH */                                      \
+    .rbar = NOT_EXEC | P_RW_U_NA_MSK | NON_SHAREABLE_MSK, \
+    /* Cache-ability */                                   \
+    .mair_idx = MPU_MAIR_INDEX_SRAM,                      \
+  }
+
+#define REGION_RAM_TEXT_ATTR                   \
+  {                                            \
+    /* AP, XN, SH */                           \
+    .rbar = P_RO_U_RO_MSK | NON_SHAREABLE_MSK, \
+    /* Cache-ability */                        \
+    .mair_idx = MPU_MAIR_INDEX_SRAM,           \
+  }
+
+#define REGION_RAM_RO_ATTR                                \
+  {                                                       \
+    /* AP, XN, SH */                                      \
+    .rbar = NOT_EXEC | P_RO_U_RO_MSK | NON_SHAREABLE_MSK, \
+    /* Cache-ability */                                   \
+    .mair_idx = MPU_MAIR_INDEX_SRAM,                      \
+  }
+
+#ifndef __ASSEMBLY__
+
+struct arm64_mpu_region_attr
+{
+  /* Attributes belonging to PRBAR */
+
+  uint8_t rbar : 5;
+
+  /* MAIR index for attribute indirection */
+
+  uint8_t mair_idx : 3;
+};
+
+/* Region definition data structure */
+
+struct arm64_mpu_region
+{
+  /* Region Base Address */
+
+  uint64_t base;
+
+  /* Region limit Address */
+
+  uint64_t limit;
+
+  /* Region Name */
+
+  const char *name;
+
+  /* Region Attributes */
+
+  struct arm64_mpu_region_attr attr;
+};
+
+/* MPU configuration data structure */
+
+struct arm64_mpu_config
+{
+  /* Number of regions */
+
+  uint32_t num_regions;
+
+  /* Regions */
+
+  const struct arm64_mpu_region *mpu_regions;
+};
+
+#define MPU_REGION_ENTRY(_name, _base, _limit, _attr) \
+  {                                                   \
+    .name   = _name,                                  \
+    .base   = _base,                                  \
+    .limit  = _limit,                                 \
+    .attr   = _attr,                                  \
+  }
+
+/* Reference to the MPU configuration.
+ *
+ * This struct is defined and populated for each SoC (in the SoC definition),
+ * and holds the build-time configuration information for the fixed MPU
+ * regions enabled during kernel initialization.
+ */
+
+extern const struct arm64_mpu_config mpu_config;
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+void arm64_mpu_init(bool is_primary_core);
+
+#endif  /* __ASSEMBLY__ */
+
+#endif  /* __ARCH_ARM64_SRC_COMMON_ARM64_MPU_H */
diff --git a/arch/arm64/src/qemu/qemu_boot.c b/arch/arm64/src/qemu/qemu_boot.c
index 3859e37f55..aff6461b2f 100644
--- a/arch/arm64/src/qemu/qemu_boot.c
+++ b/arch/arm64/src/qemu/qemu_boot.c
@@ -70,6 +70,26 @@ const struct arm_mmu_config mmu_config =
  * Public Functions
  ****************************************************************************/
 
+/****************************************************************************
+ * Name: arm64_el_init
+ *
+ * Description:
+ *   The function called from arm64_head.S at very early stage for these
+ * platform, it's use to:
+ *   - Handling special hardware initialize routine which is need to
+ *     run at high ELs
+ *   - Initialize system software such as hypervisor or security firmware
+ *     which is need to run at high ELs
+ *
+ ****************************************************************************/
+
+void arm64_el_init(void)
+{
+  write_sysreg(CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC, cntfrq_el0);
+
+  ARM64_ISB();
+}
+
 /****************************************************************************
  * Name: arm64_chip_boot
  *
diff --git a/arch/arm64/src/qemu/qemu_boot.h b/arch/arm64/src/qemu/qemu_boot.h
index 3bee81edb1..b61c89a336 100644
--- a/arch/arm64/src/qemu/qemu_boot.h
+++ b/arch/arm64/src/qemu/qemu_boot.h
@@ -34,6 +34,12 @@
 #include "arm64_internal.h"
 #include "arm64_arch.h"
 
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC  62500000
+
 /****************************************************************************
  * Public Function Prototypes
  ****************************************************************************/
diff --git a/arch/arm64/src/qemu/qemu_serial.c b/arch/arm64/src/qemu/qemu_serial.c
index 4af6611e24..6f5d295a6b 100644
--- a/arch/arm64/src/qemu/qemu_serial.c
+++ b/arch/arm64/src/qemu/qemu_serial.c
@@ -612,7 +612,6 @@ static int qemu_pl011_attach(struct uart_dev_s *dev)
   data  = &sport->data;
 
   ret = irq_attach(sport->irq_num, qemu_pl011_irq_handler, dev);
-  arm64_gic_irq_set_priority(sport->irq_num, IRQ_TYPE_LEVEL, 0);
 
   if (ret == OK)
     {