| /* |
| * Copyright (c) 2013-2014 Wind River Systems, Inc. |
| * Copyright (c) 2020 Stephanos Ioannidis <root@stephanos.io> |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| /** |
| * @file |
| * @brief ARM Cortex-M wrapper for ISRs with parameter |
| * |
| * Wrapper installed in vector table for handling dynamic interrupts that accept |
| * a parameter. |
| */ |
| /* |
| * Tell armclang that stack alignment are ensured. |
| */ |
| .eabi_attribute Tag_ABI_align_preserved, 1 |
| |
| #include <zephyr/toolchain.h> |
| #include <zephyr/linker/sections.h> |
| #include <offsets_short.h> |
| #include <zephyr/arch/cpu.h> |
| #include <zephyr/sw_isr_table.h> |
| |
| |
| _ASM_FILE_PROLOGUE |
| |
| GDATA(_sw_isr_table) |
| |
| GTEXT(_isr_wrapper) |
| GTEXT(z_arm_int_exit) |
| |
| /** |
| * |
| * @brief Wrapper around ISRs when inserted in software ISR table |
| * |
| * When inserted in the vector table, _isr_wrapper() demuxes the ISR table |
| * using the running interrupt number as the index, and invokes the registered |
| * ISR with its corresponding argument. When returning from the ISR, it |
| * determines if a context switch needs to happen (see documentation for |
| * z_arm_pendsv()) and pends the PendSV exception if so: the latter will |
| * perform the context switch itself. |
| * |
| */ |
| SECTION_FUNC(TEXT, _isr_wrapper) |
| |
| push {r0,lr} /* r0, lr are now the first items on the stack */ |
| |
| #ifdef CONFIG_TRACING_ISR |
| bl sys_trace_isr_enter |
| #endif |
| |
| #ifdef CONFIG_PM |
| /* |
| * All interrupts are disabled when handling idle wakeup. For tickless |
| * idle, this ensures that the calculation and programming of the |
| * device for the next timer deadline is not interrupted. For |
| * non-tickless idle, this ensures that the clearing of the kernel idle |
| * state is not interrupted. In each case, z_pm_save_idle_exit |
| * is called with interrupts disabled. |
| */ |
| |
| /* |
| * Disable interrupts to prevent nesting while exiting idle state. This |
| * is only necessary for the Cortex-M because it is the only ARM |
| * architecture variant that automatically enables interrupts when |
| * entering an ISR. |
| */ |
| cpsid i /* PRIMASK = 1 */ |
| |
| /* is this a wakeup from idle ? */ |
| ldr r2, =_kernel |
| /* requested idle duration, in ticks */ |
| ldr r0, [r2, #_kernel_offset_to_idle] |
| cmp r0, #0 |
| |
| #if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE) |
| beq _idle_state_cleared |
| movs.n r1, #0 |
| /* clear kernel idle state */ |
| str r1, [r2, #_kernel_offset_to_idle] |
| bl z_pm_save_idle_exit |
| _idle_state_cleared: |
| |
| #elif defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) |
| ittt ne |
| movne r1, #0 |
| /* clear kernel idle state */ |
| strne r1, [r2, #_kernel_offset_to_idle] |
| blne z_pm_save_idle_exit |
| #else |
| #error Unknown ARM architecture |
| #endif /* CONFIG_ARMV6_M_ARMV8_M_BASELINE */ |
| |
| cpsie i /* re-enable interrupts (PRIMASK = 0) */ |
| |
| #endif /* CONFIG_PM */ |
| |
| mrs r0, IPSR /* get exception number */ |
| #if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE) |
| ldr r1, =16 |
| subs r0, r1 /* get IRQ number */ |
| lsls r0, #3 /* table is 8-byte wide */ |
| #elif defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) |
| sub r0, r0, #16 /* get IRQ number */ |
| lsl r0, r0, #3 /* table is 8-byte wide */ |
| #else |
| #error Unknown ARM architecture |
| #endif /* CONFIG_ARMV6_M_ARMV8_M_BASELINE */ |
| |
| ldr r1, =_sw_isr_table |
| add r1, r1, r0 /* table entry: ISRs must have their MSB set to stay |
| * in thumb mode */ |
| |
| ldm r1!,{r0,r3} /* arg in r0, ISR in r3 */ |
| blx r3 /* call ISR */ |
| |
| #ifdef CONFIG_TRACING_ISR |
| bl sys_trace_isr_exit |
| #endif |
| |
| #if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE) |
| pop {r0, r3} |
| mov lr, r3 |
| #elif defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) |
| pop {r0, lr} |
| #else |
| #error Unknown ARM architecture |
| #endif /* CONFIG_ARMV6_M_ARMV8_M_BASELINE */ |
| |
| /* 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() */ |
| ldr r1, =z_arm_int_exit |
| bx r1 |