1#!/usr/bin/env python3 2# 3# Copyright (c) 2017 Intel Corporation 4# Copyright (c) 2018 Foundries.io 5# Copyright (c) 2023 Nordic Semiconductor NA 6# 7# SPDX-License-Identifier: Apache-2.0 8# 9 10import struct 11 12class gen_isr_parser: 13 source_header = """ 14/* AUTO-GENERATED by gen_isr_tables.py, do not edit! */ 15 16#include <zephyr/toolchain.h> 17#include <zephyr/linker/sections.h> 18#include <zephyr/sw_isr_table.h> 19#include <zephyr/arch/cpu.h> 20 21typedef void (* ISR)(const void *); 22""" 23 24 source_assembly_header = """ 25#ifndef ARCH_IRQ_VECTOR_JUMP_CODE 26#error "ARCH_IRQ_VECTOR_JUMP_CODE not defined" 27#endif 28""" 29 30 def __init__(self, intlist_data, config, log): 31 """Initialize the parser. 32 33 The function prepares parser to work. 34 Parameters: 35 - intlist_data: The binnary data from intlist section 36 - config: The configuration object 37 - log: The logging object, has to have error and debug methods 38 """ 39 self.__config = config 40 self.__log = log 41 intlist = self.__read_intlist(intlist_data) 42 self.__vt, self.__swt, self.__nv = self.__parse_intlist(intlist) 43 44 def __read_intlist(self, intlist_data): 45 """read a binary file containing the contents of the kernel's .intList 46 section. This is an instance of a header created by 47 include/zephyr/linker/intlist.ld: 48 49 struct { 50 uint32_t num_vectors; <- typically CONFIG_NUM_IRQS 51 struct _isr_list isrs[]; <- Usually of smaller size than num_vectors 52 } 53 54 Followed by instances of struct _isr_list created by IRQ_CONNECT() 55 calls: 56 57 struct _isr_list { 58 /** IRQ line number */ 59 int32_t irq; 60 /** Flags for this IRQ, see ISR_FLAG_* definitions */ 61 int32_t flags; 62 /** ISR to call */ 63 void *func; 64 /** Parameter for non-direct IRQs */ 65 const void *param; 66 }; 67 """ 68 intlist = {} 69 prefix = self.__config.endian_prefix() 70 71 # Extract header and the rest of the data 72 intlist_header_fmt = prefix + "II" 73 header_sz = struct.calcsize(intlist_header_fmt) 74 header_raw = struct.unpack_from(intlist_header_fmt, intlist_data, 0) 75 self.__log.debug(str(header_raw)) 76 77 intlist["num_vectors"] = header_raw[0] 78 intlist["offset"] = header_raw[1] 79 intdata = intlist_data[header_sz:] 80 81 # Extract information about interrupts 82 if self.__config.check_64b(): 83 intlist_entry_fmt = prefix + "iiQQ" 84 else: 85 intlist_entry_fmt = prefix + "iiII" 86 87 intlist["interrupts"] = [i for i in 88 struct.iter_unpack(intlist_entry_fmt, intdata)] 89 90 self.__log.debug("Configured interrupt routing") 91 self.__log.debug("handler irq flags param") 92 self.__log.debug("--------------------------") 93 94 for irq in intlist["interrupts"]: 95 self.__log.debug("{0:<10} {1:<3} {2:<3} {3}".format( 96 hex(irq[2]), irq[0], irq[1], hex(irq[3]))) 97 98 return intlist 99 100 def __parse_intlist(self, intlist): 101 """All the intlist data are parsed into swt and vt arrays. 102 103 The vt array is prepared for hardware interrupt table. 104 Every entry in the selected position would contain None or the name of the function pointer 105 (address or string). 106 107 The swt is a little more complex. At every position it would contain an array of parameter and 108 function pointer pairs. If CONFIG_SHARED_INTERRUPTS is enabled there may be more than 1 entry. 109 If empty array is placed on selected position - it means that the application does not implement 110 this interrupt. 111 112 Parameters: 113 - intlist: The preprocessed list of intlist section content (see read_intlist) 114 115 Return: 116 vt, swt - parsed vt and swt arrays (see function description above) 117 """ 118 nvec = intlist["num_vectors"] 119 offset = intlist["offset"] 120 121 if nvec > pow(2, 15): 122 raise ValueError('nvec is too large, check endianness.') 123 124 self.__log.debug('offset is ' + str(offset)) 125 self.__log.debug('num_vectors is ' + str(nvec)) 126 127 # Set default entries in both tables 128 if not(self.__config.args.sw_isr_table or self.__config.args.vector_table): 129 self.__log.error("one or both of -s or -V needs to be specified on command line") 130 if self.__config.args.vector_table: 131 vt = [None for i in range(nvec)] 132 else: 133 vt = None 134 if self.__config.args.sw_isr_table: 135 swt = [[] for i in range(nvec)] 136 else: 137 swt = None 138 139 # Process intlist and write to the tables created 140 for irq, flags, func, param in intlist["interrupts"]: 141 if self.__config.test_isr_direct(flags): 142 if not vt: 143 self.__log.error("Direct Interrupt %d declared with parameter 0x%x " 144 "but no vector table in use" 145 % (irq, param)) 146 if param != 0: 147 self.__log.error("Direct irq %d declared, but has non-NULL parameter" 148 % irq) 149 if not 0 <= irq - offset < len(vt): 150 self.__log.error("IRQ %d (offset=%d) exceeds the maximum of %d" 151 % (irq - offset, offset, len(vt) - 1)) 152 vt[irq - offset] = func 153 else: 154 # Regular interrupt 155 if not swt: 156 self.__log.error("Regular Interrupt %d declared with parameter 0x%x " 157 "but no SW ISR_TABLE in use" 158 % (irq, param)) 159 160 table_index = self.__config.get_swt_table_index(offset, irq) 161 162 if not 0 <= table_index < len(swt): 163 self.__log.error("IRQ %d (offset=%d) exceeds the maximum of %d" % 164 (table_index, offset, len(swt) - 1)) 165 if self.__config.check_shared_interrupts(): 166 lst = swt[table_index] 167 if (param, func) in lst: 168 self.__log.error("Attempting to register the same ISR/arg pair twice.") 169 if len(lst) >= self.__config.get_sym("CONFIG_SHARED_IRQ_MAX_NUM_CLIENTS"): 170 self.__log.error(f"Reached shared interrupt client limit. Maybe increase" 171 + f" CONFIG_SHARED_IRQ_MAX_NUM_CLIENTS?") 172 else: 173 if len(swt[table_index]) > 0: 174 self.__log.error(f"multiple registrations at table_index {table_index} for irq {irq} (0x{irq:x})" 175 + f"\nExisting handler 0x{swt[table_index][0][1]:x}, new handler 0x{func:x}" 176 + "\nHas IRQ_CONNECT or IRQ_DIRECT_CONNECT accidentally been invoked on the same irq multiple times?" 177 ) 178 swt[table_index].append((param, func)) 179 180 return vt, swt, nvec 181 182 def __write_code_irq_vector_table(self, fp): 183 fp.write(self.source_assembly_header) 184 185 fp.write("void __irq_vector_table __attribute__((naked)) _irq_vector_table(void) {\n") 186 for i in range(self.__nv): 187 func = self.__vt[i] 188 189 if func is None: 190 func = self.__config.vt_default_handler 191 192 if isinstance(func, int): 193 func_as_string = self.__config.get_sym_from_addr(func) 194 else: 195 func_as_string = func 196 197 fp.write("\t__asm(ARCH_IRQ_VECTOR_JUMP_CODE({}));\n".format(func_as_string)) 198 fp.write("}\n") 199 200 def __write_address_irq_vector_table(self, fp): 201 fp.write("uintptr_t __irq_vector_table _irq_vector_table[%d] = {\n" % self.__nv) 202 for i in range(self.__nv): 203 func = self.__vt[i] 204 205 if func is None: 206 func = self.__config.vt_default_handler 207 208 if isinstance(func, int): 209 fp.write("\t{},\n".format(func)) 210 else: 211 fp.write("\t((uintptr_t)&{}),\n".format(func)) 212 213 fp.write("};\n") 214 215 def __write_shared_table(self, fp): 216 fp.write("struct z_shared_isr_table_entry __shared_sw_isr_table" 217 " z_shared_sw_isr_table[%d] = {\n" % self.__nv) 218 219 for i in range(self.__nv): 220 if self.__swt[i] is None: 221 client_num = 0 222 client_list = None 223 else: 224 client_num = len(self.__swt[i]) 225 client_list = self.__swt[i] 226 227 if client_num <= 1: 228 fp.write("\t{ },\n") 229 else: 230 fp.write(f"\t{{ .client_num = {client_num}, .clients = {{ ") 231 for j in range(0, client_num): 232 routine = client_list[j][1] 233 arg = client_list[j][0] 234 235 fp.write(f"{{ .isr = (ISR){ hex(routine) if isinstance(routine, int) else routine }, " 236 f".arg = (const void *){hex(arg)} }},") 237 238 fp.write(" },\n},\n") 239 240 fp.write("};\n") 241 242 def write_source(self, fp): 243 fp.write(self.source_header) 244 245 if self.__config.check_shared_interrupts(): 246 self.__write_shared_table(fp) 247 248 if self.__vt: 249 if self.__config.check_sym("CONFIG_IRQ_VECTOR_TABLE_JUMP_BY_ADDRESS"): 250 self.__write_address_irq_vector_table(fp) 251 elif self.__config.check_sym("CONFIG_IRQ_VECTOR_TABLE_JUMP_BY_CODE"): 252 self.__write_code_irq_vector_table(fp) 253 else: 254 self.__log.error("CONFIG_IRQ_VECTOR_TABLE_JUMP_BY_{ADDRESS,CODE} not set") 255 256 if not self.__swt: 257 return 258 259 fp.write("struct _isr_table_entry __sw_isr_table _sw_isr_table[%d] = {\n" 260 % self.__nv) 261 262 level2_offset = self.__config.get_irq_baseoffset(2) 263 level3_offset = self.__config.get_irq_baseoffset(3) 264 265 for i in range(self.__nv): 266 if len(self.__swt[i]) == 0: 267 # Not used interrupt 268 param = "0x0" 269 func = self.__config.swt_spurious_handler 270 elif len(self.__swt[i]) == 1: 271 # Single interrupt 272 param = "{0:#x}".format(self.__swt[i][0][0]) 273 func = self.__swt[i][0][1] 274 else: 275 # Shared interrupt 276 param = "&z_shared_sw_isr_table[{0}]".format(i) 277 func = self.__config.swt_shared_handler 278 279 if isinstance(func, int): 280 func_as_string = "{0:#x}".format(func) 281 else: 282 func_as_string = func 283 284 if level2_offset is not None and i == level2_offset: 285 fp.write("\t/* Level 2 interrupts start here (offset: {}) */\n". 286 format(level2_offset)) 287 if level3_offset is not None and i == level3_offset: 288 fp.write("\t/* Level 3 interrupts start here (offset: {}) */\n". 289 format(level3_offset)) 290 291 fp.write("\t{{(const void *){0}, (ISR){1}}}, /* {2} */\n".format(param, func_as_string, i)) 292 fp.write("};\n") 293