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 */ + /* TODO: Some arrch64 Cortex-A core maybe without security state + * it has different GIC configure with standard arrch64 A or R core + */ - 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 +#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 +#include +#include +#include + +#include +#include +#include + +#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 +#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) {