From aba1f77ee523824549aa444a832466906bb136fd Mon Sep 17 00:00:00 2001 From: Stephanos Ioannidis Date: Wed, 9 Oct 2019 00:48:11 +0900 Subject: [PATCH 01/18] arch: arm: Make PLATFORM_SPECIFIC_INIT available to all ARM variants. Move PLATFORM_SPECIFIC_INIT declaration from Cortex-M Kconfig to the ARM arch Kconfig in order to make it available for all ARM variants. The rationale is that there is really no good reason why platform-specific initialisation should be a Cortex-M-specific feature and that Cortex-R port is expected to utilise this in a near future. Signed-off-by: Stephanos Ioannidis --- arch/arm/core/Kconfig | 6 ++++++ arch/arm/core/cortex_m/Kconfig | 6 ------ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/arm/core/Kconfig b/arch/arm/core/Kconfig index cb9337a7d771..dfdfa751d4d9 100644 --- a/arch/arm/core/Kconfig +++ b/arch/arm/core/Kconfig @@ -98,6 +98,12 @@ config RUNTIME_NMI NMI handler installed when the CPU boots. If a custom handler is needed, enable this option and attach it via _NmiHandlerSet(). +config PLATFORM_SPECIFIC_INIT + bool "Enable platform (SOC) specific startup hook" + help + The platform specific initialization code (z_platform_init) is executed + at the beginning of the startup code (__start). + config FAULT_DUMP int "Fault dump level" default 2 diff --git a/arch/arm/core/cortex_m/Kconfig b/arch/arm/core/cortex_m/Kconfig index b89213dd4d5f..b864febb4534 100644 --- a/arch/arm/core/cortex_m/Kconfig +++ b/arch/arm/core/cortex_m/Kconfig @@ -258,12 +258,6 @@ config SW_VECTOR_RELAY (or an Armv8-M baseline core) with no VTOR and no other hardware relocation table mechanisms. -config PLATFORM_SPECIFIC_INIT - bool "Enable platform (SOC) specific startup hook" - help - The platform specific initialization code (z_platform_init) is executed - at the beginning of the startup code (__start). - endmenu endif # CPU_CORTEX_M From 6d8d64501d70d600d20284046378330e108a85c9 Mon Sep 17 00:00:00 2001 From: Stephanos Ioannidis Date: Wed, 9 Oct 2019 00:50:18 +0900 Subject: [PATCH 02/18] arch: arm: Add Cortex-R floating point configuration support. 1. Allow CPU_HAS_FPU_DOUBLE_PRECISION on Cortex-R4 and Cortex-R5, as the optional VFPv3-D16 is, by default, a double precision unit. 2. Add GCC compiler support for Cortex-R4F and Cortex-R5F floating point unit. The FPU type on these cores is fixed to VFPv3-D16, which supports double precision by default. While later revisions of Cortex-R5F can have single precision VFPv3-D16, GCC does not have a separate type for it. Signed-off-by: Stephanos Ioannidis --- cmake/compiler/gcc/target_arm.cmake | 2 ++ soc/arm/Kconfig | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/cmake/compiler/gcc/target_arm.cmake b/cmake/compiler/gcc/target_arm.cmake index 41d9c1c913c7..55739055dab4 100644 --- a/cmake/compiler/gcc/target_arm.cmake +++ b/cmake/compiler/gcc/target_arm.cmake @@ -19,6 +19,8 @@ endif() set(FPU_FOR_cortex-m4 fpv4-${PRECISION_TOKEN}d16) set(FPU_FOR_cortex-m7 fpv5-${PRECISION_TOKEN}d16) set(FPU_FOR_cortex-m33 fpv5-${PRECISION_TOKEN}d16) +set(FPU_FOR_cortex-r4 vfpv3-d16) +set(FPU_FOR_cortex-r5 vfpv3-d16) if(CONFIG_FLOAT) list(APPEND TOOLCHAIN_C_FLAGS -mfpu=${FPU_FOR_${GCC_M_CPU}}) diff --git a/soc/arm/Kconfig b/soc/arm/Kconfig index d83fe84ad49e..6a5a63c9e10d 100644 --- a/soc/arm/Kconfig +++ b/soc/arm/Kconfig @@ -34,7 +34,7 @@ config CPU_HAS_NRF_IDAU config CPU_HAS_FPU_DOUBLE_PRECISION bool - depends on CPU_CORTEX_M7 + depends on (CPU_CORTEX_M7 || CPU_CORTEX_R4 || CPU_CORTEX_R5) select CPU_HAS_FPU help When enabled, indicates that the SoC has a double From 0e5266cb846ec41077f2ff34d653a2116e21f349 Mon Sep 17 00:00:00 2001 From: Stephanos Ioannidis Date: Wed, 9 Oct 2019 00:51:43 +0900 Subject: [PATCH 03/18] arch: Add Dual-redundant Core Lock-step (DCLS) configuration. Add a new Kconfig configuration for specifying Dual-redundant Core Lock-step (DCLS) processor topology. Signed-off-by: Stephanos Ioannidis --- arch/Kconfig | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/Kconfig b/arch/Kconfig index 828ba24d000b..610b29901367 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -422,6 +422,12 @@ config CPU_HAS_TEE Execution Environment (e.g. when it has a security attribution unit). +config CPU_HAS_DCLS + bool + help + This option is enabled when the processor hardware is configured in + Dual-redundant Core Lock-step (DCLS) topology. + config CPU_HAS_FPU bool help From 1a5feef883c3051f7bec8b62bd05857e5798faee Mon Sep 17 00:00:00 2001 From: Stephanos Ioannidis Date: Wed, 9 Oct 2019 00:52:18 +0900 Subject: [PATCH 04/18] arch: arm: Rewrite Cortex-R reset vector function. This commit addresses the following issues: 1. Register initialisation is only required when Dual-redundant Core Lock-step (DCLS) is implemented in hardware. This initialisation is required on DCLS only because the architectural registers are in an indeterminate state after reset and therefore the initial register state of the two parallel executing cores are not guaranteed to be identical, which can lead to DCCM detecting it as a hardware fault. A conditional compilation check for this hardware configuration using the newly added CONFIG_CPU_HAS_DCLS flag has been added. 2. The existing CPU register initialisation code did not take into account the banked registers for every execution mode. The new implementation ensures that all architectural registers of every mode are initialised. 3. Add VFP register initialisation for when floating-point support is enabled and the core is configured in DCLS topology. This initialisation sequence is required for the same reason given in the first issue. 4. Add provision for platform-specific initialisation on Cortex-R using PLATFORM_SPECIFIC_INIT config and z_platform_init function. 5. Remove seemingly pointless and inadequately defined STACK_MARGIN. Not only does it violate the 8-byte stack alignment rule, it does not provide any form of real stack protection. Signed-off-by: Stephanos Ioannidis --- arch/arm/core/cortex_r/reset.S | 200 +++++++++++++++++++++++--------- include/arch/arm/cortex_r/cpu.h | 10 +- 2 files changed, 151 insertions(+), 59 deletions(-) diff --git a/arch/arm/core/cortex_r/reset.S b/arch/arm/core/cortex_r/reset.S index d88a9e2ecadf..0590bfbc592b 100644 --- a/arch/arm/core/cortex_r/reset.S +++ b/arch/arm/core/cortex_r/reset.S @@ -26,17 +26,17 @@ GDATA(z_arm_sys_stack) GDATA(z_arm_fiq_stack) GDATA(z_arm_abort_stack) GDATA(z_arm_undef_stack) - -#define STACK_MARGIN 4 - +#if defined(CONFIG_PLATFORM_SPECIFIC_INIT) +GTEXT(z_platform_init) +#endif /** * * @brief Reset vector * - * Ran when the system comes out of reset. The processor is in thread mode with - * privileged level. At this point, the main stack pointer (MSP) is already - * pointing to a valid area in SRAM. + * Ran when the system comes out of reset. The processor is in Supervisor mode + * and interrupts are disabled. The processor architectural registers are in + * an indeterminate state. * * When these steps are completed, jump to z_arm_prep_c(), which will finish * setting up the system for running C code. @@ -44,59 +44,143 @@ GDATA(z_arm_undef_stack) * @return N/A */ SECTION_SUBSEC_FUNC(TEXT, _reset_section, z_arm_reset) -SECTION_SUBSEC_FUNC(TEXT,_reset_section,__start) - mov r0, #0 - mov r1, #0 - mov r2, #0 - mov r3, #0 - mov r4, #0 - mov r5, #0 - mov r6, #0 - mov r7, #0 - mov r8, #0 - mov r9, #0 - mov r10, #0 - mov r11, #0 - mov r12, #0 - mov r14, #0 - - /* lock interrupts: will get unlocked when switch to main task */ - cpsid if - - /* Setup FIQ stack */ - msr CPSR_c, #(MODE_FIQ | I_BIT | F_BIT) - ldr sp, =(z_arm_fiq_stack + CONFIG_ARMV7_FIQ_STACK_SIZE - STACK_MARGIN) - - /* Setup IRQ stack */ - msr CPSR_c, #(MODE_IRQ | I_BIT | F_BIT) - ldr sp, =(_interrupt_stack + CONFIG_ISR_STACK_SIZE - STACK_MARGIN) - - /* Setup data abort stack */ - msr CPSR_c, #(MODE_ABT | I_BIT | F_BIT) - ldr sp, =(z_arm_abort_stack + CONFIG_ARMV7_EXCEPTION_STACK_SIZE - \ - STACK_MARGIN) - - /* Setup undefined mode stack */ - msr CPSR_c, #(MODE_UDF | I_BIT | F_BIT) - ldr sp, =(z_arm_undef_stack + CONFIG_ARMV7_EXCEPTION_STACK_SIZE - \ - STACK_MARGIN) - - /* Setup SVC mode stack */ - msr CPSR_c, #(MODE_SVC | I_BIT | F_BIT) - ldr sp, =(z_arm_svc_stack + CONFIG_ARMV7_SVC_STACK_SIZE - STACK_MARGIN) - - /* Setup System mode stack */ - msr CPSR_c, #(MODE_SYS | I_BIT | F_BIT) - ldr sp, =(z_arm_sys_stack + CONFIG_ARMV7_SYS_STACK_SIZE - STACK_MARGIN) - - /* Setup system control register */ - mrc p15, 0, r0, c1, c0, 0 /* SCTLR */ - bic r0, r0, #HIVECS /* Exception vectors from 0-0x1c */ - mcr p15, 0, r0, c1, c0, 0 +SECTION_SUBSEC_FUNC(TEXT, _reset_section, __start) + +#if defined(CONFIG_CPU_HAS_DCLS) + /* + * Initialise CPU registers to a defined state if the processor is + * configured as Dual-redundant Core Lock-step (DCLS). This is required + * for state convergence of the two parallel executing cores. + */ + + /* Common and SVC mode registers */ + mov r0, #0 + mov r1, #0 + mov r2, #0 + mov r3, #0 + mov r4, #0 + mov r5, #0 + mov r6, #0 + mov r7, #0 + mov r8, #0 + mov r9, #0 + mov r10, #0 + mov r11, #0 + mov r12, #0 + mov r13, #0 /* r13_svc */ + mov r14, #0 /* r14_svc */ + mrs r0, cpsr + msr spsr_cxsf, r0 /* spsr_svc */ + + /* FIQ mode registers */ + cps #MODE_FIQ + mov r8, #0 /* r8_fiq */ + mov r9, #0 /* r9_fiq */ + mov r10, #0 /* r10_fiq */ + mov r11, #0 /* r11_fiq */ + mov r12, #0 /* r12_fiq */ + mov r13, #0 /* r13_fiq */ + mov r14, #0 /* r14_fiq */ + mrs r0, cpsr + msr spsr_cxsf, r0 /* spsr_fiq */ + + /* IRQ mode registers */ + cps #MODE_IRQ + mov r13, #0 /* r13_irq */ + mov r14, #0 /* r14_irq */ + mrs r0, cpsr + msr spsr_cxsf, r0 /* spsr_irq */ + + /* ABT mode registers */ + cps #MODE_ABT + mov r13, #0 /* r13_abt */ + mov r14, #0 /* r14_abt */ + mrs r0, cpsr + msr spsr_cxsf, r0 /* spsr_abt */ + + /* UND mode registers */ + cps #MODE_UND + mov r13, #0 /* r13_und */ + mov r14, #0 /* r14_und */ + mrs r0, cpsr + msr spsr_cxsf, r0 /* spsr_und */ + + /* SYS mode registers */ + cps #MODE_SYS + mov r13, #0 /* r13_sys */ + mov r14, #0 /* r14_sys */ + +#if defined(CONFIG_FLOAT) + /* + * Initialise FPU registers to a defined state. + */ + + /* Allow VFP coprocessor access */ + mrc p15, 0, r0, c1, c0, 2 + orr r0, r0, #(CPACR_CP10(CPACR_FA) | CPACR_CP11(CPACR_FA)) + mcr p15, 0, r0, c1, c0, 2 + + /* Enable VFP */ + mov r0, #FPEXC_EN + fmxr fpexc, r0 + + /* Initialise VFP registers */ + fmdrr d0, r1, r1 + fmdrr d1, r1, r1 + fmdrr d2, r1, r1 + fmdrr d3, r1, r1 + fmdrr d4, r1, r1 + fmdrr d5, r1, r1 + fmdrr d6, r1, r1 + fmdrr d7, r1, r1 + fmdrr d8, r1, r1 + fmdrr d9, r1, r1 + fmdrr d10, r1, r1 + fmdrr d11, r1, r1 + fmdrr d12, r1, r1 + fmdrr d13, r1, r1 + fmdrr d14, r1, r1 + fmdrr d15, r1, r1 +#endif /* CONFIG_FLOAT */ + +#endif /* CONFIG_CPU_HAS_DCLS */ + + /* + * Configure stack. + */ + + /* FIQ mode stack */ + msr CPSR_c, #(MODE_FIQ | I_BIT | F_BIT) + ldr sp, =(z_arm_fiq_stack + CONFIG_ARMV7_FIQ_STACK_SIZE) + + /* IRQ mode stack */ + msr CPSR_c, #(MODE_IRQ | I_BIT | F_BIT) + ldr sp, =(_interrupt_stack + CONFIG_ISR_STACK_SIZE) + + /* ABT mode stack */ + msr CPSR_c, #(MODE_ABT | I_BIT | F_BIT) + ldr sp, =(z_arm_abort_stack + CONFIG_ARMV7_EXCEPTION_STACK_SIZE) + + /* UND mode stack */ + msr CPSR_c, #(MODE_UND | I_BIT | F_BIT) + ldr sp, =(z_arm_undef_stack + CONFIG_ARMV7_EXCEPTION_STACK_SIZE) + + /* SVC mode stack */ + msr CPSR_c, #(MODE_SVC | I_BIT | F_BIT) + ldr sp, =(z_arm_svc_stack + CONFIG_ARMV7_SVC_STACK_SIZE) + + /* SYS mode stack */ + msr CPSR_c, #(MODE_SYS | I_BIT | F_BIT) + ldr sp, =(z_arm_sys_stack + CONFIG_ARMV7_SYS_STACK_SIZE) + +#if defined(CONFIG_PLATFORM_SPECIFIC_INIT) + /* Execute platform-specific initialisation if applicable */ + bl z_platform_init +#endif #if defined(CONFIG_WDOG_INIT) - /* board-specific watchdog initialization is necessary */ - bl z_arm_watchdog_init + /* board-specific watchdog initialization is necessary */ + bl z_arm_watchdog_init #endif - b z_arm_prep_c + b z_arm_prep_c diff --git a/include/arch/arm/cortex_r/cpu.h b/include/arch/arm/cortex_r/cpu.h index 9ce788a511bd..28a072b908fa 100644 --- a/include/arch/arm/cortex_r/cpu.h +++ b/include/arch/arm/cortex_r/cpu.h @@ -12,7 +12,7 @@ #define MODE_IRQ 0x12 #define MODE_SVC 0x13 #define MODE_ABT 0x17 -#define MODE_UDF 0x1b +#define MODE_UND 0x1b #define MODE_SYS 0x1f #define MODE_MASK 0x1f @@ -23,6 +23,14 @@ #define HIVECS (1 << 13) +#define CPACR_NA (0U) +#define CPACR_FA (3U) + +#define CPACR_CP10(r) (r << 20) +#define CPACR_CP11(r) (r << 22) + +#define FPEXC_EN (1 << 30) + #define RET_FROM_SVC 0 #define RET_FROM_IRQ 1 From b5c2aa2c0c7855ee89beebd789794d6fb8df204c Mon Sep 17 00:00:00 2001 From: Stephanos Ioannidis Date: Mon, 14 Oct 2019 13:40:36 +0900 Subject: [PATCH 05/18] arch: arm: Reorganise ARM interrupt management routines. This commit reorganises the existing arch/arm/irq_manage.c file into three separate files: * arch/arm/irq.c: Common IRQ handlers and management routines * arch/arm/cortex_m/irq_manage.c: Cortex-M IRQ management routines * arch/arm/cortex_r/irq_manage.c: Cortex-R IRQ management routines Signed-off-by: Stephanos Ioannidis --- arch/arm/core/CMakeLists.txt | 2 +- arch/arm/core/cortex_m/CMakeLists.txt | 1 + arch/arm/core/{ => cortex_m}/irq_manage.c | 134 +--------------------- arch/arm/core/cortex_r/CMakeLists.txt | 1 + arch/arm/core/cortex_r/irq_manage.c | 69 +++++++++++ arch/arm/core/irq.c | 105 +++++++++++++++++ 6 files changed, 178 insertions(+), 134 deletions(-) rename arch/arm/core/{ => cortex_m}/irq_manage.c (55%) create mode 100644 arch/arm/core/cortex_r/irq_manage.c create mode 100644 arch/arm/core/irq.c diff --git a/arch/arm/core/CMakeLists.txt b/arch/arm/core/CMakeLists.txt index cb090dace32b..3cc39d49bb08 100644 --- a/arch/arm/core/CMakeLists.txt +++ b/arch/arm/core/CMakeLists.txt @@ -10,7 +10,7 @@ zephyr_library_sources( exc_exit.S swap.c swap_helper.S - irq_manage.c + irq.c thread.c cpu_idle.S fault_s.S diff --git a/arch/arm/core/cortex_m/CMakeLists.txt b/arch/arm/core/cortex_m/CMakeLists.txt index 556db5930b1b..44e920d13fda 100644 --- a/arch/arm/core/cortex_m/CMakeLists.txt +++ b/arch/arm/core/cortex_m/CMakeLists.txt @@ -8,6 +8,7 @@ zephyr_library_sources( fault.c scb.c irq_init.c + irq_manage.c thread_abort.c ) diff --git a/arch/arm/core/irq_manage.c b/arch/arm/core/cortex_m/irq_manage.c similarity index 55% rename from arch/arm/core/irq_manage.c rename to arch/arm/core/cortex_m/irq_manage.c index 0724be773e1d..629ef12ba177 100644 --- a/arch/arm/core/irq_manage.c +++ b/arch/arm/core/cortex_m/irq_manage.c @@ -6,7 +6,7 @@ /** * @file - * @brief ARM Cortex-M and Cortex-R interrupt management + * @brief ARM Cortex-M interrupt management * * * Interrupt management: enabling/disabling and dynamic ISR @@ -16,12 +16,7 @@ #include #include -#if defined(CONFIG_CPU_CORTEX_M) #include -#elif defined(CONFIG_CPU_CORTEX_R) -#include -#include -#endif #include #include #include @@ -32,7 +27,6 @@ extern void z_arm_reserved(void); -#if defined(CONFIG_CPU_CORTEX_M) #define NUM_IRQS_PER_REG 32 #define REG_FROM_IRQ(irq) (irq / NUM_IRQS_PER_REG) #define BIT_FROM_IRQ(irq) (irq % NUM_IRQS_PER_REG) @@ -97,121 +91,6 @@ void z_arm_irq_priority_set(unsigned int irq, unsigned int prio, u32_t flags) NVIC_SetPriority((IRQn_Type)irq, prio); } -#elif defined(CONFIG_CPU_CORTEX_R) -void z_arch_irq_enable(unsigned int irq) -{ - struct device *dev = _sw_isr_table[0].arg; - - irq_enable_next_level(dev, (irq >> 8) - 1); -} - -void z_arch_irq_disable(unsigned int irq) -{ - struct device *dev = _sw_isr_table[0].arg; - - irq_disable_next_level(dev, (irq >> 8) - 1); -} - -int z_arch_irq_is_enabled(unsigned int irq) -{ - struct device *dev = _sw_isr_table[0].arg; - - return irq_is_enabled_next_level(dev); -} - -/** - * @internal - * - * @brief Set an interrupt's priority - * - * The priority is verified if ASSERT_ON is enabled. The maximum number - * of priority levels is a little complex, as there are some hardware - * priority levels which are reserved: three for various types of exceptions, - * and possibly one additional to support zero latency interrupts. - * - * @return N/A - */ -void z_arm_irq_priority_set(unsigned int irq, unsigned int prio, u32_t flags) -{ - struct device *dev = _sw_isr_table[0].arg; - - if (irq == 0) - return; - - irq_set_priority_next_level(dev, (irq >> 8) - 1, prio, flags); -} - -#endif - -/** - * - * @brief Spurious interrupt handler - * - * Installed in all dynamic interrupt slots at boot time. Throws an error if - * called. - * - * See z_arm_reserved(). - * - * @return N/A - */ -void z_irq_spurious(void *unused) -{ - ARG_UNUSED(unused); - z_arm_reserved(); -} - -/* FIXME: IRQ direct inline functions have to be placed here and not in - * arch/cpu.h as inline functions due to nasty circular dependency between - * arch/cpu.h and kernel_structs.h; the inline functions typically need to - * perform operations on _kernel. For now, leave as regular functions, a - * future iteration will resolve this. - * - * See https://github.com/zephyrproject-rtos/zephyr/issues/3056 - */ - -#ifdef CONFIG_SYS_POWER_MANAGEMENT -void _arch_isr_direct_pm(void) -{ -#if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE) \ - || defined(CONFIG_ARMV7_R) - unsigned int key; - - /* irq_lock() does what we wan for this CPU */ - key = irq_lock(); -#elif defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) - /* Lock all interrupts. irq_lock() will on this CPU only disable those - * lower than BASEPRI, which is not what we want. See comments in - * arch/arm/core/isr_wrapper.S - */ - __asm__ volatile("cpsid i" : : : "memory"); -#else -#error Unknown ARM architecture -#endif /* CONFIG_ARMV6_M_ARMV8_M_BASELINE */ - - if (_kernel.idle) { - s32_t idle_val = _kernel.idle; - - _kernel.idle = 0; - z_sys_power_save_idle_exit(idle_val); - } - -#if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE) \ - || defined(CONFIG_ARMV7_R) - irq_unlock(key); -#elif defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) - __asm__ volatile("cpsie i" : : : "memory"); -#else -#error Unknown ARM architecture -#endif /* CONFIG_ARMV6_M_ARMV8_M_BASELINE */ - -} -#endif - -void z_arch_isr_direct_header(void) -{ - sys_trace_isr_enter(); -} - #if defined(CONFIG_ARM_SECURE_FIRMWARE) /** * @@ -267,14 +146,3 @@ int irq_target_state_is_secure(unsigned int irq) } #endif /* CONFIG_ARM_SECURE_FIRMWARE */ - -#ifdef CONFIG_DYNAMIC_INTERRUPTS -int z_arch_irq_connect_dynamic(unsigned int irq, unsigned int priority, - void (*routine)(void *parameter), void *parameter, - u32_t flags) -{ - z_isr_install(irq, routine, parameter); - z_arm_irq_priority_set(irq, priority, flags); - return irq; -} -#endif /* CONFIG_DYNAMIC_INTERRUPTS */ diff --git a/arch/arm/core/cortex_r/CMakeLists.txt b/arch/arm/core/cortex_r/CMakeLists.txt index a1154a3efb94..6782efec86b5 100644 --- a/arch/arm/core/cortex_r/CMakeLists.txt +++ b/arch/arm/core/cortex_r/CMakeLists.txt @@ -6,6 +6,7 @@ zephyr_library_sources( vector_table.S reset.S fault.c + irq_manage.c reboot.c stacks.c ) diff --git a/arch/arm/core/cortex_r/irq_manage.c b/arch/arm/core/cortex_r/irq_manage.c new file mode 100644 index 000000000000..ec99e0f7a5df --- /dev/null +++ b/arch/arm/core/cortex_r/irq_manage.c @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2013-2014 Wind River Systems, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief ARM Cortex-R interrupt management + * + * + * Interrupt management: enabling/disabling and dynamic ISR + * connecting/replacing. SW_ISR_TABLE_DYNAMIC has to be enabled for + * connecting ISRs at runtime. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void z_arch_irq_enable(unsigned int irq) +{ + struct device *dev = _sw_isr_table[0].arg; + + irq_enable_next_level(dev, (irq >> 8) - 1); +} + +void z_arch_irq_disable(unsigned int irq) +{ + struct device *dev = _sw_isr_table[0].arg; + + irq_disable_next_level(dev, (irq >> 8) - 1); +} + +int z_arch_irq_is_enabled(unsigned int irq) +{ + struct device *dev = _sw_isr_table[0].arg; + + return irq_is_enabled_next_level(dev); +} + +/** + * @internal + * + * @brief Set an interrupt's priority + * + * The priority is verified if ASSERT_ON is enabled. The maximum number + * of priority levels is a little complex, as there are some hardware + * priority levels which are reserved. + * + * @return N/A + */ +void z_arm_irq_priority_set(unsigned int irq, unsigned int prio, u32_t flags) +{ + struct device *dev = _sw_isr_table[0].arg; + + if (irq == 0) + return 0; + + irq_set_priority_next_level(dev, (irq >> 8) - 1, prio, flags); +} diff --git a/arch/arm/core/irq.c b/arch/arm/core/irq.c new file mode 100644 index 000000000000..aabdbdb342f1 --- /dev/null +++ b/arch/arm/core/irq.c @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2013-2014 Wind River Systems, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief ARM interrupt handler + * + * Interrupt management: dynamic ISR connecting/replacing; + * SW_ISR_TABLE_DYNAMIC has to be enabled for connecting ISRs at runtime. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern void z_arm_reserved(void); + +/** + * + * @brief Spurious interrupt handler + * + * Installed in all dynamic interrupt slots at boot time. Throws an error if + * called. + * + * See z_arm_reserved(). + * + * @return N/A + */ +void z_irq_spurious(void *unused) +{ + ARG_UNUSED(unused); + z_arm_reserved(); +} + +/* FIXME: IRQ direct inline functions have to be placed here and not in + * arch/cpu.h as inline functions due to nasty circular dependency between + * arch/cpu.h and kernel_structs.h; the inline functions typically need to + * perform operations on _kernel. For now, leave as regular functions, a + * future iteration will resolve this. + * + * See https://github.com/zephyrproject-rtos/zephyr/issues/3056 + */ + +#ifdef CONFIG_SYS_POWER_MANAGEMENT +void _arch_isr_direct_pm(void) +{ +#if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE) \ + || defined(CONFIG_ARMV7_R) + unsigned int key; + + /* irq_lock() does what we wan for this CPU */ + key = irq_lock(); +#elif defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) + /* Lock all interrupts. irq_lock() will on this CPU only disable those + * lower than BASEPRI, which is not what we want. See comments in + * arch/arm/core/isr_wrapper.S + */ + __asm__ volatile("cpsid i" : : : "memory"); +#else +#error Unknown ARM architecture +#endif /* CONFIG_ARMV6_M_ARMV8_M_BASELINE */ + + if (_kernel.idle) { + s32_t idle_val = _kernel.idle; + + _kernel.idle = 0; + z_sys_power_save_idle_exit(idle_val); + } + +#if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE) \ + || defined(CONFIG_ARMV7_R) + irq_unlock(key); +#elif defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) + __asm__ volatile("cpsie i" : : : "memory"); +#else +#error Unknown ARM architecture +#endif /* CONFIG_ARMV6_M_ARMV8_M_BASELINE */ + +} +#endif + +void z_arch_isr_direct_header(void) +{ + sys_trace_isr_enter(); +} + +#ifdef CONFIG_DYNAMIC_INTERRUPTS +int z_arch_irq_connect_dynamic(unsigned int irq, unsigned int priority, + void (*routine)(void *parameter), void *parameter, + u32_t flags) +{ + z_isr_install(irq, routine, parameter); + z_arm_irq_priority_set(irq, priority, flags); + return irq; +} +#endif /* CONFIG_DYNAMIC_INTERRUPTS */ From 7536fdd58c9f6ed13dc10bebc5ba9562ce35afb8 Mon Sep 17 00:00:00 2001 From: Stephanos Ioannidis Date: Tue, 15 Oct 2019 10:46:12 +0900 Subject: [PATCH 06/18] arch: arm: Fix incorrect Cortex-R interrupt management logic. This commit fixes the following incorrect implementation of Cortex-R interrupt management logic: 1. 'irq' parameter to interrupt management functions are manipulated in an interrupt controller implementation-specific way before being passed down to the interrupt controller driver. Since Cortex-R does not designate a specific interrupt controller to be used, these functions must remain interrupt controller-agnostic and any implementation-specific details involving 'irq' parameter should be handled by the interrupt controller driver. 2. 'z_arch_irq_is_enabled' is supposed to return the state of the interrupt line specified by the 'irq' parameter, but the current implementation returns the global interrupt controller state. This problem is fixed by calling the interrupt controller driver function `irq_line_is_enabled_next_level` instead. Signed-off-by: Stephanos Ioannidis --- arch/arm/core/cortex_r/irq_manage.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/arm/core/cortex_r/irq_manage.c b/arch/arm/core/cortex_r/irq_manage.c index ec99e0f7a5df..ca038e26e214 100644 --- a/arch/arm/core/cortex_r/irq_manage.c +++ b/arch/arm/core/cortex_r/irq_manage.c @@ -30,21 +30,21 @@ void z_arch_irq_enable(unsigned int irq) { struct device *dev = _sw_isr_table[0].arg; - irq_enable_next_level(dev, (irq >> 8) - 1); + irq_enable_next_level(dev, irq); } void z_arch_irq_disable(unsigned int irq) { struct device *dev = _sw_isr_table[0].arg; - irq_disable_next_level(dev, (irq >> 8) - 1); + irq_disable_next_level(dev, irq); } int z_arch_irq_is_enabled(unsigned int irq) { - struct device *dev = _sw_isr_table[0].arg; + struct device *dev = _sw_isr_table[0].arg; - return irq_is_enabled_next_level(dev); + return irq_line_is_enabled_next_level(dev, irq); } /** @@ -65,5 +65,5 @@ void z_arm_irq_priority_set(unsigned int irq, unsigned int prio, u32_t flags) if (irq == 0) return 0; - irq_set_priority_next_level(dev, (irq >> 8) - 1, prio, flags); + irq_set_priority_next_level(dev, irq, prio, flags); } From d384fe9d96425f1096b98839e0d80d880c2d311d Mon Sep 17 00:00:00 2001 From: Stephanos Ioannidis Date: Tue, 15 Oct 2019 12:45:51 +0900 Subject: [PATCH 07/18] arch: arm: Fix incorrect Cortex-R interrupt state control logic. This commit fixes incorrect Cortex-R interrupt lock, unlock and state check function implementations. The issues can be summarised as follows: 1. The current implementation of 'z_arch_irq_lock' returns the value of CPSR as the IRQ key and, since CPSR contains many other state bits, this caused 'z_arch_irq_unlocked' to return false even when IRQ is unlocked. This problem is fixed by isolating only the I-bit of CPSR and returning this value as the IRQ key, such that it returns a non-zero value when interrupt is disabled. 2. The current implementation of 'z_arch_irq_unlock' directly updates the value of CPSR control field with the IRQ key and this can cause other state bits in CPSR to be corrupted. This problem is fixed by conditionally enabling interrupt using CPSIE instruction when the value of IRQ key is a zero. 3. The current implementation of 'z_arch_is_in_isr' checks the value of CPSR MODE field and returns true if its value is IRQ or FIQ. While this does not normally cause an issue, the function can return false when IRQ offloading is used because the offload function executes in SVC mode. This problem is fixed by adding check for SVC mode. Signed-off-by: Stephanos Ioannidis --- arch/arm/include/cortex_r/exc.h | 4 +++- include/arch/arm/asm_inline_gcc.h | 20 ++++++++++++++------ 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/arch/arm/include/cortex_r/exc.h b/arch/arm/include/cortex_r/exc.h index 50b42c8d1839..c49abff09e4d 100644 --- a/arch/arm/include/cortex_r/exc.h +++ b/arch/arm/include/cortex_r/exc.h @@ -42,7 +42,9 @@ static ALWAYS_INLINE bool z_arch_is_in_isr(void) : "=r" (status) : : "memory", "cc"); status &= MODE_MASK; - return (status == MODE_FIQ) || (status == MODE_IRQ); + return (status == MODE_FIQ) || + (status == MODE_IRQ) || + (status == MODE_SVC); } /** diff --git a/include/arch/arm/asm_inline_gcc.h b/include/arch/arm/asm_inline_gcc.h index 839777904d02..1ac2a0e328a9 100644 --- a/include/arch/arm/asm_inline_gcc.h +++ b/include/arch/arm/asm_inline_gcc.h @@ -22,6 +22,10 @@ #include #include +#if defined(CONFIG_CPU_CORTEX_R) +#include +#endif + #ifdef __cplusplus extern "C" { #endif @@ -58,8 +62,10 @@ static ALWAYS_INLINE unsigned int z_arch_irq_lock(void) : "i"(_EXC_IRQ_DEFAULT_PRIO) : "memory"); #elif defined(CONFIG_ARMV7_R) - __asm__ volatile("mrs %0, cpsr;" - "cpsid i" + __asm__ volatile( + "mrs %0, cpsr;" + "and %0, #" TOSTR(I_BIT) ";" + "cpsid i;" : "=r" (key) : : "memory", "cc"); @@ -91,10 +97,12 @@ static ALWAYS_INLINE void z_arch_irq_unlock(unsigned int key) "isb;" : : "r"(key) : "memory"); #elif defined(CONFIG_ARMV7_R) - __asm__ volatile("msr cpsr_c, %0" - : - : "r" (key) - : "memory", "cc"); + if (key) { + return; + } + __asm__ volatile( + "cpsie i;" + : : : "memory", "cc"); #else #error Unknown ARM architecture #endif /* CONFIG_ARMV6_M_ARMV8_M_BASELINE */ From 7339a523c756c1f97ddaa2ddb2396495d8d6b68e Mon Sep 17 00:00:00 2001 From: Stephanos Ioannidis Date: Tue, 15 Oct 2019 15:57:04 +0900 Subject: [PATCH 08/18] arch: arm: Optimise Cortex-R exception return function. z_arm_exc_exit (z_arm_int_exit) requires the current execution mode to be specified as a parameter (through r0). This is not necessary because this value can be directly read from CPSR. This commit modifies the exception return function to retrieve the current execution mode from CPSR and removes all provisions for passing the execution mode parameter. Signed-off-by: Stephanos Ioannidis --- arch/arm/core/exc_exit.S | 22 ++++------------------ arch/arm/core/isr_wrapper.S | 4 ---- arch/arm/core/swap_helper.S | 2 -- include/arch/arm/cortex_r/cpu.h | 3 --- 4 files changed, 4 insertions(+), 27 deletions(-) diff --git a/arch/arm/core/exc_exit.S b/arch/arm/core/exc_exit.S index cc5407a3e01c..4a560be2edc0 100644 --- a/arch/arm/core/exc_exit.S +++ b/arch/arm/core/exc_exit.S @@ -71,10 +71,6 @@ SECTION_SUBSEC_FUNC(TEXT, _HandlerModeExit, z_arm_int_exit) */ SECTION_SUBSEC_FUNC(TEXT, _HandlerModeExit, z_arm_exc_exit) -#if defined(CONFIG_CPU_CORTEX_R) - /* r0 contains the caller mode */ - push {r0, lr} -#endif #ifdef CONFIG_PREEMPT_ENABLED ldr r0, =_kernel @@ -117,9 +113,6 @@ _EXIT_EXC: #if defined(CONFIG_CPU_CORTEX_M) bx lr #elif defined(CONFIG_CPU_CORTEX_R) - /* Restore the caller mode to r0 */ - pop {r0, lr} - /* * Restore r0-r3, r12 and lr stored into the process stack by the mode * entry function. These registers are saved by _isr_wrapper for IRQ mode @@ -128,22 +121,15 @@ _EXIT_EXC: * r0-r3 are either the values from the thread before it was switched out * or they are the args to _new_thread for a new thread. */ - push {r4, r5} + push {r4-r6} + mrs r6, cpsr - cmp r0, #RET_FROM_SVC cps #MODE_SYS ldmia sp!, {r0-r5} - beq _svc_exit - - cps #MODE_IRQ - b _exc_exit - -_svc_exit: - cps #MODE_SVC + msr cpsr_c, r6 -_exc_exit: mov r12, r4 mov lr, r5 - pop {r4, r5} + pop {r4-r6} movs pc, lr #endif diff --git a/arch/arm/core/isr_wrapper.S b/arch/arm/core/isr_wrapper.S index 466afa05123e..dbf529313ce5 100644 --- a/arch/arm/core/isr_wrapper.S +++ b/arch/arm/core/isr_wrapper.S @@ -171,10 +171,6 @@ _idle_state_cleared: #error Unknown ARM architecture #endif /* CONFIG_ARMV6_M_ARMV8_M_BASELINE */ -#if defined(CONFIG_CPU_CORTEX_R) - mov r0, #RET_FROM_IRQ -#endif - /* Use 'bx' instead of 'b' because 'bx' can jump further, and use * 'bx' instead of 'blx' because exception return is done in * z_arm_int_exit() */ diff --git a/arch/arm/core/swap_helper.S b/arch/arm/core/swap_helper.S index 44ee723cc492..3afc7ce4d40c 100644 --- a/arch/arm/core/swap_helper.S +++ b/arch/arm/core/swap_helper.S @@ -618,7 +618,6 @@ demux: blx z_irq_do_offload /* call C routine which executes the offload */ /* exception return is done in z_arm_int_exit() */ - mov r0, #RET_FROM_SVC b z_arm_int_exit #endif @@ -626,7 +625,6 @@ _context_switch: /* handler mode exit, to PendSV */ bl z_arm_pendsv - mov r0, #RET_FROM_SVC b z_arm_int_exit _oops: diff --git a/include/arch/arm/cortex_r/cpu.h b/include/arch/arm/cortex_r/cpu.h index 28a072b908fa..c17a24e4f068 100644 --- a/include/arch/arm/cortex_r/cpu.h +++ b/include/arch/arm/cortex_r/cpu.h @@ -31,9 +31,6 @@ #define FPEXC_EN (1 << 30) -#define RET_FROM_SVC 0 -#define RET_FROM_IRQ 1 - #define __ISB() __asm__ volatile ("isb sy" : : : "memory") #define __DMB() __asm__ volatile ("dmb sy" : : : "memory") From d0b4fe6b997e09f9589650468aa4c423c1369e1c Mon Sep 17 00:00:00 2001 From: Stephanos Ioannidis Date: Wed, 16 Oct 2019 10:11:14 +0900 Subject: [PATCH 09/18] arch: arm: Add Cortex-R direct interrupt service routine support. This commit implements direct interrupt service routine support for Cortex-R. On Cortex-R, the direct ISR function must be declared 'naked' with manual context preservation due to the following reasons: 1. 'z_arm_int_exit' does not return to the caller on Cortex-R (whereas, on Cortex-M, it can either return to the caller or directly exit the IRQ mode depending on the value of LR). 2. If 'z_arm_int_exit' is called (when ISR body returns true), since this function does not return to the caller on Cortex-R, the registers pushed into stack by the compiler will not get popped. 3. The caller-saved registers must be saved into the system mode stack because a context switch can occur. Signed-off-by: Stephanos Ioannidis --- arch/arm/core/irq.c | 5 --- include/arch/arm/irq.h | 81 +++++++++++++++++++++++++++++++++++------- 2 files changed, 69 insertions(+), 17 deletions(-) diff --git a/arch/arm/core/irq.c b/arch/arm/core/irq.c index aabdbdb342f1..1d27f59f34b0 100644 --- a/arch/arm/core/irq.c +++ b/arch/arm/core/irq.c @@ -88,11 +88,6 @@ void _arch_isr_direct_pm(void) } #endif -void z_arch_isr_direct_header(void) -{ - sys_trace_isr_enter(); -} - #ifdef CONFIG_DYNAMIC_INTERRUPTS int z_arch_irq_connect_dynamic(unsigned int irq, unsigned int priority, void (*routine)(void *parameter), void *parameter, diff --git a/include/arch/arm/irq.h b/include/arch/arm/irq.h index 3ef252ba6748..7fcb65495829 100644 --- a/include/arch/arm/irq.h +++ b/include/arch/arm/irq.h @@ -6,18 +6,22 @@ /** * @file - * @brief Cortex-M public interrupt handling + * @brief ARM public interrupt handling * * ARM-specific kernel interrupt handling interface. Included by arm/arch.h. */ -#ifndef ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_M_IRQ_H_ -#define ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_M_IRQ_H_ +#ifndef ZEPHYR_INCLUDE_ARCH_ARM_IRQ_H_ +#define ZEPHYR_INCLUDE_ARCH_ARM_IRQ_H_ #include #include #include +#if defined(CONFIG_CPU_CORTEX_R) +#include +#endif + #ifdef __cplusplus extern "C" { #endif @@ -34,7 +38,7 @@ extern int z_arch_irq_is_enabled(unsigned int irq); extern void z_arm_int_exit(void); -#if defined(CONFIG_ARMV7_R) +#if defined(CONFIG_CPU_CORTEX_R) static ALWAYS_INLINE void z_arm_int_lib_init(void) { } @@ -90,6 +94,36 @@ extern void z_arm_irq_priority_set(unsigned int irq, unsigned int prio, irq_p; \ }) +#ifndef CONFIG_CPU_CORTEX_M +static ALWAYS_INLINE void z_arm_isr_enter(void) +{ + __asm volatile( + "push {r4, r5};" + "mov r4, r12;" + "sub r5, lr, #4;" + "cps #" TOSTR(MODE_SYS) ";" + "stmdb sp!, {r0-r5};" + "cps #" TOSTR(MODE_IRQ) ";" + "pop {r4, r5};" + ); +} + +static ALWAYS_INLINE void z_arm_isr_exit(void) +{ + __asm volatile( + "push {r4-r6};" + "mrs r6, cpsr;" + "cps #" TOSTR(MODE_SYS) ";" + "ldmia sp!, {r0-r5};" + "msr cpsr_c, r6;" + "mov r12, r4;" + "mov lr, r5;" + "pop {r4-r6};" + "movs pc, lr;" + ); +} +#endif /* !CONFIG_CPU_CORTEX_M */ + /* FIXME prefer these inline, but see GH-3056 */ #ifdef CONFIG_SYS_POWER_MANAGEMENT extern void _arch_isr_direct_pm(void); @@ -99,31 +133,35 @@ extern void _arch_isr_direct_pm(void); #endif #define Z_ARCH_ISR_DIRECT_HEADER() z_arch_isr_direct_header() -extern void z_arch_isr_direct_header(void); +static ALWAYS_INLINE void z_arch_isr_direct_header(void) +{ +#ifdef CONFIG_TRACING + sys_trace_isr_enter(); +#endif +} #define Z_ARCH_ISR_DIRECT_FOOTER(swap) z_arch_isr_direct_footer(swap) -/* arch/arm/core/exc_exit.S */ -extern void z_arm_int_exit(void); - #ifdef CONFIG_TRACING extern void sys_trace_isr_exit(void); #endif -static inline void z_arch_isr_direct_footer(int maybe_swap) +static ALWAYS_INLINE void z_arch_isr_direct_footer(int maybe_swap) { - #ifdef CONFIG_TRACING sys_trace_isr_exit(); #endif + if (maybe_swap) { z_arm_int_exit(); } } +#ifdef CONFIG_CPU_CORTEX_M + #define Z_ARCH_ISR_DIRECT_DECLARE(name) \ static inline int name##_body(void); \ - __attribute__ ((interrupt ("IRQ"))) void name(void) \ + __attribute__((interrupt)) void name(void) \ { \ int check_reschedule; \ ISR_DIRECT_HEADER(); \ @@ -132,6 +170,25 @@ static inline void z_arch_isr_direct_footer(int maybe_swap) } \ static inline int name##_body(void) +#else + +#define Z_ARCH_ISR_DIRECT_DECLARE(name) \ + static int name##_body(void); \ + __attribute__((naked)) void name(void) \ + { \ + z_arm_isr_enter(); \ + { \ + int check_reschedule; \ + ISR_DIRECT_HEADER(); \ + check_reschedule = name##_body(); \ + ISR_DIRECT_FOOTER(check_reschedule); \ + } \ + z_arm_isr_exit(); \ + } \ + static __attribute__((noinline)) int name##_body(void) + +#endif /* CONFIG_CPU_CORTEX_M */ + /* Spurious interrupt handler. Throws an error if called */ extern void z_irq_spurious(void *unused); @@ -149,4 +206,4 @@ extern void _isr_wrapper(void); } #endif -#endif /* ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_M_IRQ_H_ */ +#endif /* ZEPHYR_INCLUDE_ARCH_ARM_IRQ_H_ */ From 74ed57c04a4715f14ebf7b1b4fa53ef55f31c13c Mon Sep 17 00:00:00 2001 From: Stephanos Ioannidis Date: Wed, 16 Oct 2019 13:01:55 +0900 Subject: [PATCH 10/18] arch: arm: Allow selecting instruction set for C code compilation. This commit makes the following changes to allow choosing either ARM or Thumb instruction set for C code compilation: 1. Select 'ISA_THUMB2' for 'ARMV7_R'. The semantic of 'ISA_THUMB2' is that the processor supports Thumb instruction set. Since ARMv7-R architecture supports Thumb-2 instruction set, this option should be selected alongside 'ISA_ARM'. 2. Add 'COMPILER_ISA_THUMB2' option to make C code compilation using Thumb instruction set configurable. 3. When 'ISA_ARM' and 'ISA_THUMB2' are selected simultaneously (i.e. on Cortex-R and Cortex-A processors), make all ASM functions use ARM instruction set by default. Signed-off-by: Stephanos Ioannidis --- arch/arm/core/Kconfig | 8 ++++++++ arch/arm/core/cortex_r/Kconfig | 1 + arch/arm/core/thread.c | 6 +++++- cmake/compiler/gcc/target_arm.cmake | 15 +++++++-------- include/arch/arm/irq.h | 2 +- include/toolchain/gcc.h | 24 +++++++++++++----------- 6 files changed, 35 insertions(+), 21 deletions(-) diff --git a/arch/arm/core/Kconfig b/arch/arm/core/Kconfig index dfdfa751d4d9..d308b432a625 100644 --- a/arch/arm/core/Kconfig +++ b/arch/arm/core/Kconfig @@ -76,6 +76,14 @@ config ISA_ARM processor start-up. Much of its functionality was subsumed into T32 with the introduction of Thumb-2 technology. +config COMPILER_ISA_THUMB2 + bool "Compile C functions using Thumb-2 instruction set" + depends on ISA_THUMB2 + default y + help + This option configures the compiler to compile all C functions using the + Thumb-2 instruction set. + config NUM_IRQS int diff --git a/arch/arm/core/cortex_r/Kconfig b/arch/arm/core/cortex_r/Kconfig index 366db5eecc63..d4164c479950 100644 --- a/arch/arm/core/cortex_r/Kconfig +++ b/arch/arm/core/cortex_r/Kconfig @@ -36,6 +36,7 @@ config ARMV7_R bool select ATOMIC_OPERATIONS_BUILTIN select ISA_ARM + select ISA_THUMB2 help This option signifies the use of an ARMv7-R processor implementation. diff --git a/arch/arm/core/thread.c b/arch/arm/core/thread.c index d06c8f875d62..00f678f19924 100644 --- a/arch/arm/core/thread.c +++ b/arch/arm/core/thread.c @@ -136,9 +136,13 @@ void z_arch_new_thread(struct k_thread *thread, k_thread_stack_t *stack, thread->callee_saved.psp = (u32_t)pInitCtx; #if defined(CONFIG_CPU_CORTEX_R) pInitCtx->basic.lr = (u32_t)pInitCtx->basic.pc; +#if defined(CONFIG_COMPILER_ISA_THUMB2) thread->callee_saved.spsr = A_BIT | T_BIT | MODE_SYS; +#else + thread->callee_saved.spsr = A_BIT | MODE_SYS; +#endif /* CONFIG_ISA_THUMB2 */ thread->callee_saved.lr = (u32_t)pInitCtx->basic.pc; -#endif +#endif /* CONFIG_CPU_CORTEX_R */ thread->arch.basepri = 0; #if defined(CONFIG_USERSPACE) || defined(CONFIG_FP_SHARING) diff --git a/cmake/compiler/gcc/target_arm.cmake b/cmake/compiler/gcc/target_arm.cmake index 55739055dab4..a48ea037906d 100644 --- a/cmake/compiler/gcc/target_arm.cmake +++ b/cmake/compiler/gcc/target_arm.cmake @@ -1,12 +1,11 @@ # SPDX-License-Identifier: Apache-2.0 -list(APPEND TOOLCHAIN_C_FLAGS - -mthumb - -mcpu=${GCC_M_CPU} - ) -list(APPEND TOOLCHAIN_LD_FLAGS - -mthumb - -mcpu=${GCC_M_CPU} - ) +list(APPEND TOOLCHAIN_C_FLAGS -mcpu=${GCC_M_CPU}) +list(APPEND TOOLCHAIN_LD_FLAGS -mcpu=${GCC_M_CPU}) + +if(CONFIG_COMPILER_ISA_THUMB2) + list(APPEND TOOLCHAIN_C_FLAGS -mthumb) + list(APPEND TOOLCHAIN_LD_FLAGS -mthumb) +endif() # Defines a mapping from GCC_M_CPU to FPU diff --git a/include/arch/arm/irq.h b/include/arch/arm/irq.h index 7fcb65495829..2da857d0822d 100644 --- a/include/arch/arm/irq.h +++ b/include/arch/arm/irq.h @@ -174,7 +174,7 @@ static ALWAYS_INLINE void z_arch_isr_direct_footer(int maybe_swap) #define Z_ARCH_ISR_DIRECT_DECLARE(name) \ static int name##_body(void); \ - __attribute__((naked)) void name(void) \ + __attribute__((naked, target("arm"))) void name(void) \ { \ z_arm_isr_enter(); \ { \ diff --git a/include/toolchain/gcc.h b/include/toolchain/gcc.h index 936dde341c71..21ca897f1fb7 100644 --- a/include/toolchain/gcc.h +++ b/include/toolchain/gcc.h @@ -217,14 +217,14 @@ do { \ #ifdef CONFIG_ARM -#if defined(CONFIG_ISA_THUMB2) +#if defined(CONFIG_ISA_ARM) -#define FUNC_CODE() .thumb; +#define FUNC_CODE() .code 32 #define FUNC_INSTR(a) -#elif defined(CONFIG_ISA_ARM) +#elif defined(CONFIG_ISA_THUMB2) -#define FUNC_CODE() .code 32 +#define FUNC_CODE() .thumb; #define FUNC_INSTR(a) #else @@ -238,7 +238,7 @@ do { \ #define FUNC_CODE() #define FUNC_INSTR(a) -#endif /* !CONFIG_ARM */ +#endif /* CONFIG_ARM */ #endif /* _ASMLANGUAGE */ @@ -344,14 +344,16 @@ do { \ #endif /* _ASMLANGUAGE */ -#if defined(CONFIG_ARM) && defined(_ASMLANGUAGE) -#if defined(CONFIG_ISA_THUMB2) +#if defined(_ASMLANGUAGE) +#if defined(CONFIG_ARM) +#if defined(CONFIG_ISA_ARM) +#define _ASM_FILE_PROLOGUE .text; .code 32 +#else /* '.syntax unified' is a gcc-ism used in thumb-2 asm files */ #define _ASM_FILE_PROLOGUE .text; .syntax unified; .thumb -#else -#define _ASM_FILE_PROLOGUE .text; .code 32 -#endif -#endif +#endif /* CONFIG_ISA_ARM */ +#endif /* CONFIG_ARM */ +#endif /* _ASMLANGUAGE */ /* * These macros generate absolute symbols for GCC From 45819105083df3e88dd7eb6fdc85f40efa4816df Mon Sep 17 00:00:00 2001 From: Stephanos Ioannidis Date: Wed, 16 Oct 2019 15:36:33 +0900 Subject: [PATCH 11/18] arch: arm: Add vectored interrupt support for Cortex-R. This commit defines a new Cortex-R configuration 'VIC_IRQ_VECTOR' and implements IRQ initialisation routine to configure SCTLR.VE. Signed-off-by: Stephanos Ioannidis --- arch/arm/core/cortex_r/CMakeLists.txt | 1 + arch/arm/core/cortex_r/Kconfig | 11 +++++++--- arch/arm/core/cortex_r/irq_init.c | 30 +++++++++++++++++++++++++++ include/arch/arm/irq.h | 6 ------ 4 files changed, 39 insertions(+), 9 deletions(-) create mode 100644 arch/arm/core/cortex_r/irq_init.c diff --git a/arch/arm/core/cortex_r/CMakeLists.txt b/arch/arm/core/cortex_r/CMakeLists.txt index 6782efec86b5..bbc539278e9b 100644 --- a/arch/arm/core/cortex_r/CMakeLists.txt +++ b/arch/arm/core/cortex_r/CMakeLists.txt @@ -6,6 +6,7 @@ zephyr_library_sources( vector_table.S reset.S fault.c + irq_init.c irq_manage.c reboot.c stacks.c diff --git a/arch/arm/core/cortex_r/Kconfig b/arch/arm/core/cortex_r/Kconfig index d4164c479950..e320c36c42ea 100644 --- a/arch/arm/core/cortex_r/Kconfig +++ b/arch/arm/core/cortex_r/Kconfig @@ -79,8 +79,6 @@ config ARMV7_SYS_STACK_SIZE help This option specifies the size of the stack used by the system mode. -if CPU_CORTEX_R - config RUNTIME_NMI default y @@ -90,6 +88,13 @@ config GEN_ISR_TABLES config GEN_IRQ_VECTOR_TABLE default n -endif # CPU_CORTEX_R +config VIC_IRQ_VECTOR + bool "Enable VIC port hardware IRQ vector" + depends on (CPU_CORTEX_R4 || CPU_CORTEX_R5) + help + Enable hardware IRQ vector using the handler address provided by the + the system interrupt controller through VIC port. When this option is + selected, the IRQ vector (offset 0x18) in the CPU exception vector table + is not used. endif # CPU_CORTEX_R diff --git a/arch/arm/core/cortex_r/irq_init.c b/arch/arm/core/cortex_r/irq_init.c new file mode 100644 index 000000000000..b9a42ca4796c --- /dev/null +++ b/arch/arm/core/cortex_r/irq_init.c @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2019 Stephanos Ioannidis + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief ARM Cortex-R interrupt initialization + */ + +#include + +/** + * @brief Initialize interrupts + * + * @return N/A + */ + +void z_arm_int_lib_init(void) +{ + /* Configure hardware vectored interrupt mode.*/ +#if defined(CONFIG_VIC_IRQ_VECTOR) + __asm__ volatile( + "mrc p15, #0, r0, c1, c0, #0;" + "orr r0, r0, #0x01000000;" /* [24] VE bit */ + "mcr p15, #0, r0, c1, c0, #0;" + : : : "memory"); +#endif +} diff --git a/include/arch/arm/irq.h b/include/arch/arm/irq.h index 2da857d0822d..6d463657c6db 100644 --- a/include/arch/arm/irq.h +++ b/include/arch/arm/irq.h @@ -38,13 +38,7 @@ extern int z_arch_irq_is_enabled(unsigned int irq); extern void z_arm_int_exit(void); -#if defined(CONFIG_CPU_CORTEX_R) -static ALWAYS_INLINE void z_arm_int_lib_init(void) -{ -} -#else extern void z_arm_int_lib_init(void); -#endif /* macros convert value of it's argument to a string */ #define DO_TOSTR(s) #s From ec123a468a8cc14e90d7cff493bcd3a9f2ecd09a Mon Sep 17 00:00:00 2001 From: Stephanos Ioannidis Date: Wed, 16 Oct 2019 16:46:48 +0900 Subject: [PATCH 12/18] soc: arm: xilinx_zynqmp: Relocate platform-specific initialisation. This commit relocates the exception vector table address range configuration routine that was previously implemented as part of Cortex-R architecture reset function to SoC platform-specific initialisation routine. Signed-off-by: Stephanos Ioannidis --- soc/arm/xilinx_zynqmp/Kconfig.soc | 1 + soc/arm/xilinx_zynqmp/soc.c | 10 +++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/soc/arm/xilinx_zynqmp/Kconfig.soc b/soc/arm/xilinx_zynqmp/Kconfig.soc index 4ad0bc70fa29..5040fce19920 100644 --- a/soc/arm/xilinx_zynqmp/Kconfig.soc +++ b/soc/arm/xilinx_zynqmp/Kconfig.soc @@ -8,3 +8,4 @@ config SOC_XILINX_ZYNQMP select GIC select MULTI_LEVEL_INTERRUPTS select 2ND_LEVEL_INTERRUPTS + select PLATFORM_SPECIFIC_INIT diff --git a/soc/arm/xilinx_zynqmp/soc.c b/soc/arm/xilinx_zynqmp/soc.c index 68fae6a2c8d0..9f069e6ed41e 100644 --- a/soc/arm/xilinx_zynqmp/soc.c +++ b/soc/arm/xilinx_zynqmp/soc.c @@ -9,7 +9,6 @@ #include #include -#include /** * * @brief Perform basic hardware initialization @@ -29,3 +28,12 @@ static int soc_init(struct device *arg) } SYS_INIT(soc_init, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); + +void z_platform_init(void) +{ + __asm__ volatile( + "mrc p15, 0, r0, c1, c0, 0;" /* SCTLR */ + "bic r0, r0, #" TOSTR(HIVECS) ";" /* Vector table at 0 */ + "mcr p15, 0, r0, c1, c0, 0;" + : : : "memory"); +} From b06204403215c00380a78a9c983c3620a540ce02 Mon Sep 17 00:00:00 2001 From: Stephanos Ioannidis Date: Mon, 14 Oct 2019 13:47:17 +0900 Subject: [PATCH 13/18] isr_tables: Support hardware interrupt vector table-only configuration. The existing isr_tables implementation does not allow enabling only hardware interrupt vector table without software isr table. This commit ensures that CONFIG_GEN_IRQ_VECTOR_TABLE can be used without setting CONFIG_GEN_SW_ISR_TABLE. Signed-off-by: Stephanos Ioannidis --- arch/common/isr_tables.c | 11 +++++++---- include/linker/common-ram.ld | 2 +- include/linker/common-rom.ld | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/arch/common/isr_tables.c b/arch/common/isr_tables.c index 43b4dc88e0eb..af24484779c7 100644 --- a/arch/common/isr_tables.c +++ b/arch/common/isr_tables.c @@ -29,10 +29,9 @@ Z_GENERIC_SECTION(.irq_info) struct int_list_header _iheader = { /* These are placeholder tables. They will be replaced by the real tables * generated by gen_isr_tables.py. * - * z_irq_spurious and _isr_wrapper are used as placeholder values to - * ensure that they are not optimized out in the first link. The first - * link must contain the same symbols as the second one for the code - * generation to work. + * z_irq_spurious is used as placeholder values to ensure that they are not + * optimized out in the first link. The first link must contain the same + * symbols as the second one for the code generation to work. */ /* Some arches don't use a vector table, they have a common exception entry @@ -40,7 +39,11 @@ Z_GENERIC_SECTION(.irq_info) struct int_list_header _iheader = { */ #ifdef CONFIG_GEN_IRQ_VECTOR_TABLE u32_t __irq_vector_table _irq_vector_table[IRQ_TABLE_SIZE] = { +#ifdef CONFIG_GEN_SW_ISR_TABLE [0 ...(IRQ_TABLE_SIZE - 1)] = (u32_t)&_isr_wrapper, +#else + [0 ...(IRQ_TABLE_SIZE - 1)] = (u32_t)&z_irq_spurious, +#endif }; #endif diff --git a/include/linker/common-ram.ld b/include/linker/common-ram.ld index 41525be9d657..d95a2b697c1a 100644 --- a/include/linker/common-ram.ld +++ b/include/linker/common-ram.ld @@ -5,7 +5,7 @@ DEVICE_INIT_SECTIONS() } GROUP_DATA_LINK_IN(RAMABLE_REGION, ROMABLE_REGION) -#if defined(CONFIG_GEN_ISR_TABLES) && defined(CONFIG_DYNAMIC_INTERRUPTS) +#if defined(CONFIG_GEN_SW_ISR_TABLE) && defined(CONFIG_DYNAMIC_INTERRUPTS) SECTION_DATA_PROLOGUE(sw_isr_table,,) { /* diff --git a/include/linker/common-rom.ld b/include/linker/common-rom.ld index f1e4db547036..8307edf1b12d 100644 --- a/include/linker/common-rom.ld +++ b/include/linker/common-rom.ld @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: Apache-2.0 */ -#if defined(CONFIG_GEN_ISR_TABLES) && !defined(CONFIG_DYNAMIC_INTERRUPTS) +#if defined(CONFIG_GEN_SW_ISR_TABLE) && !defined(CONFIG_DYNAMIC_INTERRUPTS) SECTION_PROLOGUE(sw_isr_table,,) { /* From 2ae2a8207bb53e6c8dc324feb98673807a8dcde5 Mon Sep 17 00:00:00 2001 From: Stephanos Ioannidis Date: Tue, 15 Oct 2019 10:08:18 +0900 Subject: [PATCH 14/18] arch: arm: Make hardware IVT generation default on Cortex-R. Make hardware interrupt vector table generation default on Cortex-R unless the SoC config specifies not to. This is desirable because most Cortex-R SoCs implement an interrupt controller that supports direct vectoring through the VIC port. Signed-off-by: Stephanos Ioannidis --- arch/arm/core/cortex_r/Kconfig | 3 --- soc/arm/xilinx_zynqmp/Kconfig.defconfig | 3 +++ 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm/core/cortex_r/Kconfig b/arch/arm/core/cortex_r/Kconfig index e320c36c42ea..0cd4b760a491 100644 --- a/arch/arm/core/cortex_r/Kconfig +++ b/arch/arm/core/cortex_r/Kconfig @@ -85,9 +85,6 @@ config RUNTIME_NMI config GEN_ISR_TABLES default y -config GEN_IRQ_VECTOR_TABLE - default n - config VIC_IRQ_VECTOR bool "Enable VIC port hardware IRQ vector" depends on (CPU_CORTEX_R4 || CPU_CORTEX_R5) diff --git a/soc/arm/xilinx_zynqmp/Kconfig.defconfig b/soc/arm/xilinx_zynqmp/Kconfig.defconfig index ba74d0a0bdd8..04b54ac4991b 100644 --- a/soc/arm/xilinx_zynqmp/Kconfig.defconfig +++ b/soc/arm/xilinx_zynqmp/Kconfig.defconfig @@ -12,6 +12,9 @@ config NUM_IRQS # - include the UART interrupts default 220 +config GEN_IRQ_VECTOR_TABLE + default n + config 2ND_LVL_ISR_TBL_OFFSET default 1 From 2fd095930b9d2ef714a2be63da8d25303a9e6a22 Mon Sep 17 00:00:00 2001 From: Stephanos Ioannidis Date: Wed, 16 Oct 2019 19:56:59 +0900 Subject: [PATCH 15/18] arch: arm: Refactor Cortex-R interrupt system. The current Cortex-R interrupt system relies on the multi-level interrupt mechanism and 'irq_nextlevel' public interface. This is a less-than-ideal implementation for the following reasons: 1. SoC main interrupt controller (e.g. GIC) is not a 2nd level interrupt controller; in fact, it is the root interrupt controller and therefore should be treated as such. 2. The only reason for using 'irq_nextlevel' here is to interface Cortex-R arch implementation to the interrupt controller functions. Since there is no nesting or multiple instances of an interrupt controller involved, there is really no point in adding such an abstraction. 3. 2nd level topology adds many unnecessary abstractions and results in strange coding artefacts as well as performance penalty due to additional branching. The solution provided by this commit is as follows: 1. Define a set of SoC layer interrupt management functions (z_soc_irq_*) to be used by the Cortex-R variants that do not have an architecturally specified interrupt controller. 2. Map arch interrupt management functiosn to the SoC layer interrupt management functions (e.g. map 'z_arch_irq_enable' to 'z_soc_irq_enable'). 3. The SoC layer interrupt management functions are implemented by soc/arm/*. If an SoC incorporates a proprietary (not commonly used) interrupt controller, the interrupt management functions can be simply implemented within the SoC layer. If an SoC incorporates a standard interrupt controller such as GIC, these functions can be mapped to the appropriate interrupt controller driver functions either through the 'irq_nextlevel' interface, or a direct driver- specific interface exported by include/drivers/interrupt_controller. Signed-off-by: Stephanos Ioannidis --- arch/arm/core/Kconfig | 7 +++ arch/arm/core/cortex_r/CMakeLists.txt | 1 - arch/arm/core/cortex_r/irq_init.c | 3 ++ arch/arm/core/cortex_r/irq_manage.c | 69 --------------------------- arch/arm/core/isr_wrapper.S | 16 ++++--- drivers/interrupt_controller/Kconfig | 6 +-- include/arch/arm/irq.h | 57 +++++++++++++++++----- 7 files changed, 68 insertions(+), 91 deletions(-) delete mode 100644 arch/arm/core/cortex_r/irq_manage.c diff --git a/arch/arm/core/Kconfig b/arch/arm/core/Kconfig index d308b432a625..b9b4caa3ddfd 100644 --- a/arch/arm/core/Kconfig +++ b/arch/arm/core/Kconfig @@ -87,6 +87,13 @@ config COMPILER_ISA_THUMB2 config NUM_IRQS int +config IRQ_COMMON_EOI + bool + help + This option signifies that the architectural interrupt controller + requires a common End of Interrupt (EOI) action after servicing every + interrupt. + config STACK_ALIGN_DOUBLE_WORD bool "Align stacks on double-words (8 octets)" default y diff --git a/arch/arm/core/cortex_r/CMakeLists.txt b/arch/arm/core/cortex_r/CMakeLists.txt index bbc539278e9b..52b6d71804e9 100644 --- a/arch/arm/core/cortex_r/CMakeLists.txt +++ b/arch/arm/core/cortex_r/CMakeLists.txt @@ -7,7 +7,6 @@ zephyr_library_sources( reset.S fault.c irq_init.c - irq_manage.c reboot.c stacks.c ) diff --git a/arch/arm/core/cortex_r/irq_init.c b/arch/arm/core/cortex_r/irq_init.c index b9a42ca4796c..e05d335015b3 100644 --- a/arch/arm/core/cortex_r/irq_init.c +++ b/arch/arm/core/cortex_r/irq_init.c @@ -19,6 +19,9 @@ void z_arm_int_lib_init(void) { + /* Invoke SoC-specific interrupt initialisation */ + z_soc_irq_init(); + /* Configure hardware vectored interrupt mode.*/ #if defined(CONFIG_VIC_IRQ_VECTOR) __asm__ volatile( diff --git a/arch/arm/core/cortex_r/irq_manage.c b/arch/arm/core/cortex_r/irq_manage.c deleted file mode 100644 index ca038e26e214..000000000000 --- a/arch/arm/core/cortex_r/irq_manage.c +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2013-2014 Wind River Systems, Inc. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file - * @brief ARM Cortex-R interrupt management - * - * - * Interrupt management: enabling/disabling and dynamic ISR - * connecting/replacing. SW_ISR_TABLE_DYNAMIC has to be enabled for - * connecting ISRs at runtime. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -void z_arch_irq_enable(unsigned int irq) -{ - struct device *dev = _sw_isr_table[0].arg; - - irq_enable_next_level(dev, irq); -} - -void z_arch_irq_disable(unsigned int irq) -{ - struct device *dev = _sw_isr_table[0].arg; - - irq_disable_next_level(dev, irq); -} - -int z_arch_irq_is_enabled(unsigned int irq) -{ - struct device *dev = _sw_isr_table[0].arg; - - return irq_line_is_enabled_next_level(dev, irq); -} - -/** - * @internal - * - * @brief Set an interrupt's priority - * - * The priority is verified if ASSERT_ON is enabled. The maximum number - * of priority levels is a little complex, as there are some hardware - * priority levels which are reserved. - * - * @return N/A - */ -void z_arm_irq_priority_set(unsigned int irq, unsigned int prio, u32_t flags) -{ - struct device *dev = _sw_isr_table[0].arg; - - if (irq == 0) - return 0; - - irq_set_priority_next_level(dev, irq, prio, flags); -} diff --git a/arch/arm/core/isr_wrapper.S b/arch/arm/core/isr_wrapper.S index dbf529313ce5..e4ad9db43e36 100644 --- a/arch/arm/core/isr_wrapper.S +++ b/arch/arm/core/isr_wrapper.S @@ -123,12 +123,11 @@ _idle_state_cleared: #elif defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) sub r0, r0, #16 /* get IRQ number */ lsl r0, r0, #3 /* table is 8-byte wide */ -#elif defined(CONFIG_ARMV7_R) - /* - * Cortex-R only has one IRQ line so the main handler will be at - * offset 0 of the table. - */ - mov r0, #0 +#elif defined(CONFIG_CPU_CORTEX_R4) || defined(CONFIG_CPU_CORTEX_R5) + /* Get active IRQ number from the SoC interrupt controller */ + bl z_soc_irq_get_active + push {r0, r1} + lsl r0, r0, #3 /* table is 8-byte wide */ #else #error Unknown ARM architecture #endif /* CONFIG_ARMV6_M_ARMV8_M_BASELINE */ @@ -151,6 +150,11 @@ _idle_state_cleared: #endif /* CONFIG_EXECUTION_BENCHMARKING */ blx r3 /* call ISR */ +#ifdef CONFIG_IRQ_COMMON_EOI + pop {r0, r1} + bl z_soc_irq_eoi +#endif + #ifdef CONFIG_TRACING bl sys_trace_isr_exit #endif diff --git a/drivers/interrupt_controller/Kconfig b/drivers/interrupt_controller/Kconfig index 53d7d8c2a529..9c590f3a67e1 100644 --- a/drivers/interrupt_controller/Kconfig +++ b/drivers/interrupt_controller/Kconfig @@ -145,10 +145,10 @@ config DW_ICTL_INIT_PRIORITY config GIC bool "ARM Generic Interrupt Controller (GIC)" - depends on CPU_CORTEX_R + select IRQ_COMMON_EOI help - The ARM Generic Interrupt Controller works with Cortex-A and - Cortex-R processors. + The ARM Generic Interrupt Controller is an interrupt controller that is + used often by ARM Cortex-A and Cortex-R devices. source "drivers/interrupt_controller/Kconfig.stm32" diff --git a/include/arch/arm/irq.h b/include/arch/arm/irq.h index 6d463657c6db..ff45c885f2f8 100644 --- a/include/arch/arm/irq.h +++ b/include/arch/arm/irq.h @@ -28,18 +28,55 @@ extern "C" { #ifdef _ASMLANGUAGE GTEXT(z_arm_int_exit); -GTEXT(z_arch_irq_enable) -GTEXT(z_arch_irq_disable) -GTEXT(z_arch_irq_is_enabled) +GTEXT(z_soc_irq_get_active); +GTEXT(z_soc_irq_eoi); #else + +#if defined(CONFIG_CPU_CORTEX_M) extern void z_arch_irq_enable(unsigned int irq); extern void z_arch_irq_disable(unsigned int irq); extern int z_arch_irq_is_enabled(unsigned int irq); +/* internal routine documented in C file, needed by IRQ_CONNECT() macro */ +extern void z_arm_irq_priority_set(unsigned int irq, unsigned int prio, + unsigned int flags); + +#else +/* + * Many Cortex-A and Cortex-R series cores do not designate an architectural + * interrupt controller and an arbitrary SoC-specific interrupt controller may + * be used. + * + * For this reason, the arch interrupt management functions are mapped to the + * SoC layer. + */ + +void z_soc_irq_init(void); +void z_soc_irq_enable(unsigned int irq); +void z_soc_irq_disable(unsigned int irq); +int z_soc_irq_is_enabled(unsigned int irq); + +unsigned int z_soc_irq_get_active(void); +void z_soc_irq_eoi(unsigned int irq); + +void z_soc_irq_priority_set( + unsigned int irq, unsigned int prio, unsigned int flags); + +#define z_arch_irq_enable(irq) z_soc_irq_enable(irq) +#define z_arch_irq_disable(irq) z_soc_irq_disable(irq) +#define z_arch_irq_is_enabled(irq) z_soc_irq_is_enabled(irq) + +#define z_arm_irq_priority_set(irq, prio, flags) \ + z_soc_irq_priority_set(irq, prio, flags) + +#endif /* CONFIG_CPU_CORTEX_M */ + + extern void z_arm_int_exit(void); extern void z_arm_int_lib_init(void); + /* macros convert value of it's argument to a string */ #define DO_TOSTR(s) #s #define TOSTR(s) DO_TOSTR(s) @@ -48,10 +85,6 @@ extern void z_arm_int_lib_init(void); #define DO_CONCAT(x, y) x ## y #define CONCAT(x, y) DO_CONCAT(x, y) -/* internal routine documented in C file, needed by IRQ_CONNECT() macro */ -extern void z_arm_irq_priority_set(unsigned int irq, unsigned int prio, - u32_t flags); - /* Flags for use with IRQ_CONNECT() */ #ifdef CONFIG_ZERO_LATENCY_IRQS @@ -126,6 +159,11 @@ extern void _arch_isr_direct_pm(void); #define Z_ARCH_ISR_DIRECT_PM() do { } while (false) #endif +#ifdef CONFIG_TRACING +extern void sys_trace_isr_enter(void); +extern void sys_trace_isr_exit(void); +#endif + #define Z_ARCH_ISR_DIRECT_HEADER() z_arch_isr_direct_header() static ALWAYS_INLINE void z_arch_isr_direct_header(void) { @@ -135,11 +173,6 @@ static ALWAYS_INLINE void z_arch_isr_direct_header(void) } #define Z_ARCH_ISR_DIRECT_FOOTER(swap) z_arch_isr_direct_footer(swap) - -#ifdef CONFIG_TRACING -extern void sys_trace_isr_exit(void); -#endif - static ALWAYS_INLINE void z_arch_isr_direct_footer(int maybe_swap) { #ifdef CONFIG_TRACING From 10a951fcf945c77d6995a7f529239be12ca9b5b5 Mon Sep 17 00:00:00 2001 From: Stephanos Ioannidis Date: Wed, 16 Oct 2019 22:34:33 +0900 Subject: [PATCH 16/18] soc: arm: xilinx_zynqmp: Use the refactored Cortex-R interrupt system. This commit updates 'xilinx_zynqmp' to use the refactored Cortex-R interrupt system. For more details on the refactored Cortex-R interrupt system, see the PR #19698. Signed-off-by: Stephanos Ioannidis --- drivers/interrupt_controller/gic-400.c | 181 +++++++++------------ include/drivers/interrupt_controller/gic.h | 21 +++ soc/arm/xilinx_zynqmp/CMakeLists.txt | 1 + soc/arm/xilinx_zynqmp/Kconfig.defconfig | 11 +- soc/arm/xilinx_zynqmp/Kconfig.soc | 2 - soc/arm/xilinx_zynqmp/dts_fixup.h | 8 +- soc/arm/xilinx_zynqmp/irq.c | 64 ++++++++ 7 files changed, 169 insertions(+), 119 deletions(-) create mode 100644 include/drivers/interrupt_controller/gic.h create mode 100644 soc/arm/xilinx_zynqmp/irq.c diff --git a/drivers/interrupt_controller/gic-400.c b/drivers/interrupt_controller/gic-400.c index 774aedb5118a..e976e4a702d4 100644 --- a/drivers/interrupt_controller/gic-400.c +++ b/drivers/interrupt_controller/gic-400.c @@ -1,13 +1,14 @@ /* * Copyright (c) 2018 Marvell * Copyright (c) 2018 Lexmark International, Inc. + * Copyright (c) 2019 Stephanos Ioannidis * * SPDX-License-Identifier: Apache-2.0 */ #include #include -#include +#include #include #define DT_GIC_DIST_BASE DT_INST_0_ARM_GIC_BASE_ADDRESS_0 @@ -44,9 +45,81 @@ #define GIC_INT_TYPE_MASK 0x3 #define GIC_INT_TYPE_EDGE (1 << 1) -struct gic_ictl_config { - u32_t isr_table_offset; -}; +void arm_gic_irq_enable(unsigned int irq) +{ + int int_grp, int_off; + + irq += GIC_SPI_INT_BASE; + int_grp = irq / 32; + int_off = irq % 32; + + sys_write32((1 << int_off), (GICD_ISENABLERn + int_grp * 4)); +} + +void arm_gic_irq_disable(unsigned int irq) +{ + int int_grp, int_off; + + irq += GIC_SPI_INT_BASE; + int_grp = irq / 32; + int_off = irq % 32; + + sys_write32((1 << int_off), (GICD_ICENABLERn + int_grp * 4)); +} + +int arm_gic_irq_is_enabled(unsigned int irq) +{ + int int_grp, int_off; + unsigned int enabler; + + irq += GIC_SPI_INT_BASE; + int_grp = irq / 32; + int_off = irq % 32; + + enabler = sys_read32(GICD_ICENABLERn + int_grp * 4); + + return (enabler & (1 << int_off)) != 0; +} + +void arm_gic_irq_set_priority( + unsigned int irq, unsigned int prio, unsigned int flags) +{ + int int_grp, int_off; + u8_t val; + + irq += GIC_SPI_INT_BASE; + + /* Set priority */ + sys_write8(prio & 0xff, GICD_IPRIORITYRn + irq); + + /* Set interrupt type */ + int_grp = irq / 4; + int_off = (irq % 4) * 2; + + val = sys_read8(GICD_ICFGRn + int_grp); + val &= ~(GIC_INT_TYPE_MASK << int_off); + if (flags & IRQ_TYPE_EDGE) + val |= (GIC_INT_TYPE_EDGE << int_off); + sys_write8(val, GICD_ICFGRn + int_grp); +} + +unsigned int arm_gic_irq_get_active(void) +{ + int irq; + + irq = sys_read32(GICC_IAR) & 0x3ff; + irq -= GIC_SPI_INT_BASE; + + return irq; +} + +void arm_gic_irq_eoi(unsigned int irq) +{ + irq += GIC_SPI_INT_BASE; + + /* set to inactive */ + sys_write32(irq, GICC_EOIR); +} static void gic_dist_init(void) { @@ -129,98 +202,6 @@ static void gic_cpu_init(void) sys_write32(val, GICC_CTRL); } -static void gic_irq_enable(struct device *dev, unsigned int irq) -{ - int int_grp, int_off; - - irq += GIC_SPI_INT_BASE; - int_grp = irq / 32; - int_off = irq % 32; - - sys_write32((1 << int_off), (GICD_ISENABLERn + int_grp * 4)); -} - -static void gic_irq_disable(struct device *dev, unsigned int irq) -{ - int int_grp, int_off; - - irq += GIC_SPI_INT_BASE; - int_grp = irq / 32; - int_off = irq % 32; - - sys_write32((1 << int_off), (GICD_ICENABLERn + int_grp * 4)); -} - -static unsigned int gic_irq_get_state(struct device *dev) -{ - return 1; -} - -static void gic_irq_set_priority(struct device *dev, - unsigned int irq, unsigned int prio, u32_t flags) -{ - int int_grp, int_off; - u8_t val; - - irq += GIC_SPI_INT_BASE; - - /* Set priority */ - sys_write8(prio & 0xff, GICD_IPRIORITYRn + irq); - - /* Set interrupt type */ - int_grp = irq / 4; - int_off = (irq % 4) * 2; - - val = sys_read8(GICD_ICFGRn + int_grp); - val &= ~(GIC_INT_TYPE_MASK << int_off); - if (flags & IRQ_TYPE_EDGE) - val |= (GIC_INT_TYPE_EDGE << int_off); - sys_write8(val, GICD_ICFGRn + int_grp); -} - -static void gic_isr(void *arg) -{ - struct device *dev = arg; - const struct gic_ictl_config *cfg = dev->config->config_info; - void (*gic_isr_handle)(void *); - int irq, isr_offset; - - irq = sys_read32(GICC_IAR); - irq &= 0x3ff; - - if (irq == NO_GIC_INT_PENDING) { - printk("gic: Invalid interrupt\n"); - return; - } - - isr_offset = cfg->isr_table_offset + irq - GIC_SPI_INT_BASE; - - gic_isr_handle = _sw_isr_table[isr_offset].isr; - if (gic_isr_handle) - gic_isr_handle(_sw_isr_table[isr_offset].arg); - else - printk("gic: no handler found for int %d\n", irq); - - /* set to inactive */ - sys_write32(irq, GICC_EOIR); -} - -static int gic_init(struct device *unused); -static const struct irq_next_level_api gic_apis = { - .intr_enable = gic_irq_enable, - .intr_disable = gic_irq_disable, - .intr_get_state = gic_irq_get_state, - .intr_set_priority = gic_irq_set_priority, -}; - -static const struct gic_ictl_config gic_config = { - .isr_table_offset = CONFIG_2ND_LVL_ISR_TBL_OFFSET, -}; - -DEVICE_AND_API_INIT(arm_gic, DT_INST_0_ARM_GIC_LABEL, - gic_init, NULL, &gic_config, - PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &gic_apis); - /** * * @brief Initialize the GIC device driver @@ -228,14 +209,8 @@ DEVICE_AND_API_INIT(arm_gic, DT_INST_0_ARM_GIC_LABEL, * * @return N/A */ -#define GIC_PARENT_IRQ 0 -#define GIC_PARENT_IRQ_PRI 0 -#define GIC_PARENT_IRQ_FLAGS 0 -static int gic_init(struct device *unused) +int arm_gic_init(void) { - IRQ_CONNECT(GIC_PARENT_IRQ, GIC_PARENT_IRQ_PRI, gic_isr, - DEVICE_GET(arm_gic), GIC_PARENT_IRQ_FLAGS); - /* Init of Distributor interface registers */ gic_dist_init(); diff --git a/include/drivers/interrupt_controller/gic.h b/include/drivers/interrupt_controller/gic.h new file mode 100644 index 000000000000..af87472007d7 --- /dev/null +++ b/include/drivers/interrupt_controller/gic.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2019 Stephanos Ioannidis + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_GIC_H_ +#define ZEPHYR_INCLUDE_DRIVERS_GIC_H_ + +int arm_gic_init(void); + +void arm_gic_irq_enable(unsigned int irq); +void arm_gic_irq_disable(unsigned int irq); +int arm_gic_irq_is_enabled(unsigned int irq); +unsigned int arm_gic_irq_get_active(void); +void arm_gic_irq_eoi(unsigned int irq); + +void arm_gic_irq_set_priority( + unsigned int irq, unsigned int prio, unsigned int flags); + +#endif /* ZEPHYR_INCLUDE_DRIVERS_GIC_400_H_ */ diff --git a/soc/arm/xilinx_zynqmp/CMakeLists.txt b/soc/arm/xilinx_zynqmp/CMakeLists.txt index 3d770db77d01..a6858f7a83dd 100644 --- a/soc/arm/xilinx_zynqmp/CMakeLists.txt +++ b/soc/arm/xilinx_zynqmp/CMakeLists.txt @@ -4,4 +4,5 @@ zephyr_sources( soc.c + irq.c ) diff --git a/soc/arm/xilinx_zynqmp/Kconfig.defconfig b/soc/arm/xilinx_zynqmp/Kconfig.defconfig index 04b54ac4991b..f06f48cfcce0 100644 --- a/soc/arm/xilinx_zynqmp/Kconfig.defconfig +++ b/soc/arm/xilinx_zynqmp/Kconfig.defconfig @@ -10,20 +10,11 @@ config SOC config NUM_IRQS # must be >= the highest interrupt number used # - include the UART interrupts - default 220 + default 219 config GEN_IRQ_VECTOR_TABLE default n -config 2ND_LVL_ISR_TBL_OFFSET - default 1 - -config MAX_IRQ_PER_AGGREGATOR - default 219 - -config NUM_2ND_LEVEL_AGGREGATORS - default 1 - config SYS_CLOCK_HW_CYCLES_PER_SEC default 12000000 diff --git a/soc/arm/xilinx_zynqmp/Kconfig.soc b/soc/arm/xilinx_zynqmp/Kconfig.soc index 5040fce19920..f89afb1497e0 100644 --- a/soc/arm/xilinx_zynqmp/Kconfig.soc +++ b/soc/arm/xilinx_zynqmp/Kconfig.soc @@ -6,6 +6,4 @@ config SOC_XILINX_ZYNQMP bool "Xilinx ZynqMP" select CPU_CORTEX_R5 select GIC - select MULTI_LEVEL_INTERRUPTS - select 2ND_LEVEL_INTERRUPTS select PLATFORM_SPECIFIC_INIT diff --git a/soc/arm/xilinx_zynqmp/dts_fixup.h b/soc/arm/xilinx_zynqmp/dts_fixup.h index 70b231a114d6..3262a429d44e 100644 --- a/soc/arm/xilinx_zynqmp/dts_fixup.h +++ b/soc/arm/xilinx_zynqmp/dts_fixup.h @@ -6,11 +6,11 @@ */ #undef DT_INST_0_XLNX_XUARTPS_IRQ_0 -#define DT_INST_0_XLNX_XUARTPS_IRQ_0 ((DT_INST_0_XLNX_XUARTPS_IRQ_IRQ_0 + 1) << 8) +#define DT_INST_0_XLNX_XUARTPS_IRQ_0 DT_INST_0_XLNX_XUARTPS_IRQ_IRQ_0 #undef DT_INST_0_CDNS_TTC_IRQ_0 -#define DT_INST_0_CDNS_TTC_IRQ_0 ((DT_INST_0_CDNS_TTC_IRQ_IRQ_0 + 1) << 8) +#define DT_INST_0_CDNS_TTC_IRQ_0 DT_INST_0_CDNS_TTC_IRQ_IRQ_0 #undef DT_INST_0_CDNS_TTC_IRQ_1 -#define DT_INST_0_CDNS_TTC_IRQ_1 ((DT_INST_0_CDNS_TTC_IRQ_IRQ_1 + 1) << 8) +#define DT_INST_0_CDNS_TTC_IRQ_1 DT_INST_0_CDNS_TTC_IRQ_IRQ_1 #undef DT_INST_0_CDNS_TTC_IRQ_2 -#define DT_INST_0_CDNS_TTC_IRQ_2 ((DT_INST_0_CDNS_TTC_IRQ_IRQ_2 + 1) << 8) +#define DT_INST_0_CDNS_TTC_IRQ_2 DT_INST_0_CDNS_TTC_IRQ_IRQ_2 diff --git a/soc/arm/xilinx_zynqmp/irq.c b/soc/arm/xilinx_zynqmp/irq.c new file mode 100644 index 000000000000..eaeea7353d5a --- /dev/null +++ b/soc/arm/xilinx_zynqmp/irq.c @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2019 Stephanos Ioannidis + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include +#include +#include +#include + +#include + +void z_soc_irq_init(void) +{ + /* Initialise GIC-400 */ + arm_gic_init(); +} + +void z_soc_irq_enable(unsigned int irq) +{ + /* Enable interrupt */ + arm_gic_irq_enable(irq); +} + +void z_soc_irq_disable(unsigned int irq) +{ + /* Disable interrupt */ + arm_gic_irq_disable(irq); +} + +int z_soc_irq_is_enabled(unsigned int irq) +{ + return arm_gic_irq_is_enabled(irq); +} + +unsigned int z_soc_irq_get_active(void) +{ + return arm_gic_irq_get_active(); +} + +void z_soc_irq_eoi(unsigned int irq) +{ + arm_gic_irq_eoi(irq); +} + +/** + * @internal + * + * @brief Set an interrupt's priority + * + * The priority is verified if ASSERT_ON is enabled. The maximum number + * of priority levels is a little complex, as there are some hardware + * priority levels which are reserved. + * + * @return N/A + */ +void z_soc_irq_priority_set( + unsigned int irq, unsigned int prio, unsigned int flags) +{ + arm_gic_irq_set_priority(irq, prio, flags); +} From b90436db50438991d552aa6d41aa150cbf77aed7 Mon Sep 17 00:00:00 2001 From: Stephanos Ioannidis Date: Thu, 17 Oct 2019 14:54:06 +0900 Subject: [PATCH 17/18] arch: arm: Update Cortex-R port to use CMSIS-Core(R). This commit updates the Cortex-R port to use the preliminary CMSIS-Core(R) implementation added in the PR #19964. Signed-off-by: Stephanos Ioannidis --- arch/arm/core/Kconfig | 1 + arch/arm/core/cortex_r/irq_init.c | 9 +++---- include/arch/arm/cortex_r/cmsis.h | 43 ++++++++++++++++++++++++++++++ include/arch/arm/cortex_r/cpu.h | 3 --- include/arch/arm/cortex_r/sys_io.h | 1 + 5 files changed, 49 insertions(+), 8 deletions(-) create mode 100644 include/arch/arm/cortex_r/cmsis.h diff --git a/arch/arm/core/Kconfig b/arch/arm/core/Kconfig index b9b4caa3ddfd..a8fffdced7f0 100644 --- a/arch/arm/core/Kconfig +++ b/arch/arm/core/Kconfig @@ -31,6 +31,7 @@ config CPU_CORTEX_M config CPU_CORTEX_R bool select CPU_CORTEX + select HAS_CMSIS_CORE select HAS_FLASH_LOAD_OFFSET help This option signifies the use of a CPU of the Cortex-R family. diff --git a/arch/arm/core/cortex_r/irq_init.c b/arch/arm/core/cortex_r/irq_init.c index e05d335015b3..70e34c0ebf43 100644 --- a/arch/arm/core/cortex_r/irq_init.c +++ b/arch/arm/core/cortex_r/irq_init.c @@ -10,6 +10,7 @@ */ #include +#include /** * @brief Initialize interrupts @@ -24,10 +25,8 @@ void z_arm_int_lib_init(void) /* Configure hardware vectored interrupt mode.*/ #if defined(CONFIG_VIC_IRQ_VECTOR) - __asm__ volatile( - "mrc p15, #0, r0, c1, c0, #0;" - "orr r0, r0, #0x01000000;" /* [24] VE bit */ - "mcr p15, #0, r0, c1, c0, #0;" - : : : "memory"); + unsigned int sctlr = __get_SCTLR(); + sctlr |= SCTLR_VE_Msk; + __set_SCTLR(sctlr); #endif } diff --git a/include/arch/arm/cortex_r/cmsis.h b/include/arch/arm/cortex_r/cmsis.h new file mode 100644 index 000000000000..14bbd015bcc3 --- /dev/null +++ b/include/arch/arm/cortex_r/cmsis.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2019 Stephanos Ioannidis + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief CMSIS interface file + * + * This header contains the interface to the ARM CMSIS Core headers. + */ + +#ifndef ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_R_CMSIS_H_ +#define ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_R_CMSIS_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __CR_REV +#define __CR_REV 0U +#endif + +#ifndef __FPU_PRESENT +#define __FPU_PRESENT CONFIG_CPU_HAS_FPU +#endif + +#ifdef __cplusplus +} +#endif + +#if defined(CONFIG_CPU_CORTEX_R4) +#include +#elif defined(CONFIG_CPU_CORTEX_R5) +#include +#else +#error "Unknown Cortex-R device" +#endif + +#endif /* ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_R_CMSIS_H_ */ diff --git a/include/arch/arm/cortex_r/cpu.h b/include/arch/arm/cortex_r/cpu.h index c17a24e4f068..984ec9d907b0 100644 --- a/include/arch/arm/cortex_r/cpu.h +++ b/include/arch/arm/cortex_r/cpu.h @@ -31,7 +31,4 @@ #define FPEXC_EN (1 << 30) -#define __ISB() __asm__ volatile ("isb sy" : : : "memory") -#define __DMB() __asm__ volatile ("dmb sy" : : : "memory") - #endif diff --git a/include/arch/arm/cortex_r/sys_io.h b/include/arch/arm/cortex_r/sys_io.h index 197d289d3f9f..06f276e654dc 100644 --- a/include/arch/arm/cortex_r/sys_io.h +++ b/include/arch/arm/cortex_r/sys_io.h @@ -16,6 +16,7 @@ #include #include +#include #ifdef __cplusplus extern "C" { From 6ac68f519170dbe5b2bc336aeaa3bb9c7fe081ea Mon Sep 17 00:00:00 2001 From: Stephanos Ioannidis Date: Thu, 17 Oct 2019 14:54:42 +0900 Subject: [PATCH 18/18] soc: arm: xilinx_zynqmp: Use CMSIS-Core(R). This commit updates the 'xilinx_zynqmp' SoC initialisation code to use the preliminary CMSIS-Core(R) implementation added in the PR #19964. In addition, it also defines the Core IP revision value for the SoC as specified in the Zynq UltraScale+ Device Technical Reference Manual. Signed-off-by: Stephanos Ioannidis --- soc/arm/xilinx_zynqmp/soc.c | 10 +++++----- soc/arm/xilinx_zynqmp/soc.h | 6 ++---- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/soc/arm/xilinx_zynqmp/soc.c b/soc/arm/xilinx_zynqmp/soc.c index 9f069e6ed41e..20e9a2a01dae 100644 --- a/soc/arm/xilinx_zynqmp/soc.c +++ b/soc/arm/xilinx_zynqmp/soc.c @@ -9,6 +9,8 @@ #include #include +#include + /** * * @brief Perform basic hardware initialization @@ -31,9 +33,7 @@ SYS_INIT(soc_init, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); void z_platform_init(void) { - __asm__ volatile( - "mrc p15, 0, r0, c1, c0, 0;" /* SCTLR */ - "bic r0, r0, #" TOSTR(HIVECS) ";" /* Vector table at 0 */ - "mcr p15, 0, r0, c1, c0, 0;" - : : : "memory"); + unsigned int sctlr = __get_SCTLR(); + sctlr &= ~SCTLR_V_Msk; + __set_SCTLR(sctlr); } diff --git a/soc/arm/xilinx_zynqmp/soc.h b/soc/arm/xilinx_zynqmp/soc.h index 6df678412334..528a82a650d0 100644 --- a/soc/arm/xilinx_zynqmp/soc.h +++ b/soc/arm/xilinx_zynqmp/soc.h @@ -8,12 +8,10 @@ #ifndef _BOARD__H_ #define _BOARD__H_ -#include - #ifndef _ASMLANGUAGE -#include -#include +/* Define CMSIS configurations */ +#define __CR_REV 1U #endif /* !_ASMLANGUAGE */