diff --git a/arch/Kconfig b/arch/Kconfig index b21206a9b57..91388ade3f3 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -418,6 +418,24 @@ config ARCH_IRQ_VECTOR_TABLE_ALIGN to be aligned to architecture specific size. The default size is 0 for no alignment. +choice IRQ_VECTOR_TABLE_TYPE + prompt "IRQ vector table type" + depends on GEN_IRQ_VECTOR_TABLE + default IRQ_VECTOR_TABLE_JUMP_BY_ADDRESS + +config IRQ_VECTOR_TABLE_JUMP_BY_ADDRESS + bool "Jump by address" + help + The IRQ vector table contains the address of the interrupt handler. + +config IRQ_VECTOR_TABLE_JUMP_BY_CODE + bool "Jump by code" + help + The IRQ vector table contains the opcode of a jump instruction to the + interrupt handler address. + +endchoice + config GEN_SW_ISR_TABLE bool "Generate a software ISR table" default y diff --git a/arch/common/gen_isr_tables.py b/arch/common/gen_isr_tables.py index 532e8ba2d4e..92b2833628c 100755 --- a/arch/common/gen_isr_tables.py +++ b/arch/common/gen_isr_tables.py @@ -125,6 +125,45 @@ def parse_args(): args = parser.parse_args() +source_assembly_header = """ +#ifndef ARCH_IRQ_VECTOR_JUMP_CODE +#error "ARCH_IRQ_VECTOR_JUMP_CODE not defined" +#endif +""" + +def get_symbol_from_addr(syms, addr): + for key, value in syms.items(): + if addr == value: + return key + return None + +def write_code_irq_vector_table(fp, vt, nv, syms): + fp.write(source_assembly_header) + + fp.write("void __irq_vector_table __attribute__((naked)) _irq_vector_table(void) {\n") + for i in range(nv): + func = vt[i] + + if isinstance(func, int): + func_as_string = get_symbol_from_addr(syms, func) + else: + func_as_string = func + + fp.write("\t__asm(ARCH_IRQ_VECTOR_JUMP_CODE({}));\n".format(func_as_string)) + fp.write("}\n") + +def write_address_irq_vector_table(fp, vt, nv): + fp.write("uintptr_t __irq_vector_table _irq_vector_table[%d] = {\n" % nv) + for i in range(nv): + func = vt[i] + + if isinstance(func, int): + fp.write("\t{},\n".format(vt[i])) + else: + fp.write("\t((uintptr_t)&{}),\n".format(vt[i])) + + fp.write("};\n") + source_header = """ /* AUTO-GENERATED by gen_isr_tables.py, do not edit! */ @@ -142,10 +181,12 @@ def write_source_file(fp, vt, swt, intlist, syms): nv = intlist["num_vectors"] if vt: - fp.write("uintptr_t __irq_vector_table _irq_vector_table[%d] = {\n" % nv) - for i in range(nv): - fp.write("\t{},\n".format(vt[i])) - fp.write("};\n") + if "CONFIG_IRQ_VECTOR_TABLE_JUMP_BY_ADDRESS" in syms: + write_address_irq_vector_table(fp, vt, nv) + elif "CONFIG_IRQ_VECTOR_TABLE_JUMP_BY_CODE" in syms: + write_code_irq_vector_table(fp, vt, nv, syms) + else: + error("CONFIG_IRQ_VECTOR_TABLE_JUMP_BY_{ADDRESS,CODE} not set") if not swt: return @@ -224,26 +265,27 @@ def main(): if nvec > pow(2, 15): raise ValueError('nvec is too large, check endianness.') - spurious_handler = "((uintptr_t)&z_irq_spurious)" - sw_irq_handler = "((uintptr_t)&_isr_wrapper)" + swt_spurious_handler = "((uintptr_t)&z_irq_spurious)" + vt_spurious_handler = "z_irq_spurious" + vt_irq_handler = "_isr_wrapper" debug('offset is ' + str(offset)) debug('num_vectors is ' + str(nvec)) # Set default entries in both tables if args.sw_isr_table: - # All vectors just jump to the common sw_irq_handler. If some entries + # All vectors just jump to the common vt_irq_handler. If some entries # are used for direct interrupts, they will be replaced later. if args.vector_table: - vt = [sw_irq_handler for i in range(nvec)] + vt = [vt_irq_handler for i in range(nvec)] else: vt = None # Default to spurious interrupt handler. Configured interrupts # will replace these entries. - swt = [(0, spurious_handler) for i in range(nvec)] + swt = [(0, swt_spurious_handler) for i in range(nvec)] else: if args.vector_table: - vt = [spurious_handler for i in range(nvec)] + vt = [vt_spurious_handler for i in range(nvec)] else: error("one or both of -s or -V needs to be specified on command line") swt = None @@ -302,7 +344,7 @@ def main(): if not 0 <= table_index < len(swt): error("IRQ %d (offset=%d) exceeds the maximum of %d" % (table_index, offset, len(swt) - 1)) - if swt[table_index] != (0, spurious_handler): + if swt[table_index] != (0, swt_spurious_handler): error(f"multiple registrations at table_index {table_index} for irq {irq} (0x{irq:x})" + f"\nExisting handler 0x{swt[table_index][1]:x}, new handler 0x{func:x}" + "\nHas IRQ_CONNECT or IRQ_DIRECT_CONNECT accidentally been invoked on the same irq multiple times?" diff --git a/arch/common/isr_tables.c b/arch/common/isr_tables.c index f8084f98079..a22776f8edb 100644 --- a/arch/common/isr_tables.c +++ b/arch/common/isr_tables.c @@ -50,9 +50,26 @@ Z_GENERIC_SECTION(.irq_info) struct int_list_header _iheader = { #define IRQ_VECTOR_TABLE_DEFAULT_ISR z_irq_spurious #endif /* CONFIG_GEN_SW_ISR_TABLE */ +#ifdef CONFIG_IRQ_VECTOR_TABLE_JUMP_BY_CODE + +/* Assembly code for a jump instruction. Must be set by the architecture. */ +#ifndef ARCH_IRQ_VECTOR_JUMP_CODE +#error "ARCH_IRQ_VECTOR_JUMP_CODE not defined" +#endif + +#define BUILD_VECTOR(n, _) __asm(ARCH_IRQ_VECTOR_JUMP_CODE(IRQ_VECTOR_TABLE_DEFAULT_ISR)) + +/* The IRQ vector table contains the jump opcodes towards the vector routine */ +void __irq_vector_table __attribute__((naked)) _irq_vector_table(void) { + LISTIFY(CONFIG_NUM_IRQS, BUILD_VECTOR, (;)); +}; +#else + +/* The IRQ vector table is an array of vector addresses */ uintptr_t __irq_vector_table _irq_vector_table[IRQ_TABLE_SIZE] = { [0 ...(IRQ_TABLE_SIZE - 1)] = (uintptr_t)&IRQ_VECTOR_TABLE_DEFAULT_ISR, }; +#endif /* CONFIG_IRQ_VECTOR_TABLE_JUMP_BY_CODE */ #endif /* CONFIG_GEN_IRQ_VECTOR_TABLE */ /* If there are no interrupts at all, or all interrupts are of the 'direct'