From 13638a03519db634c519a6511b9719f6d6f6b674 Mon Sep 17 00:00:00 2001 From: Radoslaw Koppel Date: Tue, 17 Oct 2023 17:41:17 +0200 Subject: [PATCH] arch: sw_isr_table: Implement local interrupt table entry creation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit implements the possibility to locally create an interrupt table entry. This changes the way interrput table is created, now it should not be created as an source file but rather it would be constructed by the linker. Signed-off-by: Radosław Koppel --- arch/Kconfig | 23 +++++++ include/zephyr/sw_isr_table.h | 114 ++++++++++++++++++++++++++++++++++ 2 files changed, 137 insertions(+) diff --git a/arch/Kconfig b/arch/Kconfig index b8661fa5964..39800a1b7b7 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -391,6 +391,29 @@ config NOCACHE_MEMORY menu "Interrupt Configuration" +config ISR_TABLES_LOCAL_DECLARATION_SUPPORTED + bool + default y + # Userspace is currently not supported + depends on !USERSPACE + # List of currently supported architectures + depends on ARM || ARM64 + # List of currently supported toolchains + depends on "$(ZEPHYR_TOOLCHAIN_VARIANT)" = "zephyr" || "$(ZEPHYR_TOOLCHAIN_VARIANT)" = "gnuarmemb" + +config ISR_TABLES_LOCAL_DECLARATION + bool "ISR tables created locally and placed by linker [EXPERIMENTAL]" + depends on ISR_TABLES_LOCAL_DECLARATION_SUPPORTED + select EXPERIMENTAL + help + Enable new scheme of interrupt tables generation. + This is totally different generator that would create tables entries locally + where the IRQ_CONNECT macro is called and then use the linker script to position it + in the right place in memory. + The most important advantage of such approach is that the generated interrupt tables + are LTO compatible. + The drawback is that the support on the architecture port is required. + config DYNAMIC_INTERRUPTS bool "Installation of IRQs at runtime" help diff --git a/include/zephyr/sw_isr_table.h b/include/zephyr/sw_isr_table.h index fc094b887ba..7b1bfddb2cb 100644 --- a/include/zephyr/sw_isr_table.h +++ b/include/zephyr/sw_isr_table.h @@ -18,6 +18,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { @@ -56,6 +57,9 @@ struct _irq_parent_entry { * uses it to create the IRQ vector table and the _sw_isr_table. * * More discussion in include/linker/intlist.ld + * + * This is a version used when CONFIG_ISR_TABLES_LOCAL_DECLARATION is disabled. + * See _isr_list_sname used otherwise. */ struct _isr_list { /** IRQ line number */ @@ -68,6 +72,24 @@ struct _isr_list { const void *param; }; +/* + * Data structure created in a special binary .intlist section for each + * configured interrupt. gen_isr_tables.py pulls this out of the binary and + * uses it to create linker script chunks that would place interrupt table entries + * in the right place in the memory. + * + * This is a version used when CONFIG_ISR_TABLES_LOCAL_DECLARATION is enabled. + * See _isr_list used otherwise. + */ +struct _isr_list_sname { + /** IRQ line number */ + int32_t irq; + /** Flags for this IRQ, see ISR_FLAG_* definitions */ + int32_t flags; + /** The section name */ + const char sname[]; +}; + #ifdef CONFIG_SHARED_INTERRUPTS struct z_shared_isr_table_entry { struct _isr_table_entry clients[CONFIG_SHARED_IRQ_MAX_NUM_CLIENTS]; @@ -85,6 +107,90 @@ extern struct z_shared_isr_table_entry z_shared_sw_isr_table[]; #define _MK_ISR_NAME(x, y) __MK_ISR_NAME(x, y) #define __MK_ISR_NAME(x, y) __isr_ ## x ## _irq_ ## y + +#if IS_ENABLED(CONFIG_ISR_TABLES_LOCAL_DECLARATION) + +#define _MK_ISR_ELEMENT_NAME(func, id) __MK_ISR_ELEMENT_NAME(func, id) +#define __MK_ISR_ELEMENT_NAME(func, id) __isr_table_entry_ ## func ## _irq_ ## id + +#define _MK_IRQ_ELEMENT_NAME(func, id) __MK_ISR_ELEMENT_NAME(func, id) +#define __MK_IRQ_ELEMENT_NAME(func, id) __irq_table_entry_ ## func ## _irq_ ## id + +#define _MK_ISR_SECTION_NAME(prefix, file, counter) \ + "." Z_STRINGIFY(prefix)"."file"." Z_STRINGIFY(counter) + +#define _MK_ISR_ELEMENT_SECTION(counter) _MK_ISR_SECTION_NAME(irq, __FILE__, counter) +#define _MK_IRQ_ELEMENT_SECTION(counter) _MK_ISR_SECTION_NAME(isr, __FILE__, counter) + +/* Separated macro to create ISR table entry only. + * Used by Z_ISR_DECLARE and ISR tables generation script. + */ +#define _Z_ISR_TABLE_ENTRY(irq, func, param, sect) \ + static Z_DECL_ALIGN(struct _isr_table_entry) \ + __attribute__((section(sect))) \ + __used _MK_ISR_ELEMENT_NAME(func, __COUNTER__) = { \ + .arg = (const void *)(param), \ + .isr = (void (*)(const void *))(void *)(func) \ + } + +#define Z_ISR_DECLARE_C(irq, flags, func, param, counter) \ + _Z_ISR_DECLARE_C(irq, flags, func, param, counter) + +#define _Z_ISR_DECLARE_C(irq, flags, func, param, counter) \ + _Z_ISR_TABLE_ENTRY(irq, func, param, _MK_ISR_ELEMENT_SECTION(counter)); \ + static struct _isr_list_sname Z_GENERIC_SECTION(.intList) \ + __used _MK_ISR_NAME(func, counter) = \ + {irq, flags, _MK_ISR_ELEMENT_SECTION(counter)} + +/* Create an entry for _isr_table to be then placed by the linker. + * An instance of struct _isr_list which gets put in the .intList + * section is created with the name of the section where _isr_table entry is placed to be then + * used by isr generation script to create linker script chunk. + */ +#define Z_ISR_DECLARE(irq, flags, func, param) \ + BUILD_ASSERT(((flags) & ISR_FLAG_DIRECT) == 0, "Use Z_ISR_DECLARE_DIRECT macro"); \ + Z_ISR_DECLARE_C(irq, flags, func, param, __COUNTER__) + + +/* Separated macro to create ISR Direct table entry only. + * Used by Z_ISR_DECLARE_DIRECT and ISR tables generation script. + */ +#define _Z_ISR_DIRECT_TABLE_ENTRY(irq, func, sect) \ + COND_CODE_1(CONFIG_IRQ_VECTOR_TABLE_JUMP_BY_ADDRESS, ( \ + static Z_DECL_ALIGN(uintptr_t) \ + __attribute__((section(sect))) \ + __used _MK_IRQ_ELEMENT_NAME(func, __COUNTER__) = ((uintptr_t)(func)); \ + ), ( \ + static void __attribute__((section(sect))) __attribute__((naked)) \ + __used _MK_IRQ_ELEMENT_NAME(func, __COUNTER__)(void) { \ + __asm(ARCH_IRQ_VECTOR_JUMP_CODE(func)); \ + } \ + )) + +#define Z_ISR_DECLARE_DIRECT_C(irq, flags, func, counter) \ + _Z_ISR_DECLARE_DIRECT_C(irq, flags, func, counter) + +#define _Z_ISR_DECLARE_DIRECT_C(irq, flags, func, counter) \ + _Z_ISR_DIRECT_TABLE_ENTRY(irq, func, _MK_IRQ_ELEMENT_SECTION(counter)); \ + static struct _isr_list_sname Z_GENERIC_SECTION(.intList) \ + __used _MK_ISR_NAME(func, counter) = { \ + irq, \ + ISR_FLAG_DIRECT | (flags), \ + _MK_IRQ_ELEMENT_SECTION(counter)} + +/* Create an entry to irq table and place it in specific section which name is then placed + * in an instance of struct _isr_list to be then used by the isr generation script to create + * the linker script chunks. + */ +#define Z_ISR_DECLARE_DIRECT(irq, flags, func) \ + BUILD_ASSERT(IS_ENABLED(CONFIG_IRQ_VECTOR_TABLE_JUMP_BY_ADDRESS) || \ + IS_ENABLED(CONFIG_IRQ_VECTOR_TABLE_JUMP_BY_CODE), \ + "CONFIG_IRQ_VECTOR_TABLE_JUMP_BY_{ADDRESS,CODE} not set"); \ + Z_ISR_DECLARE_DIRECT_C(irq, flags, func, __COUNTER__) + + +#else /* IS_ENABLED(CONFIG_ISR_TABLES_LOCAL_DECLARATION) */ + /* Create an instance of struct _isr_list which gets put in the .intList * section. This gets consumed by gen_isr_tables.py which creates the vector * and/or SW ISR tables. @@ -94,6 +200,14 @@ extern struct z_shared_isr_table_entry z_shared_sw_isr_table[]; __used _MK_ISR_NAME(func, __COUNTER__) = \ {irq, flags, (void *)&func, (const void *)param} +/* The version of the Z_ISR_DECLARE that should be used for direct ISR declaration. + * It is here for the API match the version with CONFIG_ISR_TABLES_LOCAL_DECLARATION enabled. + */ +#define Z_ISR_DECLARE_DIRECT(irq, flags, func) \ + Z_ISR_DECLARE(irq, ISR_FLAG_DIRECT | (flags), func, NULL) + +#endif + #define IRQ_TABLE_SIZE (CONFIG_NUM_IRQS - CONFIG_GEN_IRQ_START_VECTOR) #ifdef CONFIG_DYNAMIC_INTERRUPTS