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 <qinwei1@xiaomi.com>
This commit is contained in:
qinwei1 2023-02-28 17:01:24 +08:00 committed by Xiang Xiao
parent 4240723b78
commit 0841f4dbaa
16 changed files with 761 additions and 42 deletions

View File

@ -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

View File

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

View File

@ -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
*

View File

@ -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

View File

@ -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);

View File

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

View File

@ -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;

View File

@ -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:
{

View File

@ -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 */

View File

@ -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 " : "");

View File

@ -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 */

View File

@ -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();
}

View File

@ -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 */

View File

@ -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
*

View File

@ -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
****************************************************************************/

View File

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