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