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)
{