1 /*
2  * Copyright (c) 2014, Wind River Systems, Inc.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /**
8  * @file
9  * @brief Software-managed ISR table
10  *
11  * Data types for a software-managed ISR table, with a parameter per-ISR.
12  */
13 
14 #ifndef ZEPHYR_INCLUDE_SW_ISR_TABLE_H_
15 #define ZEPHYR_INCLUDE_SW_ISR_TABLE_H_
16 
17 #if !defined(_ASMLANGUAGE)
18 #include <zephyr/device.h>
19 #include <zephyr/types.h>
20 #include <zephyr/toolchain.h>
21 #include <zephyr/sys/util.h>
22 
23 #ifdef __cplusplus
24 extern "C" {
25 #endif
26 
27 /* Default vector for the IRQ vector table */
28 void _isr_wrapper(void);
29 
30 /* Spurious interrupt handler. Throws an error if called */
31 void z_irq_spurious(const void *unused);
32 
33 /*
34  * Note the order: arg first, then ISR. This allows a table entry to be
35  * loaded arg -> r0, isr -> r3 in _isr_wrapper with one ldmia instruction,
36  * on ARM Cortex-M (Thumb2).
37  */
38 struct _isr_table_entry {
39 	const void *arg;
40 	void (*isr)(const void *);
41 };
42 
43 /* The software ISR table itself, an array of these structures indexed by the
44  * irq line
45  */
46 extern struct _isr_table_entry _sw_isr_table[];
47 
48 struct _irq_parent_entry {
49 	const struct device *dev;
50 	unsigned int irq;
51 	unsigned int offset;
52 };
53 
54 /*
55  * Data structure created in a special binary .intlist section for each
56  * configured interrupt. gen_irq_tables.py pulls this out of the binary and
57  * uses it to create the IRQ vector table and the _sw_isr_table.
58  *
59  * More discussion in include/linker/intlist.ld
60  *
61  * This is a version used when CONFIG_ISR_TABLES_LOCAL_DECLARATION is disabled.
62  * See _isr_list_sname used otherwise.
63  */
64 struct _isr_list {
65 	/** IRQ line number */
66 	int32_t irq;
67 	/** Flags for this IRQ, see ISR_FLAG_* definitions */
68 	int32_t flags;
69 	/** ISR to call */
70 	void *func;
71 	/** Parameter for non-direct IRQs */
72 	const void *param;
73 };
74 
75 /*
76  * Data structure created in a special binary .intlist section for each
77  * configured interrupt. gen_isr_tables.py pulls this out of the binary and
78  * uses it to create linker script chunks that would place interrupt table entries
79  * in the right place in the memory.
80  *
81  * This is a version used when CONFIG_ISR_TABLES_LOCAL_DECLARATION is enabled.
82  * See _isr_list used otherwise.
83  */
84 struct _isr_list_sname {
85 	/** IRQ line number */
86 	int32_t irq;
87 	/** Flags for this IRQ, see ISR_FLAG_* definitions */
88 	int32_t flags;
89 	/** The section name */
90 	const char sname[];
91 };
92 
93 #ifdef CONFIG_SHARED_INTERRUPTS
94 struct z_shared_isr_table_entry {
95 	struct _isr_table_entry clients[CONFIG_SHARED_IRQ_MAX_NUM_CLIENTS];
96 	size_t client_num;
97 };
98 
99 void z_shared_isr(const void *data);
100 
101 extern struct z_shared_isr_table_entry z_shared_sw_isr_table[];
102 #endif /* CONFIG_SHARED_INTERRUPTS */
103 
104 /** This interrupt gets put directly in the vector table */
105 #define ISR_FLAG_DIRECT BIT(0)
106 
107 #define _MK_ISR_NAME(x, y) __MK_ISR_NAME(x, y)
108 #define __MK_ISR_NAME(x, y) __isr_ ## x ## _irq_ ## y
109 
110 
111 #if IS_ENABLED(CONFIG_ISR_TABLES_LOCAL_DECLARATION)
112 
113 #define _MK_ISR_ELEMENT_NAME(func, id) __MK_ISR_ELEMENT_NAME(func, id)
114 #define __MK_ISR_ELEMENT_NAME(func, id) __isr_table_entry_ ## func ## _irq_ ## id
115 
116 #define _MK_IRQ_ELEMENT_NAME(func, id) __MK_ISR_ELEMENT_NAME(func, id)
117 #define __MK_IRQ_ELEMENT_NAME(func, id) __irq_table_entry_ ## func ## _irq_ ## id
118 
119 #define _MK_ISR_SECTION_NAME(prefix, file, counter) \
120 	"." Z_STRINGIFY(prefix)"."file"." Z_STRINGIFY(counter)
121 
122 #define _MK_ISR_ELEMENT_SECTION(counter) _MK_ISR_SECTION_NAME(irq, __FILE__, counter)
123 #define _MK_IRQ_ELEMENT_SECTION(counter) _MK_ISR_SECTION_NAME(isr, __FILE__, counter)
124 
125 /* Separated macro to create ISR table entry only.
126  * Used by Z_ISR_DECLARE and ISR tables generation script.
127  */
128 #define _Z_ISR_TABLE_ENTRY(irq, func, param, sect) \
129 	static Z_DECL_ALIGN(struct _isr_table_entry)                                      \
130 		__attribute__((section(sect)))                                            \
131 		__used _MK_ISR_ELEMENT_NAME(func, __COUNTER__) = {                        \
132 			.arg = (const void *)(param),                                     \
133 			.isr = (void (*)(const void *))(void *)(func)                     \
134 	}
135 
136 #define Z_ISR_DECLARE_C(irq, flags, func, param, counter) \
137 	_Z_ISR_DECLARE_C(irq, flags, func, param, counter)
138 
139 #define _Z_ISR_DECLARE_C(irq, flags, func, param, counter)                                \
140 	_Z_ISR_TABLE_ENTRY(irq, func, param, _MK_ISR_ELEMENT_SECTION(counter));           \
141 	static struct _isr_list_sname Z_GENERIC_SECTION(.intList)                         \
142 		__used _MK_ISR_NAME(func, counter) =                                      \
143 		{irq, flags, _MK_ISR_ELEMENT_SECTION(counter)}
144 
145 /* Create an entry for _isr_table to be then placed by the linker.
146  * An instance of struct _isr_list which gets put in the .intList
147  * section is created with the name of the section where _isr_table entry is placed to be then
148  * used by isr generation script to create linker script chunk.
149  */
150 #define Z_ISR_DECLARE(irq, flags, func, param)                                            \
151 	BUILD_ASSERT(((flags) & ISR_FLAG_DIRECT) == 0, "Use Z_ISR_DECLARE_DIRECT macro"); \
152 	Z_ISR_DECLARE_C(irq, flags, func, param, __COUNTER__)
153 
154 
155 /* Separated macro to create ISR Direct table entry only.
156  * Used by Z_ISR_DECLARE_DIRECT and ISR tables generation script.
157  */
158 #define _Z_ISR_DIRECT_TABLE_ENTRY(irq, func, sect)                                                 \
159 	COND_CODE_1(CONFIG_IRQ_VECTOR_TABLE_JUMP_BY_ADDRESS, (                                     \
160 			static Z_DECL_ALIGN(uintptr_t)                                             \
161 			__attribute__((section(sect)))                                             \
162 			__used _MK_IRQ_ELEMENT_NAME(func, __COUNTER__) = ((uintptr_t)(func));      \
163 		), (                                                                               \
164 			static void __attribute__((section(sect))) __attribute__((naked))          \
165 			__used _MK_IRQ_ELEMENT_NAME(func, __COUNTER__)(void) {                     \
166 				__asm(ARCH_IRQ_VECTOR_JUMP_CODE(func));                            \
167 			}                                                                          \
168 		))
169 
170 #define Z_ISR_DECLARE_DIRECT_C(irq, flags, func, counter) \
171 	_Z_ISR_DECLARE_DIRECT_C(irq, flags, func, counter)
172 
173 #define _Z_ISR_DECLARE_DIRECT_C(irq, flags, func, counter)                                         \
174 	_Z_ISR_DIRECT_TABLE_ENTRY(irq, func, _MK_IRQ_ELEMENT_SECTION(counter));                    \
175 	static struct _isr_list_sname Z_GENERIC_SECTION(.intList)                                  \
176 		__used _MK_ISR_NAME(func, counter) = {                                             \
177 			irq,                                                                       \
178 			ISR_FLAG_DIRECT | (flags),                                                 \
179 			_MK_IRQ_ELEMENT_SECTION(counter)}
180 
181 /* Create an entry to irq table and place it in specific section which name is then placed
182  * in an instance of struct _isr_list to be then used by the isr generation script to create
183  * the linker script chunks.
184  */
185 #define Z_ISR_DECLARE_DIRECT(irq, flags, func)                                                     \
186 	BUILD_ASSERT(IS_ENABLED(CONFIG_IRQ_VECTOR_TABLE_JUMP_BY_ADDRESS) ||                        \
187 		IS_ENABLED(CONFIG_IRQ_VECTOR_TABLE_JUMP_BY_CODE),                                  \
188 		"CONFIG_IRQ_VECTOR_TABLE_JUMP_BY_{ADDRESS,CODE} not set");                         \
189 	Z_ISR_DECLARE_DIRECT_C(irq, flags, func, __COUNTER__)
190 
191 
192 #else /* IS_ENABLED(CONFIG_ISR_TABLES_LOCAL_DECLARATION) */
193 
194 /* Create an instance of struct _isr_list which gets put in the .intList
195  * section. This gets consumed by gen_isr_tables.py which creates the vector
196  * and/or SW ISR tables.
197  */
198 #define Z_ISR_DECLARE(irq, flags, func, param) \
199 	static Z_DECL_ALIGN(struct _isr_list) Z_GENERIC_SECTION(.intList) \
200 		__used _MK_ISR_NAME(func, __COUNTER__) = \
201 			{irq, flags, (void *)&func, (const void *)param}
202 
203 /* The version of the Z_ISR_DECLARE that should be used for direct ISR declaration.
204  * It is here for the API match the version with CONFIG_ISR_TABLES_LOCAL_DECLARATION enabled.
205  */
206 #define Z_ISR_DECLARE_DIRECT(irq, flags, func) \
207 	Z_ISR_DECLARE(irq, ISR_FLAG_DIRECT | (flags), func, NULL)
208 
209 #endif
210 
211 #define IRQ_TABLE_SIZE (CONFIG_NUM_IRQS - CONFIG_GEN_IRQ_START_VECTOR)
212 
213 #ifdef CONFIG_DYNAMIC_INTERRUPTS
214 void z_isr_install(unsigned int irq, void (*routine)(const void *),
215 		   const void *param);
216 
217 #ifdef CONFIG_SHARED_INTERRUPTS
218 int z_isr_uninstall(unsigned int irq, void (*routine)(const void *),
219 		    const void *param);
220 #endif /* CONFIG_SHARED_INTERRUPTS */
221 #endif
222 
223 #ifdef __cplusplus
224 }
225 #endif
226 
227 #endif /* _ASMLANGUAGE */
228 
229 #endif /* ZEPHYR_INCLUDE_SW_ISR_TABLE_H_ */
230