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/sys/iterable_sections.h> 20 #include <zephyr/types.h> 21 #include <zephyr/toolchain.h> 22 #include <zephyr/sys/util.h> 23 24 #ifdef __cplusplus 25 extern "C" { 26 #endif 27 28 /* Default vector for the IRQ vector table */ 29 void _isr_wrapper(void); 30 31 /* Spurious interrupt handler. Throws an error if called */ 32 void z_irq_spurious(const void *unused); 33 34 /* 35 * Note the order: arg first, then ISR. This allows a table entry to be 36 * loaded arg -> r0, isr -> r3 in _isr_wrapper with one ldmia instruction, 37 * on ARM Cortex-M (Thumb2). 38 */ 39 struct _isr_table_entry { 40 const void *arg; 41 void (*isr)(const void *); 42 }; 43 44 /* The software ISR table itself, an array of these structures indexed by the 45 * irq line 46 */ 47 extern struct _isr_table_entry _sw_isr_table[]; 48 49 struct _irq_parent_entry { 50 const struct device *dev; 51 unsigned int level; 52 unsigned int irq; 53 unsigned int offset; 54 }; 55 56 /** 57 * @cond INTERNAL_HIDDEN 58 */ 59 60 /* Mapping between aggregator level to order */ 61 #define Z_STR_L2 2ND 62 #define Z_STR_L3 3RD 63 /** 64 * @brief Get the Software ISR table offset Kconfig for the given aggregator level 65 * 66 * @param l Aggregator level, must be 2 or 3 67 * 68 * @return `CONFIG_2ND_LVL_ISR_TBL_OFFSET` if second level aggregator, 69 * `CONFIG_3RD_LVL_ISR_TBL_OFFSET` if third level aggregator 70 */ 71 #define Z_SW_ISR_TBL_KCONFIG_BY_ALVL(l) CONCAT(CONFIG_, CONCAT(Z_STR_L, l), _LVL_ISR_TBL_OFFSET) 72 73 /** 74 * INTERNAL_HIDDEN @endcond 75 */ 76 77 /** 78 * @brief Get an interrupt controller node's level base ISR table offset. 79 * 80 * @param node_id node identifier of the interrupt controller 81 * 82 * @return `CONFIG_2ND_LVL_ISR_TBL_OFFSET` if node_id is a second level aggregator, 83 * `CONFIG_3RD_LVL_ISR_TBL_OFFSET` if it is a third level aggregator 84 */ 85 #define INTC_BASE_ISR_TBL_OFFSET(node_id) \ 86 Z_SW_ISR_TBL_KCONFIG_BY_ALVL(DT_INTC_GET_AGGREGATOR_LEVEL(node_id)) 87 88 /** 89 * @brief Get the SW ISR table offset for an instance of interrupt controller 90 * 91 * @param inst DT_DRV_COMPAT interrupt controller driver instance number 92 * 93 * @return Software ISR table offset of the interrupt controller 94 */ 95 #define INTC_INST_ISR_TBL_OFFSET(inst) \ 96 (INTC_BASE_ISR_TBL_OFFSET(DT_DRV_INST(inst)) + (inst * CONFIG_MAX_IRQ_PER_AGGREGATOR)) 97 98 /** 99 * @brief Get the SW ISR table offset for a child interrupt controller 100 * 101 * @details This macro is a alternative form of the `INTC_INST_ISR_TBL_OFFSET`. This is used by 102 * pseudo interrupt controller devices that are child of a main interrupt controller device. 103 * 104 * @param node_id node identifier of the child interrupt controller 105 * 106 * @return Software ISR table offset of the child 107 */ 108 #define INTC_CHILD_ISR_TBL_OFFSET(node_id) \ 109 (INTC_BASE_ISR_TBL_OFFSET(node_id) + \ 110 (DT_NODE_CHILD_IDX(node_id) * CONFIG_MAX_IRQ_PER_AGGREGATOR)) 111 112 /** 113 * @brief Register an interrupt controller with the software ISR table 114 * 115 * @param _name Name of the interrupt controller (must be unique) 116 * @param _dev Pointer to the interrupt controller device instance 117 * @param _irq Interrupt controller IRQ number 118 * @param _offset Software ISR table offset of the interrupt controller 119 * @param _level Interrupt controller aggregator level 120 */ 121 #define IRQ_PARENT_ENTRY_DEFINE(_name, _dev, _irq, _offset, _level) \ 122 static const STRUCT_SECTION_ITERABLE_ALTERNATE(intc_table, _irq_parent_entry, _name) = { \ 123 .dev = _dev, \ 124 .level = _level, \ 125 .irq = _irq, \ 126 .offset = _offset, \ 127 } 128 129 /* 130 * Data structure created in a special binary .intlist section for each 131 * configured interrupt. gen_irq_tables.py pulls this out of the binary and 132 * uses it to create the IRQ vector table and the _sw_isr_table. 133 * 134 * More discussion in include/linker/intlist.ld 135 * 136 * This is a version used when CONFIG_ISR_TABLES_LOCAL_DECLARATION is disabled. 137 * See _isr_list_sname used otherwise. 138 */ 139 struct _isr_list { 140 /** IRQ line number */ 141 int32_t irq; 142 /** Flags for this IRQ, see ISR_FLAG_* definitions */ 143 int32_t flags; 144 /** ISR to call */ 145 void *func; 146 /** Parameter for non-direct IRQs */ 147 const void *param; 148 }; 149 150 /* 151 * Data structure created in a special binary .intlist section for each 152 * configured interrupt. gen_isr_tables.py pulls this out of the binary and 153 * uses it to create linker script chunks that would place interrupt table entries 154 * in the right place in the memory. 155 * 156 * This is a version used when CONFIG_ISR_TABLES_LOCAL_DECLARATION is enabled. 157 * See _isr_list used otherwise. 158 */ 159 struct _isr_list_sname { 160 /** IRQ line number */ 161 int32_t irq; 162 /** Flags for this IRQ, see ISR_FLAG_* definitions */ 163 int32_t flags; 164 /** The section name */ 165 const char sname[]; 166 }; 167 168 #ifdef CONFIG_SHARED_INTERRUPTS 169 struct z_shared_isr_table_entry { 170 struct _isr_table_entry clients[CONFIG_SHARED_IRQ_MAX_NUM_CLIENTS]; 171 size_t client_num; 172 }; 173 174 void z_shared_isr(const void *data); 175 176 extern struct z_shared_isr_table_entry z_shared_sw_isr_table[]; 177 #endif /* CONFIG_SHARED_INTERRUPTS */ 178 179 /** This interrupt gets put directly in the vector table */ 180 #define ISR_FLAG_DIRECT BIT(0) 181 182 #define _MK_ISR_NAME(x, y) __MK_ISR_NAME(x, y) 183 #define __MK_ISR_NAME(x, y) __isr_ ## x ## _irq_ ## y 184 185 186 #if defined(CONFIG_ISR_TABLES_LOCAL_DECLARATION) 187 188 #define _MK_ISR_ELEMENT_NAME(func, id) __MK_ISR_ELEMENT_NAME(func, id) 189 #define __MK_ISR_ELEMENT_NAME(func, id) __isr_table_entry_ ## func ## _irq_ ## id 190 191 #define _MK_IRQ_ELEMENT_NAME(func, id) __MK_ISR_ELEMENT_NAME(func, id) 192 #define __MK_IRQ_ELEMENT_NAME(func, id) __irq_table_entry_ ## func ## _irq_ ## id 193 194 #define _MK_ISR_SECTION_NAME(prefix, file, counter) \ 195 "." Z_STRINGIFY(prefix)"."file"." Z_STRINGIFY(counter) 196 197 #define _MK_ISR_ELEMENT_SECTION(counter) _MK_ISR_SECTION_NAME(irq, __FILE__, counter) 198 #define _MK_IRQ_ELEMENT_SECTION(counter) _MK_ISR_SECTION_NAME(isr, __FILE__, counter) 199 200 /* Separated macro to create ISR table entry only. 201 * Used by Z_ISR_DECLARE and ISR tables generation script. 202 */ 203 #define _Z_ISR_TABLE_ENTRY(irq, func, param, sect) \ 204 static Z_DECL_ALIGN(struct _isr_table_entry) \ 205 __attribute__((section(sect))) \ 206 __used _MK_ISR_ELEMENT_NAME(func, __COUNTER__) = { \ 207 .arg = (const void *)(param), \ 208 .isr = (void (*)(const void *))(void *)(func) \ 209 } 210 211 #define Z_ISR_DECLARE_C(irq, flags, func, param, counter) \ 212 _Z_ISR_DECLARE_C(irq, flags, func, param, counter) 213 214 #define _Z_ISR_DECLARE_C(irq, flags, func, param, counter) \ 215 _Z_ISR_TABLE_ENTRY(irq, func, param, _MK_ISR_ELEMENT_SECTION(counter)); \ 216 static struct _isr_list_sname Z_GENERIC_SECTION(.intList) \ 217 __used _MK_ISR_NAME(func, counter) = \ 218 {irq, flags, _MK_ISR_ELEMENT_SECTION(counter)} 219 220 /* Create an entry for _isr_table to be then placed by the linker. 221 * An instance of struct _isr_list which gets put in the .intList 222 * section is created with the name of the section where _isr_table entry is placed to be then 223 * used by isr generation script to create linker script chunk. 224 */ 225 #define Z_ISR_DECLARE(irq, flags, func, param) \ 226 BUILD_ASSERT(((flags) & ISR_FLAG_DIRECT) == 0, "Use Z_ISR_DECLARE_DIRECT macro"); \ 227 Z_ISR_DECLARE_C(irq, flags, func, param, __COUNTER__) 228 229 230 /* Separated macro to create ISR Direct table entry only. 231 * Used by Z_ISR_DECLARE_DIRECT and ISR tables generation script. 232 */ 233 #define _Z_ISR_DIRECT_TABLE_ENTRY(irq, func, sect) \ 234 COND_CODE_1(CONFIG_IRQ_VECTOR_TABLE_JUMP_BY_ADDRESS, ( \ 235 static Z_DECL_ALIGN(uintptr_t) \ 236 __attribute__((section(sect))) \ 237 __used _MK_IRQ_ELEMENT_NAME(func, __COUNTER__) = ((uintptr_t)(func)); \ 238 ), ( \ 239 static void __attribute__((section(sect))) __attribute__((naked)) \ 240 __used _MK_IRQ_ELEMENT_NAME(func, __COUNTER__)(void) { \ 241 __asm(ARCH_IRQ_VECTOR_JUMP_CODE(func)); \ 242 } \ 243 )) 244 245 #define Z_ISR_DECLARE_DIRECT_C(irq, flags, func, counter) \ 246 _Z_ISR_DECLARE_DIRECT_C(irq, flags, func, counter) 247 248 #define _Z_ISR_DECLARE_DIRECT_C(irq, flags, func, counter) \ 249 _Z_ISR_DIRECT_TABLE_ENTRY(irq, func, _MK_IRQ_ELEMENT_SECTION(counter)); \ 250 static struct _isr_list_sname Z_GENERIC_SECTION(.intList) \ 251 __used _MK_ISR_NAME(func, counter) = { \ 252 irq, \ 253 ISR_FLAG_DIRECT | (flags), \ 254 _MK_IRQ_ELEMENT_SECTION(counter)} 255 256 /* Create an entry to irq table and place it in specific section which name is then placed 257 * in an instance of struct _isr_list to be then used by the isr generation script to create 258 * the linker script chunks. 259 */ 260 #define Z_ISR_DECLARE_DIRECT(irq, flags, func) \ 261 BUILD_ASSERT(IS_ENABLED(CONFIG_IRQ_VECTOR_TABLE_JUMP_BY_ADDRESS) || \ 262 IS_ENABLED(CONFIG_IRQ_VECTOR_TABLE_JUMP_BY_CODE), \ 263 "CONFIG_IRQ_VECTOR_TABLE_JUMP_BY_{ADDRESS,CODE} not set"); \ 264 Z_ISR_DECLARE_DIRECT_C(irq, flags, func, __COUNTER__) 265 266 267 #else /* defined(CONFIG_ISR_TABLES_LOCAL_DECLARATION) */ 268 269 /* Create an instance of struct _isr_list which gets put in the .intList 270 * section. This gets consumed by gen_isr_tables.py which creates the vector 271 * and/or SW ISR tables. 272 */ 273 #define Z_ISR_DECLARE(irq, flags, func, param) \ 274 static Z_DECL_ALIGN(struct _isr_list) Z_GENERIC_SECTION(.intList) \ 275 __used _MK_ISR_NAME(func, __COUNTER__) = \ 276 {irq, flags, (void *)&func, (const void *)param} 277 278 /* The version of the Z_ISR_DECLARE that should be used for direct ISR declaration. 279 * It is here for the API match the version with CONFIG_ISR_TABLES_LOCAL_DECLARATION enabled. 280 */ 281 #define Z_ISR_DECLARE_DIRECT(irq, flags, func) \ 282 Z_ISR_DECLARE(irq, ISR_FLAG_DIRECT | (flags), func, NULL) 283 284 #endif 285 286 #define IRQ_TABLE_SIZE (CONFIG_NUM_IRQS - CONFIG_GEN_IRQ_START_VECTOR) 287 288 #ifdef CONFIG_DYNAMIC_INTERRUPTS 289 void z_isr_install(unsigned int irq, void (*routine)(const void *), 290 const void *param); 291 292 #ifdef CONFIG_SHARED_INTERRUPTS 293 int z_isr_uninstall(unsigned int irq, void (*routine)(const void *), 294 const void *param); 295 #endif /* CONFIG_SHARED_INTERRUPTS */ 296 #endif 297 298 #ifdef __cplusplus 299 } 300 #endif 301 302 #endif /* _ASMLANGUAGE */ 303 304 #endif /* ZEPHYR_INCLUDE_SW_ISR_TABLE_H_ */ 305