| #!/usr/bin/env python3 |
| # |
| # Copyright (c) 2017 Intel Corporation |
| # SPDX-License-Identifier: Apache-2.0 |
| # |
| |
| import argparse |
| import struct |
| import sys |
| import os |
| |
| ISR_FLAG_DIRECT = (1 << 0) |
| |
| def debug(text): |
| if not args.debug: |
| return |
| sys.stdout.write(os.path.basename(sys.argv[0]) + ": " + text + "\n") |
| |
| def error(text): |
| sys.stderr.write(os.path.basename(sys.argv[0]) + ": " + text + "\n") |
| raise Exception() |
| |
| def endian_prefix(): |
| if args.big_endian: |
| return ">" |
| else: |
| return "<" |
| |
| def read_intlist(intlist_path): |
| """read a binary file containing the contents of the kernel's .intList |
| section. This is an instance of a header created by |
| include/linker/intlist.ld: |
| |
| struct { |
| void * spurious_irq_handler; |
| void * sw_irq_handler; |
| u32_t num_isrs; |
| u32_t num_vectors; <- typically CONFIG_NUM_IRQS |
| struct _isr_list isrs[]; <- of size num_isrs |
| } |
| |
| Followed by instances of struct _isr_list created by IRQ_CONNECT() |
| calls: |
| |
| struct _isr_list { |
| /** IRQ line number */ |
| s32_t irq; |
| /** Flags for this IRQ, see ISR_FLAG_* definitions */ |
| s32_t flags; |
| /** ISR to call */ |
| void *func; |
| /** Parameter for non-direct IRQs */ |
| void *param; |
| }; |
| """ |
| |
| intlist = {} |
| |
| prefix = endian_prefix() |
| |
| intlist_header_fmt = prefix + "IIIII" |
| intlist_entry_fmt = prefix + "iiII" |
| |
| with open(intlist_path, "rb") as fp: |
| intdata = fp.read() |
| |
| header_sz = struct.calcsize(intlist_header_fmt) |
| header = struct.unpack_from(intlist_header_fmt, intdata, 0) |
| intdata = intdata[header_sz:] |
| |
| debug(str(header)) |
| |
| intlist["spurious_handler"] = header[0] |
| intlist["sw_irq_handler"] = header[1] |
| intlist["num_vectors"] = header[2] |
| intlist["offset"] = header[3] |
| intlist["num_isrs"] = header[4] |
| |
| debug("spurious handler: %s" % hex(header[0])) |
| |
| intlist["interrupts"] = [i for i in |
| struct.iter_unpack(intlist_entry_fmt, intdata)] |
| |
| debug("Configured interrupt routing") |
| debug("handler irq flags param") |
| debug("--------------------------") |
| |
| for irq in intlist["interrupts"]: |
| debug("{0:<10} {1:<3} {2:<3} {3}".format( |
| hex(irq[2]), irq[0], irq[1], hex(irq[3]))) |
| |
| return intlist |
| |
| |
| def parse_args(): |
| global args |
| |
| parser = argparse.ArgumentParser(description = __doc__, |
| formatter_class = argparse.RawDescriptionHelpFormatter) |
| |
| parser.add_argument("-e", "--big-endian", action="store_true", |
| help="Target encodes data in big-endian format (little endian is " |
| "the default)") |
| parser.add_argument("-d", "--debug", action="store_true", |
| help="Print additional debugging information") |
| parser.add_argument("-o", "--output-source", required=True, |
| help="Output source file") |
| parser.add_argument("-s", "--sw-isr-table", action="store_true", |
| help="Generate SW ISR table") |
| parser.add_argument("-V", "--vector-table", action="store_true", |
| help="Generate vector table") |
| parser.add_argument("-i", "--intlist", required=True, |
| help="Zephyr intlist binary for intList extraction") |
| |
| args = parser.parse_args() |
| |
| source_header = """ |
| /* AUTO-GENERATED by gen_isr_tables.py, do not edit! */ |
| |
| #include <toolchain.h> |
| #include <linker/sections.h> |
| #include <sw_isr_table.h> |
| |
| """ |
| |
| def write_source_file(fp, vt, swt, intlist): |
| fp.write(source_header) |
| |
| nv = intlist["num_vectors"] |
| |
| if vt: |
| fp.write("u32_t __irq_vector_table _irq_vector_table[%d] = {\n" % nv) |
| for i in range(nv): |
| fp.write("\t0x%x,\n" % vt[i]) |
| fp.write("};\n") |
| |
| if not swt: |
| return |
| |
| fp.write("struct _isr_table_entry __sw_isr_table _sw_isr_table[%d] = {\n" |
| % nv) |
| for i in range(nv): |
| param, func = swt[i] |
| fp.write("\t{(void *)0x%x, (void *)0x%x},\n" % (param, func)) |
| fp.write("};\n") |
| |
| def main(): |
| parse_args() |
| |
| intlist = read_intlist(args.intlist) |
| nvec = intlist["num_vectors"] |
| offset = intlist["offset"] |
| prefix = endian_prefix() |
| |
| # Set default entries in both tables |
| if args.sw_isr_table: |
| # All vectors just jump to the common sw_irq_handler. If some entries |
| # are used for direct interrupts, they will be replaced later. |
| if args.vector_table: |
| vt = [intlist["sw_irq_handler"] for i in range(nvec)] |
| else: |
| vt = None |
| # Default to spurious interrupt handler. Configured interrupts |
| # will replace these entries. |
| swt = [(0, intlist["spurious_handler"]) for i in range(nvec)] |
| else: |
| if args.vector_table: |
| vt = [intlist["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 |
| |
| for irq, flags, func, param in intlist["interrupts"]: |
| if (flags & ISR_FLAG_DIRECT): |
| if (param != 0): |
| error("Direct irq %d declared, but has non-NULL parameter" |
| % irq) |
| vt[irq - offset] = func |
| else: |
| # Regular interrupt |
| if not swt: |
| error("Regular Interrupt %d declared with parameter 0x%x " |
| "but no SW ISR_TABLE in use" |
| % (irq, param)) |
| swt[irq - offset] = (param, func) |
| |
| with open(args.output_source, "w") as fp: |
| write_source_file(fp, vt, swt, intlist) |
| |
| if __name__ == "__main__": |
| main() |
| |