diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 613c15199f0..9e1d3113826 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -936,6 +936,14 @@ config ARCH_CORTEXM85 select ARCH_HAVE_USAGEFAULT_DEBUG select ARCH_HAVE_SECUREFAULT_DEBUG if ARCH_TRUSTZONE_SECURE +config ARCH_ARMV8R + bool + default n + select ARCH_HAVE_CPUINFO + select ONESHOT + select ALARM_ARCH + + config ARCH_FAMILY string default "arm" if ARCH_ARM7TDMI || ARCH_ARM920T || ARCH_ARM926EJS || ARCH_ARM1136J || ARCH_ARM1156T2 || ARCH_ARM1176JZ @@ -1321,6 +1329,9 @@ endif if ARCH_ARMV8M source "arch/arm/src/armv8-m/Kconfig" endif +if ARCH_ARMV8R +source "arch/arm/src/armv8-r/Kconfig" +endif if ARCH_ARM7TDMI || ARCH_ARM920T || ARCH_ARM926EJS || ARCH_ARM1136J || ARCH_ARM1156T2 || ARCH_ARM1176JZ source "arch/arm/src/arm/Kconfig" endif diff --git a/arch/arm/include/armv8-r/irq.h b/arch/arm/include/armv8-r/irq.h new file mode 100644 index 00000000000..f0ca5e0fbd4 --- /dev/null +++ b/arch/arm/include/armv8-r/irq.h @@ -0,0 +1,430 @@ +/**************************************************************************** + * arch/arm/include/armv8-r/irq.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. + * + ****************************************************************************/ + +/* This file should never be included directly but, rather, only indirectly + * through nuttx/irq.h + */ + +#ifndef __ARCH_ARM_INCLUDE_ARMV8_R_IRQ_H +#define __ARCH_ARM_INCLUDE_ARMV8_R_IRQ_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#ifndef __ASSEMBLY__ +# include +#endif + +/**************************************************************************** + * Pre-processor Prototypes + ****************************************************************************/ + +/* IRQ Stack Frame Format: + * + * Context is always saved/restored in the same way: + * + * (1) stmia rx, {r0-r14} + * (2) then the PC and CPSR + * + * This results in the following set of indices that can be used to access + * individual registers in the xcp.regs array: + */ + +/* If the MCU supports a floating point unit, then it will be necessary + * to save the state of the FPU status register and data registers on + * each context switch. These registers are not saved during interrupt + * level processing, however. So, as a consequence, floating point + * operations may NOT be performed in interrupt handlers. + * + * The FPU provides an extension register file containing 32 single- + * precision registers. These can be viewed as: + * + * - Sixteen 64-bit double word registers, D0-D15 + * - Thirty-two 32-bit single-word registers, S0-S31 + * S<2n> maps to the least significant half of D + * S<2n+1> maps to the most significant half of D. + */ + +#ifdef CONFIG_ARCH_FPU +# define REG_D0 (0) /* D0 */ +# define REG_S0 (0) /* S0 */ +# define REG_S1 (1) /* S1 */ +# define REG_D1 (2) /* D1 */ +# define REG_S2 (2) /* S2 */ +# define REG_S3 (3) /* S3 */ +# define REG_D2 (4) /* D2 */ +# define REG_S4 (4) /* S4 */ +# define REG_S5 (5) /* S5 */ +# define REG_D3 (6) /* D3 */ +# define REG_S6 (6) /* S6 */ +# define REG_S7 (7) /* S7 */ +# define REG_D4 (8) /* D4 */ +# define REG_S8 (8) /* S8 */ +# define REG_S9 (9) /* S9 */ +# define REG_D5 (10) /* D5 */ +# define REG_S10 (10) /* S10 */ +# define REG_S11 (11) /* S11 */ +# define REG_D6 (12) /* D6 */ +# define REG_S12 (12) /* S12 */ +# define REG_S13 (13) /* S13 */ +# define REG_D7 (14) /* D7 */ +# define REG_S14 (14) /* S14 */ +# define REG_S15 (15) /* S15 */ +# define REG_D8 (16) /* D8 */ +# define REG_S16 (16) /* S16 */ +# define REG_S17 (17) /* S17 */ +# define REG_D9 (18) /* D9 */ +# define REG_S18 (18) /* S18 */ +# define REG_S19 (19) /* S19 */ +# define REG_D10 (20) /* D10 */ +# define REG_S20 (20) /* S20 */ +# define REG_S21 (21) /* S21 */ +# define REG_D11 (22) /* D11 */ +# define REG_S22 (22) /* S22 */ +# define REG_S23 (23) /* S23 */ +# define REG_D12 (24) /* D12 */ +# define REG_S24 (24) /* S24 */ +# define REG_S25 (25) /* S25 */ +# define REG_D13 (26) /* D13 */ +# define REG_S26 (26) /* S26 */ +# define REG_S27 (27) /* S27 */ +# define REG_D14 (28) /* D14 */ +# define REG_S28 (28) /* S28 */ +# define REG_S29 (29) /* S29 */ +# define REG_D15 (30) /* D15 */ +# define REG_S30 (30) /* S30 */ +# define REG_S31 (31) /* S31 */ +# ifdef CONFIG_ARM_HAVE_DPFPU32 +# define REG_D16 (32) /* D16 */ +# define REG_D17 (34) /* D17 */ +# define REG_D18 (36) /* D18 */ +# define REG_D19 (38) /* D19 */ +# define REG_D20 (40) /* D20 */ +# define REG_D21 (42) /* D21 */ +# define REG_D22 (44) /* D22 */ +# define REG_D23 (46) /* D23 */ +# define REG_D24 (48) /* D24 */ +# define REG_D25 (50) /* D25 */ +# define REG_D26 (52) /* D26 */ +# define REG_D27 (54) /* D27 */ +# define REG_D28 (56) /* D28 */ +# define REG_D29 (58) /* D29 */ +# define REG_D30 (60) /* D30 */ +# define REG_D31 (62) /* D31 */ +# define REG_FPSCR (64) /* Floating point status and control */ +# define FPU_CONTEXT_REGS (65) +# else +# define REG_FPSCR (32) /* Floating point status and control */ +# define FPU_CONTEXT_REGS (33) +# endif +#else +# define FPU_CONTEXT_REGS (0) +#endif + +#define REG_R13 (FPU_CONTEXT_REGS+0) +#define REG_R14 (FPU_CONTEXT_REGS+1) +#define REG_R0 (FPU_CONTEXT_REGS+2) +#define REG_R1 (FPU_CONTEXT_REGS+3) +#define REG_R2 (FPU_CONTEXT_REGS+4) +#define REG_R3 (FPU_CONTEXT_REGS+5) +#define REG_R4 (FPU_CONTEXT_REGS+6) +#define REG_R5 (FPU_CONTEXT_REGS+7) +#define REG_R6 (FPU_CONTEXT_REGS+8) +#define REG_R7 (FPU_CONTEXT_REGS+9) +#define REG_R8 (FPU_CONTEXT_REGS+10) +#define REG_R9 (FPU_CONTEXT_REGS+11) +#define REG_R10 (FPU_CONTEXT_REGS+12) +#define REG_R11 (FPU_CONTEXT_REGS+13) +#define REG_R12 (FPU_CONTEXT_REGS+14) +#define REG_R15 (FPU_CONTEXT_REGS+15) +#define REG_CPSR (FPU_CONTEXT_REGS+16) + +#define ARM_CONTEXT_REGS (17) + +/* The total number of registers saved by software */ + +#define XCPTCONTEXT_REGS (FPU_CONTEXT_REGS + ARM_CONTEXT_REGS) +#define XCPTCONTEXT_SIZE (4 * XCPTCONTEXT_REGS) + +/* Friendly register names */ + +#define REG_A1 REG_R0 +#define REG_A2 REG_R1 +#define REG_A3 REG_R2 +#define REG_A4 REG_R3 +#define REG_V1 REG_R4 +#define REG_V2 REG_R5 +#define REG_V3 REG_R6 +#define REG_V4 REG_R7 +#define REG_V5 REG_R8 +#define REG_V6 REG_R9 +#define REG_V7 REG_R10 +#define REG_SB REG_R9 +#define REG_SL REG_R10 +#ifdef CONFIG_ARM_THUMB + #define REG_FP REG_R7 +#else + #define REG_FP REG_R11 +#endif /* CONFIG_ARM_THUMB */ +#define REG_IP REG_R12 +#define REG_SP REG_R13 +#define REG_LR REG_R14 +#define REG_PC REG_R15 + +/* The PIC register is usually R10. It can be R9 is stack checking is enabled + * or if the user changes it with -mpic-register on the GCC command line. + */ + +#define REG_PIC REG_R10 + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +/* This structure represents the return state from a system call */ + +#ifdef CONFIG_LIB_SYSCALL +struct xcpt_syscall_s +{ +#ifdef CONFIG_BUILD_KERNEL + uint32_t cpsr; /* The CPSR value */ +#endif + uint32_t sysreturn; /* The return PC */ +}; +#endif + +/* This struct defines the way the registers are stored. We need to save: + * + * 1 CPSR + * 7 Static registers, v1-v7 (aka r4-r10) + * 1 Frame pointer, fp (aka r11) + * 1 Stack pointer, sp (aka r13) + * 1 Return address, lr (aka r14) + * --- + * 11 (XCPTCONTEXT_USER_REG) + * + * On interrupts, we also need to save: + * 4 Volatile registers, a1-a4 (aka r0-r3) + * 1 Scratch Register, ip (aka r12) + *--- + * 5 (XCPTCONTEXT_IRQ_REGS) + * + * For a total of 17 (XCPTCONTEXT_REGS) + */ + +#ifndef __ASSEMBLY__ +struct xcptcontext +{ + /* The following function pointer is non-zero if there are pending signals + * to be processed. + */ + + void *sigdeliver; /* Actual type is sig_deliver_t */ + + /* These are saved copies of the context used during + * signal processing. + */ + + uint32_t *saved_regs; + +#ifdef CONFIG_BUILD_KERNEL + /* This is the saved address to use when returning from a user-space + * signal handler. + */ + + uint32_t sigreturn; +#endif + + /* Register save area with XCPTCONTEXT_SIZE, only valid when: + * 1.The task isn't running or + * 2.The task is interrupted + * otherwise task is running, and regs contain the stale value. + */ + + uint32_t *regs; + + /* Extra fault address register saved for common paging logic. In the + * case of the pre-fetch abort, this value is the same as regs[REG_R15]; + * For the case of the data abort, this value is the value of the fault + * address register (FAR) at the time of data abort exception. + */ + +#ifdef CONFIG_PAGING + uintptr_t far; +#endif + +#ifdef CONFIG_LIB_SYSCALL + /* The following array holds the return address and the exc_return value + * needed to return from each nested system call. + */ + + uint8_t nsyscalls; + struct xcpt_syscall_s syscall[CONFIG_SYS_NNEST]; +#endif + +#ifdef CONFIG_ARCH_ADDRENV +#ifdef CONFIG_ARCH_STACK_DYNAMIC + /* This array holds the physical address of the level 2 page table used + * to map the thread's stack memory. This array will be initially of + * zeroed and would be back-up up with pages during page fault exception + * handling to support dynamically sized stacks for each thread. + */ + + uintptr_t *ustack[ARCH_STACK_NSECTS]; +#endif + +#ifdef CONFIG_ARCH_KERNEL_STACK + /* In this configuration, all syscalls execute from an internal kernel + * stack. Why? Because when we instantiate and initialize the address + * environment of the new user process, we will temporarily lose the + * address environment of the old user process, including its stack + * contents. The kernel C logic will crash immediately with no valid + * stack in place. + */ + + uint32_t *ustkptr; /* Saved user stack pointer */ + uint32_t *kstack; /* Allocate base of the (aligned) kernel stack */ + uint32_t *kstkptr; /* Saved kernel stack pointer */ +#endif +#endif +}; +#endif + +#endif /* __ASSEMBLY__ */ + +/**************************************************************************** + * Inline functions + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +/* Name: up_irq_save, up_irq_restore, and friends. + * + * NOTE: This function should never be called from application code and, + * as a general rule unless you really know what you are doing, this + * function should not be called directly from operation system code either: + * Typically, the wrapper functions, enter_critical_section() and + * leave_critical section(), are probably what you really want. + */ + +/* Return the current IRQ state */ + +static inline irqstate_t irqstate(void) +{ + unsigned int cpsr; + + __asm__ __volatile__ + ( + "\tmrs %0, cpsr\n" + : "=r" (cpsr) + : + : "memory" + ); + + return cpsr; +} + +/* Disable IRQs and return the previous IRQ state */ + +static inline irqstate_t up_irq_save(void) +{ + unsigned int cpsr; + + __asm__ __volatile__ + ( + "\tmrs %0, cpsr\n" + "\tcpsid i\n" +#if defined(CONFIG_ARMV7R_DECODEFIQ) + "\tcpsid f\n" +#endif + : "=r" (cpsr) + : + : "memory" + ); + + return cpsr; +} + +/* Enable IRQs and return the previous IRQ state */ + +static inline irqstate_t up_irq_enable(void) +{ + unsigned int cpsr; + + __asm__ __volatile__ + ( + "\tmrs %0, cpsr\n" + "\tcpsie i\n" +#if defined(CONFIG_ARMV7R_DECODEFIQ) + "\tcpsie f\n" +#endif + : "=r" (cpsr) + : + : "memory" + ); + + return cpsr; +} + +/* Restore saved IRQ & FIQ state */ + +static inline void up_irq_restore(irqstate_t flags) +{ + __asm__ __volatile__ + ( + "msr cpsr_c, %0" + : + : "r" (flags) + : "memory" + ); +} + +#endif /* __ASSEMBLY__ */ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#ifndef __ASSEMBLY__ +#ifdef __cplusplus +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#undef EXTERN +#ifdef __cplusplus +} +#endif +#endif + +#endif /* __ARCH_ARM_INCLUDE_ARMV8_R_IRQ_H */ diff --git a/arch/arm/include/irq.h b/arch/arm/include/irq.h index 1fac0e1e55c..4d44388b756 100644 --- a/arch/arm/include/irq.h +++ b/arch/arm/include/irq.h @@ -50,6 +50,8 @@ # include #elif defined(CONFIG_ARCH_ARMV7R) # include +#elif defined(CONFIG_ARCH_ARMV8R) +# include #elif defined(CONFIG_ARCH_ARMV7M) # include #elif defined(CONFIG_ARCH_ARMV8M) diff --git a/arch/arm/src/Makefile b/arch/arm/src/Makefile index 4e0c7b77671..1a4b5c272f5 100644 --- a/arch/arm/src/Makefile +++ b/arch/arm/src/Makefile @@ -25,6 +25,8 @@ ifeq ($(CONFIG_ARCH_ARMV7A),y) # ARMv7-A ARCH_SUBDIR = armv7-a else ifeq ($(CONFIG_ARCH_ARMV7R),y) # ARMv7-R ARCH_SUBDIR = armv7-r +else ifeq ($(CONFIG_ARCH_ARMV8R),y) # ARMv8-R +ARCH_SUBDIR = armv8-r else ifeq ($(CONFIG_ARCH_ARMV7M),y) # ARMv7-M ARCH_SUBDIR = armv7-m else ifeq ($(CONFIG_ARCH_ARMV8M),y) # ARMv8-M diff --git a/arch/arm/src/armv8-r/Kconfig b/arch/arm/src/armv8-r/Kconfig new file mode 100644 index 00000000000..412f51bb18f --- /dev/null +++ b/arch/arm/src/armv8-r/Kconfig @@ -0,0 +1,87 @@ +# +# For a description of the syntax of this configuration file, +# see the file kconfig-language.txt in the NuttX tools repository. +# + +comment "ARMv8-R Configuration Options" + +config ARMV8R_HAVE_GICv3 + bool "ARMV7R_GICv3 support" + select ARCH_HAVE_IRQTRIGGER + default y + ---help--- + Selected by the configuration tool if the architecture supports the + Generic Interrupt Controller (GIC) + +if ARMV8R_HAVE_GICv2 + +config ARMV8R_GIC_EOIMODE + bool + default n + ---help--- + Enable GICC_CTLR.EOImode, this will separates the priority drop and interrupt + deactivation operations. + +endif # ARMV8R_GIC_EOIMODE + +config ARMV8R_MEMINIT + bool + default y if BOOT_SDRAM_DATA + default n if !BOOT_SDRAM_DATA + ---help--- + If this configuration *not* selected, then it is assumed that all + memory resources are initialized via arm_data_initialize() and + available at power-up reset time. Other memories, such as SDRAM or + some ECC SRAM memories, require some platform-specific + initialization first. In that case, this option should be selected + and the platform-specific implementation of arm_boot() must perform + the memory initialization first, then explicitly call + arm_data_initialize(). + +config ARMV8R_HAVE_DECODEFIQ + bool + default n + +config ARMV8R_DECODEFIQ + bool "FIQ Handler" + default n + depends on ARMV7R_HAVE_DECODEFIQ + ---help--- + Select this option if your platform supports the function + arm_decodefiq(). + +config ARMV8R_ALIGNMENT_TRAP + bool "Enable Alignment Check at __start" + default n + +config ARMV8R_CACHE_ROUND_ROBIN + bool "Enable Cache Round Robin Replacement Policy at __start" + default n + +config ARMV8R_DCACHE_DISABLE + bool "Disable DCACHE at __start" + default n + +config ARMV8R_ICACHE_DISABLE + bool "Disable ICACHE at __start" + default n + +config ARMV8R_SCTLR_CCP15BEN + bool "Enable CP15 Barrier at __start" + default y + +config ARMV8R_BACKGROUND_REGION + bool "Enable MPU Background region at __start" + default y + +config ARMV8R_DIV0_FAULT + bool "Enable DIV0 Fault at __start" + default n + +config ARMV8R_FAST_INTERRUPT + bool "Enable Fast Interrupts at __start" + default n + +config ARMV8R_NONMASKABLE_FIQ + bool "Enable Non-maskable FIQ Support at __start" + default n diff --git a/arch/arm/src/armv8-r/Make.defs b/arch/arm/src/armv8-r/Make.defs new file mode 100644 index 00000000000..617afec2522 --- /dev/null +++ b/arch/arm/src/armv8-r/Make.defs @@ -0,0 +1,52 @@ +############################################################################ +# arch/arm/src/armv8-r/Make.defs +# +# 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. +# +############################################################################ + +# Common ARM files + +include common/Make.defs + +# The vector table is the "head" object, i.e., the one that must forced into +# the link in order to draw in all of the other components + +HEAD_ASRC += arm_vectortab.S + +# Common assembly language files + +CMN_CSRCS += arm_arch_timer.c arm_cache.c arm_cpuinfo.c arm_dataabort.c +CMN_CSRCS += arm_doirq.c arm_gicv3.c +CMN_CSRCS += arm_initialstate.c arm_prefetchabort.c +CMN_CSRCS += arm_schedulesigaction.c arm_sigdeliver.c +CMN_CSRCS += arm_syscall.c arm_tcbinfo.c arm_undefinedinsn.c +CMN_CSRCS += arm_perf.c cp15_cacheops.c + +# Common C source files + +CMN_ASRCS += arm_head.S arm_vectoraddrexcptn.S arm_vectors.S +CMN_ASRCS += arm_saveusercontext.S + +# ifeq ($(CONFIG_BUILD_PROTECTED),y) +# CMN_CSRCS += arm_mpu.c +# endif + +# ifeq ($(CONFIG_ARCH_FPU),y) +# CMN_CSRCS += arm_fpucmp.c +# CMN_ASRCS += arm_fpuconfig.S +# endif + diff --git a/arch/arm/src/armv8-r/Toolchain.defs b/arch/arm/src/armv8-r/Toolchain.defs new file mode 100644 index 00000000000..a7927f18bb1 --- /dev/null +++ b/arch/arm/src/armv8-r/Toolchain.defs @@ -0,0 +1,36 @@ +############################################################################ +# arch/arm/src/armv8-r/Toolchain.defs +# +# 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. +# +############################################################################ + +ARCHCPUFLAGS += -march=armv8-r + +ifeq ($(CONFIG_ARCH_FPU),y) + LLVM_ABITYPE := eabihf + ARCHCPUFLAGS += -mfpu=vfpv3-d16 + ifeq ($(CONFIG_ARM_FPU_ABI_SOFT),y) + ARCHCPUFLAGS += -mfloat-abi=softfp + else + ARCHCPUFLAGS += -mfloat-abi=hard + endif +else + LLVM_ABITYPE := eabi + ARCHCPUFLAGS += -mfloat-abi=soft +endif + +include $(TOPDIR)/arch/arm/src/common/Toolchain.defs diff --git a/arch/arm/src/armv8-r/arm.h b/arch/arm/src/armv8-r/arm.h new file mode 100644 index 00000000000..041ba84a995 --- /dev/null +++ b/arch/arm/src/armv8-r/arm.h @@ -0,0 +1,151 @@ +/**************************************************************************** + * arch/arm/src/armv8-r/arm.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. + * + ****************************************************************************/ + +/* References: + * + * "ARM Architecture Reference Manual, ARMv7-A and ARMv7-R edition", + * Copyright 1996-1998, 2000, 2004-2012 ARM. + * All rights reserved. ARM DDI 0406C.c (ID051414) + */ + +#ifndef __ARCH_ARM_SRC_ARMV8_R_ARM_H +#define __ARCH_ARM_SRC_ARMV8_R_ARM_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#ifndef __ASSEMBLY__ +# include +#endif /* __ASSEMBLY__ */ + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define BIT(n) ((1UL) << (n)) +#define BIT64(n) ((1ULL) << (n)) + +/* Bit mask with bits 0 through n-1 (inclusive) set, + * or 0 if n is 0. + */ +#define BIT_MASK(n) (BIT(n) - 1) +#define BIT64_MASK(n) (BIT64(n) - 1ULL) + +/* ARMv8-R ******************************************************************/ + +/* PSR bits */ + +#define PSR_MODE_SHIFT (0) /* Bits 0-4: Mode fields */ +#define PSR_MODE_MASK (31 << PSR_MODE_SHIFT) +# define PSR_MODE_USR (16 << PSR_MODE_SHIFT) /* User mode */ +# define PSR_MODE_FIQ (17 << PSR_MODE_SHIFT) /* FIQ mode */ +# define PSR_MODE_IRQ (18 << PSR_MODE_SHIFT) /* IRQ mode */ +# define PSR_MODE_SVC (19 << PSR_MODE_SHIFT) /* Supervisor mode */ +# define PSR_MODE_ABT (23 << PSR_MODE_SHIFT) /* Abort mode */ +# define PSR_MODE_HYP (26 << PSR_MODE_SHIFT) /* Hypervisor mode */ +# define PSR_MODE_UND (27 << PSR_MODE_SHIFT) /* Undefined mode */ +# define PSR_MODE_SYS (31 << PSR_MODE_SHIFT) /* System mode */ + +#define PSR_T_BIT (1 << 5) /* Bit 5: Thumb execution state bit */ +#define PSR_MASK_SHIFT (6) /* Bits 6-8: Mask Bits */ +#define PSR_MASK_MASK (7 << PSR_GE_SHIFT) +# define PSR_F_BIT (1 << 6) /* Bit 6: FIQ mask bit */ +# define PSR_I_BIT (1 << 7) /* Bit 7: IRQ mask bit */ +# define PSR_A_BIT (1 << 8) /* Bit 8: Asynchronous abort mask */ +#define PSR_E_BIT (1 << 9) /* Bit 9: Endianness execution state bit */ +#define PSR_IT27_SHIFT (10) /* Bits 10-15: If-Then execution state bits IT[2:7] */ +#define PSR_IT27_MASK (0x3f << PSR_IT27_SHIFT) +#define PSR_GE_SHIFT (16) /* Bits 16-19: Greater than or Equal flags */ +#define PSR_GE_MASK (15 << PSR_GE_SHIFT) + /* Bits 20-23: Reserved. RAZ/SBZP */ +#define PSR_J_BIT (1 << 24) /* Bit 24: Jazelle state bit */ +#define PSR_IT01_SHIFT (25) /* Bits 25-26: If-Then execution state bits IT[0:1] */ +#define PSR_IT01_MASK (3 << PSR_IT01_SHIFT) +#define PSR_Q_BIT (1 << 27) /* Bit 27: Cumulative saturation bit */ +#define PSR_V_BIT (1 << 28) /* Bit 28: Overflow condition flag */ +#define PSR_C_BIT (1 << 29) /* Bit 29: Carry condition flag */ +#define PSR_Z_BIT (1 << 30) /* Bit 30: Zero condition flag */ +#define PSR_N_BIT (1 << 31) /* Bit 31: Negative condition flag */ + +/**************************************************************************** + * Inline Functions + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +#endif /* __ASSEMBLY__ */ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#ifndef __ASSEMBLY__ +#ifdef __cplusplus +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Name: arm_boot + * + * Description: + * Complete boot operations started in arm_head.S + * + * Boot Sequence + * + * 1. The __start entry point in armv8-r/arm_head.S is invoked upon power- + * on reset. + * 2. __start prepares CPU for code execution. + * + ****************************************************************************/ + +void arm_boot(void); + +/**************************************************************************** + * Name: arm_data_initialize + * + * Description: + * Clear all of .bss to zero; set .data to the correct initial values. + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +void arm_data_initialize(void); + +#undef EXTERN +#ifdef __cplusplus +} +#endif +#endif /* __ASSEMBLY__ */ + +#endif /* __ARCH_ARM_SRC_ARMV8_R_ARM_H */ diff --git a/arch/arm/src/armv8-r/arm_arch_timer.c b/arch/arm/src/armv8-r/arm_arch_timer.c new file mode 100644 index 00000000000..cb64fca3450 --- /dev/null +++ b/arch/arm/src/armv8-r/arm_arch_timer.c @@ -0,0 +1,421 @@ +/**************************************************************************** + * arch/arm/src/armv8-r/arm_arch_timer.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 +#include + +#include "barriers.h" +#include "cp15.h" +#include "arm_gic.h" +#include "arm_arch_timer.h" + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct arm_oneshot_lowerhalf_s +{ + /* This is the part of the lower half driver that is visible to the upper- + * half client of the driver. This must be the first thing in this + * structure so that pointers to struct oneshot_lowerhalf_s are cast + * compatible to struct arm64_oneshot_lowerhalf_s and vice versa. + */ + + struct oneshot_lowerhalf_s lh; /* Common lower-half driver fields */ + + /* Private lower half data follows */ + + void *arg; /* Argument that is passed to the handler */ + uint64_t cycle_per_tick; /* cycle per tick */ + oneshot_callback_t callback; /* Internal handler that receives callback */ +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static inline void arm_arch_timer_set_compare(uint64_t value) +{ + CP15_SET64(CNTV_CVAL, value); +} + +static inline uint64_t arm_arch_timer_get_compare(void) +{ + return CP15_GET64(CNTV_CVAL); +} + +static inline void arm_arch_timer_enable(bool enable) +{ + uint64_t value; + + value = CP15_GET(CNTV_CTL); + + if (enable) + { + value |= CNTV_CTL_ENABLE_BIT; + } + else + { + value &= ~CNTV_CTL_ENABLE_BIT; + } + + CP15_SET(CNTV_CTL, value); +} + +static inline void arm_arch_timer_set_irq_mask(bool mask) +{ + uint64_t value; + + value = CP15_GET(CNTV_CTL); + + if (mask) + { + value |= CNTV_CTL_IMASK_BIT; + } + else + { + value &= ~CNTV_CTL_IMASK_BIT; + } + + CP15_SET(CNTV_CTL, value); +} + +static inline uint64_t arm_arch_timer_count(void) +{ + return CP15_GET64(CNTVCT); +} + +static inline uint64_t arm_arch_timer_get_cntfrq(void) +{ + return CP15_GET(CNTFRQ); +} + +/**************************************************************************** + * Name: arm_arch_timer_compare_isr + * + * Description: + * Common timer interrupt callback. When any oneshot timer interrupt + * expires, this function will be called. It will forward the call to + * the next level up. + * + * Input Parameters: + * oneshot - The state associated with the expired timer + * + * Returned Value: + * Always returns OK + * + ****************************************************************************/ + +static int arm_arch_timer_compare_isr(int irq, void *regs, void *arg) +{ + struct arm_oneshot_lowerhalf_s *priv = + (struct arm_oneshot_lowerhalf_s *)arg; + + arm_arch_timer_set_irq_mask(true); + + if (priv->callback) + { + /* Then perform the callback */ + + priv->callback(&priv->lh, priv->arg); + } + + return OK; +} + +/**************************************************************************** + * Name: arm_tick_max_delay + * + * Description: + * Determine the maximum delay of the one-shot timer (in microseconds) + * + * Input Parameters: + * lower An instance of the lower-half oneshot state structure. This + * structure must have been previously initialized via a call to + * oneshot_initialize(); + * ticks The location in which to return the maximum delay. + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned + * on failure. + * + ****************************************************************************/ + +static int arm_tick_max_delay(struct oneshot_lowerhalf_s *lower, + clock_t *ticks) +{ + DEBUGASSERT(ticks != NULL); + + *ticks = (clock_t)UINT64_MAX; + + return OK; +} + +/**************************************************************************** + * Name: arm_tick_cancel + * + * Description: + * Cancel the oneshot timer and return the time remaining on the timer. + * + * NOTE: This function may execute at a high rate with no timer running (as + * when pre-emption is enabled and disabled). + * + * Input Parameters: + * lower Caller allocated instance of the oneshot state structure. This + * structure must have been previously initialized via a call to + * oneshot_initialize(); + * ticks The location in which to return the time remaining on the + * oneshot timer. + * + * Returned Value: + * Zero (OK) is returned on success. A call to up_timer_cancel() when + * the timer is not active should also return success; a negated errno + * value is returned on any failure. + * + ****************************************************************************/ + +static int arm_tick_cancel(struct oneshot_lowerhalf_s *lower, + clock_t *ticks) +{ + struct arm_oneshot_lowerhalf_s *priv = + (struct arm_oneshot_lowerhalf_s *)lower; + + DEBUGASSERT(priv != NULL && ticks != NULL); + + /* Disable int */ + + arm_arch_timer_set_irq_mask(true); + + return OK; +} + +/**************************************************************************** + * Name: arm_tick_start + * + * Description: + * Start the oneshot timer + * + * Input Parameters: + * lower An instance of the lower-half oneshot state structure. This + * structure must have been previously initialized via a call to + * oneshot_initialize(); + * handler The function to call when when the oneshot timer expires. + * arg An opaque argument that will accompany the callback. + * ticks Provides the duration of the one shot timer. + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned + * on failure. + * + ****************************************************************************/ + +static int arm_tick_start(struct oneshot_lowerhalf_s *lower, + oneshot_callback_t callback, void *arg, + clock_t ticks) +{ + struct arm_oneshot_lowerhalf_s *priv = + (struct arm_oneshot_lowerhalf_s *)lower; + + DEBUGASSERT(priv != NULL && callback != NULL); + + /* Save the new handler and its argument */ + + priv->callback = callback; + priv->arg = arg; + + /* Set the timeout */ + + arm_arch_timer_set_compare(arm_arch_timer_count() + + priv->cycle_per_tick * ticks); + arm_arch_timer_set_irq_mask(false); + + return OK; +} + +/**************************************************************************** + * Name: arm_tick_current + * + * Description: + * Get the current time. + * + * Input Parameters: + * lower Caller allocated instance of the oneshot state structure. This + * structure must have been previously initialized via a call to + * oneshot_initialize(); + * ticks The location in which to return the current time. + * + * Returned Value: + * Zero (OK) is returned on success, a negated errno value is returned on + * any failure. + * + ****************************************************************************/ + +static int arm_tick_current(struct oneshot_lowerhalf_s *lower, + clock_t *ticks) +{ + struct arm_oneshot_lowerhalf_s *priv = + (struct arm_oneshot_lowerhalf_s *)lower; + + DEBUGASSERT(ticks != NULL); + + *ticks = arm_arch_timer_count() / priv->cycle_per_tick; + + return OK; +} + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct oneshot_operations_s g_oneshot_ops = +{ + .tick_start = arm_tick_start, + .tick_current = arm_tick_current, + .tick_max_delay = arm_tick_max_delay, + .tick_cancel = arm_tick_cancel, +}; + +/**************************************************************************** + * Name: oneshot_initialize + * + * Description: + * Initialize the oneshot timer and return a oneshot lower half driver + * instance. + * + * Returned Value: + * On success, a non-NULL instance of the oneshot lower-half driver is + * returned. NULL is return on any failure. + * + ****************************************************************************/ + +static struct oneshot_lowerhalf_s *arm_oneshot_initialize(void) +{ + struct arm_oneshot_lowerhalf_s *priv; + + tmrinfo("oneshot_initialize\n"); + + /* Allocate an instance of the lower half driver */ + + priv = (struct arm_oneshot_lowerhalf_s *) + kmm_zalloc(sizeof(struct arm_oneshot_lowerhalf_s)); + + if (priv == NULL) + { + tmrerr("ERROR: Failed to initialized state structure\n"); + + return NULL; + } + + /* Initialize the lower-half driver structure */ + + priv->lh.ops = &g_oneshot_ops; + priv->cycle_per_tick = arm_arch_timer_get_cntfrq() / TICK_PER_SEC; + tmrinfo("cycle_per_tick %" PRIu64 "\n", priv->cycle_per_tick); + + /* Attach handler */ + + irq_attach(ARM_ARCH_TIMER_IRQ, + arm_arch_timer_compare_isr, priv); + + /* Enable int */ + + up_enable_irq(ARM_ARCH_TIMER_IRQ); + + /* Start timer */ + + arm_arch_timer_enable(true); + + tmrinfo("oneshot_initialize ok %p \n", &priv->lh); + + return &priv->lh; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Function: up_timer_initialize + * + * Description: + * This function is called during start-up to initialize the system timer + * interrupt. + * + ****************************************************************************/ + +void up_timer_initialize(void) +{ + uint64_t freq; + + freq = arm_arch_timer_get_cntfrq(); + tmrinfo("%s: cp15 timer(s) running at %" PRIu64 ".%" PRIu64 "MHz\n", + __func__, freq / 1000000, (freq / 10000) % 100); + + up_alarm_set_lowerhalf(arm_oneshot_initialize()); +} + +#ifdef CONFIG_SMP +/**************************************************************************** + * Function: arm_arch_timer_secondary_init + * + * Description: + * This function is called during start-up to initialize the system timer + * interrupt for smp. + * + * Notes: + * The origin design for ARMv8-A timer is assigned private timer to + * every PE(CPU core), the ARM_ARCH_TIMER_IRQ is a PPI so it's + * should be enable at every core. + * + * But for NuttX, it's design only for primary core to handle timer + * interrupt and call nxsched_process_timer at timer tick mode. + * So we need only enable timer for primary core + * + * IMX6 use GPT which is a SPI rather than generic timer to handle + * timer interrupt + ****************************************************************************/ + +void arm_arch_timer_secondary_init() +{ +#ifdef CONFIG_SCHED_TICKLESS + tmrinfo("arm_arch_timer_secondary_init\n"); + + /* Enable int */ + + up_enable_irq(ARM_ARCH_TIMER_IRQ); + + /* Start timer */ + + arm_arch_timer_enable(true); +#endif +} +#endif \ No newline at end of file diff --git a/arch/arm/src/armv8-r/arm_arch_timer.h b/arch/arm/src/armv8-r/arm_arch_timer.h new file mode 100644 index 00000000000..19eda8d5781 --- /dev/null +++ b/arch/arm/src/armv8-r/arm_arch_timer.h @@ -0,0 +1,58 @@ +/**************************************************************************** + * arch/arm64/src/common/arm64_arch_timer.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_ARM_SRC_ARMV7_R_ARM_ARCH_TIMER_H +#define __ARCH_ARM_SRC_ARMV7_R_ARM_ARCH_TIMER_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include "arm_gic.h" +#include "arm_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* CNTV_CVAL, Counter-timer Virtual Timer CompareValue register + * CNTV_CTL, Counter-timer Virtual Timer Control register + */ + +#define CNTV_CTL_ENABLE_BIT BIT(0) +#define CNTV_CTL_IMASK_BIT BIT(1) + +#define CONFIG_ARM_TIMER_SECURE_IRQ (GIC_PPI_INT_BASE + 13) +#define CONFIG_ARM_TIMER_NON_SECURE_IRQ (GIC_PPI_INT_BASE + 14) +#define CONFIG_ARM_TIMER_VIRTUAL_IRQ (GIC_PPI_INT_BASE + 11) +#define CONFIG_ARM_TIMER_HYP_IRQ (GIC_PPI_INT_BASE + 10) + +#define ARM_ARCH_TIMER_IRQ CONFIG_ARM_TIMER_VIRTUAL_IRQ +#define ARM_ARCH_TIMER_PRIO IRQ_DEFAULT_PRIORITY +#define ARM_ARCH_TIMER_FLAGS IRQ_TYPE_LEVEL + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ +#ifdef CONFIG_SMP +void arm_arch_timer_secondary_init(void); +#endif + +#endif /* __ARCH_ARM_SRC_ARMV7_R_ARM_ARCH_TIMER_H */ diff --git a/arch/arm/src/armv8-r/arm_cache.c b/arch/arm/src/armv8-r/arm_cache.c new file mode 100644 index 00000000000..1d5adcb69cb --- /dev/null +++ b/arch/arm/src/armv8-r/arm_cache.c @@ -0,0 +1,450 @@ +/**************************************************************************** + * arch/arm/src/armv8-r/arm_cache.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 "cp15_cacheops.h" +#include "barriers.h" + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +#if defined(CONFIG_ARCH_ICACHE) || defined(CONFIG_ARCH_DCACHE) + +/**************************************************************************** + * Name: up_get_cache_linesize + * + * Description: + * Get cache linesize + * + * Input Parameters: + * None + * + * Returned Value: + * Cache line size + * + ****************************************************************************/ + +static size_t up_get_cache_linesize(void) +{ + static uint32_t clsize; + + if (clsize == 0) + { + clsize = MAX(cp15_cache_linesize(), l2cc_get_linesize()); + } + + return clsize; +} + +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +#ifdef CONFIG_ARCH_ICACHE + +/**************************************************************************** + * Name: up_get_icache_linesize + * + * Description: + * Get icache linesize + * + * Input Parameters: + * None + * + * Returned Value: + * Cache line size + * + ****************************************************************************/ + +size_t up_get_icache_linesize(void) +{ + return up_get_cache_linesize(); +} + +/**************************************************************************** + * Name: up_invalidate_icache_all + * + * Description: + * Invalidate all instruction caches to PoU, also flushes branch target + * cache + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +void up_invalidate_icache_all(void) +{ + cp15_invalidate_icache_all(); +} + +/**************************************************************************** + * Name: up_invalidate_icache + * + * Description: + * Validate the specified range instruction cache as PoU, + * and flush the branch target cache + * + * Input Parameters: + * start - virtual start address of region + * end - virtual end address of region + 1 + * + * Returned Value: + * None + * + ****************************************************************************/ + +void up_invalidate_icache(uintptr_t start, uintptr_t end) +{ + cp15_invalidate_icache(start, end); +} + +/**************************************************************************** + * Name: up_enable_icache + * + * Description: + * Enable the I-Cache + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +void up_enable_icache(void) +{ + cp15_enable_icache(); +} + +/**************************************************************************** + * Name: up_disable_icache + * + * Description: + * Disable the I-Cache + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +void up_disable_icache(void) +{ + cp15_disable_icache(); +} + +#endif /* CONFIG_ARCH_ICACHE */ + +#ifdef CONFIG_ARCH_DCACHE + +/**************************************************************************** + * Name: up_get_dcache_linesize + * + * Description: + * Get dcache linesize + * + * Input Parameters: + * None + * + * Returned Value: + * Cache line size + * + ****************************************************************************/ + +size_t up_get_dcache_linesize(void) +{ + return up_get_cache_linesize(); +} + +/**************************************************************************** + * Name: up_invalidate_dcache + * + * Description: + * Invalidate the data cache within the specified region; we will be + * performing a DMA operation in this region and we want to purge old data + * in the cache. + * + * Input Parameters: + * start - virtual start address of region + * end - virtual end address of region + 1 + * + * Returned Value: + * None + * + * Assumptions: + * This operation is not atomic. This function assumes that the caller + * has exclusive access to the address range so that no harm is done if + * the operation is pre-empted. + * + ****************************************************************************/ + +void up_invalidate_dcache(uintptr_t start, uintptr_t end) +{ + cp15_invalidate_dcache(start, end); +} + +/**************************************************************************** + * Name: up_invalidate_dcache_all + * + * Description: + * Invalidate the entire contents of D cache. + * + * NOTE: This function forces L1 and L2 cache operations to be atomic + * by disabling interrupts. + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +void up_invalidate_dcache_all(void) +{ +#ifdef CONFIG_ARCH_L2CACHE + irqstate_t flags = enter_critical_section(); + cp15_invalidate_dcache_all(); + leave_critical_section(flags); +#else + cp15_invalidate_dcache_all(); +#endif +} + +/**************************************************************************** + * Name: up_clean_dcache + * + * Description: + * Clean the data cache within the specified region by flushing the + * contents of the data cache to memory. + * + * Input Parameters: + * start - virtual start address of region + * end - virtual end address of region + 1 + * + * Returned Value: + * None + * + * Assumptions: + * This operation is not atomic. This function assumes that the caller + * has exclusive access to the address range so that no harm is done if + * the operation is pre-empted. + * + ****************************************************************************/ + +void up_clean_dcache(uintptr_t start, uintptr_t end) +{ + if ((end - start) < cp15_cache_size()) + { + cp15_clean_dcache(start, end); + } + else + { + cp15_clean_dcache_all(); + } + + l2cc_clean(start, end); +} + +/**************************************************************************** + * Name: up_clean_dcache_all + * + * Description: + * Clean the entire data cache within the specified region by flushing the + * contents of the data cache to memory. + * + * NOTE: This operation is un-necessary if the DCACHE is configured in + * write-through mode. + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions: + * This operation is not atomic. This function assumes that the caller + * has exclusive access to the address range so that no harm is done if + * the operation is pre-empted. + * + ****************************************************************************/ + +void up_clean_dcache_all(void) +{ + cp15_clean_dcache_all(); + l2cc_clean_all(); +} + +/**************************************************************************** + * Name: up_flush_dcache + * + * Description: + * Flush the data cache within the specified region by cleaning and + * invalidating the D cache. + * + * Input Parameters: + * start - virtual start address of region + * end - virtual end address of region + 1 + * + * Returned Value: + * None + * + * Assumptions: + * This operation is not atomic. This function assumes that the caller + * has exclusive access to the address range so that no harm is done if + * the operation is pre-empted. + * + ****************************************************************************/ + +void up_flush_dcache(uintptr_t start, uintptr_t end) +{ + if ((end - start) < cp15_cache_size()) + { + cp15_flush_dcache(start, end); + } + else + { + cp15_flush_dcache_all(); + } + + l2cc_flush(start, end); +} + +/**************************************************************************** + * Name: up_flush_dcache_all + * + * Description: + * Flush the entire data cache by cleaning and invalidating the D cache. + * + * NOTE: If DCACHE write-through is configured, then this operation is the + * same as up_invalidate_cache_all(). + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions: + * This operation is not atomic. This function assumes that the caller + * has exclusive access to the address range so that no harm is done if + * the operation is pre-empted. + * + ****************************************************************************/ + +void up_flush_dcache_all(void) +{ + cp15_flush_dcache_all(); + l2cc_flush_all(); +} + +/**************************************************************************** + * Name: up_enable_dcache + * + * Description: + * Enable the D-Cache + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +void up_enable_dcache(void) +{ + cp15_enable_dcache(); + l2cc_enable(); +} + +/**************************************************************************** + * Name: up_disable_dcache + * + * Description: + * Disable the D-Cache + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +void up_disable_dcache(void) +{ + cp15_disable_dcache(); + l2cc_disable(); +} + +/**************************************************************************** + * Name: up_coherent_dcache + * + * Description: + * Ensure that the I and D caches are coherent within specified region + * by cleaning the D cache (i.e., flushing the D cache contents to memory + * and invalidating the I cache. This is typically used when code has been + * written to a memory region, and will be executed. + * + * Input Parameters: + * addr - virtual start address of region + * len - Size of the address region in bytes + * + * Returned Value: + * None + * + ****************************************************************************/ + +void up_coherent_dcache(uintptr_t addr, size_t len) +{ + if (len > 0) + { + /* Perform the operation on the L1 cache */ + + cp15_coherent_dcache(addr, addr + len); + +#ifdef CONFIG_ARCH_L2CACHE + /* If we have an L2 cache, then there more things that need to done */ + +# warning This is insufficient +#endif + } +} + +#endif /* CONFIG_ARCH_DCACHE */ diff --git a/arch/arm/src/armv8-r/arm_cpuinfo.c b/arch/arm/src/armv8-r/arm_cpuinfo.c new file mode 100644 index 00000000000..af53a31719b --- /dev/null +++ b/arch/arm/src/armv8-r/arm_cpuinfo.c @@ -0,0 +1,148 @@ +/**************************************************************************** + * arch/arm/src/armv8-r/arm_cpuinfo.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 "arm_internal.h" +#include "hwcap.h" +#include "cp15.h" + +#if defined(CONFIG_FS_PROCFS) && !defined(CONFIG_FS_PROCFS_EXCLUDE_CPUINFO) + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * name: hwcap_extract_field + ****************************************************************************/ + +static int hwcap_extract_field(uint32_t features, int field) +{ + int feature; + + feature = (features >> field) & 0xf; + if (feature > 7) + { + feature -= 16; + } + + return feature; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * name: up_show_cpuinfo + ****************************************************************************/ + +ssize_t up_show_cpuinfo(FAR char *buf, size_t buf_size, off_t file_off) +{ + int i; + uint32_t cpuid; + + for (i = 0; i < CONFIG_SMP_NCPUS; i++) + { + procfs_sprintf(buf, buf_size, &file_off, "processor\t: %d\n", i); + procfs_sprintf(buf, buf_size, &file_off, "BogoMIPS\t: %u.%02u\n", + (CONFIG_BOARD_LOOPSPERMSEC / 1000), + (CONFIG_BOARD_LOOPSPERMSEC / 10) % 100); + procfs_sprintf(buf, buf_size, &file_off, "cpu MHz\t\t: %lu.%02lu\n", + up_perf_getfreq() / 1000000, + (up_perf_getfreq() / 10000) % 100); + + /* CPU Features */ + + procfs_sprintf(buf, buf_size, &file_off, "Features\t:"); + procfs_sprintf(buf, buf_size, &file_off, " %s %s %s", + HWCAP_HALF, HWCAP_FAST_MULT, HWCAP_EDSP); + + /* If the CPU supports LDREX/STREX and LDREXB/STREXB, + * avoid advertising SWP; it may not be atomic with + * multiprocessing cores. + */ + + if (hwcap_extract_field(CP15_GET(ID_ISAR3), 12) <= 1 && + hwcap_extract_field(CP15_GET(ID_ISAR4), 20) < 3) + { + procfs_sprintf(buf, buf_size, &file_off, " %s", HWCAP_SWP); + } + +#ifdef CONFIG_ARM_THUMB + if (hwcap_extract_field(CP15_GET(ID_ISAR0), 24) >= 1) + { + procfs_sprintf(buf, buf_size, &file_off, " %s", HWCAP_IDIVT); + } + + procfs_sprintf(buf, buf_size, &file_off, " %s", HWCAP_THUMB); +#endif + if (hwcap_extract_field(CP15_GET(ID_ISAR0), 24) == 2) + { + procfs_sprintf(buf, buf_size, &file_off, " %s", HWCAP_IDIVA); + } + +#ifdef CONFIG_SCHED_THREAD_LOCAL + procfs_sprintf(buf, buf_size, &file_off, " %s", HWCAP_TLS); +#endif + + /* LPAE implies atomic ldrd/strd instructions */ + + if (hwcap_extract_field(CP15_GET(ID_ISAR2), 0) == 1) + { + procfs_sprintf(buf, buf_size, &file_off, " %s", HWCAP_LPAE); + } + + /* VFP Features */ + +#if defined(CONFIG_ARCH_FPU) + procfs_sprintf(buf, buf_size, &file_off, " %s %s %s %s", + HWCAP_VFPV3, HWCAP_FPSP, HWCAP_FPDP, HWCAP_VFPV3D16); +#endif + + /* Cpuid info */ + + cpuid = CP15_GET(MIDR); + procfs_sprintf(buf, buf_size, &file_off, + "\nmodel name\t: %s rev %" PRIx32 " (%s)\n" + "CPU architecture: %s\n", + "ARMv8 Processor", cpuid & 15, "v8", "8"); + + procfs_sprintf(buf, buf_size, &file_off, + "CPU implementer\t: 0x%02" PRIx32 "\n" + "CPU variant\t: 0x%" PRIx32 "\n" + "CPU part\t: 0x%03" PRIx32 "\n" + "CPU revision\t: %" PRIu32 "\n\n", + cpuid >> 24, + (cpuid >> 20) & 0xf, + (cpuid >> 4) & 0xfff, + cpuid & 0xf); + } + + return -file_off; +} +#endif /* CONFIG_FS_PROCFS && !CONFIG_FS_PROCFS_EXCLUDE_CPUINFO */ diff --git a/arch/arm/src/armv8-r/arm_dataabort.c b/arch/arm/src/armv8-r/arm_dataabort.c new file mode 100644 index 00000000000..4df2a002aae --- /dev/null +++ b/arch/arm/src/armv8-r/arm_dataabort.c @@ -0,0 +1,68 @@ +/**************************************************************************** + * arch/arm/src/armv8-r/arm_dataabort.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 "sched/sched.h" +#include "arm_internal.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: arm_dataabort + * + * Input Parameters: + * regs - The standard, ARM register save array. + * dfar - Fault address register. + * dfsr - Fault status register. + * + * Description: + * This is the data abort exception handler. The ARM data abort exception + * occurs when a memory fault is detected during a data transfer. + * + ****************************************************************************/ + +uint32_t *arm_dataabort(uint32_t *regs, uint32_t dfar, uint32_t dfsr) +{ + /* Save the saved processor context in CURRENT_REGS where it can be + * accessed for register dumps and possibly context switching. + */ + + CURRENT_REGS = regs; + + /* Crash -- possibly showing diagnostic debug information. */ + + _alert("Data abort. PC: %08x DFAR: %08x DFSR: %08x\n", + regs[REG_PC], dfar, dfsr); + PANIC_WITH_REGS("panic", regs); + return regs; /* To keep the compiler happy */ +} diff --git a/arch/arm/src/armv8-r/arm_doirq.c b/arch/arm/src/armv8-r/arm_doirq.c new file mode 100644 index 00000000000..c265a14976a --- /dev/null +++ b/arch/arm/src/armv8-r/arm_doirq.c @@ -0,0 +1,109 @@ +/**************************************************************************** + * arch/arm/src/armv8-r/arm_doirq.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 "arm_internal.h" +#include "arm_gic.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +uint32_t *arm_doirq(int irq, uint32_t *regs) +{ + board_autoled_on(LED_INIRQ); + +#ifdef CONFIG_SUPPRESS_INTERRUPTS + PANIC(); +#else + /* Nested interrupts are not supported */ + + DEBUGASSERT(CURRENT_REGS == NULL); + + /* Current regs non-zero indicates that we are processing an interrupt; + * CURRENT_REGS is also used to manage interrupt level context switches. + */ + + CURRENT_REGS = regs; + + /* Deliver the IRQ */ + + irq_dispatch(irq, regs); + + /* Restore the cpu lock */ + + if (regs != CURRENT_REGS) + { + restore_critical_section(); + regs = (uint32_t *)CURRENT_REGS; + } + + /* Set CURRENT_REGS to NULL to indicate that we are no longer in an + * interrupt handler. + */ + + CURRENT_REGS = NULL; + + board_autoled_off(LED_INIRQ); +#endif + return regs; +} + +/**************************************************************************** + * Name: up_irqinitialize + * + * Description: + * This function is called by up_initialize() during the bring-up of the + * system. It is the responsibility of this function to but the interrupt + * subsystem into the working and ready state. + * + ****************************************************************************/ + +void up_irqinitialize(void) +{ + /* The following operations need to be atomic, but since this function is + * called early in the initialization sequence, we expect to have exclusive + * access to the GIC. + */ + + /* Initialize the Generic Interrupt Controller (GIC) for CPU0 */ + + arm_gic_initialize(); /* Initialization common to all CPUs */ + +#ifndef CONFIG_SUPPRESS_INTERRUPTS + + /* And finally, enable interrupts */ + + up_irq_enable(); +#endif +} diff --git a/arch/arm/src/armv8-r/arm_gic.h b/arch/arm/src/armv8-r/arm_gic.h new file mode 100644 index 00000000000..d7ad47474d7 --- /dev/null +++ b/arch/arm/src/armv8-r/arm_gic.h @@ -0,0 +1,369 @@ +/**************************************************************************** + * arch/arm/src/armv8-r/arm_gic.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_ARM_SRC_ARMV8_R_ARM_GIC_H +#define __ARCH_ARM_SRC_ARMV8_R_ARM_GIC_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include + +#include "arm.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* GIC Distributor register Interface Base Addresses + * Arm® Generic Interrupt Controller Architecture Specification + * GIC architecture version 3 and version 4 + */ + +#define GIC_DIST_BASE CONFIG_GICD_BASE +#define GICD_CTLR (GIC_DIST_BASE + 0x0) +#define GICD_TYPER (GIC_DIST_BASE + 0x4) +#define GICD_IIDR (GIC_DIST_BASE + 0x8) +#define GICD_STATUSR (GIC_DIST_BASE + 0x10) +#define GICD_SETSPI_NSR (GIC_DIST_BASE + 0x40) +#define GICD_CLRSPI_NSR (GIC_DIST_BASE + 0x48) +#define GICD_SETSPI_SR (GIC_DIST_BASE + 0x50) +#define GICD_CLRSPI_SR (GIC_DIST_BASE + 0x58) +#define GICD_IGROUPRn (GIC_DIST_BASE + 0x80) +#define GICD_ISENABLERn (GIC_DIST_BASE + 0x100) +#define GICD_ICENABLERn (GIC_DIST_BASE + 0x180) +#define GICD_ISPENDRn (GIC_DIST_BASE + 0x200) +#define GICD_ICPENDRn (GIC_DIST_BASE + 0x280) +#define GICD_ISACTIVERn (GIC_DIST_BASE + 0x300) +#define GICD_ICACTIVERn (GIC_DIST_BASE + 0x380) +#define GICD_IPRIORITYRn (GIC_DIST_BASE + 0x400) +#define GICD_ITARGETSRn (GIC_DIST_BASE + 0x800) +#define GICD_ICFGRn (GIC_DIST_BASE + 0xc00) +#define GICD_SGIR (GIC_DIST_BASE + 0xf00) +#define GICD_IDREGS (GIC_DIST_BASE + 0xFFD0) +#define GICD_PIDR2 (GIC_DIST_BASE + 0xFFE8) + +/* Offsets from GICD base or GICR(n) SGI_base */ + +#define GIC_DIST_IGROUPR 0x0080 +#define GIC_DIST_ISENABLER 0x0100 +#define GIC_DIST_ICENABLER 0x0180 +#define GIC_DIST_ISPENDR 0x0200 +#define GIC_DIST_ICPENDR 0x0280 +#define GIC_DIST_ISACTIVER 0x0300 +#define GIC_DIST_ICACTIVER 0x0380 +#define GIC_DIST_IPRIORITYR 0x0400 +#define GIC_DIST_ITARGETSR 0x0800 +#define GIC_DIST_ICFGR 0x0c00 +#define GIC_DIST_IGROUPMODR 0x0d00 +#define GIC_DIST_SGIR 0x0f00 + +/* GICD GICR common access macros */ + +#define IGROUPR(base, n) (base + GIC_DIST_IGROUPR + (n) * 4) +#define ISENABLER(base, n) (base + GIC_DIST_ISENABLER + (n) * 4) +#define ICENABLER(base, n) (base + GIC_DIST_ICENABLER + (n) * 4) +#define ISPENDR(base, n) (base + GIC_DIST_ISPENDR + (n) * 4) +#define ICPENDR(base, n) (base + GIC_DIST_ICPENDR + (n) * 4) +#define IPRIORITYR(base, n) (base + GIC_DIST_IPRIORITYR + n) +#define ITARGETSR(base, n) (base + GIC_DIST_ITARGETSR + (n) * 4) +#define ICFGR(base, n) (base + GIC_DIST_ICFGR + (n) * 4) +#define IGROUPMODR(base, n) (base + GIC_DIST_IGROUPMODR + (n) * 4) + +/* GICD_PIDR2 : Peripheral ID2 Register + * bit assignments + * [31:8] - IMPLEMENTATION DEFINED + * [7:4] ArchRev 0x1. GICv1. + * 0x2. GICv2. + * 0x3. GICv3. + * 0x4. GICv4. + * [3:0] - IMPLEMENTATION DEFINED. + */ +#define GICD_PIDR2_ARCH_MASK 0xf0 +#define GICD_PIDR2_ARCH_GICV2 0x20 +#define GICD_PIDR2_ARCH_GICV3 0x30 +#define GICD_PIDR2_ARCH_GICV4 0x40 + +/* GICD_TYPER : Interrupt Controller Type Register + * Arm® Generic Interrupt Controller Architecture Specification + * GIC architecture version 3 and version 4 + */ +#define GICD_TYPER_RSS BIT(26) +#define GICD_TYPER_LPIS BIT(17) +#define GICD_TYPER_MBIS BIT(16) +#define GICD_TYPER_ESPI BIT(8) +#define GICD_TYPER_ID_BITS(typer) ((((typer) >> 19) & 0x1f) + 1) +#define GICD_TYPER_NUM_LPIS(typer) ((((typer) >> 11) & 0x1f) + 1) +#define GICD_TYPER_SPIS(typer) ((((typer) & 0x1f) + 1) * 32) +#define GICD_TYPER_ESPIS(typer) \ + (((typer) & GICD_TYPER_ESPI) ? GICD_TYPER_SPIS((typer) >> 27) : 0) + +/* Common Helper Constants */ +#define GIC_SGI_INT_BASE 0 +#define GIC_PPI_INT_BASE 16 +#define GIC_IS_SGI(intid) (((intid) >= GIC_SGI_INT_BASE) && \ + ((intid) < GIC_PPI_INT_BASE)) + +#define GIC_SPI_INT_BASE 32 +#define GIC_NUM_INTR_PER_REG 32 +#define GIC_NUM_CFG_PER_REG 16 +#define GIC_NUM_PRI_PER_REG 4 + +/* GIC idle priority : value '0xff' will allow all interrupts */ + +#define GIC_IDLE_PRIO 0xff + +/* Priority levels 0:255 */ + +#define GIC_PRI_MASK 0xff + +/* '0xa0'is used to initialize each interrtupt default priority. + * This is an arbitrary value in current context. + * Any value '0x80' to '0xff' will work for both NS and S state. + * The values of individual interrupt and default has to be chosen + * carefully if PMR and BPR based nesting and preemption has to be done. + */ + +#define GIC_INT_DEF_PRI_X4 0xa0a0a0a0 + +/* 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 + */ + +#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_DS 6 +#define GICD_CGRL_E1NWF 7 + +/* GICD_CTLR Register write progress bit */ +#define GICD_CTLR_RWP 31 + +/* GICR_CTLR */ +#define GICR_CTLR_ENABLE_LPIS BIT(0) +#define GICR_CTLR_RWP 3 + +/* GICD_TYPER.ITLinesNumber 0:4 */ +#define GICD_TYPER_ITLINESNUM_MASK 0x1f + +/* GICR: Re-Distributor registers, offsets from RD_base(n) */ +#define GICR_CTLR 0x0000 +#define GICR_IIDR 0x0004 +#define GICR_TYPER 0x0008 +#define GICR_STATUSR 0x0010 +#define GICR_WAKER 0x0014 +#define GICR_PWRR 0x0024 +#define GICR_SETLPIR 0x0040 +#define GICR_CLRLPIR 0x0048 +#define GICR_PROPBASER 0x0070 +#define GICR_PENDBASER 0x0078 +#define GICR_INVLPIR 0x00A0 +#define GICR_INVALLR 0x00B0 +#define GICR_SYNCR 0x00C0 +#define GICR_MOVLPIR 0x0100 +#define GICR_MOVALLR 0x0110 +#define GICR_IDREGS 0xFFD0 +#define GICR_PIDR2 0xFFE8 + +/* GICR_PIDR2 : Peripheral ID2 Register + * bit assignments are the same as those for GICD_PIDR2) + * [31:8] - IMPLEMENTATION DEFINED + * [7:4] ArchRev 0x1. GICv1. + * 0x2. GICv2. + * 0x3. GICv3. + * 0x4. GICv4. + * [3:0] - IMPLEMENTATION DEFINED. + */ + +#define GICR_PIDR2_ARCH_MASK 0xf0 +#define GICR_PIDR2_ARCH_GICV3 0x30 +#define GICR_PIDR2_ARCH_GICV4 0x40 + +/* GICR_TYPER : Redistributor Type Register + * Arm® Generic Interrupt Controller Architecture Specification + * GIC architecture version 3 and version 4 + * chapter 9.11.35 for detail descriptions + */ + +#define GICR_TYPER_PLPIS BIT(0) +#define GICR_TYPER_VLPIS BIT(1) +#define GICR_TYPER_DIRECTLPIS BIT(3) +#define GICR_TYPER_LAST BIT(4) + +/* GICR_WAKER */ +#define GICR_WAKER_PS 1 +#define GICR_WAKER_CA 2 + +/* SGI base is at 64K offset from Redistributor */ +#define GICR_SGI_BASE_OFF 0x10000 + +/* GICD_ICFGR */ +#define GICD_ICFGR_MASK BIT_MASK(2) +#define GICD_ICFGR_TYPE BIT(1) + +/* BIT(0) reserved for IRQ_ZERO_LATENCY */ +#define IRQ_TYPE_LEVEL BIT(1) +#define IRQ_TYPE_EDGE BIT(2) + +#define GIC_SPI_INT_BASE 32 +#define GIC_SPI_MAX_INTID 1019 +#define GIC_IS_SPI(intid) (((intid) >= GIC_SPI_INT_BASE) && \ + ((intid) <= GIC_SPI_MAX_INTID)) + +/* GITCD_IROUTER */ +#define GIC_DIST_IROUTER 0x6000 +#define IROUTER(base, n) (base + GIC_DIST_IROUTER + (n) * 8) + +/* BIT(0) reserved for IRQ_ZERO_LATENCY */ +#define IRQ_TYPE_LEVEL BIT(1) +#define IRQ_TYPE_EDGE BIT(2) + +#define IRQ_DEFAULT_PRIORITY 0xa0 + +#define GIC_IRQ_SGI0 0 +#define GIC_IRQ_SGI1 1 +#define GIC_IRQ_SGI2 2 +#define GIC_IRQ_SGI3 3 +#define GIC_IRQ_SGI4 4 +#define GIC_IRQ_SGI5 5 +#define GIC_IRQ_SGI6 6 +#define GIC_IRQ_SGI7 7 +#define GIC_IRQ_SGI8 8 +#define GIC_IRQ_SGI9 9 +#define GIC_IRQ_SGI10 10 +#define GIC_IRQ_SGI11 11 +#define GIC_IRQ_SGI12 12 +#define GIC_IRQ_SGI13 13 +#define GIC_IRQ_SGI14 14 +#define GIC_IRQ_SGI15 15 + +/* register constants */ +#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) + +/* ICC SGI macros */ +#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)) + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +bool arm_gic_irq_is_enabled(unsigned int intid); +int arm_gic_initialize(void); +void arm_gic_irq_set_priority(unsigned int intid, unsigned int prio, + uint32_t flags); +int arm_gic_irq_trigger(unsigned int intid, uint32_t flags); + +int arm_gic_raise_sgi(unsigned int sgi_id, uint16_t target_list); + +#ifdef CONFIG_SMP + +/**************************************************************************** + * Name: arm_pause_handler + * + * Description: + * This is the handler for SGI2. It performs the following operations: + * + * 1. It saves the current task state at the head of the current assigned + * task list. + * 2. It waits on a spinlock, then + * 3. Returns from interrupt, restoring the state of the new task at the + * head of the ready to run list. + * + * Input Parameters: + * Standard interrupt handling + * + * Returned Value: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +int arm_pause_handler(int irq, void *context, void *arg); + +void arm_gic_secondary_init(void); + +#endif + +/**************************************************************************** + * Name: arm_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_SMP +uint64_t arm_get_mpid(int cpu); +#else +# define arm_get_mpid(cpu) GET_MPIDR() +#endif /* CONFIG_SMP */ + +#endif /* __ARCH_ARM_SRC_ARMV8_R_ARM_GIC_H */ diff --git a/arch/arm/src/armv8-r/arm_gicv3.c b/arch/arm/src/armv8-r/arm_gicv3.c new file mode 100644 index 00000000000..a351ae68d1b --- /dev/null +++ b/arch/arm/src/armv8-r/arm_gicv3.c @@ -0,0 +1,831 @@ +/*************************************************************************** + * arch/arm/src/armv8-r/arm_gicv3.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 "arm_internal.h" +#include "barriers.h" +#include "cp15.h" +#include "arm_gic.h" + +/*************************************************************************** + * Pre-processor Definitions + ***************************************************************************/ + +#define MIN(_x,_y) ((_x<_y) ? _x : _y) + +#define GICR_TYPER_NR_PPIS(r) \ + ({ \ + unsigned int __ppinum = ((r) >> 27) & 0x1f; \ + unsigned int __nr_ppis = 16; \ + if (__ppinum == 1 || __ppinum == 2) \ + { __nr_ppis += __ppinum * 32; } \ + __nr_ppis; \ + }) + +/* selects redistributor SGI_base for current core for PPI and SGI + * selects distributor base for SPI + * The macro translates to distributor base for GICv2 and GICv1 + */ +#define GET_DIST_BASE(intid) ((intid < GIC_SPI_INT_BASE) ? \ + (gic_get_rdist() + GICR_SGI_BASE_OFF) \ + : GIC_DIST_BASE) + +#define IGROUPR_VAL 0xFFFFFFFFU + +/*************************************************************************** + * Private Data + ***************************************************************************/ + +/* Redistributor base addresses for each core */ + +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()]; +} + +static inline uint32_t read_gicd_wait_rwp(void) +{ + uint32_t value; + + value = getreg32(GICD_CTLR); + + while (value & BIT(GICD_CTLR_RWP)) + { + value = getreg32(GICD_CTLR); + } + + return value; +} + +/* Wait for register write pending + * TODO: add timed wait + */ + +static int gic_wait_rwp(uint32_t intid) +{ + uint32_t rwp_mask; + unsigned long base; + + if (intid < GIC_SPI_INT_BASE) + { + base = (gic_get_rdist() + GICR_CTLR); + rwp_mask = BIT(GICR_CTLR_RWP); + } + else + { + base = GICD_CTLR; + rwp_mask = BIT(GICD_CTLR_RWP); + } + + while (getreg32(base) & rwp_mask) + { + } + + return 0; +} + +static inline void arm_gic_write_irouter(uint64_t val, unsigned int intid) +{ + unsigned long addr = IROUTER(GET_DIST_BASE(intid), intid); + + putreg64(val, addr); +} + +void arm_gic_irq_set_priority(unsigned int intid, unsigned int prio, + uint32_t flags) +{ + uint32_t mask = BIT(intid & (GIC_NUM_INTR_PER_REG - 1)); + uint32_t idx = intid / GIC_NUM_INTR_PER_REG; + uint32_t shift; + uint32_t val; + unsigned long base = GET_DIST_BASE(intid); + + /* Disable the interrupt */ + + putreg32(mask, ICENABLER(base, idx)); + gic_wait_rwp(intid); + + /* PRIORITYR registers provide byte access */ + + putreg8(prio & GIC_PRI_MASK, IPRIORITYR(base, intid)); + + /* Interrupt type config */ + + if (!GIC_IS_SGI(intid)) + { + idx = intid / GIC_NUM_CFG_PER_REG; + shift = (intid & (GIC_NUM_CFG_PER_REG - 1)) * 2; + + val = getreg32(ICFGR(base, idx)); + val &= ~(GICD_ICFGR_MASK << shift); + if (flags & IRQ_TYPE_EDGE) + { + val |= (GICD_ICFGR_TYPE << shift); + } + + putreg32(val, ICFGR(base, idx)); + } +} + +/*************************************************************************** + * Name: arm_gic_irq_trigger + * + * Description: + * Set the trigger type for the specified IRQ source and the current CPU. + * + * Since this API is not supported on all architectures, it should be + * avoided in common implementations where possible. + * + * Input Parameters: + * irq - The interrupt request to modify. + * flags - irq type, IRQ_TYPE_EDGE or IRQ_TYPE_LEVEL + * Default is IRQ_TYPE_LEVEL + * + * Returned Value: + * Zero (OK) on success; a negated errno value is returned on any failure. + * + ***************************************************************************/ + +int arm_gic_irq_trigger(unsigned int intid, uint32_t flags) +{ + uint32_t idx = intid / GIC_NUM_INTR_PER_REG; + uint32_t shift; + uint32_t val; + unsigned long base = GET_DIST_BASE(intid); + + if (!GIC_IS_SGI(intid)) + { + idx = intid / GIC_NUM_CFG_PER_REG; + shift = (intid & (GIC_NUM_CFG_PER_REG - 1)) * 2; + + val = getreg32(ICFGR(base, idx)); + val &= ~(GICD_ICFGR_MASK << shift); + if (flags & IRQ_TYPE_EDGE) + { + val |= (GICD_ICFGR_TYPE << shift); + } + + putreg32(val, ICFGR(base, idx)); + return OK; + } + + return -EINVAL; +} + +void arm_gic_irq_enable(unsigned int intid) +{ + uint32_t mask = BIT(intid & (GIC_NUM_INTR_PER_REG - 1)); + uint32_t idx = intid / GIC_NUM_INTR_PER_REG; + + putreg32(mask, ISENABLER(GET_DIST_BASE(intid), idx)); + + /* Affinity routing is enabled for Non-secure state (GICD_CTLR.ARE_NS + * is set to '1' when GIC distributor is initialized) ,so need to set + * SPI's affinity, now set it to be the PE on which it is enabled. + */ + + if (GIC_IS_SPI(intid)) + { + arm_gic_write_irouter(up_cpu_index(), intid); + } +} + +void arm_gic_irq_disable(unsigned int intid) +{ + uint32_t mask = BIT(intid & (GIC_NUM_INTR_PER_REG - 1)); + uint32_t idx = intid / GIC_NUM_INTR_PER_REG; + + putreg32(mask, ICENABLER(GET_DIST_BASE(intid), idx)); + + /* poll to ensure write is complete */ + + gic_wait_rwp(intid); +} + +bool arm_gic_irq_is_enabled(unsigned int intid) +{ + uint32_t mask = BIT(intid & (GIC_NUM_INTR_PER_REG - 1)); + uint32_t idx = intid / GIC_NUM_INTR_PER_REG; + uint32_t val; + + val = getreg32(ISENABLER(GET_DIST_BASE(intid), idx)); + + return (val & mask) != 0; +} + +unsigned int arm_gic_get_active(void) +{ + int intid; + + /* (Pending -> Active / AP) or (AP -> AP) */ + + intid = CP15_GET(ICC_IAR1); + + return intid; +} + +void arm_gic_eoi(unsigned int intid) +{ + /* Interrupt request deassertion from peripheral to GIC happens + * by clearing interrupt condition by a write to the peripheral + * register. It is desired that the write transfer is complete + * before the core tries to change GIC state from 'AP/Active' to + * a new state on seeing 'EOI write'. + * Since ICC interface writes are not ordered against Device + * memory writes, a barrier is required to ensure the ordering. + * The dsb will also ensure *completion* of previous writes with + * DEVICE nGnRnE attribute. + */ + + ARM_DSB(); + + /* (AP -> Pending) Or (Active -> Inactive) or (AP to AP) nested case */ + + CP15_SET(ICC_EOIR1, intid); +} + +static int arm_gic_send_sgi(unsigned int sgi_id, uint64_t target_aff, + uint16_t target_list) +{ + uint32_t aff3; + uint32_t aff2; + uint32_t aff1; + uint64_t sgi_val; + + assert(GIC_IS_SGI(sgi_id)); + + /* Extract affinity fields from target */ + + aff1 = MPIDR_AFFLVL(target_aff, 1); + aff2 = MPIDR_AFFLVL(target_aff, 2); + aff3 = 0; + + sgi_val = GICV3_SGIR_VALUE(aff3, aff2, aff1, sgi_id, SGIR_IRM_TO_AFF, + target_list); + + ARM_DSB(); + CP15_SET64(ICC_SGI1R, sgi_val); + ARM_ISB(); + + return 0; +} + +int arm_gic_raise_sgi(unsigned int sgi_id, uint16_t target_list) +{ + uint64_t pre_cluster_id = UINT64_MAX; + uint64_t curr_cluster_id; + uint64_t curr_mpidr; + uint16_t tlist = 0; + uint16_t cpu = 0; + uint16_t i; + + while ((i = ffs(target_list))) + { + cpu += (i - 1); + + target_list >>= i; + + curr_mpidr = arm_get_mpid(cpu); + curr_cluster_id = MPID_TO_CLUSTER_ID(curr_mpidr); + + if (pre_cluster_id != UINT64_MAX && + pre_cluster_id != curr_cluster_id) + { + arm_gic_send_sgi(sgi_id, pre_cluster_id, tlist); + } + + tlist |= 1 << (curr_mpidr & MPIDR_AFFLVL_MASK); + + cpu += i; + pre_cluster_id = curr_cluster_id; + } + + arm_gic_send_sgi(sgi_id, pre_cluster_id, tlist); + + return 0; +} + +/* Wake up GIC redistributor. + * clear ProcessorSleep and wait till ChildAsleep is cleared. + * ProcessSleep to be cleared only when ChildAsleep is set + * Check if redistributor is not powered already. + */ + +static void gicv3_rdist_enable(unsigned long rdist) +{ + if (!(getreg32(rdist + GICR_WAKER) & BIT(GICR_WAKER_CA))) + { + return; + } + + /* Power up sequence of the Redistributors for GIC600/GIC700 + * please check GICR_PWRR define at trm of GIC600/GIC700 + */ + + putreg32(0x2, rdist + GICR_PWRR); + + sys_clear_bit(rdist + GICR_WAKER, GICR_WAKER_PS); + + while (getreg32(rdist + GICR_WAKER) & BIT(GICR_WAKER_CA)) + { + } +} + +/* Initialize the cpu interface. This should be called by each core. */ + +static void gicv3_cpuif_init(void) +{ + uint32_t icc_sre; + uint32_t intid; + unsigned long base = gic_get_rdist() + GICR_SGI_BASE_OFF; + + /* Disable all sgi ppi */ + + putreg32(BIT64_MASK(GIC_NUM_INTR_PER_REG), ICENABLER(base, 0)); + + /* Any sgi/ppi intid ie. 0-31 will select GICR_CTRL */ + + gic_wait_rwp(0); + + /* Clear pending */ + + putreg32(BIT64_MASK(GIC_NUM_INTR_PER_REG), ICPENDR(base, 0)); + + /* Configure all SGIs/PPIs as G1S or G1NS depending on Zephyr + * is run in EL1S or EL1NS respectively. + * All interrupts will be delivered as irq + */ + + putreg32(IGROUPR_VAL, IGROUPR(base, 0)); + putreg32(BIT64_MASK(GIC_NUM_INTR_PER_REG), IGROUPMODR(base, 0)); + + /* Configure default priorities for SGI 0:15 and PPI 0:15. */ + + for (intid = 0; intid < GIC_SPI_INT_BASE; + intid += GIC_NUM_PRI_PER_REG) + { + putreg32(GIC_INT_DEF_PRI_X4, IPRIORITYR(base, intid)); + } + + /* Configure PPIs as level triggered */ + + putreg32(0, ICFGR(base, 1)); + + /* Check if system interface can be enabled. + * 'icc_sre_el3' needs to be configured at 'EL3' + * to allow access to 'icc_sre_el1' at 'EL1' + * eg: z_arch_el3_plat_init can be used by platform. + */ + + icc_sre = CP15_GET(ICC_SRE); + + if (!(icc_sre & ICC_SRE_ELX_SRE_BIT)) + { + icc_sre = + (icc_sre | ICC_SRE_ELX_SRE_BIT | ICC_SRE_ELX_DIB_BIT | + ICC_SRE_ELX_DFB_BIT); + CP15_SET(ICC_SRE, icc_sre); + icc_sre = CP15_GET(ICC_SRE); + + assert(icc_sre & ICC_SRE_ELX_SRE_BIT); + } + + CP15_SET(ICC_PMR, GIC_IDLE_PRIO); + + /* Allow group1 interrupts */ + + CP15_SET(ICC_IGRPEN1, 1); +} + +static void gicv3_dist_init(void) +{ + unsigned int num_ints; + unsigned int intid; + unsigned int idx; + unsigned long base = GIC_DIST_BASE; + + num_ints = getreg32(GICD_TYPER); + num_ints &= GICD_TYPER_ITLINESNUM_MASK; + num_ints = (num_ints + 1) << 5; + + /* Disable the distributor */ + + putreg32(0, GICD_CTLR); + gic_wait_rwp(GIC_SPI_INT_BASE); + +#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_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 */ + + for (intid = GIC_SPI_INT_BASE; intid < num_ints; + intid += GIC_NUM_INTR_PER_REG) + { + idx = intid / GIC_NUM_INTR_PER_REG; + + /* Disable interrupt */ + + putreg32(BIT64_MASK(GIC_NUM_INTR_PER_REG), + ICENABLER(base, idx)); + + /* Clear pending */ + + putreg32(BIT64_MASK(GIC_NUM_INTR_PER_REG), + ICPENDR(base, idx)); + putreg32(IGROUPR_VAL, IGROUPR(base, idx)); + putreg32(BIT64_MASK(GIC_NUM_INTR_PER_REG), + IGROUPMODR(base, idx)); + } + + /* wait for rwp on GICD */ + + gic_wait_rwp(GIC_SPI_INT_BASE); + + /* Configure default priorities for all SPIs. */ + + for (intid = GIC_SPI_INT_BASE; intid < num_ints; + intid += GIC_NUM_PRI_PER_REG) + { + putreg32(GIC_INT_DEF_PRI_X4, IPRIORITYR(base, intid)); + } + + /* Configure all SPIs as active low, level triggered by default */ + + for (intid = GIC_SPI_INT_BASE; intid < num_ints; + intid += GIC_NUM_CFG_PER_REG) + { + idx = intid / GIC_NUM_CFG_PER_REG; + putreg32(0, ICFGR(base, idx)); + } + + /* TODO: Some arrch64 Cortex-A core maybe without security state + * it has different GIC configure with standard arrch64 A or R core + */ + +#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. + * Then set GICD_CTLR_ARE and GICD_CTLR_ENABLE_G1 to enable Group 1 + * interrupt. + * Since the GICD_CTLR_ARE and GICD_CTRL_ARE_S share BIT(4), and + * similarly the GICD_CTLR_ENABLE_G1 and GICD_CTLR_ENABLE_G1NS share + * BIT(1), we can reuse them. + */ + + 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 + +#ifdef CONFIG_SMP + /* Attach SGI interrupt handlers. This attaches the handler to all CPUs. */ + + DEBUGVERIFY(irq_attach(GIC_IRQ_SGI2, arm64_pause_handler, NULL)); +#endif +} + +void up_enable_irq(int irq) +{ + arm_gic_irq_enable(irq); +} + +void up_disable_irq(int irq) +{ + arm_gic_irq_disable(irq); +} + +/*************************************************************************** + * Name: up_prioritize_irq + * + * Description: + * Set the priority of an IRQ. + * + * Since this API is not supported on all architectures, it should be + * avoided in common implementations where possible. + * + ***************************************************************************/ + +int up_prioritize_irq(int irq, int priority) +{ + unsigned long base = GET_DIST_BASE(irq); + + DEBUGASSERT(irq >= 0 && irq < NR_IRQS && + priority >= 0 && priority <= 255); + + /* Ignore invalid interrupt IDs */ + + if (irq >= 0 && irq < NR_IRQS) + { + /* PRIORITYR registers provide byte access */ + + putreg8(priority & GIC_PRI_MASK, IPRIORITYR(base, irq)); + return OK; + } + + return -EINVAL; +} + +/*************************************************************************** + * Name: up_affinity_irq + * + * Description: + * Set an IRQ affinity by software. + * + ***************************************************************************/ + +void up_affinity_irq(int irq, cpu_set_t cpuset) +{ + if (GIC_IS_SPI(irq)) + { + arm_gic_write_irouter(cpuset, irq); + } +} + +/*************************************************************************** + * Name: up_trigger_irq + * + * Description: + * Perform a Software Generated Interrupt (SGI). If CONFIG_SMP is + * selected, then the SGI is sent to all CPUs specified in the CPU set. + * That set may include the current CPU. + * + * If CONFIG_SMP is not selected, the cpuset is ignored and SGI is sent + * only to the current CPU. + * + * Input Parameters + * irq - The SGI interrupt ID (0-15) + * cpuset - The set of CPUs to receive the SGI + * + ***************************************************************************/ + +void up_trigger_irq(int irq, cpu_set_t cpuset) +{ + uint32_t mask = BIT(irq & (GIC_NUM_INTR_PER_REG - 1)); + uint32_t idx = irq / GIC_NUM_INTR_PER_REG; + + if (GIC_IS_SGI(irq)) + { + arm_gic_raise_sgi(irq, cpuset); + } + else if (irq >= 0 && irq < NR_IRQS) + { + /* Write '1' to the corresponding bit in the distributor Interrupt + * Set-Pending (ISPENDR) + * GICD_ISPENDRn: Interrupt Set-Pending Registers + */ + + putreg32(mask, ISPENDR(GET_DIST_BASE(irq), idx)); + } +} + +/*************************************************************************** + * Name: arm64_decodeirq + * + * Description: + * This function is called from the IRQ vector handler in arm64_vectors.S. + * At this point, the interrupt has been taken and the registers have + * been saved on the stack. This function simply needs to determine the + * the irq number of the interrupt and then to call arm_doirq to dispatch + * the interrupt. + * + * Input Parameters: + * regs - A pointer to the register save area on the stack. + ***************************************************************************/ + +uint32_t * arm_decodeirq(uint32_t * regs) +{ + int irq; + + /* Read the interrupt acknowledge register and get the interrupt ID */ + + irq = arm_gic_get_active(); + + /* Ignore spurions IRQs. ICCIAR will report 1023 if there is no pending + * interrupt. + */ + + DEBUGASSERT(irq < NR_IRQS || irq == 1023); + if (irq < NR_IRQS) + { + /* Dispatch the interrupt */ + + regs = arm_doirq(irq, regs); + } + + /* Write to the end-of-interrupt register */ + + arm_gic_eoi(irq); + + return regs; +} + +static int gic_validate_dist_version(void) +{ + uint32_t typer; + bool has_rss; + uint32_t reg = getreg32(GICD_PIDR2) & GICD_PIDR2_ARCH_MASK; + int spis; + int espis; + + if (reg == GICD_PIDR2_ARCH_GICV3) + { + sinfo("GICv3 version detect\n"); + } + else if (reg == GICD_PIDR2_ARCH_GICV4) + { + sinfo("GICv4 version detect\n"); + } + else + { + sinfo("No GIC version detect\n"); + return -ENODEV; + } + + /* Find out how many interrupts are supported. */ + + typer = getreg32(GICD_TYPER); + spis = MIN(GICD_TYPER_SPIS(typer), 1020U) - 32; + espis = GICD_TYPER_ESPIS(typer); + + sinfo("GICD_TYPER = 0x%x\n", typer); + sinfo("%d SPIs implemented\n", spis); + sinfo("%d Extended SPIs implemented\n", espis); + + has_rss = !!(typer & GICD_TYPER_RSS); + sinfo("Distributor has %sRange Selector support\n", has_rss ? "" : "no "); + + if (typer & GICD_TYPER_MBIS) + { + sinfo("MBIs is present, But No support\n"); + } + + return 0; +} + +static int gic_validate_redist_version(void) +{ + uint64_t typer; + unsigned int ppi_nr; + bool has_vlpis = true; + bool has_direct_lpi = true; + uint32_t reg; + unsigned long redist_base = gic_get_rdist(); + + ppi_nr = (~0U); + reg = getreg32(redist_base + + GICR_PIDR2) & GICR_PIDR2_ARCH_MASK; + if (reg != GICR_PIDR2_ARCH_GICV3 && + reg != GICR_PIDR2_ARCH_GICV4) + { + sinfo("No redistributor present 0x%lx\n", redist_base); + return -ENODEV; + } + + typer = getreg64(redist_base + GICR_TYPER); + has_vlpis &= !!(typer & GICR_TYPER_VLPIS); + has_direct_lpi &= !!(typer & GICR_TYPER_DIRECTLPIS); + ppi_nr = MIN(GICR_TYPER_NR_PPIS(typer), ppi_nr); + + if (ppi_nr == (~0U)) + { + ppi_nr = 0; + } + + 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 " : ""); + + return 0; +} + +static void arm_gic_init(void) +{ + uint8_t cpu; + int err; + + cpu = this_cpu(); + gic_rdists[cpu] = CONFIG_GICR_BASE + + up_cpu_index() * CONFIG_GICR_OFFSET; + + err = gic_validate_redist_version(); + if (err) + { + sinfo("no redistributor detected, giving up ret=%d\n", err); + return; + } + + gicv3_rdist_enable(gic_get_rdist()); + + gicv3_cpuif_init(); + +#ifdef CONFIG_SMP + up_enable_irq(GIC_IRQ_SGI2); +#endif +} + +int arm_gic_initialize(void) +{ + int err; + + err = gic_validate_dist_version(); + if (err) + { + sinfo("no distributor detected, giving up ret=%d\n", err); + return err; + } + + gicv3_dist_init(); + + arm_gic_init(); + + return 0; +} + +#ifdef CONFIG_SMP +void arm_gic_secondary_init(void) +{ + arm_gic_init(); +} + +#endif diff --git a/arch/arm/src/armv8-r/arm_head.S b/arch/arm/src/armv8-r/arm_head.S new file mode 100644 index 00000000000..7822140ec8e --- /dev/null +++ b/arch/arm/src/armv8-r/arm_head.S @@ -0,0 +1,528 @@ +/**************************************************************************** + * arch/arm/src/armv8-r/arm_head.S + * + * 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 "arm.h" +#include "cp15.h" +#include "cp15_cacheops.h" +#include "sctlr.h" +#include "arm_internal.h" + + .file "arm_head.S" + +/**************************************************************************** + * Configuration + ****************************************************************************/ + +/* There are three operational memory configurations: + * + * 1. We execute in place in FLASH (CONFIG_BOOT_RUNFROMFLASH=y). In this case + * the boot logic must: + * + * - Configure SDRAM (if present), + * - Initialize the .data section in RAM, and + * - Clear .bss section + * + * 2. We boot in FLASH but copy ourselves to SDRAM from better performance. + * (CONFIG_BOOT_RUNFROMFLASH=n && CONFIG_BOOT_COPYTORAM=y). In this case + * the boot logic must: + * + * - Configure SDRAM (if present), + * - Copy ourself to DRAM, and + * - Clear .bss section (data should be fully initialized) + * + * In this case, we assume that the logic within this file executes from FLASH. + * + * 3. There is bootloader that copies us to SDRAM (but probably not to the beginning) + * (CONFIG_BOOT_RUNFROMFLASH=n && CONFIG_BOOT_COPYTORAM=n). In this case SDRAM + * was initialized by the boot loader, and this boot logic must: + * + * - Clear .bss section (data should be fully initialized) + */ + +/* Beginning (BOTTOM/BASE) and End+1 (TOP) of the IDLE stack. + * + * The IDLE stack is the stack that is used during initialization and, + * eventually, becomes the stack of the IDLE task when initialization + * is complete. + * + * REVISIT: There are issues here in some configurations. The stack + * pointer is initialized very early in the boot sequence. But in some + * architectures the memory supporting the stack may not yet be + * initialized (SDRAM, for example, would not be ready yet). In that + * case, ideally the IDLE stack should be in some other memory that does + * not require initialization (such as internal SRAM) + */ + +#ifndef IDLE_STACK_BASE +# ifdef CONFIG_SMP +# define IDLE_STACK_BASE _enoinit +# else +# define IDLE_STACK_BASE _ebss +# endif +#endif + +#define IDLE_STACK_TOP IDLE_STACK_BASE+CONFIG_IDLETHREAD_STACKSIZE + +/**************************************************************************** + * Global Symbols + ****************************************************************************/ + +/* Imported symbols */ + + .global arm_boot /* Branch to continue initialization in C */ + + .global _sbss /* Start of .bss in RAM */ + .global _ebss /* End+1 of .bss in RAM */ + + .global _hyp_vector_start + .global _sys_vector_start +#ifdef CONFIG_BOOT_RUNFROMFLASH + .global _eronly /* Where .data defaults are stored in FLASH */ + .global _sdata /* Where .data needs to reside in SDRAM */ + .global _edata +#endif +#ifdef CONFIG_ARCH_RAMFUNCS + .global _framfuncs /* Where RAM functions are stored in FLASH */ + .global _sramfuncs /* Where RAM functions needs to reside in RAM */ + .global _eramfuncs +#endif + +/* Exported symbols */ + + .global __start /* Power-up/Reset entry point */ + .global arm_data_initialize /* Perform C data initialization */ + .global g_idle_topstack /* Top of the initial/IDLE stack */ + +/**************************************************************************** + * Name: __start + ****************************************************************************/ + +/* We assume the bootloader has already initialized most of the h/w for + * us and that only leaves us having to do some os specific things + * below. + */ + + .text + .syntax unified + .arm + .global __start + .type __start, #function + +__start: +#if defined(CONFIG_SMP) && CONFIG_SMP_NCPUS > 1 + /* Get cpuindex, cpu0 continue boot, others wait event from cpu0 */ + + mrc CP15_MPIDR(r0) + and r0, r0, #0x3 + cmp r0, #0 + beq __cpu0_start + wfe + cmp r0, #1 + beq __cpu1_start +# if CONFIG_SMP_NCPUS > 2 + cmp r0, #2 + beq __cpu2_start +# endif +# if CONFIG_SMP_NCPUS > 3 + cmp r0, #3 + beq __cpu3_start +# endif +# if CONFIG_SMP_NCPUS > 4 + cmp r0, #4 + beq __cpu4_start +# endif + +__cpu0_start: +#endif + + /* Make sure that IRQs and FIQs are disabled */ + + cpsid if + + /* Set up the stack pointer and clear the frame pointer. */ + + ldr sp, .Lstackpointer + mov fp, #0 + + /* Set Hyp/PL2 Vector table base register */ + ldr r0, .Lhypvectorstart + mcr CP15_HVBAR(r0) + + /* Invalidate caches and TLBs. + * + * NOTE: "The ARMv7 Virtual Memory System Architecture (VMSA) does not + * support a CP15 operation to invalidate the entire data cache. ... + * In normal usage the only time the entire data cache has to be + * invalidated is on reset." + * + * The instruction cache is virtually indexed and physically tagged but + * the data cache is physically indexed and physically tagged. So it + * should not be an issue if the system comes up with a dirty Dcache; + * the ICache, however, must be invalidated. + */ + + mov r0, #0 + mcr CP15_BPIALL(r0) /* Invalidate entire branch prediction array */ + mcr CP15_ICIALLU(r0) /* Invalidate I-cache */ + mov r0, CP15_CACHE_INVALIDATE + bl cp15_dcache_op_level + isb + + bl sctlr_initialize + + /* Initialize .bss and .data assumt that RAM that is ready to use. */ + bl arm_data_initialize + + /* Platform hook for highest EL */ + bl arm_el_init + + /* Move to PL1 SYS with all exceptions masked */ + mov r0, #(PSR_MODE_SYS | PSR_I_BIT | PSR_F_BIT | PSR_A_BIT) + msr spsr_hyp, r0 + + adr r0, 1f + msr elr_hyp, r0 + eret + +1: + /* Set up the stack pointer and clear the frame pointer. */ + ldr sp, .Lstackpointer + mov fp, #0 + + /* Set PL1 Vector table base register */ + ldr r0, .Lsysvectorstart + mcr CP15_VBAR(r0) + + bl sctlr_initialize + bl arm_boot + + mov lr, #0 /* LR = return address (none) */ + b nx_start /* Branch to nx_start */ + + /* .text Data */ + +.Lstackpointer: + .long IDLE_STACK_TOP + .size __start, .-__start + +/*************************************************************************** + * Name: arm_data_initialize + ***************************************************************************/ + + .global arm_data_initialize + .type arm_data_initialize, #function + +arm_data_initialize: + + /* Zero BSS */ + + adr r0, .Linitparms + ldmia r0, {r0, r1} + + mov r2, #0 +1: + cmp r0, r1 /* Clear up to _bss_end_ */ + strcc r2, [r0], #4 + bcc 1b + +#ifdef CONFIG_BOOT_RUNFROMFLASH + /* If the .data section is in a separate, uninitialized address space, + * then we will also need to copy the initial values of the .data + * section from the .text region into that .data region. This would + * be the case if we are executing from FLASH and the .data section + * lies in a different physical address region OR if we are support + * on-demand paging and the .data section lies in a different virtual + * address region. + */ + + adr r3, .Ldatainit + ldmia r3, {r0, r1, r2} + +2: + ldr r3, [r0], #4 + str r3, [r1], #4 + cmp r1, r2 + blt 2b +#endif + +#ifdef CONFIG_ARCH_RAMFUNCS + /* Copy any necessary code sections from FLASH to RAM. The correct + * destination in SRAM is given by _sramfuncs and _eramfuncs. The + * temporary location is in flash after the data initialization code + * at _framfuncs + */ + + adr r3, .Lfuncinit + ldmia r3, {r0, r1, r2} + +3: + ldr r3, [r0], #4 + str r3, [r1], #4 + cmp r1, r2 + blt 3b + +#ifndef CONFIG_ARMV7R_DCACHE_DISABLE + /* Flush the copied RAM functions into physical RAM so that will + * be available when fetched into the I-Cache. + * + * Note that this is a branch, not a call and so will return + * directly to the caller without returning here. + */ + + adr r3, ..Lramfunc + ldmia r3, {r0, r1} + ldr r3, =up_clean_dcache + b r3 +#else + /* Otherwise return to the caller */ + + bx lr +#endif +#else + /* Return to the caller */ + + bx lr +#endif + +/*************************************************************************** + * Name: arm_data_initialize + ***************************************************************************/ + + .global sctlr_initialize + .type sctlr_initialize, #function + +sctlr_initialize: + /* Configure the system control register (see sctrl.h) */ + + mrc CP15_SCTLR(r0) /* Get control register */ + + /* Clear bits to reset values. This is only necessary in situations like, for + * example, we get here via a bootloader and the control register is in some + * unknown state. + * + * SCTLR_M Bit 0: MPU enable bit + * SCTLR_A Bit 1: Strict alignment disabled + * SCTLR_C Bit 2: DCache disabled + * SCTLR_CCP15BEN Bit 5: CP15 barrier enable + * SCTLR_B Bit 7: Should be zero on ARMv7R + * + * SCTLR_SW Bit 10: SWP/SWPB not enabled + * SCTLR_I Bit 12: ICache disabled + * SCTLR_V Bit 13: Assume low vectors + * SCTLR_RR Bit 14: Round-robin replacement strategy. + * + * SCTLR_BR Bit 17: Background Region bit + * SCTLR_DZ Bit 19: Divide by Zero fault enable bit + * SCTLR_FI Bit 21: Fast interrupts configuration enable bit + * SCTLR_U Bit 22: Unaligned access model (always one) + * + * SCTLR_VE Bit 24: Interrupt Vectors Enable bit + * SCTLR_EE Bit 25: 0=Little endian. + * SCTLR_NMFI Bit 27: Non-maskable FIQ (NMFI) support + * SCTLR_TE Bit 30: All exceptions handled in ARM state. + */ + + /* Clear all configurable bits */ + + bic r0, r0, #(SCTLR_A | SCTLR_C | SCTLR_CCP15BEN | SCTLR_B) + bic r0, r0, #(SCTLR_SW | SCTLR_I | SCTLR_V | SCTLR_RR) + bic r0, r0, #(SCTLR_BR | SCTLR_DZ | SCTLR_FI) + bic r0, r0, #(SCTLR_VE | SCTLR_EE | SCTLR_NMFI | SCTLR_TE) + +#ifndef CONFIG_SMP + /* Set bits to enable the MPU + * + * SCTLR_M Bit 0: Enable the MPU + */ + + orr r0, r0, #(SCTLR_M) +#endif + + /* Set configured bits */ + +#ifdef CONFIG_ARMV8R_ALIGNMENT_TRAP + /* Alignment abort enable + * + * SCTLR_A Bit 1: Strict alignment enabled + */ + + orr r0, r0, #(SCTLR_A) +#endif + +#if !defined(CONFIG_ARMV8R_DCACHE_DISABLE) && !defined(CONFIG_SMP) + /* Dcache enable + * + * SCTLR_C Bit 2: DCache enable + */ + + orr r0, r0, #(SCTLR_C) +#endif + +#ifdef CONFIG_ARMV8R_SCTLR_CCP15BEN + /* Enable memory barriers + * + * SCTLR_CCP15BEN Bit 5: CP15 barrier enable + */ + + orr r0, r0, #(SCTLR_CCP15BEN) +#endif + +#if !defined(CONFIG_ARMV8R_ICACHE_DISABLE) && !defined(CONFIG_SMP) + /* Icache enable + * + * SCTLR_I Bit 12: ICache enable + */ + + orr r0, r0, #(SCTLR_I) +#endif + +#ifdef CONFIG_ARMV8R_CACHE_ROUND_ROBIN + /* Round Robin cache replacement + * + * SCTLR_RR Bit 14: Round-robin replacement strategy. + */ + + orr r0, r0, #(SCTLR_RR) +#endif + +#ifdef CONFIG_ARMV8R_BACKGROUND_REGION + /* Allow PL1 access to back region when MPU is enabled + * + * SCTLR_BR Bit 17: Background Region bit + */ + + orr r0, r0, #(SCTLR_BR) +#endif + +#ifdef CONFIG_ARMV8R_DIV0_FAULT + /* Enable divide by zero faults + * + * SCTLR_DZ Bit 19: Divide by Zero fault enable bit + */ + + orr r0, r0, #(SCTLR_DZ) +#endif + +#ifdef CONFIG_ARMV8R_FAST_INTERRUPT + /* Fast interrupts configuration enable bit + * + * SCTLR_FI Bit 21: Fast interrupts configuration enable bit + */ + + orr r0, r0, #(SCTLR_FI) +#endif + +#ifdef CONFIG_ENDIAN_BIG + /* Big endian mode + * + * SCTLR_EE Bit 25: 1=Big endian. + */ + + orr r0, r0, #(SCTLR_EE) +#endif + +#ifdef CONFIG_ARMV8R_NONMASKABLE_FIQ + /* Non-maskable FIQ support + * + * SCTLR_NMFI Bit 27: Non-maskable FIQ (NMFI) support + */ + + orr r0, r0, #(SCTLR_NMFI) +#endif + + /* Then write the configured control register */ + + mcr CP15_SCTLR(r0) /* Write control reg */ + isb + .rept 12 /* Some CPUs want want lots of NOPs here */ + nop + .endr + + /* Return to the caller */ + bx lr + +/*************************************************************************** + * Text-section constants + ***************************************************************************/ + + /* Text-section constants: + * + * _sbss is the start of the BSS region (see linker script) + * _ebss is the end of the BSS region (see linker script) + * + * Typical Configuration: + * The idle task stack usually starts at the end of BSS and is of size + * CONFIG_IDLETHREAD_STACKSIZE. The heap continues from there until the + * end of memory. See g_idle_topstack below. + */ + + .type .Linitparms, %object +.Linitparms: + .long _sbss + .long _ebss + +.Lhypvectorstart: + .long _hyp_vector_start +.Lsysvectorstart: + .long _sys_vector_start + +#ifdef CONFIG_BOOT_RUNFROMFLASH + .type .Ldatainit, %object +.Ldatainit: + .long _eronly /* Where .data defaults are stored in FLASH */ + .long _sdata /* Where .data needs to reside in SDRAM */ + .long _edata +#endif + +#ifdef CONFIG_ARCH_RAMFUNCS + .type .Lfuncinit, %object +.Lfuncinit: + .long _framfuncs /* Where RAM functions are stored in FLASH */ +.Lramfuncs: + .long _sramfuncs /* Where RAM functions needs to reside in RAM */ + .long _eramfuncs +#endif + .size arm_data_initialize, . - arm_data_initialize + +/*************************************************************************** + * Data section variables + ***************************************************************************/ + + /* This global variable is unsigned long g_idle_topstack and is + * exported from here only because of its coupling to .Lstackpointer + * above. + */ + + .section .rodata, "a" + .align 4 + .globl g_idle_topstack + .type g_idle_topstack, object + +g_idle_topstack: + + .long IDLE_STACK_TOP + .size g_idle_topstack, .-g_idle_topstack + .end diff --git a/arch/arm/src/armv8-r/arm_initialstate.c b/arch/arm/src/armv8-r/arm_initialstate.c new file mode 100644 index 00000000000..6d46abbb937 --- /dev/null +++ b/arch/arm/src/armv8-r/arm_initialstate.c @@ -0,0 +1,154 @@ +/**************************************************************************** + * arch/arm/src/armv8-r/arm_initialstate.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 "arm.h" +#include "arm_internal.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_initial_state + * + * Description: + * A new thread is being started and a new TCB has been created. This + * function is called to initialize the processor specific portions of + * the new TCB. + * + * This function must setup the initial architecture registers and/or + * stack so that execution will begin at tcb->start on the next context + * switch. + * + ****************************************************************************/ + +void up_initial_state(struct tcb_s *tcb) +{ + struct xcptcontext *xcp = &tcb->xcp; + uint32_t cpsr; + + /* Initialize the initial exception register context structure */ + + memset(xcp, 0, sizeof(struct xcptcontext)); + + /* Initialize the idle thread stack */ + + if (tcb->pid == IDLE_PROCESS_ID) + { + tcb->stack_alloc_ptr = (void *)(g_idle_topstack - + CONFIG_IDLETHREAD_STACKSIZE); + tcb->stack_base_ptr = tcb->stack_alloc_ptr; + tcb->adj_stack_size = CONFIG_IDLETHREAD_STACKSIZE; + +#ifdef CONFIG_STACK_COLORATION + /* If stack debug is enabled, then fill the stack with a + * recognizable value that we can use later to test for high + * water marks. + */ + + arm_stack_color(tcb->stack_alloc_ptr, 0); +#endif /* CONFIG_STACK_COLORATION */ + + return; + } + + /* Initialize the context registers to stack top */ + + xcp->regs = (void *)((uint32_t)tcb->stack_base_ptr + + tcb->adj_stack_size - + XCPTCONTEXT_SIZE); + + /* Initialize the xcp registers */ + + memset(xcp->regs, 0, XCPTCONTEXT_SIZE); + + /* Save the initial stack pointer */ + + xcp->regs[REG_SP] = (uint32_t)tcb->stack_base_ptr + + tcb->adj_stack_size; + + /* Save the task entry point */ + + xcp->regs[REG_PC] = (uint32_t)tcb->start; + + /* If this task is running PIC, then set the PIC base register to the + * address of the allocated D-Space region. + */ + +#ifdef CONFIG_PIC + if (tcb->dspace != NULL) + { + /* Set the PIC base register (probably R10) to the address of the + * alloacated D-Space region. + */ + + xcp->regs[REG_PIC] = (uint32_t)tcb->dspace->region; + } +#endif + + /* Set supervisor-mode and disable FIQs, regardless of how NuttX is + * configured and of what kind of thread is being started. That is + * because all threads, even user-mode threads will start in kernel + * trampoline at nxtask_start() or pthread_start(). The thread's + * privileges will be dropped before transitioning to user code. + */ + + cpsr = PSR_MODE_SYS; + + /* Enable or disable interrupts, based on user configuration */ + +#ifdef CONFIG_SUPPRESS_INTERRUPTS + /* Disable interrupts (both IRQs and FIQs) */ + + cpsr |= (PSR_I_BIT | PSR_F_BIT); + +#else /* CONFIG_SUPPRESS_INTERRUPTS */ + /* Leave IRQs enabled (Also FIQs if CONFIG_ARMV7R_DECODEFIQ is selected) */ + +#ifndef CONFIG_ARMV8R_DECODEFIQ + + cpsr |= PSR_F_BIT; + +#endif /* !CONFIG_ARMV7R_DECODEFIQ */ + +#ifdef CONFIG_ARM_THUMB + cpsr |= PSR_T_BIT; +#endif + +#ifdef CONFIG_ENDIAN_BIG + + cpsr |= PSR_E_BIT; + +#endif /* CONFIG_ENDIAN_BIG */ +#endif /* CONFIG_SUPPRESS_INTERRUPTS */ + + xcp->regs[REG_CPSR] = cpsr; +} diff --git a/arch/arm/src/armv8-r/arm_perf.c b/arch/arm/src/armv8-r/arm_perf.c new file mode 100644 index 00000000000..b0564f60f83 --- /dev/null +++ b/arch/arm/src/armv8-r/arm_perf.c @@ -0,0 +1,87 @@ +/**************************************************************************** + * arch/arm/src/armv8-r/arm_perf.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 "arm_internal.h" +#include "sctlr.h" + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static unsigned long g_cpu_freq; + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_perf_* + * + * Description: + * The first interface simply provides the current time value in unknown + * units. NOTE: This function may be called early before the timer has + * been initialized. In that event, the function should just return a + * start time of zero. + * + * Nothing is assumed about the units of this time value. The following + * are assumed, however: (1) The time is an unsigned integer value, (2) + * the time is monotonically increasing, and (3) the elapsed time (also + * in unknown units) can be obtained by subtracting a start time from + * the current time. + * + * The second interface simple converts an elapsed time into well known + * units. + * + ****************************************************************************/ + +void up_perf_init(void *arg) +{ + g_cpu_freq = (unsigned long)(uintptr_t)arg; + + cp15_pmu_uer(PMUER_UME); + cp15_pmu_pmcr(PMCR_E); + cp15_pmu_cesr(PMCESR_CCES); +} + +unsigned long up_perf_getfreq(void) +{ + return g_cpu_freq; +} + +unsigned long up_perf_gettime(void) +{ + return cp15_pmu_rdccr(); +} + +void up_perf_convert(unsigned long elapsed, struct timespec *ts) +{ + unsigned long left; + + ts->tv_sec = elapsed / g_cpu_freq; + left = elapsed - ts->tv_sec * g_cpu_freq; + ts->tv_nsec = NSEC_PER_SEC * (uint64_t)left / g_cpu_freq; +} diff --git a/arch/arm/src/armv8-r/arm_prefetchabort.c b/arch/arm/src/armv8-r/arm_prefetchabort.c new file mode 100644 index 00000000000..d851f0a688d --- /dev/null +++ b/arch/arm/src/armv8-r/arm_prefetchabort.c @@ -0,0 +1,64 @@ +/**************************************************************************** + * arch/arm/src/armv8-r/arm_prefetchabort.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 "sched/sched.h" +#include "arm_internal.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: arm_prefetchabort + * + * Description: + * This is the prefetch abort exception handler. The ARM prefetch abort + * exception occurs when a memory fault is detected during an an + * instruction fetch. + * + ****************************************************************************/ + +uint32_t *arm_prefetchabort(uint32_t *regs, uint32_t ifar, uint32_t ifsr) +{ + /* Save the saved processor context in CURRENT_REGS where it can be + * accessed for register dumps and possibly context switching. + */ + + CURRENT_REGS = regs; + + /* Crash -- possibly showing diagnostic debug information. */ + + _alert("Prefetch abort. PC: %08x IFAR: %08x IFSR: %08x\n", + regs[REG_PC], ifar, ifsr); + PANIC_WITH_REGS("panic", regs); + return regs; /* To keep the compiler happy */ +} diff --git a/arch/arm/src/armv8-r/arm_saveusercontext.S b/arch/arm/src/armv8-r/arm_saveusercontext.S new file mode 100644 index 00000000000..0d0f506582d --- /dev/null +++ b/arch/arm/src/armv8-r/arm_saveusercontext.S @@ -0,0 +1,97 @@ +/**************************************************************************** + * arch/arm/src/armv8-r/arm_saveusercontext.S + * + * 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 + + .file "arm_saveusercontext.S" + + .text + .syntax unified + .arm + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_saveusercontext + * + * Description: + * Save the current context. Full prototype is: + * + * int up_saveusercontext(void *saveregs); + * + * R0 = saveregs = pinter saved array + * + * Returned Value: + * None + * + ****************************************************************************/ + + .globl up_saveusercontext + .globl up_saveusercontext + .type up_saveusercontext, %function + +up_saveusercontext: + + /* Save r0, r1 */ + + str r0, [r0, #(4*REG_R0)] + str r1, [r0, #(4*REG_R1)] + +#ifdef CONFIG_ARCH_FPU + /* Save fpu */ + +# ifdef CONFIG_ARM_DPFPU32 + vstmia.64 r0!, {d0-d15} + vstmia.64 r0!, {d16-d31} +# else + vstmia r0!, {s0-s31} +# endif + /* Save fpscr, r13 and r14 */ + + vmrs r1, fpscr + stmia r0!, {r1, r13, r14} +#else + /* Save r13, r14 */ + + stmia r0!, {r13, r14} +#endif + + /* Save r2~r12, and store the return address as PC */ + + add r0, r0, #8 + stmia r0!, {r2-r12, r14} + + /* Save cpsr */ + + mrs r1, CPSR + str r1, [r0] + + mov r0, #0 + bx lr + + .size up_saveusercontext, . - up_saveusercontext + .end diff --git a/arch/arm/src/armv8-r/arm_schedulesigaction.c b/arch/arm/src/armv8-r/arm_schedulesigaction.c new file mode 100644 index 00000000000..cad2c59f689 --- /dev/null +++ b/arch/arm/src/armv8-r/arm_schedulesigaction.c @@ -0,0 +1,426 @@ +/**************************************************************************** + * arch/arm/src/armv8-r/arm_schedulesigaction.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 "arm.h" +#include "sched/sched.h" +#include "arm_internal.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_schedule_sigaction + * + * Description: + * This function is called by the OS when one or more + * signal handling actions have been queued for execution. + * The architecture specific code must configure things so + * that the 'sigdeliver' callback is executed on the thread + * specified by 'tcb' as soon as possible. + * + * This function may be called from interrupt handling logic. + * + * This operation should not cause the task to be unblocked + * nor should it cause any immediate execution of sigdeliver. + * Typically, a few cases need to be considered: + * + * (1) This function may be called from an interrupt handler + * During interrupt processing, all xcptcontext structures + * should be valid for all tasks. That structure should + * be modified to invoke sigdeliver() either on return + * from (this) interrupt or on some subsequent context + * switch to the recipient task. + * (2) If not in an interrupt handler and the tcb is NOT + * the currently executing task, then again just modify + * the saved xcptcontext structure for the recipient + * task so it will invoke sigdeliver when that task is + * later resumed. + * (3) If not in an interrupt handler and the tcb IS the + * currently executing task -- just call the signal + * handler now. + * + * Assumptions: + * Called from critical section + * + ****************************************************************************/ + +#ifndef CONFIG_SMP +void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) +{ + sinfo("tcb=%p sigdeliver=%p\n", tcb, sigdeliver); + + /* Refuse to handle nested signal actions */ + + if (!tcb->xcp.sigdeliver) + { + tcb->xcp.sigdeliver = sigdeliver; + + /* First, handle some special cases when the signal is being delivered + * to the currently executing task. + */ + + sinfo("rtcb=%p CURRENT_REGS=%p\n", this_task(), CURRENT_REGS); + + if (tcb == this_task()) + { + /* CASE 1: We are not in an interrupt handler and a task is + * signalling itself for some reason. + */ + + if (!CURRENT_REGS) + { + /* In this case just deliver the signal now. */ + + sigdeliver(tcb); + tcb->xcp.sigdeliver = NULL; + } + + /* CASE 2: We are in an interrupt handler AND the interrupted + * task is the same as the one that must receive the signal, then + * we will have to modify the return state as well as the state + * in the TCB. + * + * Hmmm... there looks like a latent bug here: The following logic + * would fail in the strange case where we are in an interrupt + * handler, the thread is signalling itself, but a context switch + * to another task has occurred so that CURRENT_REGS does not + * refer to the thread of this_task()! + */ + + else + { + /* Save the return lr and cpsr and one scratch register + * These will be restored by the signal trampoline after + * the signals have been delivered. + */ + + /* And make sure that the saved context in the TCB is the same + * as the interrupt return context. + */ + + arm_savestate(tcb->xcp.saved_regs); + + /* Duplicate the register context. These will be + * restored by the signal trampoline after the signal has been + * delivered. + */ + + CURRENT_REGS = (void *) + ((uint32_t)CURRENT_REGS - + XCPTCONTEXT_SIZE); + memcpy((uint32_t *)CURRENT_REGS, tcb->xcp.saved_regs, + XCPTCONTEXT_SIZE); + + CURRENT_REGS[REG_SP] = (uint32_t)CURRENT_REGS + + XCPTCONTEXT_SIZE; + + /* Then set up to vector to the trampoline with interrupts + * disabled + */ + + CURRENT_REGS[REG_PC] = (uint32_t)arm_sigdeliver; + CURRENT_REGS[REG_CPSR] = (PSR_MODE_SYS | PSR_I_BIT | + PSR_F_BIT); +#ifdef CONFIG_ARM_THUMB + CURRENT_REGS[REG_CPSR] |= PSR_T_BIT; +#endif + +#ifdef CONFIG_ENDIAN_BIG + CURRENT_REGS[REG_CPSR] |= PSR_E_BIT; +#endif + } + } + + /* Otherwise, we are (1) signaling a task is not running from an + * interrupt handler or (2) we are not in an interrupt handler and the + * running task is signalling some non-running task. + */ + + else + { + /* Save the return lr and cpsr and one scratch register. These + * will be restored by the signal trampoline after the signals + * have been delivered. + */ + + /* Save the current register context location */ + + tcb->xcp.saved_regs = tcb->xcp.regs; + + /* Duplicate the register context. These will be + * restored by the signal trampoline after the signal has been + * delivered. + */ + + tcb->xcp.regs = (void *) + ((uint32_t)tcb->xcp.regs - + XCPTCONTEXT_SIZE); + memcpy(tcb->xcp.regs, tcb->xcp.saved_regs, XCPTCONTEXT_SIZE); + + tcb->xcp.regs[REG_SP] = (uint32_t)tcb->xcp.regs + + XCPTCONTEXT_SIZE; + + /* Then set up to vector to the trampoline with interrupts + * disabled + */ + + tcb->xcp.regs[REG_PC] = (uint32_t)arm_sigdeliver; + tcb->xcp.regs[REG_CPSR] = (PSR_MODE_SYS | PSR_I_BIT | + PSR_F_BIT); +#ifdef CONFIG_ARM_THUMB + tcb->xcp.regs[REG_CPSR] |= PSR_T_BIT; +#endif + +#ifdef CONFIG_ENDIAN_BIG + tcb->xcp.regs[REG_CPSR] |= PSR_E_BIT; +#endif + } + } +} +#else +void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) +{ + int cpu; + int me; + + sinfo("tcb=%p sigdeliver=%p\n", tcb, sigdeliver); + + /* Refuse to handle nested signal actions */ + + if (!tcb->xcp.sigdeliver) + { + tcb->xcp.sigdeliver = sigdeliver; + + /* First, handle some special cases when the signal is being delivered + * to task that is currently executing on any CPU. + */ + + sinfo("rtcb=%p CURRENT_REGS=%p\n", this_task(), CURRENT_REGS); + + if (tcb->task_state == TSTATE_TASK_RUNNING) + { + me = this_cpu(); + cpu = tcb->cpu; + + /* CASE 1: We are not in an interrupt handler and a task is + * signaling itself for some reason. + */ + + if (cpu == me && !CURRENT_REGS) + { + /* In this case just deliver the signal now. + * REVISIT: Signal handler will run in a critical section! + */ + + sigdeliver(tcb); + tcb->xcp.sigdeliver = NULL; + } + + /* CASE 2: The task that needs to receive the signal is running. + * This could happen if the task is running on another CPU OR if + * we are in an interrupt handler and the task is running on this + * CPU. In the former case, we will have to PAUSE the other CPU + * first. But in either case, we will have to modify the return + * state as well as the state in the TCB. + */ + + else + { + /* If we signaling a task running on the other CPU, we have + * to PAUSE the other CPU. + */ + + if (cpu != me) + { + /* Pause the CPU */ + + up_cpu_pause(cpu); + + /* Wait while the pause request is pending */ + + while (up_cpu_pausereq(cpu)) + { + } + + /* Now tcb on the other CPU can be accessed safely */ + + /* Copy tcb->xcp.regs to tcp.xcp.saved. These will be + * restored by the signal trampoline after the signal has + * been delivered. + */ + + /* Save the current register context location */ + + tcb->xcp.saved_regs = tcb->xcp.regs; + + /* Duplicate the register context. These will be + * restored by the signal trampoline after the signal has + * been delivered. + */ + + tcb->xcp.regs = (void *) + ((uint32_t)tcb->xcp.regs - + XCPTCONTEXT_SIZE); + memcpy(tcb->xcp.regs, tcb->xcp.saved_regs, + XCPTCONTEXT_SIZE); + + tcb->xcp.regs[REG_SP] = (uint32_t)tcb->xcp.regs + + XCPTCONTEXT_SIZE; + + /* Then set up to vector to the trampoline with interrupts + * disabled + */ + + tcb->xcp.regs[REG_PC] = (uint32_t)arm_sigdeliver; + tcb->xcp.regs[REG_CPSR] = (PSR_MODE_SYS | PSR_I_BIT | + PSR_F_BIT); +#ifdef CONFIG_ARM_THUMB + tcb->xcp.regs[REG_CPSR] |= PSR_T_BIT; +#endif + } + else + { + /* tcb is running on the same CPU */ + + /* Save the return PC, CPSR and either the BASEPRI or + * PRIMASK registers (and perhaps also the LR). These will + * be restored by the signal trampoline after the signal + * has been delivered. + */ + + /* And make sure that the saved context in the TCB is the + * same as the interrupt return context. + */ + + arm_savestate(tcb->xcp.saved_regs); + + /* Duplicate the register context. These will be + * restored by the signal trampoline after the signal has + * been delivered. + */ + + CURRENT_REGS = (void *) + ((uint32_t)CURRENT_REGS - + XCPTCONTEXT_SIZE); + memcpy((uint32_t *)CURRENT_REGS, tcb->xcp.saved_regs, + XCPTCONTEXT_SIZE); + + CURRENT_REGS[REG_SP] = (uint32_t)CURRENT_REGS + + XCPTCONTEXT_SIZE; + + /* Then set up vector to the trampoline with interrupts + * disabled. The kernel-space trampoline must run in + * privileged thread mode. + */ + + CURRENT_REGS[REG_PC] = (uint32_t)arm_sigdeliver; + CURRENT_REGS[REG_CPSR] = (PSR_MODE_SYS | PSR_I_BIT | + PSR_F_BIT); +#ifdef CONFIG_ARM_THUMB + CURRENT_REGS[REG_CPSR] |= PSR_T_BIT; +#endif + } + + /* Increment the IRQ lock count so that when the task is + * restarted, it will hold the IRQ spinlock. + */ + + DEBUGASSERT(tcb->irqcount < INT16_MAX); + tcb->irqcount++; + + /* NOTE: If the task runs on another CPU(cpu), adjusting + * global IRQ controls will be done in the pause handler + * on the CPU(cpu) by taking a critical section. + * If the task is scheduled on this CPU(me), do nothing + * because this CPU already took a critical section + */ + + /* RESUME the other CPU if it was PAUSED */ + + if (cpu != me) + { + up_cpu_resume(cpu); + } + } + } + + /* Otherwise, we are (1) signaling a task is not running from an + * interrupt handler or (2) we are not in an interrupt handler and the + * running task is signaling some other non-running task. + */ + + else + { + /* Save the return lr and cpsr and one scratch register. These + * will be restored by the signal trampoline after the signals + * have been delivered. + */ + + /* Save the current register context location */ + + tcb->xcp.saved_regs = tcb->xcp.regs; + + /* Duplicate the register context. These will be + * restored by the signal trampoline after the signal has been + * delivered. + */ + + tcb->xcp.regs = (void *) + ((uint32_t)tcb->xcp.regs - + XCPTCONTEXT_SIZE); + memcpy(tcb->xcp.regs, tcb->xcp.saved_regs, XCPTCONTEXT_SIZE); + + tcb->xcp.regs[REG_SP] = (uint32_t)tcb->xcp.regs + + XCPTCONTEXT_SIZE; + + /* Increment the IRQ lock count so that when the task is restarted, + * it will hold the IRQ spinlock. + */ + + DEBUGASSERT(tcb->irqcount < INT16_MAX); + tcb->irqcount++; + + /* Then set up to vector to the trampoline with interrupts + * disabled + */ + + tcb->xcp.regs[REG_PC] = (uint32_t)arm_sigdeliver; + tcb->xcp.regs[REG_CPSR] = (PSR_MODE_SYS | PSR_I_BIT | PSR_F_BIT); +#ifdef CONFIG_ARM_THUMB + tcb->xcp.regs[REG_CPSR] |= PSR_T_BIT; +#endif + } + } +} +#endif diff --git a/arch/arm/src/armv8-r/arm_sigdeliver.c b/arch/arm/src/armv8-r/arm_sigdeliver.c new file mode 100644 index 00000000000..809da73a171 --- /dev/null +++ b/arch/arm/src/armv8-r/arm_sigdeliver.c @@ -0,0 +1,155 @@ +/**************************************************************************** + * arch/arm/src/armv8-r/arm_sigdeliver.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 +#include + +#include "sched/sched.h" +#include "arm_internal.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: arm_sigdeliver + * + * Description: + * This is the a signal handling trampoline. When a signal action was + * posted. The task context was mucked with and forced to branch to this + * location with interrupts disabled. + * + ****************************************************************************/ + +void arm_sigdeliver(void) +{ + struct tcb_s *rtcb = this_task(); + uint32_t *regs = rtcb->xcp.saved_regs; + +#ifdef CONFIG_SMP + /* In the SMP case, we must terminate the critical section while the signal + * handler executes, but we also need to restore the irqcount when the + * we resume the main thread of the task. + */ + + int16_t saved_irqcount; +#endif + + board_autoled_on(LED_SIGNAL); + + sinfo("rtcb=%p sigdeliver=%p sigpendactionq.head=%p\n", + rtcb, rtcb->xcp.sigdeliver, rtcb->sigpendactionq.head); + DEBUGASSERT(rtcb->xcp.sigdeliver != NULL); + +retry: +#ifdef CONFIG_SMP + /* In the SMP case, up_schedule_sigaction(0) will have incremented + * 'irqcount' in order to force us into a critical section. Save the + * pre-incremented irqcount. + */ + + saved_irqcount = rtcb->irqcount; + DEBUGASSERT(saved_irqcount >= 1); + + /* Now we need call leave_critical_section() repeatedly to get the irqcount + * to zero, freeing all global spinlocks that enforce the critical section. + */ + + do + { + leave_critical_section(regs[REG_CPSR]); + } + while (rtcb->irqcount > 0); +#endif /* CONFIG_SMP */ + +#ifndef CONFIG_SUPPRESS_INTERRUPTS + /* Then make sure that interrupts are enabled. Signal handlers must always + * run with interrupts enabled. + */ + + up_irq_enable(); +#endif + + /* Deliver the signal */ + + ((sig_deliver_t)rtcb->xcp.sigdeliver)(rtcb); + + /* Output any debug messages BEFORE restoring errno (because they may + * alter errno), then disable interrupts again and restore the original + * errno that is needed by the user logic (it is probably EINTR). + */ + + sinfo("Resuming\n"); + +#ifdef CONFIG_SMP + /* Restore the saved 'irqcount' and recover the critical section + * spinlocks. + */ + + DEBUGASSERT(rtcb->irqcount == 0); + while (rtcb->irqcount < saved_irqcount) + { + enter_critical_section(); + } +#endif + +#ifndef CONFIG_SUPPRESS_INTERRUPTS + up_irq_save(); +#endif + + if (!sq_empty(&rtcb->sigpendactionq) && + (rtcb->flags & TCB_FLAG_SIGNAL_ACTION) == 0) + { + goto retry; + } + + /* Modify the saved return state with the actual saved values in the + * TCB. This depends on the fact that nested signal handling is + * not supported. Therefore, these values will persist throughout the + * signal handling action. + * + * Keeping this data in the TCB resolves a security problem in protected + * and kernel mode: The regs[] array is visible on the user stack and + * could be modified by a hostile program. + */ + + rtcb->xcp.sigdeliver = NULL; /* Allows next handler to be scheduled */ + + /* Then restore the correct state for this thread of execution. */ + + board_autoled_off(LED_SIGNAL); +#ifdef CONFIG_SMP + rtcb->irqcount--; +#endif + arm_fullcontextrestore(regs); +} diff --git a/arch/arm/src/armv8-r/arm_syscall.c b/arch/arm/src/armv8-r/arm_syscall.c new file mode 100644 index 00000000000..51425e1278f --- /dev/null +++ b/arch/arm/src/armv8-r/arm_syscall.c @@ -0,0 +1,592 @@ +/**************************************************************************** + * arch/arm/src/armv8-r/arm_syscall.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 + +#include "arm.h" +#include "arm_internal.h" +#include "sched/sched.h" +#include "signal/signal.h" + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: dump_syscall + * + * Description: + * Dump the syscall registers + * + ****************************************************************************/ + +static void dump_syscall(const char *tag, uint32_t cmd, const uint32_t *regs) +{ + /* The SVCall software interrupt is called with R0 = system call command + * and R1..R7 = variable number of arguments depending on the system call. + */ + +#ifdef CONFIG_LIB_SYSCALL + if (cmd >= CONFIG_SYS_RESERVED) + { + svcinfo("SYSCALL %s: regs: %p cmd: %" PRId32 " name: %s\n", tag, + regs, cmd, g_funcnames[cmd - CONFIG_SYS_RESERVED]); + } + else +#endif + { + svcinfo("SYSCALL %s: regs: %p cmd: %" PRId32 "\n", tag, regs, cmd); + } + + svcinfo(" R0: %08" PRIx32 " %08" PRIx32 " %08" PRIx32 " %08" PRIx32 + " %08" PRIx32 " %08" PRIx32 " %08" PRIx32 " %08" PRIx32 "\n", + regs[REG_R0], regs[REG_R1], regs[REG_R2], regs[REG_R3], + regs[REG_R4], regs[REG_R5], regs[REG_R6], regs[REG_R7]); + svcinfo(" R8: %08" PRIx32 " %08" PRIx32 " %08" PRIx32 " %08" PRIx32 + " %08" PRIx32 " %08" PRIx32 " %08" PRIx32 " %08" PRIx32 "\n", + regs[REG_R8], regs[REG_R9], regs[REG_R10], regs[REG_R11], + regs[REG_R12], regs[REG_R13], regs[REG_R14], regs[REG_R15]); + svcinfo("CPSR: %08" PRIx32 "\n", regs[REG_CPSR]); +} + +/**************************************************************************** + * Name: dispatch_syscall + * + * Description: + * Call the stub function corresponding to the system call. NOTE the non- + * standard parameter passing: + * + * R0 = SYS_ call number + * R1 = parm0 + * R2 = parm1 + * R3 = parm2 + * R4 = parm3 + * R5 = parm4 + * R6 = parm5 + * + * The values of R4-R5 may be preserved in the proxy called by the user + * code if they are used (but otherwise will not be). + * + * WARNING: There are hard-coded values in this logic! + * + * Register usage: + * + * R0 - Need not be preserved. + * R1-R3 - Need to be preserved until the stub is called. The values of + * R0 and R1 returned by the stub must be preserved. + * R4-R11 must be preserved to support the expectations of the user-space + * callee. R4-R6 may have been preserved by the proxy, but don't know + * for sure. + * R12 - Need not be preserved + * R13 - (stack pointer) + * R14 - Need not be preserved + * R15 - (PC) + * + ****************************************************************************/ + +#ifdef CONFIG_LIB_SYSCALL +static void dispatch_syscall(void) naked_function; +static void dispatch_syscall(void) +{ + __asm__ __volatile__ + ( + " sub sp, sp, #16\n" /* Create a stack frame to hold 3 parms + lr */ + " str r4, [sp, #0]\n" /* Move parameter 4 (if any) into position */ + " str r5, [sp, #4]\n" /* Move parameter 5 (if any) into position */ + " str r6, [sp, #8]\n" /* Move parameter 6 (if any) into position */ + " str lr, [sp, #12]\n" /* Save lr in the stack frame */ + " ldr ip, =g_stublookup\n" /* R12=The base of the stub lookup table */ + " ldr ip, [ip, r0, lsl #2]\n" /* R12=The address of the stub for this SYSCALL */ + " blx ip\n" /* Call the stub (modifies lr) */ + " ldr lr, [sp, #12]\n" /* Restore lr */ + " add sp, sp, #16\n" /* Destroy the stack frame */ + " mov r2, r0\n" /* R2=Save return value in R2 */ + " mov r0, %0\n" /* R0=SYS_syscall_return */ + " svc %1\n"::"i"(SYS_syscall_return), + "i"(SYS_syscall) /* Return from the SYSCALL */ + ); +} +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: arm_syscall + * + * Description: + * SVC interrupts will vector here with insn=the SVC instruction and + * xcp=the interrupt context + * + * The handler may get the SVC number be de-referencing the return + * address saved in the xcp and decoding the SVC instruction + * + ****************************************************************************/ + +uint32_t *arm_syscall(uint32_t *regs) +{ + uint32_t cmd; +#ifdef CONFIG_BUILD_PROTECTED + uint32_t cpsr; +#endif + + /* Nested interrupts are not supported */ + + DEBUGASSERT(CURRENT_REGS == NULL); + + /* Current regs non-zero indicates that we are processing an interrupt; + * CURRENT_REGS is also used to manage interrupt level context switches. + */ + + CURRENT_REGS = regs; + + /* The SYSCALL command is in R0 on entry. Parameters follow in R1..R7 */ + + cmd = regs[REG_R0]; + + /* The SVCall software interrupt is called with R0 = system call command + * and R1..R7 = variable number of arguments depending on the system call. + */ + + dump_syscall("Entry", cmd, regs); + + /* Handle the SVCall according to the command in R0 */ + + switch (cmd) + { + /* R0=SYS_syscall_return: This a SYSCALL return command: + * + * void arm_syscall_return(void); + * + * At this point, the following values are saved in context: + * + * R0 = SYS_syscall_return + * + * We need to restore the saved return address and return in + * unprivileged thread mode. + */ + +#ifdef CONFIG_LIB_SYSCALL + case SYS_syscall_return: + { + struct tcb_s *rtcb = nxsched_self(); + int index = (int)rtcb->xcp.nsyscalls - 1; + + /* Make sure that there is a saved SYSCALL return address. */ + + DEBUGASSERT(index >= 0); + + /* Setup to return to the saved SYSCALL return address in + * the original mode. + */ + + regs[REG_PC] = rtcb->xcp.syscall[index].sysreturn; +#ifdef CONFIG_BUILD_PROTECTED + regs[REG_CPSR] = rtcb->xcp.syscall[index].cpsr; +#endif + /* The return value must be in R0-R1. dispatch_syscall() + * temporarily moved the value for R0 into R2. + */ + + regs[REG_R0] = regs[REG_R2]; + +#ifdef CONFIG_ARCH_KERNEL_STACK + /* If this is the outermost SYSCALL and if there is a saved user + * stack pointer, then restore the user stack pointer on this + * final return to user code. + */ + + if (index == 0 && rtcb->xcp.ustkptr != NULL) + { + regs[REG_SP] = (uint32_t)rtcb->xcp.ustkptr; + rtcb->xcp.ustkptr = NULL; + } +#endif + + /* Save the new SYSCALL nesting level */ + + rtcb->xcp.nsyscalls = index; + + /* Handle any signal actions that were deferred while processing + * the system call. + */ + + rtcb->flags &= ~TCB_FLAG_SYSCALL; + nxsig_unmask_pendingsignal(); + } + break; +#endif + + /* R0=SYS_restore_context: Restore task context + * + * void arm_fullcontextrestore(uint32_t *restoreregs) + * noreturn_function; + * + * At this point, the following values are saved in context: + * + * R0 = SYS_restore_context + * R1 = restoreregs + */ + + case SYS_restore_context: + { + /* Replace 'regs' with the pointer to the register set in + * regs[REG_R1]. On return from the system call, that register + * set will determine the restored context. + */ + + CURRENT_REGS = (uint32_t *)regs[REG_R1]; + DEBUGASSERT(CURRENT_REGS); + } + break; + + /* R0=SYS_switch_context: This a switch context command: + * + * void arm_switchcontext(uint32_t **saveregs, + * uint32_t *restoreregs); + * + * At this point, the following values are saved in context: + * + * R0 = SYS_switch_context + * R1 = saveregs + * R2 = restoreregs + * + * In this case, we do both: We save the context registers to the save + * register area reference by the saved contents of R1 and then set + * regs to the save register area referenced by the saved + * contents of R2. + */ + + case SYS_switch_context: + { + DEBUGASSERT(regs[REG_R1] != 0 && regs[REG_R2] != 0); + *(uint32_t **)regs[REG_R1] = regs; + CURRENT_REGS = (uint32_t *)regs[REG_R2]; + } + break; + + /* R0=SYS_task_start: This a user task start + * + * void up_task_start(main_t taskentry, int argc, char *argv[]) + * noreturn_function; + * + * At this point, the following values are saved in context: + * + * R0 = SYS_task_start + * R1 = taskentry + * R2 = argc + * R3 = argv + */ + +#ifdef CONFIG_BUILD_PROTECTED + case SYS_task_start: + { + /* Set up to return to the user-space _start function in + * unprivileged mode. We need: + * + * R0 = argc + * R1 = argv + * PC = taskentry + * CSPR = user mode + */ + + regs[REG_PC] = regs[REG_R1]; + regs[REG_R0] = regs[REG_R2]; + regs[REG_R1] = regs[REG_R3]; + + cpsr = regs[REG_CPSR] & ~PSR_MODE_MASK; + regs[REG_CPSR] = cpsr | PSR_MODE_USR; + } + break; +#endif + + /* R0=SYS_pthread_start: This a user pthread start + * + * void up_pthread_start(pthread_startroutine_t entrypt, + * pthread_addr_t arg) noreturn_function; + * + * At this point, the following values are saved in context: + * + * R0 = SYS_pthread_start + * R1 = entrypt + * R2 = arg + */ + +#if !defined(CONFIG_BUILD_FLAT) && !defined(CONFIG_DISABLE_PTHREAD) + case SYS_pthread_start: + { + /* Set up to enter the user-space pthread start-up function in + * unprivileged mode. We need: + * + * R0 = startup + * R1 = arg + * PC = entrypt + * CSPR = user mode + */ + + regs[REG_PC] = regs[REG_R1]; + regs[REG_R0] = regs[REG_R2]; + regs[REG_R1] = regs[REG_R3]; + + cpsr = regs[REG_CPSR] & ~PSR_MODE_MASK; + regs[REG_CPSR] = cpsr | PSR_MODE_USR; + } + break; +#endif + +#ifdef CONFIG_BUILD_PROTECTED + /* R0=SYS_signal_handler: This a user signal handler callback + * + * void signal_handler(_sa_sigaction_t sighand, int signo, + * siginfo_t *info, void *ucontext); + * + * At this point, the following values are saved in context: + * + * R0 = SYS_signal_handler + * R1 = sighand + * R2 = signo + * R3 = info + * R4 = ucontext + */ + + case SYS_signal_handler: + { + struct tcb_s *rtcb = nxsched_self(); + + /* Remember the caller's return address */ + + DEBUGASSERT(rtcb->xcp.sigreturn == 0); + rtcb->xcp.sigreturn = regs[REG_PC]; + + /* Set up to return to the user-space trampoline function in + * unprivileged mode. + */ + + regs[REG_PC] = (uint32_t)ARCH_DATA_RESERVE->ar_sigtramp; + cpsr = regs[REG_CPSR] & ~PSR_MODE_MASK; + regs[REG_CPSR] = cpsr | PSR_MODE_USR; + + /* Change the parameter ordering to match the expectation of struct + * userpace_s signal_handler. + */ + + regs[REG_R0] = regs[REG_R1]; /* sighand */ + regs[REG_R1] = regs[REG_R2]; /* signal */ + regs[REG_R2] = regs[REG_R3]; /* info */ + regs[REG_R3] = regs[REG_R4]; /* ucontext */ + +#ifdef CONFIG_ARCH_KERNEL_STACK + /* If we are signalling a user process, then we must be operating + * on the kernel stack now. We need to switch back to the user + * stack before dispatching the signal handler to the user code. + * The existence of an allocated kernel stack is sufficient + * information to make this decision. + */ + + if (rtcb->xcp.kstack != NULL) + { + uint32_t usp; + + DEBUGASSERT(rtcb->xcp.kstkptr == NULL); + + /* Copy "info" into user stack */ + + if (rtcb->xcp.sigdeliver) + { + usp = rtcb->xcp.saved_regs[REG_SP]; + } + else + { + usp = rtcb->xcp.regs[REG_SP]; + } + + /* Create a frame for info and copy the kernel info */ + + usp = usp - sizeof(siginfo_t); + memcpy((void *)usp, (void *)regs[REG_R2], sizeof(siginfo_t)); + + /* Now set the updated SP and user copy of "info" to R2 */ + + rtcb->xcp.kstkptr = (uint32_t *)regs[REG_SP]; + regs[REG_SP] = usp; + regs[REG_R2] = usp; + } +#endif + } + break; +#endif + +#ifdef CONFIG_BUILD_PROTECTED + /* R0=SYS_signal_handler_return: This a user signal handler callback + * + * void signal_handler_return(void); + * + * At this point, the following values are saved in context: + * + * R0 = SYS_signal_handler_return + */ + + case SYS_signal_handler_return: + { + struct tcb_s *rtcb = nxsched_self(); + + /* Set up to return to the kernel-mode signal dispatching logic. */ + + DEBUGASSERT(rtcb->xcp.sigreturn != 0); + + regs[REG_PC] = rtcb->xcp.sigreturn; + cpsr = regs[REG_CPSR] & ~PSR_MODE_MASK; + regs[REG_CPSR] = cpsr | PSR_MODE_SYS; + rtcb->xcp.sigreturn = 0; + +#ifdef CONFIG_ARCH_KERNEL_STACK + /* We must enter here be using the user stack. We need to switch + * to back to the kernel user stack before returning to the kernel + * mode signal trampoline. + */ + + if (rtcb->xcp.kstack != NULL) + { + DEBUGASSERT(rtcb->xcp.kstkptr != NULL); + + regs[REG_SP] = (uint32_t)rtcb->xcp.kstkptr; + rtcb->xcp.kstkptr = NULL; + } +#endif + } + break; +#endif + + /* This is not an architecture-specific system call. If NuttX is built + * as a standalone kernel with a system call interface, then all of the + * additional system calls must be handled as in the default case. + */ + + default: + { +#ifdef CONFIG_LIB_SYSCALL + struct tcb_s *rtcb = nxsched_self(); + int index = rtcb->xcp.nsyscalls; + + /* Verify that the SYS call number is within range */ + + DEBUGASSERT(cmd >= CONFIG_SYS_RESERVED && cmd < SYS_maxsyscall); + + /* Make sure that there is a no saved SYSCALL return address. We + * cannot yet handle nested system calls. + */ + + DEBUGASSERT(index < CONFIG_SYS_NNEST); + + /* Setup to return to dispatch_syscall in privileged mode. */ + + rtcb->xcp.syscall[index].sysreturn = regs[REG_PC]; +#ifdef CONFIG_BUILD_PROTECTED + rtcb->xcp.syscall[index].cpsr = regs[REG_CPSR]; +#endif + + regs[REG_PC] = (uint32_t)dispatch_syscall; +#ifdef CONFIG_BUILD_PROTECTED + cpsr = regs[REG_CPSR] & ~PSR_MODE_MASK; + regs[REG_CPSR] = cpsr | PSR_MODE_SYS; +#endif + /* Offset R0 to account for the reserved values */ + + regs[REG_R0] -= CONFIG_SYS_RESERVED; + + /* Indicate that we are in a syscall handler. */ + + rtcb->flags |= TCB_FLAG_SYSCALL; + +#ifdef CONFIG_ARCH_KERNEL_STACK + /* If this is the first SYSCALL and if there is an allocated + * kernel stack, then switch to the kernel stack. + */ + + if (index == 0 && rtcb->xcp.kstack != NULL) + { + rtcb->xcp.ustkptr = (uint32_t *)regs[REG_SP]; + if (rtcb->xcp.kstkptr != NULL) + { + regs[REG_SP] = (uint32_t)rtcb->xcp.kstkptr; + } + else + { + regs[REG_SP] = (uint32_t)rtcb->xcp.kstack + + ARCH_KERNEL_STACKSIZE; + } + } +#endif + + /* Save the new SYSCALL nesting level */ + + rtcb->xcp.nsyscalls = index + 1; +#else + svcerr("ERROR: Bad SYS call: 0x%" PRIx32 "\n", regs[REG_R0]); +#endif + } + break; + } + + /* Restore the cpu lock */ + + if (regs != CURRENT_REGS) + { + /* Record the new "running" task. g_running_tasks[] is only used by + * assertion logic for reporting crashes. + */ + + g_running_tasks[this_cpu()] = this_task(); + + restore_critical_section(); + regs = (uint32_t *)CURRENT_REGS; + } + + /* Report what happened */ + + dump_syscall("Exit", cmd, regs); + + /* Set CURRENT_REGS to NULL to indicate that we are no longer in an + * interrupt handler. + */ + + CURRENT_REGS = NULL; + + /* Return the last value of curent_regs. This supports context switches + * on return from the exception. That capability is only used with the + * SYS_context_switch system call. + */ + + return regs; +} diff --git a/arch/arm/src/armv8-r/arm_tcbinfo.c b/arch/arm/src/armv8-r/arm_tcbinfo.c new file mode 100644 index 00000000000..c070864806d --- /dev/null +++ b/arch/arm/src/armv8-r/arm_tcbinfo.c @@ -0,0 +1,122 @@ +/**************************************************************************** + * arch/arm/src/armv8-r/arm_tcbinfo.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 + +#ifdef CONFIG_DEBUG_TCBINFO + +#include +#include + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const uint16_t g_reg_offs[] = +{ + TCB_REG_OFF(REG_R0), + TCB_REG_OFF(REG_R1), + TCB_REG_OFF(REG_R2), + TCB_REG_OFF(REG_R3), + TCB_REG_OFF(REG_R4), + TCB_REG_OFF(REG_R5), + TCB_REG_OFF(REG_R6), + TCB_REG_OFF(REG_R7), + TCB_REG_OFF(REG_R8), + TCB_REG_OFF(REG_R9), + TCB_REG_OFF(REG_R10), + TCB_REG_OFF(REG_R11), + TCB_REG_OFF(REG_R12), + TCB_REG_OFF(REG_R13), + TCB_REG_OFF(REG_R14), + TCB_REG_OFF(REG_R15), + TCB_REG_OFF(REG_CPSR), + +#ifdef CONFIG_ARCH_FPU + TCB_REG_OFF(REG_D0), + TCB_REG_OFF(REG_D1), + TCB_REG_OFF(REG_D2), + TCB_REG_OFF(REG_D3), + TCB_REG_OFF(REG_D4), + TCB_REG_OFF(REG_D5), + TCB_REG_OFF(REG_D6), + TCB_REG_OFF(REG_D7), + TCB_REG_OFF(REG_D8), + TCB_REG_OFF(REG_D9), + TCB_REG_OFF(REG_D10), + TCB_REG_OFF(REG_D11), + TCB_REG_OFF(REG_D12), + TCB_REG_OFF(REG_D13), + TCB_REG_OFF(REG_D14), + TCB_REG_OFF(REG_D15), +#endif + +#ifdef CONFIG_ARM_DPFPU32 + TCB_REG_OFF(REG_D16), + TCB_REG_OFF(REG_D17), + TCB_REG_OFF(REG_D18), + TCB_REG_OFF(REG_D19), + TCB_REG_OFF(REG_D20), + TCB_REG_OFF(REG_D21), + TCB_REG_OFF(REG_D22), + TCB_REG_OFF(REG_D23), + TCB_REG_OFF(REG_D24), + TCB_REG_OFF(REG_D25), + TCB_REG_OFF(REG_D26), + TCB_REG_OFF(REG_D27), + TCB_REG_OFF(REG_D28), + TCB_REG_OFF(REG_D29), + TCB_REG_OFF(REG_D30), + TCB_REG_OFF(REG_D31), +#endif + +#ifdef CONFIG_ARCH_FPU + TCB_REG_OFF(REG_FPSCR), +#endif +}; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +const struct tcbinfo_s g_tcbinfo = +{ + .pid_off = TCB_PID_OFF, + .state_off = TCB_STATE_OFF, + .pri_off = TCB_PRI_OFF, + .name_off = TCB_NAME_OFF, + .regs_off = TCB_REGS_OFF, + .basic_num = 17, + .total_num = sizeof(g_reg_offs) / sizeof(g_reg_offs[0]), + { + .p = g_reg_offs, + }, +}; + +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + diff --git a/arch/arm/src/armv8-r/arm_undefinedinsn.c b/arch/arm/src/armv8-r/arm_undefinedinsn.c new file mode 100644 index 00000000000..97d24ed4483 --- /dev/null +++ b/arch/arm/src/armv8-r/arm_undefinedinsn.c @@ -0,0 +1,49 @@ +/**************************************************************************** + * arch/arm/src/armv8-r/arm_undefinedinsn.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 "arm_internal.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: arm_undefinedinsn + ****************************************************************************/ + +uint32_t *arm_undefinedinsn(uint32_t *regs) +{ + _alert("Undefined instruction at 0x%x\n", regs[REG_PC]); + CURRENT_REGS = regs; + PANIC_WITH_REGS("panic", regs); + return regs; /* To keep the compiler happy */ +} diff --git a/arch/arm/src/armv8-r/arm_vectoraddrexcptn.S b/arch/arm/src/armv8-r/arm_vectoraddrexcptn.S new file mode 100644 index 00000000000..88a5ce9cf8a --- /dev/null +++ b/arch/arm/src/armv8-r/arm_vectoraddrexcptn.S @@ -0,0 +1,67 @@ +/**************************************************************************** + * arch/arm/src/armv8-r/arm_vectoraddrexceptn.S + * + * 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 + + .file "arm_vectoraddrexcptn.S" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Symbols + ****************************************************************************/ + + .globl arm_vectoraddrexcptn + +/**************************************************************************** + * Assembly Macros + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + + .text + .syntax unified + .arm + +/**************************************************************************** + * Name: arm_vectoraddrexcptn + * + * Description: + * Shouldn't happen. This exception handler is in a separate file from + * other vector handlers because some processors do not support the + * Address Exception vector. + * + ****************************************************************************/ + + .globl arm_vectoraddrexcptn + .type arm_vectoraddrexcptn, %function +arm_vectoraddrexcptn: + b arm_vectoraddrexcptn + .size arm_vectoraddrexcptn, . - arm_vectoraddrexcptn + .end diff --git a/arch/arm/src/armv8-r/arm_vectors.S b/arch/arm/src/armv8-r/arm_vectors.S new file mode 100644 index 00000000000..cd62baf4f6b --- /dev/null +++ b/arch/arm/src/armv8-r/arm_vectors.S @@ -0,0 +1,756 @@ +/**************************************************************************** + * arch/arm/src/armv8-r/arm_vectors.S + * + * 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 "arm.h" +#include "cp15.h" + + .file "arm_vectors.S" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Assembly Macros + ****************************************************************************/ + +/**************************************************************************** + * Name: setirqstack + * + * Description: + * Set the current stack pointer to the "top" of the IRQ interrupt stack. Single + * CPU case. Must be provided by MCU-specific logic in chip.h for the SMP case. + * + ****************************************************************************/ + +#if !defined(CONFIG_SMP) && CONFIG_ARCH_INTERRUPTSTACK > 7 + .macro setirqstack, tmp1, tmp2 + ldr sp, .Lirqstacktop /* SP = IRQ stack top */ + .endm +#endif + +/**************************************************************************** + * Name: setfiqstack + * + * Description: + * Set the current stack pointer to the "top" of the FIQ interrupt stack. Single + * CPU case. Must be provided by MCU-specific logic in chip.h for the SMP case. + * + ****************************************************************************/ + +#if !defined(CONFIG_SMP) && CONFIG_ARCH_INTERRUPTSTACK > 7 + .macro setfiqstack, tmp1, tmp2 + ldr sp, .Lfiqstacktop /* SP = FIQ stack top */ + .endm +#endif + +/**************************************************************************** + * Name: savefpu + * + * Description: + * Save the state of the floating point registers. + * + ****************************************************************************/ + +#ifdef CONFIG_ARCH_FPU + .macro savefpu, out, tmp + /* Store all floating point registers. Registers are stored in numeric order, + * s0, s1, ... in increasing address order. + */ + + /* Store the floating point control and status register. */ + + vmrs \tmp, fpscr /* Fetch the FPSCR */ + str \tmp, [\out, #-4]! /* Save the floating point control and status register */ + +#ifdef CONFIG_ARM_DPFPU32 + vstmdb.64 \out!, {d16-d31} /* Save the full FP context */ + vstmdb.64 \out!, {d0-d15} +#else + vstmdb \out!, {s0-s31} /* Save the full FP context */ +#endif + + .endm +#endif + +/**************************************************************************** + * Name: restorefpu + * + * Description: + * Restore the state of the floating point registers. + * + ****************************************************************************/ + +#ifdef CONFIG_ARCH_FPU + .macro restorefpu, in, tmp + /* Load all floating point registers. Registers are loaded in numeric order, + * s0, s1, ... in increasing address order. + */ + +#ifdef CONFIG_ARM_DPFPU32 + vldmia.64 \in!, {d0-d15} /* Restore the full FP context */ + vldmia.64 \in!, {d16-d31} +#else + vldmia \in!, {s0-s31} /* Restore the full FP context */ +#endif + + /* Load the floating point control and status register. At the end of the + * vstmia, \in will point to the FPSCR storage location. + */ + + ldr \tmp, [\in], #4 /* Fetch the floating point control and status register */ + vmsr fpscr, \tmp /* Restore the FPSCR */ + .endm +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + + .text + .syntax unified + .arm + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: arm_vectorirq + * + * Description: + * Interrupt exception. Entered in IRQ mode with spsr = SVC CPSR, lr = SVC PC + * + ****************************************************************************/ + + .globl arm_decodeirq + .globl arm_vectorirq + .type arm_vectorirq, %function + +arm_vectorirq: + + /* Save the LR and SPSR onto the SYS mode stack before switch. */ + + sub lr, lr, #4 + srsdb sp!, #PSR_MODE_SYS + + /* Switch to SYS mode */ + +#ifdef CONFIG_ARMV8R_DECODEFIQ + cpsid if, #PSR_MODE_SYS +#else + cpsid i, #PSR_MODE_SYS +#endif + + /* Create a context structure. First set aside a stack frame + * and store r0-r12 into the frame. + */ + + stmdb sp!, {r0-r12} /* Save the SYS mode regs */ + + /* Get the correct values of USR/SYS r13(sp) in r1 and + * save r13 and r14 into the frame. + */ + + add r1, sp, #(XCPTCONTEXT_SIZE-4*REG_R0) + stmdb sp!, {r1, r14} + +#ifdef CONFIG_ARCH_FPU + /* Save the state of the floating point registers. */ + + savefpu sp, r1 +#endif + + /* Then call the IRQ handler with interrupts disabled. */ + + mov fp, #0 /* Init frame pointer */ + mov r0, sp /* Get r0=xcp */ + + mov r4, sp /* Save the SP in a preserved register */ + +#if CONFIG_ARCH_INTERRUPTSTACK > 7 + /* Call arm_decodeirq() on the interrupt stack */ + + setirqstack r1, r3 /* SP = interrupt stack top */ +#else + /* Call arm_decodeirq() on the user stack */ + + /* If the interrupt stack is disabled, reserve xcpcontext to ensure + * that signal processing can have a separate xcpcontext to handle + * signal context (reference: arm_schedulesigaction.c): + * ---------------------- + * | IRQ XCP context | + * ------------------- + * | Signal XCP context | + * ---------------------- <- SP + */ + + sub sp, sp, #XCPTCONTEXT_SIZE /* Reserve signal context */ +#endif + + bic sp, sp, #7 /* Force 8-byte alignment */ + bl arm_decodeirq /* Call the handler */ + mov sp, r4 /* Restore the possibly unaligned stack pointer */ + +#ifdef CONFIG_ARCH_FPU + /* Restore the state of the floating point registers. */ + + restorefpu r0, r2 +#endif + + /* Switch back IRQ mode and return with shadow SPSR */ + + cps #PSR_MODE_IRQ + + /* Upon return from arm_decodeirq, r0 holds the pointer to the register + * state save area to use to restore the registers. This may or may not + * be the same value that was passed to arm_decodeirq: It will differ if a + * context switch is required. + */ + + /* Life is simple when everything is IRQ mode */ + + ldmia r0, {r13, r14}^ /* Restore user mode r13 and r14 */ + add r14, r0, #8 + ldmia r14!, {r0-r12} /* Restore common r0-r12 */ + + /* Restore the CPSR, SYS mode registers and return. */ + + rfeia r14 + +#if !defined(CONFIG_SMP) && CONFIG_ARCH_INTERRUPTSTACK > 7 +.Lirqstacktop: + .word g_intstacktop +#endif + .size arm_vectorirq, . - arm_vectorirq + + .align 5 + +/**************************************************************************** + * Function: arm_vectorsvc + * + * Description: + * SVC interrupt. We enter the SVC in SYS mode. + * + ****************************************************************************/ + + .globl arm_syscall + .globl arm_vectorsvc + .type arm_vectorsvc, %function + +arm_vectorsvc: + + /* Save the LR and SPSR onto the SYS mode stack before switch. */ + + srsdb sp!, #PSR_MODE_SYS + + /* Switch to SYS mode */ + +#ifdef CONFIG_ARMV8R_DECODEFIQ + cpsid if, #PSR_MODE_SYS +#else + cpsid i, #PSR_MODE_SYS +#endif + + /* Create a context structure. First set aside a stack frame + * and store r0-r12 into the frame. + */ + + stmdb sp!, {r0-r12} /* Save the SYS mode regs */ + + /* Get the correct values of USR/SYS r13(sp) in r1 and + * save r13 and r14 into the frame. + */ + + add r1, sp, #(XCPTCONTEXT_SIZE-4*REG_R0) + stmdb sp!, {r1, r14} + +#ifdef CONFIG_ARCH_FPU + /* Save the state of the floating point registers. */ + + savefpu sp, r1 +#endif + + /* Then call the SVC handler with interrupts disabled. + * void arm_syscall(struct xcptcontext *xcp) + */ + + mov fp, #0 /* Init frame pointer */ + mov r0, sp /* Get r0=xcp */ + + mov r4, sp /* Save the SP in a preserved register */ + +#if CONFIG_ARCH_INTERRUPTSTACK > 7 + /* Call arm_syscall() on the interrupt stack */ + + setirqstack r1, r3 /* SP = interrupt stack top */ +#else + /* Call arm_syscall() on the user stack */ + + /* If the interrupt stack is disabled, reserve xcpcontext to ensure + * that signal processing can have a separate xcpcontext to handle + * signal context (reference: arm_schedulesigaction.c): + * ---------------------- + * | IRQ XCP context | + * ------------------- + * | Signal XCP context | + * ---------------------- <- SP + */ + + sub sp, sp, #XCPTCONTEXT_SIZE /* Reserve signal context */ +#endif + + bic sp, sp, #7 /* Force 8-byte alignment */ + bl arm_syscall /* Call the handler */ + mov sp, r4 /* Restore the possibly unaligned stack pointer */ + +#ifdef CONFIG_ARCH_FPU + /* Restore the state of the floating point registers. */ + + restorefpu r0, r2 +#endif + + /* Switch back SVC mode and return with shadow SPSR */ + + cps #PSR_MODE_SVC + + /* Upon return from arm_syscall, r0 holds the pointer to the register + * state save area to use to restore the registers. This may or may not + * be the same value that was passed to arm_syscall: It will differ if a + * context switch is required. + */ + + /* Life is simple when everything is SVC mode */ + + ldmia r0, {r13, r14}^ /* Restore user mode r13 and r14 */ + add r14, r0, #8 + ldmia r14!, {r0-r12} /* Restore common r0-r12 */ + + /* Restore the CPSR, SYS mode registers and return. */ + + rfeia r14 + .size arm_vectorsvc, . - arm_vectorsvc + + .align 5 + +/**************************************************************************** + * Name: arm_vectordata + * + * Description: + * This is the data abort exception dispatcher. The ARM data abort exception occurs + * when a memory fault is detected during a data transfer. This handler saves the + * current processor state and gives control to data abort handler. This function + * is entered in ABORT mode with spsr = SVC CPSR, lr = SVC PC + * + ****************************************************************************/ + + .globl arm_dataabort + .globl arm_vectordata + .type arm_vectordata, %function + +arm_vectordata: + + /* Save the LR and SPSR onto the SYS mode stack before switch. */ + + sub lr, lr, #8 + srsdb sp!, #PSR_MODE_SYS + + /* Switch to SYS mode */ + +#ifdef CONFIG_ARMV8R_DECODEFIQ + cpsid if, #PSR_MODE_SYS +#else + cpsid i, #PSR_MODE_SYS +#endif + + /* Create a context structure. First set aside a stack frame + * and store r0-r12 into the frame. + */ + + stmdb sp!, {r0-r12} /* Save the SYS mode regs */ + + /* Get the correct values of USR/SYS r13(sp) in r1 and + * save r13 and r14 into the frame. + */ + + add r1, sp, #(XCPTCONTEXT_SIZE-4*REG_R0) + stmdb sp!, {r1, r14} + +#ifdef CONFIG_ARCH_FPU + /* Save the state of the floating point registers. */ + + savefpu sp, r1 +#endif + + /* Then call the data abort handler with interrupts disabled. + * void arm_dataabort(struct xcptcontext *xcp) + */ + + mov fp, #0 /* Init frame pointer */ + mov r0, sp /* Get r0=xcp */ + mrc CP15_DFAR(r1) /* Get R1=DFAR */ + mrc CP15_DFSR(r2) /* Get r2=DFSR */ + mov r4, sp /* Save the SP in a preserved register */ + bic sp, sp, #7 /* Force 8-byte alignment */ + bl arm_dataabort /* Call the handler */ + mov sp, r4 /* Restore the possibly unaligned stack pointer */ + +#ifdef CONFIG_ARCH_FPU + /* Restore the state of the floating point registers. */ + + restorefpu r0, r2 +#endif + + /* Switch back ABT mode and return with shadow SPSR */ + + cps #PSR_MODE_ABT + + /* Upon return from arm_dataabort, r0 holds the pointer to the register + * state save area to use to restore the registers. This may or may not + * be the same value that was passed to arm_dataabort: It will differ if a + * context switch is required. + */ + + /* Life is simple when everything is ABT mode */ + + ldmia r0, {r13, r14}^ /* Restore user mode r13 and r14 */ + add r14, r0, #8 + ldmia r14!, {r0-r12} /* Restore common r0-r12 */ + + /* Restore the CPSR, SYS mode registers and return. */ + + rfeia r14 + .size arm_vectordata, . - arm_vectordata + + .align 5 + +/**************************************************************************** + * Name: arm_vectorprefetch + * + * Description: + * This is the prefetch abort exception dispatcher. The ARM prefetch abort exception + * occurs when a memory fault is detected during an an instruction fetch. This + * handler saves the current processor state and gives control to prefetch abort + * handler. This function is entered in ABT mode with spsr = SVC CPSR, lr = SVC PC. + * + ****************************************************************************/ + + .globl arm_prefetchabort + .globl arm_vectorprefetch + .type arm_vectorprefetch, %function + +arm_vectorprefetch: + + /* Save the LR and SPSR onto the SYS mode stack before switch. */ + + sub lr, lr, #4 + srsdb sp!, #PSR_MODE_SYS + + cpsid if, #PSR_MODE_SYS /* Switch to SYS mode */ + + /* Create a context structure. First set aside a stack frame + * and store r0-r12 into the frame. + */ + + stmdb sp!, {r0-r12} /* Save the SYS mode regs */ + + /* Get the correct values of USR/SYS r13(sp) in r1 and + * save r13 and r14 into the frame. + */ + + add r1, sp, #(XCPTCONTEXT_SIZE-4*REG_R0) + stmdb sp!, {r1, r14} + +#ifdef CONFIG_ARCH_FPU + /* Save the state of the floating point registers. */ + + savefpu sp, r1 +#endif + + /* Then call the prefetch abort handler with interrupts disabled. + * void arm_prefetchabort(struct xcptcontext *xcp) + */ + + mov fp, #0 /* Init frame pointer */ + mov r0, sp /* Get r0=xcp */ + mrc CP15_IFAR(r1) /* Get R1=IFAR */ + mrc CP15_IFSR(r2) /* Get r2=IFSR */ + mov r4, sp /* Save the SP in a preserved register */ + bic sp, sp, #7 /* Force 8-byte alignment */ + bl arm_prefetchabort /* Call the handler */ + mov sp, r4 /* Restore the possibly unaligned stack pointer */ + +#ifdef CONFIG_ARCH_FPU + /* Restore the state of the floating point registers. */ + + restorefpu r0, r2 +#endif + + /* Switch back ABT mode and return with shadow SPSR */ + + cps #PSR_MODE_ABT + + /* Upon return from arm_prefetchabort, r0 holds the pointer to the register + * state save area to use to restore the registers. This may or may not + * be the same value that was passed to arm_prefetchabort: It will differ if a + * context switch is required. + */ + + /* Life is simple when everything is ABT mode */ + + ldmia r0, {r13, r14}^ /* Restore user mode r13 and r14 */ + add r14, r0, #8 + ldmia r14!, {r0-r12} /* Restore common r0-r12 */ + + /* Restore the CPSR, SYS mode registers and return. */ + + rfeia r14 + .size arm_vectorprefetch, . - arm_vectorprefetch + + .align 5 + +/**************************************************************************** + * Name: arm_vectorundefinsn + * + * Description: + * Undefined instruction entry exception. Entered in UND mode, spsr = SVC CPSR, + * lr = SVC PC + * + ****************************************************************************/ + + .globl arm_undefinedinsn + .globl arm_vectorundefinsn + .type arm_vectorundefinsn, %function + +arm_vectorundefinsn: + + /* Save the LR and SPSR onto the SYS mode stack before switch. */ + + srsdb sp!, #PSR_MODE_SYS + + cpsid if, #PSR_MODE_SYS /* Switch to SYS mode */ + + /* Create a context structure. First set aside a stack frame + * and store r0-r12 into the frame. + */ + + stmdb sp!, {r0-r12} /* Save the SYS mode regs */ + + /* Get the correct values of USR/SYS r13(sp) in r1 and + * save r13 and r14 into the frame. + */ + + add r1, sp, #(XCPTCONTEXT_SIZE-4*REG_R0) + stmdb sp!, {r1, r14} + +#ifdef CONFIG_ARCH_FPU + /* Save the state of the floating point registers. */ + + savefpu sp, r1 +#endif + + /* Then call the undef insn handler with interrupts disabled. + * void arm_undefinedinsn(struct xcptcontext *xcp) + */ + + mov fp, #0 /* Init frame pointer */ + mov r0, sp /* Get r0=xcp */ + mov r4, sp /* Save the SP in a preserved register */ + bic sp, sp, #7 /* Force 8-byte alignment */ + bl arm_undefinedinsn /* Call the handler */ + mov sp, r4 /* Restore the possibly unaligned stack pointer */ + +#ifdef CONFIG_ARCH_FPU + /* Restore the state of the floating point registers. */ + + restorefpu r0, r2 +#endif + + /* Switch back UND mode and return with shadow SPSR */ + + cps #PSR_MODE_UND + + /* Upon return from arm_undefinedinsn, r0 holds the pointer to the register + * state save area to use to restore the registers. This may or may not + * be the same value that was passed to arm_undefinedinsn: It will differ if a + * context switch is required. + */ + + /* Life is simple when everything is UND mode */ + + ldmia r0, {r13, r14}^ /* Restore user mode r13 and r14 */ + add r14, r0, #8 + ldmia r14!, {r0-r12} /* Restore common r0-r12 */ + + /* Restore the CPSR, SYS mode registers and return. */ + + rfeia r14 + .size arm_vectorundefinsn, . - arm_vectorundefinsn + + .align 5 + +/**************************************************************************** + * Name: arm_vectorfiq + * + * Description: + * Shouldn't happen unless a arm_decodefiq() is provided. FIQ is primarily used + * with the TrustZone feature in order to handle secure interrupts. + * + ****************************************************************************/ + +#ifdef CONFIG_ARMV8R_DECODEFIQ + .globl arm_decodefiq +#endif + .globl arm_vectorfiq + .type arm_vectorfiq, %function + +arm_vectorfiq: +#ifdef CONFIG_ARMV8R_DECODEFIQ + + /* Save the LR and SPSR onto the SYS mode stack before switch. */ + + sub lr, lr, #4 + srsdb sp!, #PSR_MODE_SYS + + cpsid if, #PSR_MODE_SYS /* Switch to SYS mode */ + + /* Create a context structure. First set aside a stack frame + * and store r0-r12 into the frame. + */ + + stmdb sp!, {r0-r12} /* Save the SYS mode regs */ + + /* Get the correct values of USR/SYS r13(sp) in r1 and + * save r13 and r14 into the frame. + */ + + add r1, sp, #(XCPTCONTEXT_SIZE-4*REG_R0) + stmdb sp!, {r1, r14} + +#ifdef CONFIG_ARCH_FPU + /* Save the state of the floating point registers. */ + + savefpu sp, r1 +#endif + + /* Then call the FIQ handler with interrupts disabled. */ + + mov fp, #0 /* Init frame pointer */ + mov r0, sp /* Get r0=xcp */ + + mov r4, sp /* Save the SP in a preserved register */ + +#if CONFIG_ARCH_INTERRUPTSTACK > 7 + /* Call arm_decodefiq() on the interrupt stack */ + + setfiqstack r1, r3 /* SP = interrupt stack top */ +#endif + + bic sp, sp, #7 /* Force 8-byte alignment */ + bl arm_decodefiq /* Call the handler */ + mov sp, r4 /* Restore the possibly unaligned stack pointer */ + +#ifdef CONFIG_ARCH_FPU + /* Restore the state of the floating point registers. */ + + restorefpu r0, r2 +#endif + + /* Switch back FIQ mode and return with shadow SPSR */ + + cps #PSR_MODE_FIQ + + /* Upon return from arm_decodefiq, r0 holds the pointer to the register + * state save area to use to restore the registers. This may or may not + * be the same value that was passed to arm_decodefiq: It will differ if a + * context switch is required. + */ + + /* Life is simple when everything is FIQ mode */ + + ldmia r0, {r13, r14}^ /* Restore user mode r13 and r14 */ + add r14, r0, #8 + ldmia r14!, {r0-r7} /* Restore common r0-r7 */ + ldmia r14, {r8-r12}^ /* Restore user mode r8-r12 */ + add r14, r14, #20 + + /* Restore the CPSR, SYS mode registers and return. */ + + rfeia r14 + +#if !defined(CONFIG_SMP) && CONFIG_ARCH_INTERRUPTSTACK > 7 +.Lfiqstacktop: + .word g_fiqstacktop +#endif + +#else + subs pc, lr, #4 +#endif + .size arm_vectorfiq, . - arm_vectorfiq + +/**************************************************************************** + * Name: g_intstackalloc/g_intstacktop + ****************************************************************************/ + +#if !defined(CONFIG_SMP) && CONFIG_ARCH_INTERRUPTSTACK > 7 + .bss + .balign 8 + + .globl g_intstackalloc + .type g_intstackalloc, object + .globl g_intstacktop + .type g_intstacktop, object + +g_intstackalloc: + .skip ((CONFIG_ARCH_INTERRUPTSTACK + 4) & ~7) +g_intstacktop: + .size g_intstacktop, 0 + .size g_intstackalloc, (CONFIG_ARCH_INTERRUPTSTACK & ~7) + +/**************************************************************************** + * Name: g_fiqstackalloc/g_fiqstacktop + ****************************************************************************/ + +#ifdef CONFIG_ARMV7R_DECODEFIQ + .globl g_fiqstackalloc + .type g_fiqstackalloc, object + .globl g_fiqstacktop + .type g_fiqstacktop, object + +g_fiqstackalloc: + .skip ((CONFIG_ARCH_INTERRUPTSTACK + 4) & ~7) +g_fiqstacktop: + .size g_fiqstacktop, 0 + .size g_fiqstackalloc, (CONFIG_ARCH_INTERRUPTSTACK & ~7) +#endif + +#endif /* !CONFIG_SMP && CONFIG_ARCH_INTERRUPTSTACK > 7 */ + .end diff --git a/arch/arm/src/armv8-r/arm_vectortab.S b/arch/arm/src/armv8-r/arm_vectortab.S new file mode 100644 index 00000000000..fcd8e9a67e7 --- /dev/null +++ b/arch/arm/src/armv8-r/arm_vectortab.S @@ -0,0 +1,126 @@ +/**************************************************************************** + * arch/arm/src/armv8-r/arm_vectortab.S + * + * 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 + + .file "arm_vectortab.S" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Symbols + ****************************************************************************/ + +#ifdef CONFIG_ARM_TOOLCHAIN_ARMCLANG + .eabi_attribute Tag_ABI_align_preserved, 1 +#endif + + .syntax unified + .arm + + .globl _sys_vector_start + .globl _sys_vector_end + +/**************************************************************************** + * Assembly Macros + ****************************************************************************/ + +/**************************************************************************** + * Name: _vector_start + * + * Description: + * Vector initialization block + ****************************************************************************/ + + .section .sys_vectors, "ax" + +_sys_vector_start: + ldr pc, .Lresethandler /* 0x00: Reset */ + ldr pc, .Lundefinedhandler /* 0x04: Undefined instruction */ + ldr pc, .Lsvchandler /* 0x08: Software interrupt */ + ldr pc, .Lprefetchaborthandler /* 0x0c: Prefetch abort */ + ldr pc, .Ldataaborthandler /* 0x10: Data abort */ + ldr pc, .Laddrexcptnhandler /* 0x14: Address exception (reserved) */ + ldr pc, .Lirqhandler /* 0x18: IRQ */ + ldr pc, .Lfiqhandler /* 0x1c: FIQ */ + + .globl __start + .globl arm_vectorundefinsn + .globl arm_vectorsvc + .globl arm_vectorprefetch + .globl arm_vectordata + .globl arm_vectoraddrexcptn + .globl arm_vectorirq + .globl arm_vectorfiq + +.Lresethandler: + .long __start +.Lundefinedhandler: + .long arm_vectorundefinsn +.Lsvchandler: + .long arm_vectorsvc +.Lprefetchaborthandler: + .long arm_vectorprefetch +.Ldataaborthandler: + .long arm_vectordata +.Laddrexcptnhandler: + .long arm_vectoraddrexcptn +.Lirqhandler: + .long arm_vectorirq +.Lfiqhandler: + .long arm_vectorfiq + +_sys_vector_end: + .size _sys_vector_start, . - _sys_vector_start + +/**************************************************************************** + * Name: _hyp_vector_start + * + * Description: + * Vector initialization block + ****************************************************************************/ + + .section .hyp_vectors, "ax" + .globl _hyp_vector_start + +_hyp_vector_start: + ldr pc, .Lhypresethandler /* 0x00: Reset */ + b $+0x0 /* 0x04: Undefined instruction */ + b $+0x0 /* 0x08: Software interrupt */ + b $+0x0 /* 0x0c: Prefetch abort */ + b $+0x0 /* 0x10: Data abort */ + b $+0x0 /* 0x14: Address exception (reserved) */ + b $+0x0 /* 0x18: IRQ */ + b $+0x0 /* 0x1c: FIQ */ + + .globl __start + +.Lhypresethandler: + .long __start + +_hyp_vector_end: + .size _hyp_vector_start, . - _hyp_vector_start + .end \ No newline at end of file diff --git a/arch/arm/src/armv8-r/barriers.h b/arch/arm/src/armv8-r/barriers.h new file mode 100644 index 00000000000..0fd9f5790ba --- /dev/null +++ b/arch/arm/src/armv8-r/barriers.h @@ -0,0 +1,46 @@ +/**************************************************************************** + * arch/arm/src/armv8-r/barriers.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_ARM_SRC_ARMV8_R_BARRIERS_H +#define __ARCH_ARM_SRC_ARMV8_R_BARRIERS_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* ARMv8-R memory barriers */ + +#define arm_isb(n) __asm__ __volatile__ ("isb " #n : : : "memory") +#define arm_dsb(n) __asm__ __volatile__ ("dsb " #n : : : "memory") +#define arm_dmb(n) __asm__ __volatile__ ("dmb " #n : : : "memory") +#define arm_nop() __asm__ __volatile__ ("nop\n") +#define arm_sev() __asm__ __volatile__ ("sev\n") + +#define ARM_DSB() arm_dsb(15) +#define ARM_ISB() arm_isb(15) +#define ARM_DMB() arm_dmb(15) +#define ARM_NOP() arm_nop() +#define ARM_SEV() arm_sev() + +#endif /* __ARCH_ARM_SRC_ARMV8_R_BARRIERS_H */ diff --git a/arch/arm/src/armv8-r/cp15.h b/arch/arm/src/armv8-r/cp15.h new file mode 100644 index 00000000000..ddc550e35a2 --- /dev/null +++ b/arch/arm/src/armv8-r/cp15.h @@ -0,0 +1,224 @@ +/**************************************************************************** + * arch/arm/src/armv8-r/cp15.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. + * + ****************************************************************************/ + +/* References: + * "ARM Architecture Reference Manual, ARMv7-A and ARMv7-R edition", + * Copyright 1996-1998, 2000, 2004-2012 ARM. + * All rights reserved. ARM DDI 0406C.c (ID051414) + */ + +#ifndef __ARCH_ARM_SRC_ARMV8_R_CP15_H +#define __ARCH_ARM_SRC_ARMV8_R_CP15_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* System control register descriptions. + * + * CP15 registers are accessed with MRC and MCR instructions as follows: + * + * MRC p15, , , , , ; Read CP15 Register + * MCR p15, , , , , ; Write CP15 Register + * + * Where + * + * is the Opcode_1 value for the register + * is a general purpose register + * is the register number within CP15 + * is the operational register + * is the Opcode_2 value for the register. + * + */ + +#ifdef __ASSEMBLY__ +# define _CP15(op1,rd,crn,crm,op2) p15, op1, rd, crn, crm, op2 +# define _CP15_64(op1,lo,hi,op2) p15, op1, lo, hi, op2 +#else +# define _CP15(op1,rd,crn,crm,op2) "p15, " #op1 ", %0, " #crn ", " #crm ", " #op2 +# define _CP15_64(op1,lo,hi,op2) "p15, " #op1 ", %Q0, %R0, " #op2 +#endif + +#define CP15_MIDR(r) _CP15(0, r, c0, c0, 0) /* Main ID Register */ +#define CP15_CTR(r) _CP15(0, r, c0, c0, 1) /* Cache Type Register */ +#define CP15_TCMTR(r) _CP15(0, r, c0, c0, 2) /* TCM Type Register */ +#define CP15_MPUIR(r) _CP15(0, r, c0, c0, 4) /* MPU Type Register */ +#define CP15_MPIDR(r) _CP15(0, r, c0, c0, 5) /* Multiprocessor Affinity Register */ +#define CP15_REVIDR(r) _CP15(0, r, c0, c0, 6) /* Revision ID register (Cortex-A9) */ +#define CP15_MID_PFR0(r) _CP15(0, r, c0, c1, 0) /* Processor Feature Register 0 */ +#define CP15_MID_PFR1(r) _CP15(0, r, c0, c1, 1) /* Processor Feature Register 1 */ +#define CP15_MID_DFR0(r) _CP15(0, r, c0, c1, 2) /* Debug Feature Register 0 */ +#define CP15_MID_AFR0(r) _CP15(0, r, c0, c1, 3) /* Auxiliary Feature Register 0 (Cortex-A9) */ +#define CP15_MID_MMFR0(r) _CP15(0, r, c0, c1, 4) /* Memory Model Features Register 0 */ +#define CP15_MID_MMFR1(r) _CP15(0, r, c0, c1, 5) /* Memory Model Features Register 1 */ +#define CP15_MID_MMFR2(r) _CP15(0, r, c0, c1, 6) /* Memory Model Features Register 2 */ +#define CP15_MID_MMFR3(r) _CP15(0, r, c0, c1, 7) /* Memory Model Features Register 3 */ +#define CP15_ID_ISAR0(r) _CP15(0, r, c0, c2, 0) /* Instruction Set Attributes Register 0 */ +#define CP15_ID_ISAR1(r) _CP15(0, r, c0, c2, 1) /* Instruction Set Attributes Register 1 */ +#define CP15_ID_ISAR2(r) _CP15(0, r, c0, c2, 2) /* Instruction Set Attributes Register 2 */ +#define CP15_ID_ISAR3(r) _CP15(0, r, c0, c2, 3) /* Instruction Set Attributes Register 3 */ +#define CP15_ID_ISAR4(r) _CP15(0, r, c0, c2, 4) /* Instruction Set Attributes Register 4 */ +#define CP15_ID_ISAR5(r) _CP15(0, r, c0, c2, 5) /* Instruction Set Attributes Register 5 (Cortex-A5) */ +#define CP15_CCSIDR(r) _CP15(1, r, c0, c0, 0) /* Cache Size Identification Register */ +#define CP15_CLIDR(r) _CP15(1, r, c0, c0, 1) /* Cache Level ID Register */ +#define CP15_AIDR(r) _CP15(1, r, c0, c0, 7) /* Auxiliary ID Register */ +#define CP15_CSSELR(r) _CP15(2, r, c0, c0, 0) /* Cache Size Selection Register */ + +#define CP15_SCTLR(r) _CP15(0, r, c1, c0, 0) /* System Control Register */ +#define CP15_ACTLR(r) _CP15(0, r, c1, c0, 1) /* Auxiliary Control Register */ +#define CP15_CPACR(r) _CP15(0, r, c1, c0, 2) /* Coprocessor Access Control Register */ + +#define CP15_DFSR(r) _CP15(0, r, c5, c0, 0) /* Data Fault Status Register */ +#define CP15_IFSR(r) _CP15(0, r, c5, c0, 1) /* Instruction Fault Status Register */ +#define CP15_ADFSR(r) _CP15(0, r, c5, c1, 0) /* Auxiliary Data Fault Status Register */ +#define CP15_AIFSR(r) _CP15(0, r, c5, c1, 1) /* Auxiliary Instruction Fault Status Register */ + +#define CP15_DFAR(r) _CP15(0, r, c6, c0, 0) /* Data Fault Address Register */ +#define CP15_IFAR(r) _CP15(0, r, c6, c0, 2) /* Instruction Fault Address Register */ +#define CP15_DRBAR(r) _CP15(0, r, c6, c1, 0) /* Data Region Base Address Register */ +#define CP15_DRSR(r) _CP15(0, r, c6, c1, 2) /* Data Region Size and Enable Register */ +#define CP15_DRACR(r) _CP15(0, r, c6, c1, 4) /* Data Region Access Control Register */ +#ifndef CONFIG_ARM_HAVE_MPU_UNIFIED +# define CP15_IRBAR(r) _CP15(0, r, c6, c1, 1) /* Instruction Region Base Address Register */ +# define CP15_IRSR(r) _CP15(0, r, c6, c1, 3) /* Instruction Region Size and Enable Register */ +# define CP15_IRACR(r) _CP15(0, r, c6, c1, 5) /* Instruction Region Access Control Register */ +#endif +#define CP15_RGNR(r) _CP15(0, r, c6, c2, 0) /* MPU Region Number Register */ + +#define CP15_ICIALLUIS(r) _CP15(0, r, c7, c1, 0) /* Cache Operations Registers */ +#define CP15_BPIALLIS(r) _CP15(0, r, c7, c1, 6) + +#define CP15_ICIALLU(r) _CP15(0, r, c7, c5, 0) /* Cache Operations Registers */ +#define CP15_ICIMVAU(r) _CP15(0, r, c7, c5, 1) +#define CP15_CP15ISB(r) _CP15(0, r, c7, c5, 4) /* CP15 Instruction Synchronization Barrier operation */ +#define CP15_BPIALL(r) _CP15(0, r, c7, c5, 6) /* Cache Operations Registers */ +#define CP15_BPIMVA(r) _CP15(0, r, c7, c5, 7) /* Cortex-A5 */ +#define CP15_DCIMVAC(r) _CP15(0, r, c7, c6, 1) +#define CP15_DCISW(r) _CP15(0, r, c7, c6, 2) +#define CP15_DCCMVAC(r) _CP15(0, r, c7, c10, 1) /* Data Cache Clean by MVA to PoC */ +#define CP15_DCCSW(r) _CP15(0, r, c7, c10, 2) /* Data Cache Clean by Set/Way */ +#define CP15_CP15DSB(r) _CP15(0, r, c7, c10, 4) /* CP15 Data Synchronization Barrier operation */ +#define CP15_CP15DMB(r) _CP15(0, r, c7, c10, 5) /* CP15 Instruction Synchronization Barrier operation */ +#define CP15_DCCMVAU(r) _CP15(0, r, c7, c11, 1) /* Cache Operations Registers */ +#define CP15_DCCIMVAC(r) _CP15(0, r, c7, c14, 1) +#define CP15_DCCISW(r) _CP15(0, r, c7, c14, 2) + +#define CP15_PMCR(r) _CP15(0, r, c9, c12, 0) /* Performance Monitor Control Register */ +#define CP15_PMCNTENSET(r) _CP15(0, r, c9, c12, 1) /* Count Enable Set Register */ +#define CP15_PMCNTENCLR(r) _CP15(0, r, c9, c12, 2) /* Count Enable Clear Register */ +#define CP15_PMOVSR(r) _CP15(0, r, c9, c12, 3) /* Overflow Flag Status Register */ +#define CP15_PMSWINC(r) _CP15(0, r, c9, c12, 4) /* Software Increment Register */ +#define CP15_PMSELR(r) _CP15(0, r, c9, c12, 5) /* Event Counter Selection Register */ +#define CP15_PMCEID0(r) _CP15(0, r, c9, c12, 6) /* Common Event Identification Registers (Cortex-A5) */ +#define CP15_PMCEID1(r) _CP15(0, r, c9, c12, 7) +#define CP15_PMCCNTR(r) _CP15(0, r, c9, c13, 0) /* Cycle Count Register */ +#define CP15_PMXEVTYPER(r) _CP15(0, r, c9, c13, 1) /* Event Type Select Register */ +#define CP15_PMXEVCNTR(r) _CP15(0, r, c9, c13, 2) /* Event Count Registers (Cortex-A5) */ +#define CP15_PMUSERENR(r) _CP15(0, r, c9, c14, 0) /* User Enable Register */ +#define CP15_PMINTENSET(r) _CP15(0, r, c9, c14, 1) /* Interrupt Enable Set Register */ +#define CP15_PMINTENCLR(r) _CP15(0, r, c9, c14, 2) /* Interrupt Enable Clear Register */ + +#define CP15_VBAR(r) _CP15(0, r, c12, c0, 0) /* Vector Base Address Register */ +#define CP15_HVBAR(r) _CP15(4, r, c12, c0, 0) /* Hypervisor Vector Base Address Register */ + +#define CP15_CONTEXTIDR(r) _CP15(0, r, c13, c0, 1) /* Context ID Register */ +#define CP15_TPIDRURW(r) _CP15(0, r, c13, c0, 2) /* Software Thread ID Registers */ +#define CP15_TPIDRURO(r) _CP15(0, r, c13, c0, 3) +#define CP15_TPIDRPRW(r) _CP15(0, r, c13, c0, 4) + +#define CP15_CNTFRQ(r) _CP15(0, r, c14, c0, 0) /* CNTFRQ */ +#define CP15_CNTVCT(lo,hi) _CP15_64(1, lo, hi, c14) /* CNTVCT */ +#define CP15_CNTV_CTL(r) _CP15(0, r, c14, c3, 1) /* CNTV_CTL */ +#define CP15_CNTV_CVAL(lo,hi) _CP15_64(3, lo, hi, c14) /* CNTV_CVAL */ + +#define CP15_CNTPCT(lo,hi) _CP15_64(0, lo, hi, c14) /* Physical Count register */ + +#define CP15_DCIALLU(r) _CP15(0, r, c15, c5, 0) /* Invalidate data cache */ + +#define CP15_ICC_PMR(r) _CP15(0, r, c4, c6, 0) /* ICC_PMR */ +#define CP15_ICC_IAR1(r) _CP15(0, r, c12, c12, 0) /* ICC_IAR1 */ +#define CP15_ICC_EOIR1(r) _CP15(0, r, c12, c12, 1) /* ICC_EOIR1 */ +#define CP15_ICC_SRE(r) _CP15(0, r, c12, c12, 5) /* ICC_SRE */ +#define CP15_ICC_HSRE(r) _CP15(4, r, c12, c9, 5) /* ICC_HSRE */ +#define CP15_ICC_IGRPEN1(r) _CP15(0, r, c12, c12, 7) /* ICC_IGRPEN1 */ +#define CP15_ICC_SGI1R(lo,hi) _CP15_64(2, lo, hi, c12) /* ICC_SGI1R */ + +#define CP15_SET(reg, value) \ + do \ + { \ + __asm__ __volatile__ \ + ( \ + "mcr " CP15_ ## reg(0) "\n" \ + :: "r"(value): "memory" \ + ); \ + } \ + while(0) \ + +#define CP15_SET2(reg, op, value) \ + do \ + { \ + __asm__ __volatile__ \ + ( \ + "mcr " CP15_ ## reg(0, op) "\n" \ + :: "r"(value): "memory" \ + ); \ + } \ + while(0) \ + +#define CP15_GET(reg) \ + ({ \ + uint32_t _value; \ + __asm__ __volatile__ \ + ( \ + "mrc " CP15_ ## reg(0) "\n" \ + : "=r"(_value) :: "memory" \ + ); \ + _value; \ + }) \ + +#define CP15_SET64(reg, value) \ + do \ + { \ + __asm__ __volatile__ \ + ( \ + "mcrr " CP15_ ## reg(0,0) "\n" \ + :: "r"(value): "memory" \ + ); \ + } \ + while(0) \ + +#define CP15_GET64(reg) \ + ({ \ + uint64_t _value; \ + __asm__ __volatile__ \ + ( \ + "mrrc " CP15_ ## reg(0,0) "\n" \ + : "=r"(_value) :: "memory" \ + ); \ + _value; \ + }) \ + +#endif /* __ARCH_ARM_SRC_ARMV8_R_CP15_H */ diff --git a/arch/arm/src/armv8-r/cp15_cacheops.c b/arch/arm/src/armv8-r/cp15_cacheops.c new file mode 100644 index 00000000000..538de979684 --- /dev/null +++ b/arch/arm/src/armv8-r/cp15_cacheops.c @@ -0,0 +1,276 @@ +/**************************************************************************** + * arch/arm/src/armv8-r/cp15_cacheops.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 "cp15_cacheops.h" + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static inline uint32_t ilog2(uint32_t u) +{ + int i = 0; + + while (u >>= 1) + { + i++; + } + + return i; +} + +static inline uint32_t cp15_cache_get_info(uint32_t *sets, uint32_t *ways) +{ + uint32_t ccsidr = CP15_GET(CCSIDR); + + if (sets) + { + *sets = ((ccsidr >> 13) & 0x7fff) + 1; + } + + if (ways) + { + *ways = ((ccsidr >> 3) & 0x3ff) + 1; + } + + return (1 << ((ccsidr & 0x7) + 2)) * 4; +} + +static void cp15_dcache_op(int op) +{ + uint32_t clidr = CP15_GET(CLIDR); + int level; + + for (level = 0; level < 7; level++) + { + uint32_t ctype = clidr & 0x7; + + switch (ctype) + { + case 0x2: + case 0x3: + case 0x4: + cp15_dcache_op_level(level, op); + break; + default: + break; + } + + clidr >>= 3; + if (clidr == 0) + { + break; + } + } +} + +static void cp15_dcache_op_mva(uintptr_t start, uintptr_t end, int op) +{ + uint32_t line; + + line = cp15_cache_get_info(NULL, NULL); + + ARM_DSB(); + + if ((start & (line - 1)) != 0) + { + start &= ~(line - 1); + if (op == CP15_CACHE_INVALIDATE) + { + cp15_cleaninvalidate_dcacheline_bymva(start); + start += line; + } + } + + while (start < end) + { + switch (op) + { + case CP15_CACHE_INVALIDATE: + if (start + line <= end) + { + cp15_invalidate_dcacheline_bymva(start); + } + else + { + cp15_cleaninvalidate_dcacheline_bymva(start); + } + break; + case CP15_CACHE_CLEAN: + cp15_clean_dcache_bymva(start); + break; + case CP15_CACHE_CLEANINVALIDATE: + cp15_cleaninvalidate_dcacheline_bymva(start); + break; + default: + break; + } + + start += line; + } + + ARM_ISB(); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +void cp15_dcache_op_level(uint32_t level, int op) +{ + uint32_t sets; + uint32_t ways; + uint32_t set; + uint32_t way; + uint32_t line; + uint32_t way_shift; + uint32_t set_shift; + uint32_t val = level << 1; + + /* Select by CSSELR */ + + CP15_SET(CSSELR, val); + + /* Get cache info */ + + line = cp15_cache_get_info(&sets, &ways); + + way_shift = 32 - ilog2(ways); + set_shift = ilog2(line); + + ARM_DSB(); + + /* A: Log2(ways) + * B: L+S + * L: Log2(line) + * S: Log2(sets) + * + * The bits are packed as follows: + * 31 31-A B B-1 L L-1 4 3 1 0 + * |---|-------------|--------|-------|-----|-| + * |Way| zeros | Set | zeros |level|0| + * |---|-------------|--------|-------|-----|-| + */ + + for (way = 0; way < ways; way++) + { + for (set = 0; set < sets; set++) + { + val = level << 1; + val |= way << way_shift; + val |= set << set_shift; + + switch (op) + { + case CP15_CACHE_INVALIDATE: + cp15_invalidate_dcacheline_bysetway(val); + break; + case CP15_CACHE_CLEAN: + cp15_clean_dcache_bysetway(val); + break; + case CP15_CACHE_CLEANINVALIDATE: + cp15_cleaninvalidate_dcacheline(val); + break; + default: + break; + } + } + } + + ARM_ISB(); +} + +void cp15_invalidate_icache(uintptr_t start, uintptr_t end) +{ + uint32_t line; + + line = cp15_cache_get_info(NULL, NULL); + start &= ~(line - 1); + + ARM_DSB(); + + while (start < end) + { + cp15_invalidate_icache_bymva(start); + start += line; + } + + ARM_ISB(); +} + +void cp15_coherent_dcache(uintptr_t start, uintptr_t end) +{ + cp15_dcache_op_mva(start, end, CP15_CACHE_CLEANINVALIDATE); + cp15_invalidate_icache_all(); +} + +void cp15_invalidate_dcache(uintptr_t start, uintptr_t end) +{ + cp15_dcache_op_mva(start, end, CP15_CACHE_INVALIDATE); +} + +void cp15_invalidate_dcache_all(void) +{ + cp15_dcache_op(CP15_CACHE_INVALIDATE); +} + +void cp15_clean_dcache(uintptr_t start, uintptr_t end) +{ + cp15_dcache_op_mva(start, end, CP15_CACHE_CLEAN); +} + +void cp15_clean_dcache_all(void) +{ + cp15_dcache_op(CP15_CACHE_CLEAN); +} + +void cp15_flush_dcache(uintptr_t start, uintptr_t end) +{ + cp15_dcache_op_mva(start, end, CP15_CACHE_CLEANINVALIDATE); +} + +void cp15_flush_dcache_all(void) +{ + cp15_dcache_op(CP15_CACHE_CLEANINVALIDATE); +} + +uint32_t cp15_cache_size(void) +{ + uint32_t sets; + uint32_t ways; + uint32_t line; + + line = cp15_cache_get_info(&sets, &ways); + + return sets * ways * line; +} + +uint32_t cp15_cache_linesize(void) +{ + return cp15_cache_get_info(NULL, NULL); +} diff --git a/arch/arm/src/armv8-r/cp15_cacheops.h b/arch/arm/src/armv8-r/cp15_cacheops.h new file mode 100644 index 00000000000..e72998442b1 --- /dev/null +++ b/arch/arm/src/armv8-r/cp15_cacheops.h @@ -0,0 +1,1138 @@ +/**************************************************************************** + * arch/arm/src/armv8-r/cp15_cacheops.h + * + * Copyright (C) 2015 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Portions of this file derive from Atmel sample code for the SAMA5D3 + * Cortex-A5 which also has a modified BSD-style license: + * + * Copyright (c) 2012, Atmel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor Atmel nor the names of the contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/* References: + * + * "ARM Architecture Reference Manual, ARMv7-A and ARMv7-R edition", + * Copyright 1996-1998, 2000, 2004-2012 ARM. All rights reserved. + * ARM DDI 0406C.c (ID051414) + */ + +#ifndef __ARCH_ARM_SRC_ARMV7_R_CP15_CACHEOPS_H +#define __ARCH_ARM_SRC_ARMV7_R_CP15_CACHEOPS_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include "sctlr.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Cache definitions ********************************************************/ + +#define CP15_CACHE_INVALIDATE 0 +#define CP15_CACHE_CLEAN 1 +#define CP15_CACHE_CLEANINVALIDATE 2 + +/* L1 Memory */ + +#define CP15_L1_LINESIZE 32 + +/* CP15 Registers ***********************************************************/ + +/* Terms: + * 1) Point of coherency (PoC) + * The PoC is the point at which all agents that can access memory are + * guaranteed to see the same copy of a memory location + * 2) Point of unification (PoU) + * The PoU is the point by which the instruction and data caches and the + * translation table walks of the processor are guaranteed to see the same + * copy of a memory location. + * + * Cache Operations: + * + * CP15 Register: ICIALLUIS + * Description: Invalidate entire instruction cache Inner Shareable. + * Register Format: Should be zero (SBZ) + * Instruction: MCR p15, 0, , c7, c1, 0 + * CP15 Register: BPIALLIS + * Description: Invalidate entire branch predictor array Inner + * Shareable. + * Register Format: Should be zero (SBZ) + * Instruction: MCR p15, 0, , c7, c1, 6 + * CP15 Register: ICIALLU + * Description: Invalidate all instruction caches to PoU. Also flushes + * branch target cache. + * Register Format: Should be zero (SBZ) + * Instruction: MCR p15, 0, , c7, c5, 0 + * CP15 Register: ICIMVAU + * Description: Invalidate instruction cache by VA to PoU. + * Register Format: VA + * Instruction: MCR p15, 0, , c7, c5, 1 + * CP15 Register: CP15ISB + * Description: Instruction Synchronization Barrier operation + * NOTE: Deprecated and no longer documented + * Instruction: MCR p15, 0, , c7, c5, 4 + * CP15 Register: BPIALL + * Description: Invalidate entire branch predictor array. + * Register Format: Should be zero (SBZ) + * Instruction: MCR p15, 0, , c7, c5, 6 + * CP15 Register: BPIMVA + * Description: Invalidate VA from branch predictor array. + * Register Format: Should be zero (SBZ) + * Instruction: MCR p15, 0, , c7, c5, 7 + * CP15 Register: DCIMVAC + * Description: Invalidate data cache line by VA to PoC. + * Register Format: VA + * Instruction: MCR p15, 0, , c7, c6, 1 + * CP15 Register: DCISW + * Description: Invalidate data cache line by Set/Way. + * Register Format: Set/Way + * Instruction: MCR p15, 0, , c7, c6, 2 + * CP15 Register: DCCMVAC + * Description: Clean data cache line to PoC by VA. + * Register Format: VA + * Instruction: MCR p15, 0, , c7, c10, 1 + * CP15 Register: DCCSW + * Description: Clean data cache line by Set/Way. + * Register Format: Set/Way + * Instruction: MCR p15, 0, , c7, c10, 2 + * CP15 Register: CP15DSB + * Description: Data Synchronization Barrier operation + * NOTE: Deprecated and no longer documented + * Instruction: MCR p15, 0, , c7, c10, 4 + * CP15 Register: CP15DMB + * Description: Data Memory Barrier operation + * NOTE: Deprecated and no longer documented + * Instruction: MCR p15, 0, , c7, c10, 5 + * CP15 Register: DCCMVAU + * Description: Clean data or unified cache line by VA to PoU. + * Register Format: VA + * Instruction: MCR p15, 0, , c7, c11, 1 + * CP15 Register: DCCIMVAC + * Description: Clean and invalidate data cache line by VA to PoC. + * Register Format: VA + * Instruction: MCR p15, 0, , c7, c14, 1 + * CP15 Register: DCCISW + * Description: Clean and invalidate data cache line by Set/Way. + * Register Format: Set/Way + * Instruction: MCR p15, 0, , c7, c14, 2 + */ + +/* Set/way format */ + +#define CACHE_WAY_SHIFT (3) /* Bits 30-31: Way in set being accessed */ +#define CACHE_WAY_MASK (3 << CACHE_WAY_SHIFT) +#define CACHE_SET_SHIFT (5) /* Bits 5-(S+4): Way in set being accessed */ + /* For 4KB cache size: S=5 */ +#define CACHE_SET4KB_MASK (0x1f << CACHE_SET_SHIFT) + /* Bits 10-29: Reserved */ + /* For 8KB cache size: S=6 */ +#define CACHE_SET8KB_MASK (0x3f << CACHE_SET_SHIFT) + /* Bits 11-29: Reserved */ + /* For 16KB cache size: S=7 */ +#define CACHE_SET16KB_MASK (0x7f << CACHE_SET_SHIFT) + /* Bits 12-29: Reserved */ + /* For 32KB cache size: S=8 */ +#define CACHE_SET32KB_MASK (0xff << CACHE_SET_SHIFT) + /* Bits 13-29: Reserved */ + /* For 64KB cache size: S=9 */ +#define CACHE_SET64KB_MASK (0x1fff << CACHE_SET_SHIFT) + /* Bits 14-29: Reserved */ + +/* VA and SBZ format */ + +#define CACHE_SBZ_SHIFT (4) /* Bits 0-4: Should be zero (SBZ) */ +#define CACHE_SBZ_MASK (31 << TLB_SBZ_SHIFT) +#define CACHE_VA_MASK (0xfffffffe0) /* Bits 5-31: Virtual address */ + +/**************************************************************************** + * Assembly Macros + ****************************************************************************/ + +/* cp15_cache Cache Operations + * + * Usage + * + * They are performed as MCR instructions and only operate on a level 1 cache + * associated with ARM v7 processor. + * + * The supported operations are: + * + * 1. Any of these operations can be applied to any data cache or any + * unified cache. + * 2. Invalidate by MVA. Performs an invalidate of a data or unified cache + * line + * based on the address it contains. + * 3. Invalidate by set/way. Performs an invalidate of a data or unified + * cache line based on its location in the cache hierarchy. + * 4. Clean by MVA. Performs a clean of a data or unified cache line based + * on the address it contains. + * 5. Clean by set/way. Performs a clean of a data or unified cache line + * based on its location in the cache hierarchy. + * 6. Clean and Invalidate by MVA. Performs a clean and invalidate of a + * data or unified cache line based on the address it contains. + * 7. Clean and Invalidate by set/way. Performs a clean and invalidate of + * a data or unified cache line based on its location in the cache + * hierarchy. + * + * NOTE: Many of these operations are implemented as assembly language + * macros or as C inline functions in the file cache.h. The larger functions + * are implemented here as C-callable functions. + */ + +#ifdef __ASSEMBLY__ + +/**************************************************************************** + * Name: cp15_enable_dcache + * + * Description: + * Enable L1 D Cache + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +.macro cp15_enable_dcache, tmp + mrc p15, 0, \tmp, c1, c0, 0 /* Read SCTLR */ + orr \tmp, \tmp, #(0x1 << 2) /* Enable D cache */ + mcr p15, 0, \tmp, c1, c0, 0 /* Update the SCTLR */ + isb +.endm + +/**************************************************************************** + * Name: cp15_disable_dcache + * + * Description: + * Disable L1 D Cache + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +.macro cp15_disable_dcache, tmp + mrc p15, 0, \tmp, c1, c0, 0 /* Read SCTLR */ + bic \tmp, \tmp, #(0x1 << 2) /* Disable D cache */ + mcr p15, 0, \tmp, c1, c0, 0 /* Update the SCTLR */ + isb +.endm + +/**************************************************************************** + * Name: cp15_enable_icache + * + * Description: + * Enable L1 I Cache + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +.macro cp15_enable_icache, tmp + mrc p15, 0, \tmp, c1, c0, 0 /* Read SCTLR */ + orr \tmp, \tmp, #(0x1 << 12) /* Enable I cache */ + mcr p15, 0, \tmp, c1, c0, 0 /* Update the SCTLR */ + isb +.endm + +/**************************************************************************** + * Name: cp15_disable_icache + * + * Description: + * Disable L1 I Cache + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +.macro cp15_disable_icache, tmp + mrc p15, 0, \tmp, c1, c0, 0 /* Read SCTLR */ + bic \tmp, \tmp, #(0x1 << 12) /* Disable I cache */ + mcr p15, 0, \tmp, c1, c0, 0 /* Update the SCTLR */ + isb +.endm + +/**************************************************************************** + * Name: cp15_invalidate_icache_inner_sharable + * + * Description: + * Invalidate I cache predictor array inner shareable + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +.macro cp15_invalidate_icache_inner_sharable, tmp + mov \tmp, #0 + mrc p15, 0, \tmp, c7, c1, 0 /* ICIALLUIS */ + isb +.endm + +/**************************************************************************** + * Name: cp15_invalidate_btb_inner_sharable + * + * Description: + * Invalidate entire branch predictor array inner shareable + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +.macro cp15_invalidate_btb_inner_sharable, tmp + mov \tmp, #0 + mrc p15, 0, \tmp, c7, c1, 6 /* BPIALLIS */ + isb +.endm + +/**************************************************************************** + * Name: cp15_invalidate_icache_all + * + * Description: + * Invalidate all instruction caches to PoU, also flushes branch target + * cache + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +.macro cp15_invalidate_icache_all, tmp + mov \tmp, #0 + mrc p15, 0, \tmp, c7, c5, 0 /* ICIALLU */ + isb +.endm + +/**************************************************************************** + * Name: cp15_invalidate_icache_bymva + * + * Description: + * Invalidate instruction caches by VA to PoU + * + * Input Parameters: + * va - Register with VA format + * + * Returned Value: + * None + * + ****************************************************************************/ + +.macro cp15_invalidate_icache_bymva, va + mrc p15, 0, \va, c7, c5, 1 /* ICIMVAU */ + isb +.endm + +/**************************************************************************** + * Name: cp15_flush_btb + * + * Description: + * Invalidate entire branch predictor array + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +.macro cp15_flush_btb, tmp + mov \tmp, #0 + mrc p15, 0, \tmp, c7, c5, 6 /* BPIALL */ + isb +.endm + +/**************************************************************************** + * Name: cp15_flush_btb_bymva + * + * Description: + * Invalidate branch predictor array entry by MVA + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +.macro cp15_flush_btb_bymva, va + mrc p15, 0, \va, c7, c5, 7 /* BPIMVA */ + isb +.endm + +/**************************************************************************** + * Name: cp15_invalidate_dcacheline_bymva + * + * Description: + * Invalidate data cache line by VA to PoC + * + * Input Parameters: + * va - Register with VA format + * + * Returned Value: + * None + * + ****************************************************************************/ + +.macro cp15_invalidate_dcacheline_bymva, va + mrc p15, 0, \va, c7, c6, 1 /* DCIMVAC */ + isb +.endm + +/**************************************************************************** + * Name: cp15_invalidate_dcacheline_bysetway + * + * Description: + * Invalidate data cache line by set/way + * + * Input Parameters: + * setway - Register with Set/Way format + * + * Returned Value: + * None + * + ****************************************************************************/ + +.macro cp15_invalidate_dcacheline_bysetway, setway + mrc p15, 0, \setway, c7, c6, 2 /* DCISW */ + isb +.endm + +/**************************************************************************** + * Name: cp15_clean_dcache_bymva + * + * Description: + * Clean data cache line by MVA + * + * Input Parameters: + * va - Register with VA format + * + * Returned Value: + * None + * + ****************************************************************************/ + +.macro cp15_clean_dcache_bymva, va + mrc p15, 0, \va, c7, c10, 1 /* DCCMVAC */ + isb +.endm + +/**************************************************************************** + * Name: cp15_clean_dcache_bysetway + * + * Description: + * Clean data cache line by Set/way + * + * Input Parameters: + * setway - Register with Set/Way format + * + * Returned Value: + * None + * + ****************************************************************************/ + +.macro cp15_clean_dcache_bysetway, setway + mrc p15, 0, \setway, c7, c10, 2 /* DCCSW */ + isb +.endm + +/**************************************************************************** + * Name: cp15_clean_ucache_bymva + * + * Description: + * Clean unified cache line by MVA + * + * Input Parameters: + * setway - Register with VA format + * + * Returned Value: + * None + * + ****************************************************************************/ + +.macro cp15_clean_ucache_bymva, va + mrc p15, 0, \va, c7, c11, 1 /* DCCMVAU */ + isb +.endm + +/**************************************************************************** + * Name: cp15_cleaninvalidate_dcacheline_bymva + * + * Description: + * Clean and invalidate data cache line by VA to PoC + * + * Input Parameters: + * va - Register with VA format + * + * Returned Value: + * None + * + ****************************************************************************/ + +.macro cp15_cleaninvalidate_dcacheline_bymva, va + mrc p15, 0, \va, c7, c14, 1 /* DCCIMVAC */ + isb +.endm + +/**************************************************************************** + * Name: cp15_cleaninvalidate_dcacheline + * + * Description: + * Clean and Incalidate data cache line by Set/Way + * + * Input Parameters: + * setway - Register with Set/Way format + * + * Returned Value: + * None + * + ****************************************************************************/ + +.macro cp15_cleaninvalidate_dcacheline, setway + mrc p15, 0, \setway, c7, c14, 2 /* DCCISW */ + isb +.endm + +#endif /* __ASSEMBLY__ */ + +/**************************************************************************** + * Inline Functions + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +/**************************************************************************** + * Name: cp15_enable_dcache + * + * Description: + * Enable L1 D Cache + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +static inline void cp15_enable_dcache(void) +{ + uint32_t sctlr; + + sctlr = CP15_GET(SCTLR); + sctlr |= SCTLR_C; + CP15_SET(SCTLR, sctlr); + ARM_ISB(); +} + +/**************************************************************************** + * Name: cp15_disable_dcache + * + * Description: + * Disable L1 D Cache + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +static inline void cp15_disable_dcache(void) +{ + uint32_t sctlr; + + sctlr = CP15_GET(SCTLR); + sctlr &= ~SCTLR_C; + CP15_SET(SCTLR, sctlr); + ARM_ISB(); +} + +/**************************************************************************** + * Name: cp15_enable_icache + * + * Description: + * Enable L1 I Cache + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +static inline void cp15_enable_icache(void) +{ + uint32_t sctlr; + + sctlr = CP15_GET(SCTLR); + sctlr |= SCTLR_I; + CP15_SET(SCTLR, sctlr); + ARM_ISB(); +} + +/**************************************************************************** + * Name: cp15_disable_icache + * + * Description: + * Disable L1 I Cache + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +static inline void cp15_disable_icache(void) +{ + uint32_t sctlr; + + sctlr = CP15_GET(SCTLR); + sctlr &= ~SCTLR_I; + CP15_SET(SCTLR, sctlr); + ARM_ISB(); +} + +/**************************************************************************** + * Name: cp15_invalidate_icache_inner_sharable + * + * Description: + * Invalidate I cache predictor array inner shareable + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +static inline void cp15_invalidate_icache_inner_sharable(void) +{ + CP15_SET(ICIALLUIS, 0); + ARM_ISB(); +} + +/**************************************************************************** + * Name: cp15_invalidate_btb_inner_sharable + * + * Description: + * Invalidate entire branch predictor array inner shareable + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +static inline void cp15_invalidate_btb_inner_sharable(void) +{ + CP15_SET(BPIALLIS, 0); + ARM_ISB(); +} + +/**************************************************************************** + * Name: cp15_invalidate_icache_all + * + * Description: + * Invalidate all instruction caches to PoU, also flushes branch target + * cache + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +static inline void cp15_invalidate_icache_all(void) +{ + CP15_SET(ICIALLU, 0); + ARM_ISB(); +} + +/**************************************************************************** + * Name: cp15_invalidate_icache_bymva + * + * Description: + * Invalidate instruction caches by VA to PoU + * + * Input Parameters: + * va - 32-bit value with VA format + * + * Returned Value: + * None + * + ****************************************************************************/ + +static inline void cp15_invalidate_icache_bymva(unsigned int va) +{ + CP15_SET(ICIMVAU, va); + ARM_ISB(); +} + +/**************************************************************************** + * Name: cp15_flush_btb + * + * Description: + * Invalidate entire branch predictor array + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +static inline void cp15_flush_btb(void) +{ + CP15_SET(BPIALL, 0); + ARM_ISB(); +} + +/**************************************************************************** + * Name: cp15_flush_btb_bymva + * + * Description: + * Invalidate branch predictor array entry by MVA + * + * Input Parameters: + * va - 32-bit value with VA format + * + * Returned Value: + * None + * + ****************************************************************************/ + +static inline void cp15_flush_btb_bymva(unsigned int va) +{ + CP15_SET(BPIMVA, va); + ARM_ISB(); +} + +/**************************************************************************** + * Name: cp15_invalidate_dcacheline_bymva + * + * Description: + * Invalidate data cache line by VA to PoC + * + * Input Parameters: + * va - 32-bit value with VA format + * + * Returned Value: + * None + * + ****************************************************************************/ + +/* Invalidate data cache line by VA to PoC */ + +static inline void cp15_invalidate_dcacheline_bymva(unsigned int va) +{ + CP15_SET(DCIMVAC, va); + ARM_ISB(); +} + +/**************************************************************************** + * Name: cp15_invalidate_dcacheline_bysetway + * + * Description: + * Invalidate data cache line by set/way + * + * Input Parameters: + * setway - 32-bit value with Set/Way format + * + * Returned Value: + * None + * + ****************************************************************************/ + +/* Invalidate data cache line by set/way */ + +static inline void cp15_invalidate_dcacheline_bysetway(unsigned int setway) +{ + CP15_SET(DCISW, setway); + ARM_ISB(); +} + +/**************************************************************************** + * Name: cp15_clean_dcache_bymva + * + * Description: + * Clean data cache line by MVA + * + * Input Parameters: + * va - 32-bit value with VA format + * + * Returned Value: + * None + * + ****************************************************************************/ + +/* Clean data cache line by MVA */ + +static inline void cp15_clean_dcache_bymva(unsigned int va) +{ + CP15_SET(DCCMVAC, va); + ARM_ISB(); +} + +/**************************************************************************** + * Name: cp15_clean_dcache_bysetway + * + * Description: + * Clean data cache line by Set/way + * + * Input Parameters: + * setway - 32-bit value with Set/Way format + * + * Returned Value: + * None + * + ****************************************************************************/ + +static inline void cp15_clean_dcache_bysetway(unsigned int setway) +{ + CP15_SET(DCCSW, setway); + ARM_ISB(); +} + +/**************************************************************************** + * Name: cp15_clean_ucache_bymva + * + * Description: + * Clean unified cache line by MVA + * + * Input Parameters: + * va - 32-bit value with VA format + * + * Returned Value: + * None + * + ****************************************************************************/ + +static inline void cp15_clean_ucache_bymva(unsigned int va) +{ + CP15_SET(DCCMVAU, va); + ARM_ISB(); +} + +/**************************************************************************** + * Name: cp15_cleaninvalidate_dcacheline_bymva + * + * Description: + * Clean and invalidate data cache line by VA to PoC + * + * Input Parameters: + * va - 32-bit value with VA format + * + * Returned Value: + * None + * + ****************************************************************************/ + +static inline void cp15_cleaninvalidate_dcacheline_bymva(unsigned int va) +{ + CP15_SET(DCCIMVAC, va); + ARM_ISB(); +} + +/**************************************************************************** + * Name: cp15_cleaninvalidate_dcacheline + * + * Description: + * Clean and Incalidate data cache line by Set/Way + * + * Input Parameters: + * setway - 32-bit value with Set/Way format + * + * Returned Value: + * None + * + ****************************************************************************/ + +static inline void cp15_cleaninvalidate_dcacheline(unsigned int setway) +{ + CP15_SET(DCCISW, setway); + ARM_ISB(); +} + +#endif /* __ASSEMBLY__ */ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#ifndef __ASSEMBLY__ +#ifdef __cplusplus +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: cp15_invalidate_icache + * + * Description: + * Invalidate the instruction cache within the specified region. + * + * Input Parameters: + * start - virtual start address of region + * end - virtual end address of region + 1 + * + * Returned Value: + * None + * + ****************************************************************************/ + +void cp15_invalidate_icache(uintptr_t start, uintptr_t end); + +/**************************************************************************** + * Name: cp15_dcache_op_level + * + * Description: + * Dcache operation from level + * + * Input Parameters: + * level - cache level + * op - CP15_CACHE_XX + * + * Returned Value: + * None + * + ****************************************************************************/ + +void cp15_dcache_op_level(uint32_t level, int op); + +/**************************************************************************** + * Name: cp15_coherent_dcache + * + * Description: + * Ensure that the I and D caches are coherent within specified region + * by cleaning the D cache (i.e., flushing the D cache contents to memory + * and invalidating the I cache). This is typically used when code has been + * written to a memory region, and will be executed. + * + * Input Parameters: + * start - virtual start address of region + * end - virtual end address of region + 1 + * + * Returned Value: + * None + * + ****************************************************************************/ + +void cp15_coherent_dcache(uintptr_t start, uintptr_t end); + +/**************************************************************************** + * Name: cp15_invalidate_dcache + * + * Description: + * Invalidate the data cache within the specified region; we will be + * performing a DMA operation in this region and we want to purge old data + * in the cache. + * + * Input Parameters: + * start - virtual start address of region + * end - virtual end address of region + 1 + * + * Returned Value: + * None + * + ****************************************************************************/ + +void cp15_invalidate_dcache(uintptr_t start, uintptr_t end); + +/**************************************************************************** + * Name: cp15_invalidate_dcache_all + * + * Description: + * Invalidate the entire contents of D cache. + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +void cp15_invalidate_dcache_all(void); + +/**************************************************************************** + * Name: cp15_clean_dcache + * + * Description: + * Clean the data cache within the specified region by flushing the + * contents of the data cache to memory. + * + * Input Parameters: + * start - virtual start address of region + * end - virtual end address of region + 1 + * + * Returned Value: + * None + * + ****************************************************************************/ + +void cp15_clean_dcache(uintptr_t start, uintptr_t end); + +/**************************************************************************** + * Name: cp15_clean_dcache_all + * + * Description: + * Clean the entire contents of D cache. + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +void cp15_clean_dcache_all(void); + +/**************************************************************************** + * Name: cp15_flush_dcache + * + * Description: + * Flush the data cache within the specified region by cleaning and + * invalidating the D cache. + * + * Input Parameters: + * start - virtual start address of region + * end - virtual end address of region + 1 + * + * Returned Value: + * None + * + ****************************************************************************/ + +void cp15_flush_dcache(uintptr_t start, uintptr_t end); + +/**************************************************************************** + * Name: cp15_flush_dcache_all + * + * Description: + * Flush the entire contents of D cache. + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +void cp15_flush_dcache_all(void); + +/**************************************************************************** + * Name: cp15_cache_size + * + * Description: + * Get cp15 cache size in byte + * + * Input Parameters: + * None + * + * Returned Value: + * Cache size in byte + * + ****************************************************************************/ + +uint32_t cp15_cache_size(void); + +/**************************************************************************** + * Name: cp15_cache_linesize + * + * Description: + * Get cp15 cache linesize in byte + * + * Input Parameters: + * None + * + * Returned Value: + * Cache linesize in byte + * + ****************************************************************************/ + +uint32_t cp15_cache_linesize(void); + +#undef EXTERN +#ifdef __cplusplus +} +#endif +#endif /* __ASSEMBLY__ */ + +#endif /* __ARCH_ARM_SRC_ARMV7_R_CP15_CACHEOPS_H */ diff --git a/arch/arm/src/armv8-r/sctlr.h b/arch/arm/src/armv8-r/sctlr.h new file mode 100644 index 00000000000..bbfaadd1943 --- /dev/null +++ b/arch/arm/src/armv8-r/sctlr.h @@ -0,0 +1,822 @@ +/**************************************************************************** + * arch/arm/src/armv8-r/sctlr.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. + * + ****************************************************************************/ + +/* References: + * + * "ARM Architecture Reference Manual, ARMv7-A and ARMv7-R edition", + * Copyright 1996-1998, 2000, 2004-2012 ARM. + * All rights reserved. ARM DDI 0406C.c (ID051414) + */ + +#ifndef __ARCH_ARM_SRC_ARMV8_R_SCTLR_H +#define __ARCH_ARM_SRC_ARMV8_R_SCTLR_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include "barriers.h" +#include "cp15.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* CP15 c0 Registers ********************************************************/ + +/* Main ID Register (MIDR): CRn=c0, opc1=0, CRm=c0, opc2=0 + * TODO: To be provided + */ + +/* Cache Type Register (CTR): CRn=c0, opc1=0, CRm=c0, opc2=1 + * TODO: To be provided + */ + +/* TCM Type Register (TCMTR): CRn=c0, opc1=0, CRm=c0, opc2=2 + * Details implementation defined. + */ + +/* Aliases of Main ID register (MIDR): CRn=c0, opc1=0, CRm=c0, opc2=3,7 + * TODO: To be provided + */ + +/* MPU Type Register (MPUIR): CRn=c0, opc1=0, CRm=c0, opc2=4 + * TODO: To be provided + */ + +/* Multiprocessor Affinity Register (MPIDR): CRn=c0, opc1=0, CRm=c0, opc2=5 */ + +#define MPIDR_CPUID_SHIFT (0) /* Bits 0-1: CPU ID */ +#define MPIDR_CPUID_MASK (3 << MPIDR_CPUID_SHIFT) +# define MPIDR_CPUID_CPU0 (0 << MPIDR_CPUID_SHIFT) +# define MPIDR_CPUID_CPU1 (1 << MPIDR_CPUID_SHIFT) +# define MPIDR_CPUID_CPU2 (2 << MPIDR_CPUID_SHIFT) +# define MPIDR_CPUID_CPU3 (3 << MPIDR_CPUID_SHIFT) + /* Bits 2-7: Reserved */ +#define MPIDR_CLUSTID_SHIFT (8) /* Bits 8-11: Cluster ID value */ +#define MPIDR_CLUSTID_MASK (15 << MPIDR_CLUSTID_SHIFT) + /* Bits 12-29: Reserved */ +#define MPIDR_U (1 << 30) /* Bit 30: Multiprocessing Extensions. */ + +/* Revision ID Register (REVIDR): CRn=c0, opc1=0, CRm=c0, opc2=6 + * TODO: To be provided + */ + +/* Processor Feature Register 0 (ID_PFR0): CRn=c0, opc1=0, CRm=c1, opc2=0 + * Processor Feature Register 1 (ID_PFR1): CRn=c0, opc1=0, CRm=c1, opc2=1 + * TODO: To be provided + */ + +/* Debug Feature Register 0 (ID_DFR0): CRn=c0, opc1=0, CRm=c1, opc2=2 + * TODO: To be provided + */ + +/* Auxiliary Feature Register 0 (ID_AFR0): CRn=c0, opc1=0, CRm=c1, opc2=3 + * TODO: To be provided + */ + +/* Memory Model Features Register 0 (ID_MMFR0): + * CRn=c0, opc1=0, CRm=c1, opc2=4 + * Memory Model Features Register 1 (ID_MMFR1): + * CRn=c0, opc1=0, CRm=c1, opc2=5 + * Memory Model Features Register 2 (ID_MMFR2): + * CRn=c0, opc1=0, CRm=c1, opc2=6 + * Memory Model Features Register 3 (ID_MMFR3): + * CRn=c0, opc1=0, CRm=c1, opc2=7 + * TODO: To be provided + */ + +/* Instruction Set Attributes Register 0 (ID_ISAR0): + * CRn=c0, opc1=0, CRm=c2, opc2=0 + * Instruction Set Attributes Register 1 (ID_ISAR1): + * CRn=c0, opc1=0, CRm=c2, opc2=1 + * Instruction Set Attributes Register 2 (ID_ISAR2): + * CRn=c0, opc1=0, CRm=c2, opc2=2 + * Instruction Set Attributes Register 3 (ID_ISAR3): + * CRn=c0, opc1=0, CRm=c2, opc2=3 + * Instruction Set Attributes Register 4 (ID_ISAR4): + * CRn=c0, opc1=0, CRm=c2, opc2=4 + * Instruction Set Attributes Register 5 (ID_ISAR5): + * CRn=c0, opc1=0, CRm=c2, opc2=5 + * Instruction Set Attributes Register 6-7 (ID_ISAR6-7). + * Reserved. + * TODO: Others to be provided + */ + +/* Reserved: CRn=c0, opc1=0, CRm=c3-c7, opc2=* */ + +/* Cache Size Identification Register (CCSIDR): + * CRn=c0, opc1=1, CRm=c0, opc2=0 + * TODO: To be provided + */ + +/* Cache Level ID Register (CLIDR): CRn=c0, opc1=1, CRm=c0, opc2=1 + * TODO: To be provided + */ + +/* Auxiliary ID Register (AIDR): CRn=c0, opc1=1, CRm=c0, opc2=7 + * TODO: To be provided + */ + +/* Cache Size Selection Register (CSSELR): CRn=c0, opc1=2, CRm=c0, opc2=0 + * TODO: To be provided + */ + +/* CP15 c1 Registers ********************************************************/ + +/* System Control Register (SCTLR): CRn=c1, opc1=0, CRm=c0, opc2=0 + */ + +#define SCTLR_M (1 << 0) /* Bit 0: MPU enable bit */ +#define SCTLR_A (1 << 1) /* Bit 1: Enables strict alignment of data */ +#define SCTLR_C (1 << 2) /* Bit 2: Determines if data can be cached */ + /* Bits 3-4: Reserved */ +#define SCTLR_CCP15BEN (1 << 5) /* Bit 5: CP15 barrier enable */ + /* Bit 6: Reserved */ +#define SCTLR_B (1 << 7) /* Bit 7: Should be zero on ARMv7-R */ + /* Bits 8-9: Reserved */ +#define SCTLR_SW (1 << 10) /* Bit 10: SWP/SWPB Enable bit */ +#define SCTLR_Z (1 << 11) /* Bit 11: Program flow prediction control */ +#define SCTLR_I (1 << 12) /* Bit 12: Determines if instructions can be cached */ +#define SCTLR_V (1 << 13) /* Bit 13: Vectors bit */ +#define SCTLR_RR (1 << 14) /* Bit 14: Cache replacement strategy */ + /* Bits 15-16: Reserved */ +#define SCTLR_BR (1 << 17) /* Bit 17: Background Region bit */ + /* Bit 18: Reserved */ +#define SCTLR_DZ (1 << 19) /* Bit 19: Divide by Zero fault enable bit */ + /* Bit 20: Reserved */ +#define SCTLR_FI (1 << 21) /* Bit 21: Fast interrupts configuration enable bit */ +#define SCTLR_U (1 << 22) /* Bit 22: Unaligned access model (always one) */ +#define SCTLR_VE (1 << 24) /* Bit 24: Interrupt Vectors Enable bit */ +#define SCTLR_EE (1 << 25) /* Bit 25: Determines the value the CPSR.E */ +#define SCTLR_NMFI (1 << 27) /* Bit 27: Non-maskable FIQ (NMFI) support */ + /* Bits 28-29: Reserved */ +#define SCTLR_TE (1 << 30) /* Bit 30: Thumb exception enable */ + +/* Auxiliary Control Register (ACTLR): CRn=c1, opc1=0, CRm=c0, opc2=1 */ + +#define ACTLR_FW (1 << 0) /* Bit 0: Enable Cache/TLB maintenance broadcast */ + /* Bits 1-2: Reserved */ +#define ACTLR_MRP (1 << 3) /* Bit 3: Enable MRP */ + /* Bits 4-5: Reserved */ +#define ACTLR_SMP (1 << 6) /* Bit 6: Cortex-A9 taking part in coherency */ + /* Bits 7: Reserved */ +#define ACTLR_ALLOC_1WAY (1 << 8) /* Bit 8: Allocation in 1-way cache only */ +#define ACTLR_DTCM_ECC (1 << 9) /* Bit 9: ECC on caches and DTCM */ +#define ACTLR_ITCM_ECC (1 << 10) /* Bit 10: ECC on caches and ITCM */ +#define ACTLR_ITCM_QOS (1 << 11) /* Bit 11: Enable QoS*/ + /* Bits 12-31: Reserved */ + +/* Coprocessor Access Control Register (CPACR): + * CRn=c1, opc1=0, CRm=c0, opc2=2 + * TODO: To be provided + */ + +/* CP15 c2-c4 Registers *****************************************************/ + +/* Not used on ARMv7-R */ + +/* CP15 c5 Registers ********************************************************/ + +/* Data Fault Status Register (DFSR): CRn=c5, opc1=0, CRm=c0, opc2=0 + * TODO: To be provided + */ + +/* Instruction Fault Status Register (IFSR): CRn=c5, opc1=0, CRm=c0, opc2=1 + * TODO: To be provided + */ + +/* Auxiliary DFSR (ADFSR): CRn=c5, opc1=0, CRm=c1, opc2=0 + * TODO: To be provided + */ + +/* Auxiliary IFSR (AIFSR): CRn=c5, opc1=0, CRm=c1, opc2=1 + * TODO: To be provided + */ + +/* CP15 c6 Registers ********************************************************/ + +/* Data Fault Address Register(DFAR): CRn=c6, opc1=0, CRm=c0, opc2=0 + * + * Holds the MVA of the faulting address when a synchronous fault occurs + */ + +/* Instruction Fault Address Register(IFAR): CRn=c6, opc1=0, CRm=c0, opc2=1 + * + * Holds the MVA of the faulting address of the instruction that caused a + * prefetch abort. + */ + +/* Data Region Base Address Register (DRBAR): CRn=c6, opc1=0, CRm=c1, opc2=0 + * TODO: To be provided + */ + +/* Instruction Region Base Address Register (IRBAR): + * CRn=c6, opc1=0, CRm=c1, opc2=1 + * TODO: To be provided + */ + +/* Data Region Size and Enable Register (DRSR): + * CRn=c6, opc1=0, CRm=c1, opc2=2 + * TODO: To be provided + */ + +/* Instruction Region Size and Enable Register (IRSR): + * CRn=c6, opc1=0, CRm=c1, opc2=3 + * TODO: To be provided + */ + +/* Data Region Access Control Register (DRACR): + * CRn=c6, opc1=0, CRm=c1, opc2=4 + * TODO: To be provided + */ + +/* Instruction Region Access Control Register (IRACR): + * CRn=c6, opc1=0, CRm=c1, opc2=5 + * TODO: To be provided + */ + +/* MPU Region Number Register (RGNR): + * CRn=c6, opc1=0, CRm=c2, opc2=0 + * TODO: To be provided + */ + +/* CP15 c7 Registers ********************************************************/ + +/* See cp15_cacheops.h */ + +/* CP15 c8 Registers ********************************************************/ + +/* Not used on ARMv7-R */ + +/* CP15 c9 Registers ********************************************************/ + +/* 32-bit Performance Monitors Control Register (PMCR): + * CRn=c9, opc1=0, CRm=c12, opc2=0 + */ + +#define PMCR_E (1 << 0) /* Enable all counters */ +#define PMCR_P (1 << 1) /* Reset all counter events (except PMCCNTR) */ +#define PMCR_C (1 << 2) /* Reset cycle counter (PMCCNTR) to zero */ +#define PMCR_D (1 << 3) /* Enable cycle counter clock (PMCCNTR) divider */ +#define PMCR_X (1 << 4) /* Export of events is enabled */ +#define PMCR_DP (1 << 5) /* Disable PMCCNTR if event counting is prohibited */ +#define PMCR_N_SHIFT (11) /* Bits 11-15: Number of event counters */ +#define PMCR_N_MASK (0x1f << PMCR_N_SHIFT) +#define PMCR_IDCODE_SHIFT (16) /* Bits 16-23: Identification code */ +#define PMCR_IDCODE_MASK (0xff << PMCR_IDCODE_SHIFT) +#define PMCR_IMP_SHIFT (24) /* Bits 24-31: Implementer code */ +#define PMCR_IMP_MASK (0xff << PMCR_IMP_SHIFT) + +/* 32-bit Performance Monitors Count Enable Set register (PMCNTENSET): + * CRn=c9, opc1=0, CRm=c12, opc2=1 + */ + +#define PMCESR_CCES (1 << 31) /* Bits 31: Count Enable Set Register */ + +/* 32-bit Performance Monitors Count Enable Clear register (PMCNTENCLR): + * CRn=c9, opc1=0, CRm=c12, opc2=2 + */ + +#define PMCECR_CCEC (1 << 31) /* Bits 31: Count Enable Clear Register */ + +/* 32-bit Performance Monitors Overflow Flag Status Register (PMOVSR): + * CRn=c9, opc1=0, CRm=c12, opc2=3 + */ + +#define PMOFSR_COF0 (1 << 0) /* Bits 0: Counter 0 overflow flag */ +#define PMOFSR_COF1 (1 << 1) /* Bits 1: Counter 1 overflow flag */ +#define PMOFSR_COF2 (1 << 2) /* Bits 2: Counter 2 overflow flag */ +#define PMOFSR_COF3 (1 << 3) /* Bits 3: Counter 3 overflow flag */ +#define PMOFSR_COF4 (1 << 4) /* Bits 4: Counter 4 overflow flag */ +#define PMOFSR_COF5 (1 << 5) /* Bits 5: Counter 5 overflow flag */ +#define PMOFSR_CCOF (1 << 31) /* Bits 31: Cycle counter overflow flag */ + +/* 32-bit Performance Monitors Software Increment register (PMSWINC): + * CRn=c9, opc1=0, CRm=c12, opc2=4 + * TODO: To be provided + */ + +/* 32-bit Performance Monitors Event Counter Selection Register (PMSELR): + * CRn=c9, opc1=0, CRm=c12, opc2=5 + */ + +#define PMECSR_CS_MASK (0x1f) /* Bits 0-5: Counter select */ + +/* 32-bit Performance Monitors Common Event Identification (PMCEID0): + * CRn=c9, opc1=0, CRm=c12, opc2=6 + * TODO: To be provided + */ + +/* 32-bit Performance Monitors Common Event Identification (PMCEID1): + * CRn=c9, opc1=0, CRm=c12, opc2=7 + * TODO: To be provided + */ + +/* 32-bit Performance Monitors Cycle Count Register (PMCCNTR): + * CRn=c9, opc1=0, CRm=c13, opc2=0 + * TODO: To be provided + */ + +/* 32-bit Performance Monitors Event Type Select Register (PMETSR): + * CRn=c9, opc1=0, CRm=c13, opc2=1 + */ + +#define PMETSR_L1_IC_FILL (0x1) /* Level 1 instruction cache refill */ +#define PMETSR_L1_ITLB_FILL (0x2) /* Level 1 instruction TLB refill */ +#define PMETSR_L1_DC_FILL (0x3) /* Level 1 data cache refill */ +#define PMETSR_L1_DC_ACC (0x4) /* Level 1 data cache access */ +#define PMETSR_L1_DTLB_FILL (0x5) /* Level 1 data TLB refill */ +#define PMETSR_LOAD (0x6) /* Data read architecturally executed */ +#define PMETSR_STORE (0x7) /* Data write architecturally executed */ +#define PMETSR_INSTARCHEXEC (0x8) /* Instruction architecturally executed */ +#define PMETSR_EXCEPETIONTAKEN (0x9) /* Exception taken */ +#define PMETSR_EXCEPETIONRET (0xa) /* Exception return */ +#define PMETSR_WRCONTEXTIDR (0xb) /* Write to CONTEXTIDR */ +#define PMETSR_SOFTPCCHANGE (0xc) /* Software change of the PC */ +#define PMETSR_IMMBR (0xd) /* Immediate branch */ +#define PMETSR_PROCRET (0xe) /* Procedure return */ +#define PMETSR_UNALINGEDLDSTR (0xf) /* Unaligned load or store */ +#define PMETSR_MISPREDICTEDBRANCHEXEC (0x10) /* Mispredicted or not predicted branch speculatively executed */ +#define PMETSR_PREDICTEDBRANCHEXEC (0x12) /* Predictable branch speculatively executed */ +#define PMETSR_DATAMEMACC (0x13) /* Data memory access. */ +#define PMETSR_ICACC (0x14) /* Instruction Cache access. */ +#define PMETSR_DCEVICTION (0x15) /* Data cache eviction. */ +#define PMETSR_IRQEXCEPTION (0x86) /* IRQ exception taken. */ +#define PMETSR_FIQEXCEPTION (0x87) /* FIQ exception taken. */ +#define PMETSR_EXTMEMREQ (0xc0) /* External memory request. */ +#define PMETSR_NCEXTMEMREQ (0xc1) /* Non-cacheable external memory request */ +#define PMETSR_PREFETCHLINEFILL (0xc2) /* Linefill because of prefetch. */ +#define PMETSR_PREFETCHLINEDROP (0xc3) /* Prefetch linefill dropped. */ +#define PMETSR_ENTERINGRAMODE (0xc4) /* Entering read allocate mode. */ +#define PMETSR_RAMODE (0xc5) /* Read allocate mode. */ +#define PMETSR_RESERVED (0xc6) /* Reserved, do not use */ +#define PMETSR_DWSTALLSBFFULL (0xc9) /* Data Write operation that stalls the pipeline because the store buffer is full. */ +#define PMETSR_EVENT_MASK (0xff) + +/* 32-bit Performance Monitors Event Count Register (PMXEVCNTR): + * CRn=c9, opc1=0, CRm=c13, opc2=2 + * TODO: To be provided + */ + +/* 32-bit Performance Monitors User Enable Register (PMUSERENR): + * CRn=c9, opc1=0, CRm=c14, opc2=0 + */ + +#define PMUER_UME_SHIFT (0) /* Bits 0: User mode enable */ +#define PMUER_UME (1 << PMUER_UME_SHIFT) + +/* 32-bit Performance Monitors Interrupt Enable Set register (PMINTENSET): + * CRn=c9, opc1=0, CRm=c14, opc2=1 + */ + +#define PMIESR_CCNTOIE_SHIFT (31) /* Bits 31: CCNT overflow interrupt enable. */ +#define PMIESR_CCNTOIE (1 << PMIESR_CCNTOIE_SHIFT) + +/* 32-bit Performance Monitors Interrupt Enable Clear register (PMINTENCLR): + * CRn=c9, opc1=0, CRm=c14, opc2=2 + */ + +#define PMIECR_CCNTOIE_SHIFT (31) /* Bits 31: CCNT overflow interrupt enable. */ +#define PMIECR_CCNTOIE (1 << PMIECR_CCNTOIE_SHIFT) + +/* CP15 c10 Registers *******************************************************/ + +/* Not used on ARMv7-R */ + +/* CP15 c11 Registers *******************************************************/ + +/* Reserved for implementation defined DMA functions */ + +/* CP15 c12 Registers *******************************************************/ + +/* Not used on ARMv7-R */ + +/* CP15 c13 Registers *******************************************************/ + +/* Context ID Register (CONTEXTIDR): CRn=c13, opc1=0, CRm=c0, opc2=1 + * 32-Bit ContextID value. + */ + +/* User Read/Write (TPIDRURW): CRn=c13, opc1=0, CRm=c0, opc2=2 + * TODO: To be provided + */ + +/* User Read Only (TPIDRURO): CRn=c13, opc1=0, CRm=c0, opc2=3 + * TODO: To be provided + */ + +/* PL1 only (TPIDRPRW): CRn=c13, opc1=0, CRm=c0, opc2=4 + * TODO: To be provided + */ + +/* CP15 c14 Registers *******************************************************/ + +/* Counter Frequency register (CNTFRQ): CRn=c14, opc1=0, CRm=c0, opc2=0 + * TODO: To be provided + */ + +/* Timer PL1 Control register (CNTKCTL): CRn=c14, opc1=0, CRm=c1, opc2=0 + * TODO: To be provided + */ + +/* PL1 Physical TimerValue register (CNTP_TVAL): + * CRn=c14, opc1=0, CRm=c2, opc2=0 + * TODO: To be provided + */ + +/* PL1 Physical Timer Control register (CNTP_CTL): + * CRn=c14, opc1=0, CRm=c2, opc2=0 + * TODO: To be provided + */ + +/* Virtual TimerValue register (CNTV_TVAL): CRn=c14, opc1=0, CRm=c3, opc2=0 + * TODO: To be provided + */ + +/* Virtual Timer Control register (CNTV_CTL): CRn=c14, opc1=0, CRm=c3, opc2=0 + * TODO: To be provided + */ + +/* 64-bit Physical Count register (CNTPCT): CRn=c14, opc1=0, CRm=c14, opc2=n + * TODO: To be provided + */ + +/* Virtual Count register (CNTVCT): CRn=c14, opc1=1, CRm=c14, opc2=n + * TODO: To be provided + */ + +/* PL1 Physical Timer CompareValue register (CNTP_CVAL): + * CRn=c14, opc1=2, CRm=c14, opc2=n + * TODO: To be provided + */ + +/* Virtual Timer CompareValue register (CNTV_CVAL): + * CRn=c14, opc1=3, CRm=c14, opc2=n + * TODO: To be provided + */ + +/* CP15 c15 Registers *******************************************************/ + +/* Implementation defined */ + +/**************************************************************************** + * Assembly Macros + ****************************************************************************/ + +#ifdef __ASSEMBLY__ + +/* Get the device ID */ + +.macro cp15_rdid, id + mrc p15, 0, \id, c0, c0, 0 +.endm + +/* Read/write the system control register (SCTLR) */ + +.macro cp15_rdsctlr, sctlr + mrc p15, 0, \sctlr, c1, c0, 0 +.endm + +.macro cp15_wrsctlr, sctlr + mcr p15, 0, \sctlr, c1, c0, 0 + nop + nop + nop + nop + nop + nop + nop + nop +.endm +#endif /* __ASSEMBLY__ */ + +/**************************************************************************** + * Inline Functions + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +/* Get the device ID register */ + +static inline unsigned int cp15_rdid(void) +{ + return CP15_GET(MIDR); +} + +/* Get the Multiprocessor Affinity Register (MPIDR) */ + +static inline unsigned int cp15_rdmpidr(void) +{ + return CP15_GET(MPIDR); +} + +/* Read/write the system control register (SCTLR) */ + +static inline unsigned int cp15_rdsctlr(void) +{ + return CP15_GET(SCTLR); +} + +static inline void cp15_wrsctlr(unsigned int sctlr) +{ + CP15_SET(SCTLR, sctlr); + ARM_NOP(); + ARM_NOP(); + ARM_NOP(); + ARM_NOP(); + ARM_NOP(); + ARM_NOP(); + ARM_NOP(); + ARM_NOP(); +} + +/* Read/write the vector base address register (VBAR) */ + +static inline unsigned int cp15_rdvbar(void) +{ + return CP15_GET(VBAR); +} + +static inline void cp15_wrvbar(unsigned int vbar) +{ + CP15_SET(VBAR, vbar); +} + +/* Read/write the implementation defined Auxiliary Control Register (ACTLR) */ + +static inline unsigned int cp15_rdactlr(void) +{ + return CP15_GET(ACTLR); +} + +static inline void cp15_wractlr(unsigned int actlr) +{ + CP15_SET(ACTLR, actlr); +} + +/**************************************************************************** + * Name: cp15_pmu_rdpmcr/cp15_pmu_wrpmcr/cp15_pmu_pmcr + * + * Description: + * Read/Write the Performance Monitor Control Register (PMCR) + * + ****************************************************************************/ + +static inline unsigned int cp15_pmu_rdpmcr(void) +{ + return CP15_GET(PMCR); +} + +static inline void cp15_pmu_wrpmcr(unsigned int pmcr) +{ + CP15_SET(PMCR, pmcr); +} + +static inline void cp15_pmu_pmcr(unsigned int pmcr) +{ + cp15_pmu_wrpmcr(pmcr | cp15_pmu_rdpmcr()); +} + +/**************************************************************************** + * Name: cp15_pmu_rdcesr/cp15_pmu_wrcesr/cp15_pmu_cesr + * + * Description: + * Read/Write the Performance Monitors + * Count Enable Set register (PMCNTENSET) + * + ****************************************************************************/ + +static inline unsigned int cp15_pmu_rdcesr(void) +{ + return CP15_GET(PMCNTENSET); +} + +static inline void cp15_pmu_wrcesr(unsigned int cesr) +{ + CP15_SET(PMCNTENSET, cesr); +} + +static inline void cp15_pmu_cesr(unsigned int cesr) +{ + cp15_pmu_wrcesr(cesr | cp15_pmu_rdcesr()); +} + +/**************************************************************************** + * Name: cp15_pmu_rdcecr/cp15_pmu_wrcecr/cp15_pmu_cecr + * + * Description: + * Read/Write the Performance Monitors + * Count Enable Clear register (PMCNTENCLR) + * + ****************************************************************************/ + +static inline unsigned int cp15_pmu_rdcecr(void) +{ + return CP15_GET(PMCNTENCLR); +} + +static inline void cp15_pmu_wrcecr(unsigned int cecr) +{ + CP15_SET(PMCNTENCLR, cecr); +} + +static inline void cp15_pmu_cecr(unsigned int cecr) +{ + cp15_pmu_wrcecr(cecr | cp15_pmu_rdcecr()); +} + +/**************************************************************************** + * Name: cp15_pmu_rdcecr/cp15_pmu_wrcecr/cp15_pmu_cecr + * + * Description: + * Read/Write the Performance Monitors + * Overflow Flag Status Register (PMOVSR) + * + ****************************************************************************/ + +static inline unsigned int cp15_pmu_rdofsr(void) +{ + return CP15_GET(PMOVSR); +} + +static inline void cp15_pmu_wrofsr(unsigned int ofsr) +{ + CP15_SET(PMOVSR, ofsr); +} + +static inline void cp15_pmu_ofsr(unsigned int ofsr) +{ + cp15_pmu_wrofsr(ofsr | cp15_pmu_rdofsr()); +} + +/**************************************************************************** + * Name: cp15_pmu_rdsir/cp15_pmu_wrsir/cp15_pmu_sir + * + * Description: + * Read/Write the Performance Monitors + * Software Increment register (PMSWINC) + * + ****************************************************************************/ + +static inline unsigned int cp15_pmu_rdsir(void) +{ + return CP15_GET(PMSWINC); +} + +static inline void cp15_pmu_wrsir(unsigned int sir) +{ + CP15_SET(PMSWINC, sir); +} + +static inline void cp15_pmu_sir(unsigned int sir) +{ + cp15_pmu_wrsir(sir | cp15_pmu_rdsir()); +} + +/**************************************************************************** + * Name: cp15_pmu_wrecsr + * + * Description: + * Write the Performance Monitors Event Counter Selection Register (PMSELR) + * + ****************************************************************************/ + +static inline void cp15_pmu_wrecsr(unsigned int ecsr) +{ + CP15_SET(PMSELR, ecsr); +} + +/**************************************************************************** + * Name: cp15_pmu_wretsr + * + * Description: + * Write the Performance Monitors Event Type Select Register (PMXEVTYPER) + * + ****************************************************************************/ + +static inline void cp15_pmu_wretsr(unsigned int etsr) +{ + CP15_SET(PMXEVTYPER, etsr); +} + +/**************************************************************************** + * Name: cp15_pmu_wruer + * + * Description: + * Write the Performance Monitors User Enable Register (PMUSERENR) + * + ****************************************************************************/ + +static inline unsigned int cp15_pmu_rduer(void) +{ + return CP15_GET(PMUSERENR); +} + +static inline void cp15_pmu_wruer(unsigned int uer) +{ + CP15_SET(PMUSERENR, uer); +} + +static inline void cp15_pmu_uer(unsigned int uer) +{ + cp15_pmu_wruer(uer | cp15_pmu_rduer()); +} + +/**************************************************************************** + * Name: cp15_pmu_wriesr + * + * Description: + * Write the Performance Monitors + * Interrupt Enable Set register (PMINTENSET) + * + ****************************************************************************/ + +static inline void cp15_pmu_wriesr(unsigned int iesr) +{ + CP15_SET(PMINTENSET, iesr); +} + +/**************************************************************************** + * Name: cp15_pmu_wriecr + * + * Description: + * Write the Performance Monitors + * Interrupt Enable Clear register (PMINTENCLR) + * + ****************************************************************************/ + +static inline void cp15_pmu_wriecr(unsigned int iecr) +{ + CP15_SET(PMINTENCLR, iecr); +} + +/**************************************************************************** + * Name: cp15_pmu_rdccr + * + * Description: + * Read the Performance Monitors Cycle Count Register (PMCCNTR) + * + ****************************************************************************/ + +static inline unsigned int cp15_pmu_rdccr(void) +{ + return CP15_GET(PMCCNTR); +} + +/**************************************************************************** + * Name: cp15_pmu_rdecr + * + * Description: + * Read the Performance Monitors Event Count Register (PMXEVCNTR) + * + ****************************************************************************/ + +static inline unsigned int cp15_pmu_rdecr(void) +{ + return CP15_GET(PMXEVCNTR); +} + +#endif /* __ASSEMBLY__ */ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#ifndef __ASSEMBLY__ +#ifdef __cplusplus +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +#undef EXTERN +#ifdef __cplusplus +} +#endif +#endif /* __ASSEMBLY__ */ + +#endif /* __ARCH_ARM_SRC_ARMV8_R_SCTLR_H */ diff --git a/arch/arm/src/common/arm_internal.h b/arch/arm/src/common/arm_internal.h index 3f68b495364..773650d5f22 100644 --- a/arch/arm/src/common/arm_internal.h +++ b/arch/arm/src/common/arm_internal.h @@ -133,12 +133,15 @@ #define putreg16(v,a) (*(volatile uint16_t *)(a) = (v)) #define getreg32(a) (*(volatile uint32_t *)(a)) #define putreg32(v,a) (*(volatile uint32_t *)(a) = (v)) +#define getreg64(a) (*(volatile uint64_t *)(a)) +#define putreg64(v,a) (*(volatile uint64_t *)(a) = (v)) /* Non-atomic, but more effective modification of registers */ #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)) +#define modreg64(v,m,a) putreg64((getreg64(a) & ~(m)) | ((v) & (m)), (a)) /* Context switching */ @@ -175,6 +178,45 @@ extern void arm_switchcontext(uint32_t **saveregs, # define _enoinit Image$$noinit$$Limit #endif +/* MPIDR_EL1, Multiprocessor Affinity Register */ + +#define MPIDR_AFFLVL_MASK (0xff) +#define MPIDR_ID_MASK (0x00ffffff) + +#define MPIDR_AFF0_SHIFT (0) +#define MPIDR_AFF1_SHIFT (8) +#define MPIDR_AFF2_SHIFT (16) + +/* mpidr register, the register is define: + * - bit 0~7: Aff0 + * - bit 8~15: Aff1 + * - bit 16~23: Aff2 + * - bit 24: MT, multithreading + * - bit 25~29: RES0 + * - bit 30: U, multiprocessor/Uniprocessor + * - bit 31: RES1 + * Different ARM/ARM64 cores will use different Affn define, the mpidr + * value is not CPU number, So we need to change CPU number to mpid + * and vice versa + */ + +#define GET_MPIDR() CP15_GET(MPIDR) + +#define MPIDR_AFFLVL(mpidr, aff_level) \ + (((mpidr) >> MPIDR_AFF ## aff_level ## _SHIFT) & MPIDR_AFFLVL_MASK) + +#define MPID_TO_CORE(mpid, aff_level) \ + (((mpid) >> 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 |= (cpu << MPIDR_AFF ## aff_level ## _SHIFT); \ + __mpidr &= MPIDR_ID_MASK; \ + __mpidr; \ + }) + /**************************************************************************** * Public Types ****************************************************************************/ @@ -344,7 +386,7 @@ int arm_securefault(int irq, void *context, void *arg); * (but should be back-ported to the ARM7 and ARM9 families). */ -#elif defined(CONFIG_ARCH_ARMV7A) || defined(CONFIG_ARCH_ARMV7R) +#elif defined(CONFIG_ARCH_ARMV7A) || defined(CONFIG_ARCH_ARMV7R) || defined(CONFIG_ARCH_ARMV8R) /* Interrupt acknowledge and dispatch */