arch: Add support for IRQ vector tables with jump opcodes
The whole mechanism of IRQ table generation is build around the assumption that the IRQ vector table contains an array of addresses the PC will be assigned to when the corresponding interrupt is triggered. While this is correct for the majority of architectures (ARM, RISCV with CLIC in vectored mode, etc...) this is not valid in general (for example RISCV with CLINT/HLINT in vectored mode). In this alternative format for the IRQ vector table, the pc will get assigned by the hardware to the address of the vector table index corresponding to the interrupt ID. From the vector table index, a subsequent jump will occur from there to service the interrupt. This means that the IRQ vector table contains an opcode that is a jump instruction to a specific location instead of the address of the location itself. This patch is introducing support for this alternative IRQ vector table format. The user can now select one format or the other one by acting on IRQ_VECTOR_TABLE_JUMP_BY_ADDRESS or IRQ_VECTOR_TABLE_JUMP_BY_CODE Kconfig symbols. Signed-off-by: Carlo Caione <ccaione@baylibre.com>
This commit is contained in:
parent
e381170282
commit
86a67faeaa
18
arch/Kconfig
18
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
|
||||
|
|
|
@ -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?"
|
||||
|
|
|
@ -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'
|
||||
|
|
Loading…
Reference in a new issue