1 /*
2  * Copyright (c) 2013-2014 Wind River Systems, Inc.
3  * Copyright (c) 2020 Stephanos Ioannidis <root@stephanos.io>
4  * Copyright (c) 2023 Arm Limited
5  *
6  * SPDX-License-Identifier: Apache-2.0
7  */
8 
9 /**
10  * @file
11  * @brief ARM Cortex-M wrapper for ISRs with parameter
12  *
13  * Wrapper installed in vector table for handling dynamic interrupts that accept
14  * a parameter.
15  */
16 #include <zephyr/kernel.h>
17 #include <zephyr/irq.h>
18 #include <zephyr/pm/pm.h>
19 #include <cmsis_core.h>
20 
21 /**
22  *
23  * @brief Wrapper around ISRs when inserted in software ISR table
24  *
25  * When inserted in the vector table, _isr_wrapper() demuxes the ISR table
26  * using the running interrupt number as the index, and invokes the registered
27  * ISR with its corresponding argument. When returning from the ISR, it
28  * determines if a context switch needs to happen (see documentation for
29  * z_arm_pendsv()) and pends the PendSV exception if so: the latter will
30  * perform the context switch itself.
31  *
32  */
_isr_wrapper(void)33 void _isr_wrapper(void)
34 {
35 #ifdef CONFIG_TRACING_ISR
36 	sys_trace_isr_enter();
37 #endif /* CONFIG_TRACING_ISR */
38 
39 #ifdef CONFIG_PM
40 	/*
41 	 * All interrupts are disabled when handling idle wakeup.  For tickless
42 	 * idle, this ensures that the calculation and programming of the
43 	 * device for the next timer deadline is not interrupted.  For
44 	 * non-tickless idle, this ensures that the clearing of the kernel idle
45 	 * state is not interrupted.  In each case, pm_system_resume
46 	 * is called with interrupts disabled.
47 	 */
48 
49 	/*
50 	 * Disable interrupts to prevent nesting while exiting idle state. This
51 	 * is only necessary for the Cortex-M because it is the only ARM
52 	 * architecture variant that automatically enables interrupts when
53 	 * entering an ISR.
54 	 */
55 	__disable_irq();
56 
57 	/* is this a wakeup from idle ? */
58 	/* requested idle duration, in ticks */
59 	if (_kernel.idle != 0) {
60 		/* clear kernel idle state */
61 		_kernel.idle = 0;
62 		pm_system_resume();
63 	}
64 	/* re-enable interrupts */
65 	__enable_irq();
66 #endif /* CONFIG_PM */
67 
68 #if defined(CONFIG_ARM_CUSTOM_INTERRUPT_CONTROLLER)
69 	int32_t irq_number = z_soc_irq_get_active();
70 #else
71 	/* _sw_isr_table does not map the expections, only the interrupts. */
72 	int32_t irq_number = __get_IPSR();
73 #endif
74 	irq_number -= 16;
75 
76 	struct _isr_table_entry *entry = &_sw_isr_table[irq_number];
77 	(entry->isr)(entry->arg);
78 
79 #if defined(CONFIG_ARM_CUSTOM_INTERRUPT_CONTROLLER)
80 	z_soc_irq_eoi(irq_number);
81 #endif
82 
83 #ifdef CONFIG_TRACING_ISR
84 	sys_trace_isr_exit();
85 #endif /* CONFIG_TRACING_ISR */
86 
87 	z_arm_exc_exit();
88 }
89