* arch/arm64/src/common/arm64_arch.h
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
#ifndef ___ARCH_ARM64_SRC_COMMON_ARM64_ARCH_H
#define ___ARCH_ARM64_SRC_COMMON_ARM64_ARCH_H
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <arch/arch.h>
* assembly language).
*/
#ifndef __ASSEMBLY__
#include <stdint.h>
#include <nuttx/nuttx.h>
#endif
#include <sys/param.h>
#include <nuttx/bits.h>
#include <arch/barriers.h>
* Pre-processor Definitions
****************************************************************************/
#define DAIFSET_FIQ_BIT BIT(0)
#define DAIFSET_IRQ_BIT BIT(1)
#define DAIFSET_ABT_BIT BIT(2)
#define DAIFSET_DBG_BIT BIT(3)
#define DAIFCLR_FIQ_BIT BIT(0)
#define DAIFCLR_IRQ_BIT BIT(1)
#define DAIFCLR_ABT_BIT BIT(2)
#define DAIFCLR_DBG_BIT BIT(3)
#define DAIF_FIQ_BIT BIT(6)
#define DAIF_IRQ_BIT BIT(7)
#define DAIF_ABT_BIT BIT(8)
#define DAIF_DBG_BIT BIT(9)
#define DAIF_MASK (0xf << 6)
* ( DDI 0595, ID121321 ), defined:
*
* SCTLR_EL1: System Control Register (EL1)
* SCTLR_EL2: System Control Register (EL2)
* SCTLR_EL3: System Control Register (EL3)
*
*/
#define SCTLR_EL3_RES1 (BIT(29) | BIT(28) | BIT(23) | \
BIT(22) | BIT(18) | BIT(16) | \
BIT(11) | BIT(5) | BIT(4))
#define SCTLR_EL2_RES1 (BIT(29) | BIT(28) | BIT(23) | \
BIT(22) | BIT(18) | BIT(16) | \
BIT(11) | BIT(5) | BIT(4))
#define SCTLR_EL1_RES1 (BIT(29) | BIT(28) | BIT(23) | \
BIT(22) | BIT(20) | BIT(11))
#define SCTLR_M_BIT BIT(0)
#define SCTLR_A_BIT BIT(1)
#define SCTLR_C_BIT BIT(2)
#define SCTLR_SA_BIT BIT(3)
#define SCTLR_I_BIT BIT(12)
#define SCTLR_BR_BIT BIT(17)
* due to loads and stores in EL0 EL1.
*/
#define SCTLR_TCF0_BIT BIT(38)
#define SCTLR_TCF1_BIT BIT(40)
#define SCTLR_ATA0_BIT BIT(42)
#define SCTLR_ATA_BIT BIT(43)
#define ACTLR_AUX_BIT BIT(9)
#define ACTLR_CLPORTS_BIT BIT(8)
#define ACTLR_CLPMU_BIT BIT(7)
#define ACTLR_TESTR1_BIT BIT(6)
#define ACTLR_CDBG_BIT BIT(5)
#define ACTLR_PATCH_BIT BIT(4)
#define ACTLR_BPRED_BIT BIT(3)
#define ACTLR_POWER_BIT BIT(2)
#define ACTLR_DIAGNOSTIC_BIT BIT(1)
#define ACTLR_REGIONS_BIT BIT(0)
*
* Arm® Architecture Registers Armv8, for Armv8-A architecture profile
* ( DDI 0595, ID121321 ), defined:
* SPSR_EL1: Saved Program Status Register (EL1)
* SPSR_EL2: Saved Program Status Register (EL2)
* SPSR_EL3: Saved Program Status Register (EL3)
*
* reference to Programmer’s Guide for ARMv8-A
* (ARM DEN0024A, ID050815 ), 4.1.2 Stack pointer
*
* The T suffix, indicates use of the SP_EL0 stack pointer.
* The H suffix, indicates use of the SP_ELx stack pointer.
*
*/
#define SPSR_DAIF_SHIFT (6)
#define SPSR_DAIF_MASK (0xf << SPSR_DAIF_SHIFT)
#define SPSR_MODE_EL0T (0x0)
#define SPSR_MODE_EL1T (0x4)
#define SPSR_MODE_EL1H (0x5)
#define SPSR_MODE_EL2T (0x8)
#define SPSR_MODE_EL2H (0x9)
#define SPSR_MODE_EL3T (0xc)
#define SPSR_MODE_EL3H (0xd)
#define SPSR_MODE_MASK (0xf)
#define RGSR_EL1_TAG_MASK 0xfUL
#define RGSR_EL1_SEED_SHIFT 8
#define RGSR_EL1_SEED_MASK 0xffffUL
#define TTBR_CNP_BIT BIT(0)
#define MODE_EL_SHIFT (0x2)
#define MODE_EL_MASK (0x3)
#define MODE_EL3 (0x3)
#define MODE_EL2 (0x2)
#define MODE_EL1 (0x1)
#define MODE_EL0 (0x0)
#ifndef __ASSEMBLY__
* Pre-processor Definitions
****************************************************************************/
#define GET_EL(mode) (((mode) >> MODE_EL_SHIFT) & MODE_EL_MASK)
#define MPIDR_ID_MASK (0xff00ffffff)
#define MPIDR_AFFLVL(mpidr, aff_level) \
(((mpidr) >> MPIDR_AFF ## aff_level ## _SHIFT) & MPIDR_AFFLVL_MASK)
#define CORE_TO_MPID(core, aff_level) \
({ \
uint64_t __mpidr = GET_MPIDR(); \
__mpidr &= ~(MPIDR_AFFLVL_MASK << MPIDR_AFF ## aff_level ## _SHIFT); \
__mpidr |= ((core) << MPIDR_AFF ## aff_level ## _SHIFT); \
__mpidr &= MPIDR_ID_MASK; \
__mpidr; \
})
#define ICC_IGRPEN1_EL1 S3_0_C12_C12_7
#define ICC_SGI1R S3_0_C12_C11_5
#define ICC_SRE_EL1 S3_0_C12_C12_5
#define ICC_SRE_EL2 S3_4_C12_C9_5
#define ICC_SRE_EL3 S3_6_C12_C12_5
#define ICC_CTLR_EL1 S3_0_C12_C12_4
#define ICC_CTLR_EL3 S3_6_C12_C12_4
#define ICC_PMR_EL1 S3_0_C4_C6_0
#define ICC_RPR_EL1 S3_0_C12_C11_3
#define ICC_IGRPEN1_EL3 S3_6_C12_C12_7
#define ICC_IGRPEN0_EL1 S3_0_C12_C12_6
#define ICC_HPPIR0_EL1 S3_0_C12_C8_2
#define ICC_HPPIR1_EL1 S3_0_C12_C12_2
#define ICC_IAR0_EL1 S3_0_C12_C8_0
#define ICC_IAR1_EL1 S3_0_C12_C12_0
#define ICC_EOIR0_EL1 S3_0_C12_C8_1
#define ICC_EOIR1_EL1 S3_0_C12_C12_1
#define ICC_SGI0R_EL1 S3_0_C12_C11_7
#define ICC_SRE_ELX_SRE_BIT BIT(0)
#define ICC_SRE_ELX_DFB_BIT BIT(1)
#define ICC_SRE_ELX_DIB_BIT BIT(2)
#define ICC_SRE_EL3_EN_BIT BIT(3)
#define SGIR_TGT_MASK (0xffff)
#define SGIR_AFF1_SHIFT (16)
#define SGIR_AFF2_SHIFT (32)
#define SGIR_AFF3_SHIFT (48)
#define SGIR_AFF_MASK (0xf)
#define SGIR_INTID_SHIFT (24)
#define SGIR_INTID_MASK (0xf)
#define SGIR_IRM_SHIFT (40)
#define SGIR_IRM_MASK (0x1)
#define SGIR_IRM_TO_AFF (0)
#define SGIR_IRM_TO_ALL (1)
#define GICV3_SGIR_VALUE(_aff3, _aff2, _aff1, _intid, _irm, _tgt) \
((((uint64_t)(_aff3) & SGIR_AFF_MASK) << SGIR_AFF3_SHIFT) | \
(((uint64_t)(_irm) & SGIR_IRM_MASK) << SGIR_IRM_SHIFT) | \
(((uint64_t)(_aff2) & SGIR_AFF_MASK) << SGIR_AFF2_SHIFT) | \
(((_intid) & SGIR_INTID_MASK) << SGIR_INTID_SHIFT) | \
(((_aff1) & SGIR_AFF_MASK) << SGIR_AFF1_SHIFT) | \
((_tgt) & SGIR_TGT_MASK))
#define CPTR_EZ_BIT BIT(8)
#define CPTR_TFP_BIT BIT(10)
#define CPTR_TTA_BIT BIT(20)
#define CPTR_TCPAC_BIT BIT(31)
#define CPTR_EL2_RES1 BIT(13) | BIT(12) | BIT(9) | (0xff)
#define CPACR_EL1_FPEN_NOTRAP (0x3 << 20)
#define SCR_NS_BIT BIT(0)
#define SCR_IRQ_BIT BIT(1)
#define SCR_FIQ_BIT BIT(2)
#define SCR_EA_BIT BIT(3)
#define SCR_SMD_BIT BIT(7)
#define SCR_HCE_BIT BIT(8)
#define SCR_RW_BIT BIT(10)
#define SCR_ST_BIT BIT(11)
#define SCR_RES1 (BIT(4) | BIT(5))
#define HCR_FMO_BIT BIT(3)
#define HCR_IMO_BIT BIT(4)
#define HCR_AMO_BIT BIT(5)
#define HCR_RW_BIT BIT(31)
#define HCR_ATA_BIT BIT(56)
#define CNTHCTL_EL2_EL1PCEN_EN BIT(1)
#define CNTHCTL_EL2_EL1PCTEN_EN BIT(0)
* CNTV_CTL, Counter-timer Virtual Timer Control register
*/
#define CNTV_CTL_ENABLE_BIT BIT(0)
#define CNTV_CTL_IMASK_BIT BIT(1)
* This option specifies the maximum numbers of translation tables
* excluding the base translation table. Based on this, translation
* tables are allocated at compile time and used at runtime as needed.
* If the runtime need exceeds preallocated numbers of translation
* tables, it will result in assert. Number of translation tables
* required is decided based on how many discrete memory regions
* (both normal and device memory) are present on given platform and
* how much granularity is required while assigning attributes
* to these memory regions.
*/
#define L1_CACHE_SHIFT (6)
#define L1_CACHE_BYTES BIT(L1_CACHE_SHIFT)
* Public Function Prototypes
****************************************************************************/
* Name:
* getreg8/16/32/64
* putreg8/16/32/64
*
* Description:
* We need to use explicit assembler instruction there, because with
* classic "volatile pointer" approach compiler might generate
* instruction with immediate value like
*
* str w4, [x1], #4
*
* Such instructions produce invalid syndrome in HSR register,
* so hypervisor can't emulate MMIO when it traps memory access.
*
****************************************************************************/
static inline uint8_t getreg8(unsigned long addr)
{
uint8_t val;
__asm__ volatile ("ldrb %w0, [%1]" : "=r" (val) : "r" (addr));
UP_DMB();
return val;
}
static inline void putreg8(uint8_t data, unsigned long addr)
{
UP_DMB();
__asm__ volatile ("strb %w0, [%1]" : : "r" (data), "r" (addr));
}
static inline uint16_t getreg16(unsigned long addr)
{
uint16_t val;
__asm__ volatile ("ldrh %w0, [%1]" : "=r" (val) : "r" (addr));
UP_DMB();
return val;
}
static inline void putreg16(uint16_t data, unsigned long addr)
{
UP_DMB();
__asm__ volatile ("strh %w0, [%1]" : : "r" (data), "r" (addr));
}
static inline uint32_t getreg32(unsigned long addr)
{
uint32_t val;
__asm__ volatile ("ldr %w0, [%1]" : "=r" (val) : "r" (addr));
UP_DMB();
return val;
}
static inline void putreg32(uint32_t data, unsigned long addr)
{
UP_DMB();
__asm__ volatile ("str %w0, [%1]" : : "r" (data), "r" (addr));
}
static inline uint64_t getreg64(unsigned long addr)
{
uint64_t val;
__asm__ volatile ("ldr %x0, [%1]" : "=r" (val) : "r" (addr));
UP_DMB();
return val;
}
static inline void putreg64(uint64_t data, unsigned long addr)
{
UP_DMB();
__asm__ volatile ("str %x0, [%1]" : : "r" (data), "r" (addr));
}
static inline void arch_nop(void)
{
__asm__ volatile ("nop");
}
* Name:
* arm64_current_el()
*
* Description:
*
* Get current execution level
*
****************************************************************************/
#define arm64_current_el() \
({ \
uint64_t __el; \
int __ret; \
__asm__ volatile ("mrs %0, CurrentEL" \
: "=r" (__el)); \
__ret = GET_EL(__el); \
__ret; \
})
#define modreg8(v,m,a) putreg8((getreg8(a) & ~(m)) | ((v) & (m)), (a))
#define modreg16(v,m,a) putreg16((getreg16(a) & ~(m)) | ((v) & (m)), (a))
#define modreg32(v,m,a) putreg32((getreg32(a) & ~(m)) | ((v) & (m)), (a))
void modifyreg8(unsigned int addr, uint8_t clearbits, uint8_t setbits);
void modifyreg16(unsigned int addr, uint16_t clearbits, uint16_t setbits);
void modifyreg32(unsigned int addr, uint32_t clearbits, uint32_t setbits);
void arch_cpu_idle(void);
* Name: arm64_cpu_disable
*
* Description:
* Called from CPU0 to make sure that all other CPUs are in the disabled
* state. This is a formality because the other CPUs are actually running
* then we have probably already crashed.
*
* Input Parameters:
* None
*
* Returned Value:
* None
*
****************************************************************************/
#ifdef CONFIG_SMP
void arm64_cpu_disable(void);
#else
# define arm64_cpu_disable()
#endif
* Name: arm64_cpu_enable
*
* Description:
* Called from CPU0 to enable all other CPUs. The enabled CPUs will start
* execution at __cpuN_start and, after very low-level CPU initialization
* has been performed, will branch to arm_cpu_boot()
*
* Input Parameters:
* None
*
* Returned Value:
* None
*
****************************************************************************/
#ifdef CONFIG_SMP
void arm64_cpu_enable(void);
#else
# define arm64_cpu_enable()
#endif
* Name: arm64_get_mpid
*
* Description:
* The function from cpu index to get cpu mpid which is reading
* from mpidr_el1 register. Different ARM64 Core will use different
* Affn define, the mpidr_el1 value is not CPU number, So we need
* to change CPU number to mpid and vice versa
*
****************************************************************************/
#ifdef CONFIG_ARCH_HAVE_MULTICPU
uint64_t arm64_get_mpid(int cpu);
#else
# define arm64_get_mpid(cpu) ((void)(cpu), (GET_MPIDR() & MPIDR_ID_MASK))
#endif
* Name: arm64_get_cpuid
*
* Description:
* The function from mpid to get cpu id
*
****************************************************************************/
#ifdef CONFIG_ARCH_HAVE_MULTICPU
int arm64_get_cpuid(uint64_t mpid);
#endif
* Name: arm64_mte_init
*
* Description:
* Initialize MTE settings and enable memory tagging
*
****************************************************************************/
void arm64_mte_init(void);
#endif
#endif